Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
46089d76
Commit
46089d76
authored
Mar 13, 2016
by
Vladislav Vaintroub
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MDEV-9659 : AWS KMS encryption plugin
parent
517584dd
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
740 additions
and
2 deletions
+740
-2
plugin/aws_key_management/CMakeLists.txt
plugin/aws_key_management/CMakeLists.txt
+151
-0
plugin/aws_key_management/aws_key_management_plugin.cc
plugin/aws_key_management/aws_key_management_plugin.cc
+587
-0
win/packaging/CPackWixConfig.cmake
win/packaging/CPackWixConfig.cmake
+2
-2
No files found.
plugin/aws_key_management/CMakeLists.txt
0 → 100644
View file @
46089d76
# We build parts of AWS C++ SDK as CMake external project
# The restrictions of the SDK (https://github.com/awslabs/aws-sdk-cpp/blob/master/README.md)
# are
# - OS : Windows,Linux or OSX
# - C++11 compiler : VS2013+, gcc 4.7+, clang 3.3+
# - libcurl development package needs to be present on Unixes
#
# If we build SDK outselves, we'll need require GIT to be present on the build machine
# Give message why the building this plugin is skipped (only if -DVERBOSE is defined)
# or if plugin is explicitely requested to build. Then bail out.
MACRO
(
SKIP_AWS_PLUGIN msg
)
IF
(
VERBOSE OR
"
${
PLUGIN_AWS_KEY_MANAGEMENT
}
"
MATCHES
"^(STATIC|DYNAMIC)$"
)
MESSAGE
(
STATUS
"Skip aws_key_management -
${
msg
}
"
)
ENDIF
()
RETURN
()
ENDMACRO
()
# This plugin needs recent C++ compilers (AWS C++ SDK header files are using C++11 features)
SET
(
CXX11_FLAGS
)
SET
(
OLD_COMPILER_MSG
"AWS SDK requires c++11 -capable compiler (minimal supported versions are g++ 4.7, clang 3.3, VS2103)"
)
IF
(
CMAKE_CXX_COMPILER_ID MATCHES
"GNU"
)
EXECUTE_PROCESS
(
COMMAND
${
CMAKE_CXX_COMPILER
}
-dumpversion OUTPUT_VARIABLE GCC_VERSION
)
IF
(
GCC_VERSION VERSION_LESS 4.8
)
SKIP_AWS_PLUGIN
(
"
${
OLD_COMPILER_MSG
}
"
)
ENDIF
()
SET
(
CXX11_FLAGS
"-std=c++11"
)
ELSEIF
(
CMAKE_CXX_COMPILER_ID MATCHES
"Clang"
)
IF
((
CMAKE_CXX_COMPILER_VERSION AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.3
)
OR
(
CLANG_VERSION_STRING AND CLANG_VERSION_STRING VERSION_LESS 3.3
))
SKIP_AWS_PLUGIN
(
"
${
OLD_COMPILER_MSG
}
"
)
ENDIF
()
SET
(
CXX11_FLAGS
"-stdlib=libc++"
)
ELSEIF
(
MSVC
)
IF
(
MSVC_VERSION LESS 1800
)
SKIP_AWS_PLUGIN
(
"
${
OLD_COMPILER_MSG
}
"
)
ENDIF
()
ELSE
()
SKIP_AWS_PLUGIN
(
"Compiler not supported by AWS C++ SDK"
)
ENDIF
()
IF
(
NOT
(
WIN32 OR APPLE
OR
(
CMAKE_SYSTEM_NAME MATCHES
"Linux"
)))
SKIP_AWS_PLUGIN
(
"OS unsupported by AWS SDK"
)
ENDIF
()
# Figure out where AWS installs SDK libraries
# The below is defined in AWS SDK's CMakeLists.txt
# (and their handling is weird, every OS has special install directory)
IF
(
WIN32
)
SET
(
SDK_INSTALL_BINARY_PREFIX
"windows"
)
ELSEIF
(
APPLE
)
SET
(
SDK_INSTALL_BINARY_PREFIX
"mac"
)
ELSEIF
(
UNIX
)
SET
(
SDK_INSTALL_BINARY_PREFIX
"linux"
)
ENDIF
()
IF
(
NOT APPLE
)
IF
(
CMAKE_SIZEOF_VOID_P EQUAL 8
)
SET
(
SDK_INSTALL_BINARY_PREFIX
"
${
SDK_INSTALL_BINARY_PREFIX
}
/intel64"
)
ELSE
()
SET
(
SDK_INSTALL_BINARY_PREFIX
"
${
SDK_INSTALL_BINARY_PREFIX
}
/ia32"
)
ENDIF
()
ENDIF
()
IF
(
CMAKE_CONFIGURATION_TYPES
)
SET
(
SDK_INSTALL_BINARY_PREFIX
"
${
SDK_INSTALL_BINARY_PREFIX
}
/
${
CMAKE_CFG_INTDIR
}
"
)
ENDIF
()
FIND_LIBRARY
(
AWS_CPP_SDK_CORE NAMES aws-cpp-sdk-core PATH_SUFFIXES
"
${
SDK_INSTALL_BINARY_PREFIX
}
"
)
FIND_LIBRARY
(
AWS_CPP_SDK_KMS NAMES aws-cpp-sdk-core PATH_SUFFIXES
"
${
SDK_INSTALL_BINARY_PREFIX
}
"
)
SET
(
CMAKE_REQUIRED_FLAGS
${
CXX11_FLAGS
}
)
CHECK_INCLUDE_FILE_CXX
(
aws/kms/KMSClient.h HAVE_AWS_HEADERS
)
IF
(
AWS_CPP_SDK_CORE AND AWS_CPP_SDK_KMS AND HAVE_AWS_HEADERS
)
# AWS C++ SDK installed
SET
(
AWS_SDK_LIBS
${
AWS_CPP_SDK_CORE
}
${
AWS_CPP_SDK_KMS
}
)
ELSE
()
# Build from source, using ExternalProject_Add
IF
(
CMAKE_VERSION VERSION_LESS
"2.8.8"
)
SKIP_AWS_PLUGIN
(
"CMake is too old"
)
ENDIF
()
FIND_PACKAGE
(
Git
)
IF
(
NOT GIT_FOUND
)
SKIP_AWS_PLUGIN
(
"no GIT"
)
ENDIF
()
INCLUDE
(
ExternalProject
)
IF
(
UNIX
)
FIND_PACKAGE
(
CURL
)
IF
(
NOT CURL_FOUND
)
SKIP_AWS_PLUGIN
(
"AWS C++ SDK requires libcurl development package"
)
ENDIF
()
SET
(
PIC_FLAG -fPIC
)
ENDIF
()
IF
(
MSVC
)
SET
(
EXTRA_SDK_CMAKE_FLAGS -DCMAKE_CXX_FLAGS_DEBUGOPT=
""
-DCMAKE_EXE_LINKER_FLAGS_DEBUGOPT=
""
-DCMAKE_CXX_FLAGS=/wd4592
)
ENDIF
()
IF
(
CMAKE_CXX_COMPILER
)
SET
(
EXTRA_SDK_CMAKE_FLAGS
${
EXTRA_SDK_CMAKE_FLAGS
}
-DCMAKE_CXX_COMPILER=
${
CMAKE_CXX_COMPILER
}
)
ENDIF
()
# Relax AWS C++ SDK unreasonably high requirements for CMake version. Use replace utility (from MariaDB build)
# to patch their CMakeLists.txt
SET
(
AWS_SDK_PATCH_COMMAND
)
ExternalProject_Add
(
aws_sdk_cpp
GIT_REPOSITORY
"https://github.com/awslabs/aws-sdk-cpp.git"
GIT_TAG
"0.9.6"
# single tag
UPDATE_COMMAND
""
PATCH_COMMAND replace 3.1.2 2.8 --
${
CMAKE_BINARY_DIR
}
/aws-sdk-cpp/CMakeLists.txt
SOURCE_DIR
"
${
CMAKE_BINARY_DIR
}
/aws-sdk-cpp"
CMAKE_ARGS
-DBUILD_ONLY=aws-cpp-sdk-kms -DSTATIC_LINKING=1
"-DCMAKE_CXX_FLAGS_DEBUG=
${
CMAKE_CXX_FLAGS_DEBUG
}
${
PIC_FLAG
}
"
"-DCMAKE_CXX_FLAGS_RELWITHDEBINFO=
${
CMAKE_CXX_FLAGS_RELWITHDEBINFO
}
${
PIC_FLAG
}
"
"-DCMAKE_CXX_FLAGS_RELEASE=
${
CMAKE_CXX_FLAGS_RELEASE
}
${
PIC_FLAG
}
"
"-DCMAKE_CXX_FLAGS_MINSIZEREL=
${
CMAKE_CXX_FLAGS_MINSIZEREL
}
${
PIC_FLAG
}
"
${
EXTRA_SDK_CMAKE_FLAGS
}
-DCMAKE_INSTALL_PREFIX=
${
CMAKE_BINARY_DIR
}
/aws_sdk_cpp
TEST_COMMAND
""
)
# We do not need to build the whole SDK , just 2 of its libs
set
(
AWS_SDK_LIBS aws-cpp-sdk-core aws-cpp-sdk-kms
)
FOREACH
(
lib
${
AWS_SDK_LIBS
}
)
ADD_LIBRARY
(
${
lib
}
STATIC IMPORTED GLOBAL
)
ADD_DEPENDENCIES
(
${
lib
}
aws_sdk_cpp
)
SET
(
loc
"
${
CMAKE_BINARY_DIR
}
/aws_sdk_cpp/lib/
${
SDK_INSTALL_BINARY_PREFIX
}
/
${
CMAKE_STATIC_LIBRARY_PREFIX
}${
lib
}${
CMAKE_STATIC_LIBRARY_SUFFIX
}
"
)
SET_TARGET_PROPERTIES
(
${
lib
}
PROPERTIES IMPORTED_LOCATION
${
loc
}
)
IF
(
WIN32
)
SET_TARGET_PROPERTIES
(
${
lib
}
PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES
"bcrypt;winhttp;wininet;userenv"
)
ELSE
()
SET_TARGET_PROPERTIES
(
${
lib
}
PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES
"
${
SSL_LIBRARIES
}
;
${
CURL_LIBRARIES
}
"
)
ENDIF
()
ENDFOREACH
()
IF
(
CMAKE_SYSTEM_NAME MATCHES
"Linux"
)
# Need whole-archive , otherwise static libraries are not linked
SET
(
AWS_SDK_LIBS -Wl,--whole-archive
${
AWS_SDK_LIBS
}
-Wl,--no-whole-archive
)
ENDIF
()
SET_TARGET_PROPERTIES
(
aws_sdk_cpp PROPERTIES EXCLUDE_FROM_ALL TRUE
)
INCLUDE_DIRECTORIES
(
${
CMAKE_BINARY_DIR
}
/aws_sdk_cpp/include
)
ENDIF
()
SET
(
CMAKE_CXX_FLAGS
"
${
CMAKE_CXX_FLAGS
}
${
CXX11_FLAGS
}
"
)
MYSQL_ADD_PLUGIN
(
aws_key_management aws_key_management_plugin.cc
COMPONENT aws-key-management
LINK_LIBRARIES
${
AWS_SDK_LIBS
}
DISABLED
)
plugin/aws_key_management/aws_key_management_plugin.cc
0 → 100644
View file @
46089d76
/*
Copyright (c) 2016 MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include <my_global.h>
#include <my_pthread.h>
#include <my_sys.h>
#include <my_dir.h>
#include <mysql/plugin_encryption.h>
#include <my_crypt.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <mysqld_error.h>
#include <base64.h>
#include <map>
#include <algorithm>
#include <string>
#include <vector>
#include <iterator>
#include <sstream>
#include <fstream>
#include <aws/core/client/AWSError.h>
#include <aws/core/utils/logging/AWSLogging.h>
#include <aws/core/utils/logging/ConsoleLogSystem.h>
#include <aws/kms/KMSClient.h>
#include <aws/kms/model/DecryptRequest.h>
#include <aws/kms/model/DecryptResult.h>
#include <aws/kms/model/GenerateDataKeyWithoutPlaintextRequest.h>
#include <aws/kms/model/GenerateDataKeyWithoutPlaintextResult.h>
#include <aws/core/utils/Outcome.h>
using
namespace
std
;
using
namespace
Aws
::
KMS
;
using
namespace
Aws
::
KMS
::
Model
;
using
namespace
Aws
::
Utils
::
Logging
;
extern
void
sql_print_error
(
const
char
*
format
,
...);
extern
void
sql_print_warning
(
const
char
*
format
,
...);
extern
void
sql_print_information
(
const
char
*
format
,
...);
/* Plaintext key info struct */
struct
KEY_INFO
{
unsigned
int
key_id
;
unsigned
int
key_version
;
unsigned
int
length
;
unsigned
char
data
[
MY_AES_MAX_KEY_LENGTH
];
bool
load_failed
;
/* if true, do not attempt to reload?*/
public:
KEY_INFO
()
:
key_id
(
0
),
key_version
(
0
),
length
(
0
),
load_failed
(
false
){};
};
#define KEY_ID_AND_VERSION(key_id,version) ((longlong)key_id << 32 | version)
/* Cache for the latest version, per key id */
static
std
::
map
<
uint
,
uint
>
latest_version_cache
;
/* Cache for plaintext keys */
static
std
::
map
<
ulonglong
,
KEY_INFO
>
key_info_cache
;
static
const
char
*
key_spec_names
[]
=
{
"AES_128"
,
"AES_256"
,
0
};
/* Plugin variables */
static
char
*
master_key_id
;
static
unsigned
long
key_spec
;
static
unsigned
long
log_level
;
static
int
rotate_key
;
/* AWS functionality*/
static
int
aws_decrypt_key
(
const
char
*
path
,
KEY_INFO
*
info
);
static
int
aws_generate_datakey
(
uint
key_id
,
uint
version
);
static
int
extract_id_and_version
(
const
char
*
name
,
uint
*
id
,
uint
*
ver
);
static
unsigned
int
get_latest_key_version
(
unsigned
int
key_id
);
static
unsigned
int
get_latest_key_version_nolock
(
unsigned
int
key_id
);
static
int
load_key
(
KEY_INFO
*
info
);
/* Mutex to serialize access to caches */
static
mysql_mutex_t
mtx
;
#ifdef HAVE_PSI_INTERFACE
static
uint
mtx_key
;
static
PSI_mutex_info
mtx_info
=
{
&
mtx_key
,
"mtx"
,
0
};
#endif
static
Aws
::
KMS
::
KMSClient
*
client
;
/* Redirect AWS trace to error log */
class
MySQLLogSystem
:
public
Aws
::
Utils
::
Logging
::
FormattedLogSystem
{
public:
using
Base
=
FormattedLogSystem
;
MySQLLogSystem
(
LogLevel
logLevel
)
:
Base
(
logLevel
)
{
}
virtual
LogLevel
GetLogLevel
(
void
)
const
override
{
return
(
LogLevel
)
log_level
;
}
virtual
~
MySQLLogSystem
()
{
}
protected:
virtual
void
ProcessFormattedStatement
(
Aws
::
String
&&
statement
)
override
{
#ifdef _WIN32
/*
On Windows, we can't use C runtime functions to write to stdout,
because we compile with static C runtime, so plugin has a stdout
different from server. Thus we're using WriteFile().
*/
DWORD
nSize
=
(
DWORD
)
statement
.
size
();
DWORD
nWritten
;
const
char
*
s
=
statement
.
c_str
();
HANDLE
h
=
GetStdHandle
(
STD_OUTPUT_HANDLE
);
WriteFile
(
h
,
s
,
nSize
,
&
nWritten
,
NULL
);
#else
printf
(
"%s"
,
statement
.
c_str
());
#endif
}
};
/*
Plugin initialization.
Create KMS client and scan datadir to find out which keys and versions
are present.
*/
static
int
plugin_init
(
void
*
p
)
{
DBUG_ENTER
(
"plugin_init"
);
client
=
new
KMSClient
();
if
(
!
client
)
{
sql_print_error
(
"Can not initialize KMS client"
);
DBUG_RETURN
(
-
1
);
}
InitializeAWSLogging
(
Aws
::
MakeShared
<
MySQLLogSystem
>
(
"aws_key_management_plugin"
,
(
Aws
::
Utils
::
Logging
::
LogLevel
)
log_level
));
#ifdef HAVE_PSI_INTERFACE
mysql_mutex_register
(
"aws_key_management"
,
&
mtx_info
,
1
);
#endif
mysql_mutex_init
(
mtx_key
,
&
mtx
,
NULL
);
MY_DIR
*
dirp
=
my_dir
(
"."
,
MYF
(
0
));
if
(
!
dirp
)
{
sql_print_error
(
"Can't scan current directory"
);
DBUG_RETURN
(
-
1
);
}
for
(
unsigned
int
i
=
0
;
i
<
dirp
->
number_of_files
;
i
++
)
{
KEY_INFO
info
;
if
(
extract_id_and_version
(
dirp
->
dir_entry
[
i
].
name
,
&
info
.
key_id
,
&
info
.
key_version
)
==
0
)
{
key_info_cache
[
KEY_ID_AND_VERSION
(
info
.
key_id
,
info
.
key_version
)]
=
info
;
latest_version_cache
[
info
.
key_id
]
=
max
(
info
.
key_version
,
latest_version_cache
[
info
.
key_id
]);
}
}
my_dirend
(
dirp
);
DBUG_RETURN
(
0
);
}
static
int
plugin_deinit
(
void
*
p
)
{
DBUG_ENTER
(
"plugin_deinit"
);
latest_version_cache
.
clear
();
key_info_cache
.
clear
();
mysql_mutex_destroy
(
&
mtx
);
delete
client
;
ShutdownAWSLogging
();
DBUG_RETURN
(
0
);
}
/* Generate filename to store the ciphered key */
static
void
format_keyfile_name
(
char
*
buf
,
size_t
size
,
uint
key_id
,
uint
version
)
{
snprintf
(
buf
,
size
,
"aws-kms-key.%u.%u"
,
key_id
,
version
);
}
/* Extract key id and version from file name */
static
int
extract_id_and_version
(
const
char
*
name
,
uint
*
id
,
uint
*
ver
)
{
int
len
;
int
n
=
sscanf
(
name
,
"aws-kms-key.%u.%u%n"
,
id
,
ver
,
&
len
);
if
(
n
==
2
&&
*
id
>
0
&&
*
ver
>
0
&&
len
==
(
int
)
strlen
(
name
))
return
0
;
return
1
;
}
/*
Decrypt key stored in aws-kms-key.<id>.<version>
Cache the decrypted key.
*/
static
int
load_key
(
KEY_INFO
*
info
)
{
int
ret
;
char
path
[
256
];
DBUG_ENTER
(
"load_key"
);
DBUG_PRINT
(
"enter"
,
(
"id=%u,ver=%u"
,
info
->
key_id
,
info
->
key_version
));
format_keyfile_name
(
path
,
sizeof
(
path
),
info
->
key_id
,
info
->
key_version
);
ret
=
aws_decrypt_key
(
path
,
info
);
if
(
ret
)
info
->
load_failed
=
true
;
latest_version_cache
[
info
->
key_id
]
=
max
(
latest_version_cache
[
info
->
key_id
],
info
->
key_version
);
key_info_cache
[
KEY_ID_AND_VERSION
(
info
->
key_id
,
info
->
key_version
)]
=
*
info
;
if
(
!
ret
)
{
sql_print_information
(
"AWS KMS plugin: loaded key %u, version %u, key length %u bit"
,
info
->
key_id
,
info
->
key_version
,(
uint
)
info
->
length
*
8
);
}
else
{
sql_print_warning
(
"AWS KMS plugin: key %u, version %u could not be decrypted"
,
info
->
key_id
,
info
->
key_version
);
}
DBUG_RETURN
(
ret
);
}
/*
Get latest version for the key.
If key is not decrypted yet, this function also decrypt the key
and error will be returned if decryption fails.
The reason for that is that Innodb crashes
in case errors are returned by get_key(),
A new key will be created if it does not exist, provided there is
valid master_key_id.
*/
static
unsigned
int
get_latest_key_version
(
unsigned
int
key_id
)
{
unsigned
int
ret
;
DBUG_ENTER
(
"get_latest_key_version"
);
mysql_mutex_lock
(
&
mtx
);
ret
=
get_latest_key_version_nolock
(
key_id
);
mysql_mutex_unlock
(
&
mtx
);
DBUG_PRINT
(
"info"
,
(
"key=%u,ret=%u"
,
key_id
,
ret
));
DBUG_RETURN
(
ret
);
}
static
unsigned
int
get_latest_key_version_nolock
(
unsigned
int
key_id
)
{
KEY_INFO
info
;
uint
ver
;
DBUG_ENTER
(
"get_latest_key_version_nolock"
);
ver
=
latest_version_cache
[
key_id
];
if
(
ver
>
0
)
{
info
=
key_info_cache
[
KEY_ID_AND_VERSION
(
key_id
,
ver
)];
}
if
(
info
.
load_failed
)
{
/* Decryption failed previously, don't retry */
DBUG_RETURN
(
ENCRYPTION_KEY_VERSION_INVALID
);
}
else
if
(
ver
>
0
)
{
/* Key exists already, return it*/
if
(
info
.
length
>
0
)
DBUG_RETURN
(
ver
);
}
else
// (ver == 0)
{
/* Generate a new key, version 1 */
if
(
!
master_key_id
[
0
])
{
my_printf_error
(
ER_UNKNOWN_ERROR
,
"Can't generate encryption key %u, because 'aws_key_management_master_key_id' parameter is not set"
,
MYF
(
0
),
key_id
);
DBUG_RETURN
(
ENCRYPTION_KEY_VERSION_INVALID
);
}
if
(
aws_generate_datakey
(
key_id
,
1
)
!=
0
)
DBUG_RETURN
(
ENCRYPTION_KEY_VERSION_INVALID
);
info
.
key_id
=
key_id
;
info
.
key_version
=
1
;
info
.
length
=
0
;
}
if
(
load_key
(
&
info
))
DBUG_RETURN
(
ENCRYPTION_KEY_VERSION_INVALID
);
DBUG_RETURN
(
info
.
key_version
);
}
/*
Decrypt a file with KMS
*/
static
int
aws_decrypt_key
(
const
char
*
path
,
KEY_INFO
*
info
)
{
DBUG_ENTER
(
"aws_decrypt_key"
);
/* Read file content into memory */
ifstream
ifs
(
path
,
ios
::
binary
|
ios
::
ate
);
if
(
!
ifs
.
good
())
{
sql_print_error
(
"can't open file %s"
,
path
);
DBUG_RETURN
(
-
1
);
}
size_t
pos
=
(
size_t
)
ifs
.
tellg
();
if
(
!
pos
||
pos
==
SIZE_T_MAX
)
{
sql_print_error
(
"invalid key file %s"
,
path
);
DBUG_RETURN
(
-
1
);
}
std
::
vector
<
char
>
contents
(
pos
);
ifs
.
seekg
(
0
,
ios
::
beg
);
ifs
.
read
(
&
contents
[
0
],
pos
);
/* Decrypt data the with AWS */
DecryptRequest
request
;
Aws
::
Utils
::
ByteBuffer
byteBuffer
((
unsigned
char
*
)
contents
.
data
(),
pos
);
request
.
SetCiphertextBlob
(
byteBuffer
);
DecryptOutcome
outcome
=
client
->
Decrypt
(
request
);
if
(
!
outcome
.
IsSuccess
())
{
sql_print_error
(
"AWS KMS plugin: Decrypt failed for %s : %s"
,
path
,
outcome
.
GetError
().
GetMessage
().
c_str
());
DBUG_RETURN
(
-
1
);
}
Aws
::
Utils
::
ByteBuffer
plaintext
=
outcome
.
GetResult
().
GetPlaintext
();
size_t
len
=
plaintext
.
GetLength
();
if
(
len
>
(
int
)
sizeof
(
info
->
data
))
{
sql_print_error
(
"AWS KMS plugin: encoding key too large for %s"
,
path
);
DBUG_RETURN
(
ENCRYPTION_KEY_BUFFER_TOO_SMALL
);
}
memcpy
(
info
->
data
,
plaintext
.
GetUnderlyingData
(),
len
);
info
->
length
=
len
;
DBUG_RETURN
(
0
);
}
/* Generate a new datakey and store it a file */
static
int
aws_generate_datakey
(
uint
keyid
,
uint
version
)
{
DBUG_ENTER
(
"aws_generate_datakey"
);
GenerateDataKeyWithoutPlaintextRequest
request
;
request
.
SetKeyId
(
master_key_id
);
request
.
SetKeySpec
(
DataKeySpecMapper
::
GetDataKeySpecForName
(
key_spec_names
[
key_spec
]));
GenerateDataKeyWithoutPlaintextOutcome
outcome
;
outcome
=
client
->
GenerateDataKeyWithoutPlaintext
(
request
);
if
(
!
outcome
.
IsSuccess
())
{
sql_print_error
(
"AWS KMS plugin : GenerateDataKeyWithoutPlaintext failed : %s - %s"
,
outcome
.
GetError
().
GetExceptionName
().
c_str
(),
outcome
.
GetError
().
GetMessage
().
c_str
());
DBUG_RETURN
(
-
1
);
}
string
out
;
char
filename
[
20
];
Aws
::
Utils
::
ByteBuffer
byteBuffer
=
outcome
.
GetResult
().
GetCiphertextBlob
();
format_keyfile_name
(
filename
,
sizeof
(
filename
),
keyid
,
version
);
int
fd
=
my_open
(
filename
,
O_RDWR
|
O_CREAT
,
0
);
if
(
fd
<
0
)
{
sql_print_error
(
"AWS KMS plugin: Can't create file %s"
,
filename
);
DBUG_RETURN
(
-
1
);
}
size_t
len
=
byteBuffer
.
GetLength
();
if
(
my_write
(
fd
,
byteBuffer
.
GetUnderlyingData
(),
len
,
0
)
!=
len
)
{
sql_print_error
(
"AWS KMS plugin: can't write to %s"
,
filename
);
my_close
(
fd
,
0
);
my_delete
(
filename
,
0
);
DBUG_RETURN
(
-
1
);
}
my_close
(
fd
,
0
);
sql_print_information
(
"AWS KMS plugin: generated encrypted datakey for key id=%u, version=%u"
,
keyid
,
version
);
DBUG_RETURN
(
0
);
}
/* Key rotation for a single key */
static
int
rotate_single_key
(
uint
key_id
)
{
uint
ver
;
ver
=
latest_version_cache
[
key_id
];
if
(
!
ver
)
{
my_printf_error
(
ER_UNKNOWN_ERROR
,
"key %u does not exist"
,
MYF
(
ME_JUST_WARNING
),
key_id
);
return
-
1
;
}
else
if
(
aws_generate_datakey
(
key_id
,
ver
+
1
))
{
my_printf_error
(
ER_UNKNOWN_ERROR
,
"Could not generate datakey for key id= %u, ver= %u"
,
MYF
(
ME_JUST_WARNING
),
key_id
,
ver
);
return
-
1
;
}
else
{
KEY_INFO
info
;
info
.
key_id
=
key_id
;
info
.
key_version
=
ver
+
1
;
if
(
load_key
(
&
info
))
{
my_printf_error
(
ER_UNKNOWN_ERROR
,
"Could not load datakey for key id= %u, ver= %u"
,
MYF
(
ME_JUST_WARNING
),
key_id
,
ver
);
return
-
1
;
}
}
return
0
;
}
/* Key rotation for all key ids */
static
int
rotate_all_keys
()
{
int
ret
=
0
;
for
(
map
<
uint
,
uint
>::
iterator
it
=
latest_version_cache
.
begin
();
it
!=
latest_version_cache
.
end
();
it
++
)
{
ret
=
rotate_single_key
(
it
->
first
);
if
(
ret
)
break
;
}
return
ret
;
}
static
void
update_rotate
(
MYSQL_THD
,
struct
st_mysql_sys_var
*
,
void
*
,
const
void
*
val
)
{
if
(
!
master_key_id
[
0
])
{
my_printf_error
(
ER_UNKNOWN_ERROR
,
"aws_key_management_master_key_id must be set to generate new data keys"
,
MYF
(
ME_JUST_WARNING
));
return
;
}
mysql_mutex_lock
(
&
mtx
);
rotate_key
=
*
(
int
*
)
val
;
switch
(
rotate_key
)
{
case
0
:
break
;
case
-
1
:
rotate_all_keys
();
break
;
default:
rotate_single_key
(
rotate_key
);
break
;
}
rotate_key
=
0
;
mysql_mutex_unlock
(
&
mtx
);
}
static
unsigned
int
get_key
(
unsigned
int
key_id
,
unsigned
int
version
,
unsigned
char
*
dstbuf
,
unsigned
int
*
buflen
)
{
KEY_INFO
info
;
DBUG_ENTER
(
"get_key"
);
mysql_mutex_lock
(
&
mtx
);
info
=
key_info_cache
[
KEY_ID_AND_VERSION
(
key_id
,
version
)];
if
(
info
.
length
==
0
&&
!
info
.
load_failed
)
{
info
.
key_id
=
key_id
;
info
.
key_version
=
version
;
load_key
(
&
info
);
}
mysql_mutex_unlock
(
&
mtx
);
if
(
info
.
load_failed
)
DBUG_RETURN
(
ENCRYPTION_KEY_VERSION_INVALID
);
if
(
*
buflen
<
info
.
length
)
{
*
buflen
=
info
.
length
;
DBUG_RETURN
(
ENCRYPTION_KEY_BUFFER_TOO_SMALL
);
}
*
buflen
=
info
.
length
;
memcpy
(
dstbuf
,
info
.
data
,
info
.
length
);
DBUG_RETURN
(
0
);
}
/* Plugin defs */
struct
st_mariadb_encryption
aws_key_management_plugin
=
{
MariaDB_ENCRYPTION_INTERFACE_VERSION
,
get_latest_key_version
,
get_key
,
// use default encrypt/decrypt functions
0
,
0
,
0
,
0
,
0
};
static
TYPELIB
key_spec_typelib
=
{
array_elements
(
key_spec_names
)
-
1
,
""
,
key_spec_names
,
NULL
};
const
char
*
log_level_names
[]
=
{
"Off"
,
"Fatal"
,
"Error"
,
"Warn"
,
"Info"
,
"Debug"
,
"Trace"
,
0
};
static
TYPELIB
log_level_typelib
=
{
array_elements
(
log_level_names
)
-
1
,
""
,
log_level_names
,
NULL
};
static
MYSQL_SYSVAR_STR
(
master_key_id
,
master_key_id
,
PLUGIN_VAR_RQCMDARG
|
PLUGIN_VAR_MEMALLOC
,
"Key id for master encryption key. Used to create new datakeys. If not set, no new keys will be created"
,
NULL
,
NULL
,
""
);
static
MYSQL_SYSVAR_ENUM
(
key_spec
,
key_spec
,
PLUGIN_VAR_RQCMDARG
,
"Encryption algorithm used to create new keys."
,
NULL
,
NULL
,
0
,
&
key_spec_typelib
);
static
MYSQL_SYSVAR_ENUM
(
log_level
,
log_level
,
PLUGIN_VAR_RQCMDARG
,
"Logging for AWS API"
,
NULL
,
NULL
,
0
,
&
log_level_typelib
);
static
MYSQL_SYSVAR_INT
(
rotate_key
,
rotate_key
,
PLUGIN_VAR_RQCMDARG
,
"Set this variable to key id to perform rotation of the key. Specify -1 to rotate all keys"
,
NULL
,
update_rotate
,
0
,
-
1
,
INT_MAX
,
1
);
static
struct
st_mysql_sys_var
*
settings
[]
=
{
MYSQL_SYSVAR
(
master_key_id
),
MYSQL_SYSVAR
(
key_spec
),
MYSQL_SYSVAR
(
rotate_key
),
MYSQL_SYSVAR
(
log_level
),
NULL
};
/*
Plugin library descriptor
*/
maria_declare_plugin
(
aws_key_management
)
{
MariaDB_ENCRYPTION_PLUGIN
,
&
aws_key_management_plugin
,
"aws_key_management"
,
"MariaDB Corporation"
,
"AWS key management plugin"
,
PLUGIN_LICENSE_GPL
,
plugin_init
,
plugin_deinit
,
0x0100
,
NULL
,
settings
,
"1.0"
,
MariaDB_PLUGIN_MATURITY_EXPERIMENTAL
}
maria_declare_plugin_end
;
win/packaging/CPackWixConfig.cmake
View file @
46089d76
...
...
@@ -9,7 +9,7 @@ IF(ESSENTIALS)
ENDIF
()
ELSE
()
SET
(
CPACK_COMPONENTS_USED
"Server;Client;Development;SharedLibraries;Embedded;Documentation;IniFiles;Readme;Debuginfo;Common;connect-engine;ClientPlugins;gssapi-server;gssapi-client"
)
"Server;Client;Development;SharedLibraries;Embedded;Documentation;IniFiles;Readme;Debuginfo;Common;connect-engine;ClientPlugins;gssapi-server;gssapi-client
;aws-key-management
"
)
ENDIF
()
SET
(
WIX_FEATURE_MySQLServer_EXTRA_FEATURES
"DBInstance;SharedClientServerComponents"
)
...
...
@@ -57,7 +57,7 @@ SET(CPACK_COMPONENT_GROUP_MYSQLSERVER_DESCRIPTION "Install server")
#Miscellaneous (hidden) components, part of server / or client programs
FOREACH
(
comp connect-engine ClientPlugins gssapi-server gssapi-client
)
FOREACH
(
comp connect-engine ClientPlugins gssapi-server gssapi-client
aws-key-management
)
STRING
(
TOUPPER
"
${
comp
}
"
comp
)
SET
(
CPACK_COMPONENT_
${
comp
}
_GROUP
"MySQLServer"
)
SET
(
CPACK_COMPONENT_
${
comp
}
_HIDDEN 1
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment