Skip to content

Commit 08aa9af

Browse files
authored
Merge pull request #20670 from mberhault/marc/add_key_manager
libroach: add key manager
2 parents a91ebbf + 5202bdf commit 08aa9af

File tree

20 files changed

+523
-34
lines changed

20 files changed

+523
-34
lines changed

Makefile

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ build/variables.mk: Makefile build/archive/contents/Makefile $(UI_ROOT)/Makefile
391391
# common because both the root Makefile and protobuf.mk have C dependencies.
392392

393393
C_DEPS_DIR := $(abspath c-deps)
394+
CRYPTOPP_SRC_DIR := $(C_DEPS_DIR)/cryptopp
394395
JEMALLOC_SRC_DIR := $(C_DEPS_DIR)/jemalloc
395396
PROTOBUF_SRC_DIR := $(C_DEPS_DIR)/protobuf
396397
ROCKSDB_SRC_DIR := $(C_DEPS_DIR)/rocksdb
@@ -459,6 +460,7 @@ ifdef MINGW
459460
BUILD_DIR := $(shell cygpath -m $(BUILD_DIR))
460461
endif
461462

463+
CRYPTOPP_DIR := $(BUILD_DIR)/cryptopp
462464
JEMALLOC_DIR := $(BUILD_DIR)/jemalloc
463465
PROTOBUF_DIR := $(BUILD_DIR)/protobuf
464466
ROCKSDB_DIR := $(BUILD_DIR)/rocksdb$(STDMALLOC_SUFFIX)$(if $(ENABLE_ROCKSDB_ASSERTIONS),_assert)
@@ -469,7 +471,7 @@ PROTOC_DIR := $(GOPATH)/native/$(HOST_TRIPLE)/protobuf
469471
PROTOC := $(PROTOC_DIR)/protoc
470472

471473
C_LIBS_OSS = $(if $(USE_STDMALLOC),,libjemalloc) libprotobuf libsnappy librocksdb libroach
472-
C_LIBS_CCL = $(C_LIBS_OSS) libroachccl
474+
C_LIBS_CCL = $(C_LIBS_OSS) libcryptopp libroachccl
473475

474476
# Go does not permit dashes in build tags. This is undocumented. Fun!
475477
NATIVE_SPECIFIER_TAG := $(subst -,_,$(NATIVE_SPECIFIER))$(STDMALLOC_SUFFIX)
@@ -510,7 +512,7 @@ $(CGO_FLAGS_FILES): Makefile
510512
@echo 'package $(notdir $(@D))' >> $@
511513
@echo >> $@
512514
@echo '// #cgo CPPFLAGS: -I$(JEMALLOC_DIR)/include' >> $@
513-
@echo '// #cgo LDFLAGS: $(addprefix -L,$(PROTOBUF_DIR) $(JEMALLOC_DIR)/lib $(SNAPPY_DIR) $(ROCKSDB_DIR) $(LIBROACH_DIR))' >> $@
515+
@echo '// #cgo LDFLAGS: $(addprefix -L,$(CRYPTOPP_DIR) $(PROTOBUF_DIR) $(JEMALLOC_DIR)/lib $(SNAPPY_DIR) $(ROCKSDB_DIR) $(LIBROACH_DIR))' >> $@
514516
@echo 'import "C"' >> $@
515517

516518
# BUILD ARTIFACT CACHING
@@ -532,6 +534,12 @@ $(CGO_FLAGS_FILES): Makefile
532534
# only rebuild the affected objects, but in practice dependencies on configure
533535
# flags are not tracked correctly, and these stale artifacts can cause
534536
# particularly hard-to-debug errors.
537+
$(CRYPTOPP_DIR)/Makefile: $(C_DEPS_DIR)/cryptopp-rebuild $(BOOTSTRAP_TARGET)
538+
rm -rf $(CRYPTOPP_DIR)
539+
mkdir -p $(CRYPTOPP_DIR)
540+
@# NOTE: If you change the CMake flags below, bump the version in
541+
@# $(C_DEPS_DIR)/cryptopp-rebuild. See above for rationale.
542+
cd $(CRYPTOPP_DIR) && cmake $(CMAKE_FLAGS) $(CRYPTOPP_SRC_DIR)
535543

536544
$(JEMALLOC_SRC_DIR)/configure.ac: $(BOOTSTRAP_TARGET)
537545

@@ -591,7 +599,8 @@ $(LIBROACH_DIR)/Makefile: $(C_DEPS_DIR)/libroach-rebuild $(BOOTSTRAP_TARGET)
591599
@# $(C_DEPS_DIR)/libroach-rebuild. See above for rationale.
592600
cd $(LIBROACH_DIR) && cmake $(CMAKE_FLAGS) $(LIBROACH_SRC_DIR) -DCMAKE_BUILD_TYPE=Release \
593601
-DPROTOBUF_LIB=$(PROTOBUF_DIR)/libprotobuf.a -DROCKSDB_LIB=$(ROCKSDB_DIR)/librocksdb.a \
594-
-DJEMALLOC_LIB=$(JEMALLOC_DIR)/lib/libjemalloc.a -DSNAPPY_LIB=$(SNAPPY_DIR)/libsnappy.a
602+
-DJEMALLOC_LIB=$(JEMALLOC_DIR)/lib/libjemalloc.a -DSNAPPY_LIB=$(SNAPPY_DIR)/libsnappy.a \
603+
-DCRYPTOPP_LIB=$(CRYPTOPP_DIR)/libcryptopp.a
595604

596605
# We mark C and C++ dependencies as .PHONY (or .ALWAYS_REBUILD) to avoid
597606
# having to name the artifact (for .PHONY), which can vary by platform, and so
@@ -602,6 +611,10 @@ $(LIBROACH_DIR)/Makefile: $(C_DEPS_DIR)/libroach-rebuild $(BOOTSTRAP_TARGET)
602611
$(PROTOC): $(PROTOC_DIR)/Makefile .ALWAYS_REBUILD | libprotobuf
603612
@$(MAKE) --no-print-directory -C $(PROTOC_DIR) protoc
604613

614+
.PHONY: libcryptopp
615+
libcryptopp: $(CRYPTOPP_DIR)/Makefile
616+
@$(MAKE) --no-print-directory -C $(CRYPTOPP_DIR) static
617+
605618
.PHONY: libjemalloc
606619
libjemalloc: $(JEMALLOC_DIR)/Makefile
607620
@$(MAKE) --no-print-directory -C $(JEMALLOC_DIR) build_lib_static
@@ -627,7 +640,7 @@ libroachccl: $(LIBROACH_DIR)/Makefile $(CPP_PROTOS_CCL_TARGET) libroach
627640
@$(MAKE) --no-print-directory -C $(LIBROACH_DIR) roachccl
628641

629642
PHONY: check-libroach
630-
check-libroach: $(LIBROACH_DIR)/Makefile libjemalloc libprotobuf libsnappy librocksdb
643+
check-libroach: $(LIBROACH_DIR)/Makefile libjemalloc libprotobuf libsnappy librocksdb libcryptopp
631644
@$(MAKE) --no-print-directory -C $(LIBROACH_DIR) check
632645

633646
override TAGS += make $(NATIVE_SPECIFIER_TAG)
@@ -1143,13 +1156,15 @@ c-deps-fmt: $(shell find $(LIBROACH_SRC_DIR) \( -name '*.cc' -o -name '*.h' \) -
11431156

11441157
.PHONY: clean-c-deps
11451158
clean-c-deps:
1159+
rm -rf $(CRYPTOPP_DIR)
11461160
rm -rf $(JEMALLOC_DIR)
11471161
rm -rf $(PROTOBUF_DIR)
11481162
rm -rf $(ROCKSDB_DIR)
11491163
rm -rf $(SNAPPY_DIR)
11501164

11511165
.PHONY: unsafe-clean-c-deps
11521166
unsafe-clean-c-deps:
1167+
git -C $(CRYPTOPP_SRC_DIR) clean -dxf
11531168
git -C $(JEMALLOC_SRC_DIR) clean -dxf
11541169
git -C $(PROTOBUF_SRC_DIR) clean -dxf
11551170
git -C $(ROCKSDB_SRC_DIR) clean -dxf

build/variables.mk

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ define VALID_VARS
3636
CPP_PROTO_ROOT
3737
CPP_SOURCES
3838
CPP_SOURCES_CCL
39+
CRYPTOPP_DIR
40+
CRYPTOPP_SRC_DIR
3941
CXX_PATH
4042
C_DEPS_DIR
4143
C_LIBS_CCL

c-deps/cryptopp-rebuild

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Bump the version below when changing cryptopp configure flags. Search for "BUILD
2+
ARTIFACT CACHING" in build/common.mk for rationale.
3+
4+
1

c-deps/libroach-rebuild

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
Bump the version below when changing libroach CMake flags. Search for "BUILD
22
ARTIFACT CACHING" in build/common.mk for rationale.
33

4-
1
4+
2

c-deps/libroach/CMakeLists.txt

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,22 @@ add_library(roach
3939
)
4040
target_include_directories(roach
4141
PUBLIC ./include
42-
PRIVATE ../protobuf/src ../rocksdb/include protos
42+
PRIVATE ../protobuf/src
43+
PRIVATE ../rocksdb/include
44+
PRIVATE protos
4345
)
4446

4547
add_library(roachccl
4648
ccl/db.cc
49+
ccl/key.cc
50+
ccl/key_manager.cc
4751
protosccl/ccl/baseccl/encryption_options.pb.cc
4852
)
4953
target_include_directories(roachccl
54+
PRIVATE .. # CryptoPP headers are directly in the directory. Include .. to be able to include <cryptopp/....h>
55+
PRIVATE ../protobuf/src
5056
PRIVATE ../rocksdb/include
51-
PRIVATE ../protobuf/src protosccl
57+
PRIVATE protosccl
5258
)
5359
target_link_libraries(roachccl roach)
5460

@@ -67,6 +73,7 @@ set(tests
6773
db_test.cc
6874
encoding_test.cc
6975
ccl/db_test.cc
76+
ccl/key_manager_test.cc
7077
)
7178

7279
# "test" doesn't depend on the actual tests. Let's add a "check" target
@@ -92,20 +99,34 @@ foreach(tsrc ${tests})
9299
endif()
93100

94101
# Add a new executable and set includes/libraries/properties.
95-
add_executable(${tname} ${tsrc})
102+
add_executable(${tname} ${tsrc} testutils.cc)
96103
target_include_directories(${tname}
97104
PRIVATE ../googletest/googletest/include
98-
PRIVATE ../rocksdb/include
99105
PRIVATE ../protobuf/src
106+
PRIVATE ../rocksdb/include
100107
)
101108

102-
# Link `ccl/` tests against roachccl.
109+
# Link `ccl/` tests against roachccl and CryptoPP.
103110
if(${tsrc} MATCHES "^ccl/")
104-
target_link_libraries(${tname} roachccl)
111+
target_link_libraries(${tname}
112+
roachccl
113+
${CRYPTOPP_LIB}
114+
)
115+
target_include_directories(${tname}
116+
PRIVATE ../cryptopp
117+
)
105118
endif()
106119

107120
# Add all other libraries.
108-
target_link_libraries(${tname} roach ${PROTOBUF_LIB} ${ROCKSDB_LIB} ${SNAPPY_LIB} ${JEMALLOC_LIB} gtest_main pthread)
121+
target_link_libraries(${tname}
122+
roach
123+
gtest_main
124+
pthread
125+
${ROCKSDB_LIB}
126+
${PROTOBUF_LIB}
127+
${JEMALLOC_LIB}
128+
${SNAPPY_LIB}
129+
)
109130

110131
set_target_properties(${tname} PROPERTIES
111132
CXX_STANDARD 11

c-deps/libroach/ccl/db.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <rocksdb/utilities/write_batch_with_index.h>
1616
#include <rocksdb/write_batch.h>
1717
#include "../protosccl/ccl/baseccl/encryption_options.pb.h"
18+
#include "key_manager.h"
1819

1920
const DBStatus kSuccess = {NULL, 0};
2021

@@ -37,6 +38,14 @@ rocksdb::Status parse_extra_options(const DBSlice s) {
3738
<< " old key: " << opts.key_files().old_key() << "\n"
3839
<< " rotation duration: " << opts.data_key_rotation_period() << "\n";
3940

41+
std::shared_ptr<FileKeyManager> key_manager(
42+
new FileKeyManager(rocksdb::Env::Default(), opts.key_files().current_key(), opts.key_files().old_key()));
43+
44+
rocksdb::Status status = key_manager->LoadKeys();
45+
if (!status.ok()) {
46+
return status;
47+
}
48+
4049
return rocksdb::Status::InvalidArgument("encryption is not supported");
4150
}
4251

c-deps/libroach/ccl/db_test.cc

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
1-
#include <gtest/gtest.h>
1+
// Copyright 2017 The Cockroach Authors.
2+
//
3+
// Licensed as a CockroachDB Enterprise file under the Cockroach Community
4+
// License (the "License"); you may not use this file except in compliance with
5+
// the License. You may obtain a copy of the License at
6+
//
7+
// https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt
8+
29
#include "../db.h"
10+
#include "../testutils.h"
311

412
TEST(LibroachCCL, DBOpenHook) {
513
DBOptions db_opts;
614

715
// Try an empty extra_options.
816
db_opts.extra_options = ToDBSlice("");
9-
EXPECT_TRUE(DBOpenHook(db_opts).ok());
17+
EXPECT_OK(DBOpenHook(db_opts));
1018

1119
// Try extra_options with bad data.
1220
db_opts.extra_options = ToDBSlice("blah");
13-
EXPECT_STREQ("failed to parse extra options", DBOpenHook(db_opts).getState());
21+
EXPECT_ERR(DBOpenHook(db_opts), "failed to parse extra options");
1422
}

c-deps/libroach/ccl/key.cc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2017 The Cockroach Authors.
2+
//
3+
// Licensed as a CockroachDB Enterprise file under the Cockroach Community
4+
// License (the "License"); you may not use this file except in compliance with
5+
// the License. You may obtain a copy of the License at
6+
//
7+
// https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt
8+
9+
#include "key.h"
10+
#include <cryptopp/filters.h>
11+
#include <cryptopp/hex.h>
12+
#include <cryptopp/sha.h>
13+
14+
std::string KeyHash(const std::string& k) {
15+
std::string value;
16+
CryptoPP::SHA256 hash;
17+
18+
CryptoPP::StringSource ss(
19+
k, true /* PumpAll */,
20+
new CryptoPP::HashFilter(hash, new CryptoPP::HexEncoder(new CryptoPP::StringSink(value), false /* uppercase */)));
21+
22+
return value;
23+
}

c-deps/libroach/ccl/key.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2017 The Cockroach Authors.
2+
//
3+
// Licensed as a CockroachDB Enterprise file under the Cockroach Community
4+
// License (the "License"); you may not use this file except in compliance with
5+
// the License. You may obtain a copy of the License at
6+
//
7+
// https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt
8+
9+
#pragma once
10+
11+
#include <string>
12+
13+
typedef std::string KeyID;
14+
typedef std::string RawKey;
15+
16+
enum EncryptionType { PLAIN, AES };
17+
18+
// EncryptionKey represents a key: type (PLAIN or AES) and actual key contents.
19+
// TODO(mberhault): we would like to be able to mlock and madvise(MADV_DONTDUMP) the
20+
// memory handling keys. This includes the permanent EncryptionKey and any temporary
21+
// buffers (eg: when reading files).
22+
struct EncryptionKey {
23+
EncryptionType type;
24+
// The Key ID is a sha-256 hash of the key contents. It is lowercase, without groupings or terminator.
25+
// **WARNING**: the key ID is persisted to disk, do not change the format.
26+
KeyID id;
27+
RawKey key;
28+
// source describes the source of the key. This could be a filename or
29+
// simply a description of the generator (eg: "data key manager").
30+
std::string source;
31+
};
32+
33+
// KeyHash returns the sha-256 hash of the string. Returned value is in hexadecimal format.
34+
std::string KeyHash(const std::string& k);

c-deps/libroach/ccl/key_manager.cc

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2017 The Cockroach Authors.
2+
//
3+
// Licensed as a CockroachDB Enterprise file under the Cockroach Community
4+
// License (the "License"); you may not use this file except in compliance with
5+
// the License. You may obtain a copy of the License at
6+
//
7+
// https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt
8+
9+
#include "key_manager.h"
10+
#include <cryptopp/modes.h>
11+
#include <google/protobuf/stubs/stringprintf.h>
12+
#include "../fmt.h"
13+
14+
static std::string kFilenamePlain = "plain";
15+
16+
static rocksdb::Status KeyFromFile(rocksdb::Env* env, const std::string& path, EncryptionKey* key) {
17+
if (path == kFilenamePlain) {
18+
// plaintext placeholder.
19+
key->type = PLAIN;
20+
key->id = "";
21+
key->key = "";
22+
key->source = kFilenamePlain;
23+
return rocksdb::Status::OK();
24+
}
25+
26+
// Real file, try to read it.
27+
std::string contents;
28+
auto status = rocksdb::ReadFileToString(env, path, &contents);
29+
if (!status.ok()) {
30+
return status;
31+
}
32+
33+
// Check that the length is valid for AES.
34+
auto key_length = contents.size();
35+
if (key_length != 16 && key_length != 24 && key_length != 32) {
36+
return rocksdb::Status::InvalidArgument(fmt::StringPrintf(
37+
"key in file %s is %llu bytes long, AES keys can be 16, 24, or 32 bytes", path.c_str(), key_length));
38+
}
39+
40+
// Fill in the key.
41+
key->type = AES;
42+
key->id = KeyHash(contents);
43+
key->key = contents;
44+
key->source = path;
45+
46+
return rocksdb::Status::OK();
47+
}
48+
49+
rocksdb::Status FileKeyManager::LoadKeys() {
50+
std::unique_ptr<EncryptionKey> active(new EncryptionKey());
51+
rocksdb::Status status = KeyFromFile(env_, active_key_path_, active.get());
52+
if (!status.ok()) {
53+
return status;
54+
}
55+
56+
std::unique_ptr<EncryptionKey> old(new EncryptionKey());
57+
status = KeyFromFile(env_, old_key_path_, old.get());
58+
if (!status.ok()) {
59+
return status;
60+
}
61+
62+
active_key_.swap(active);
63+
old_key_.swap(old);
64+
return rocksdb::Status::OK();
65+
}

0 commit comments

Comments
 (0)