summaryrefslogtreecommitdiff
path: root/storage/innobase
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2017-02-10 20:26:02 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2017-02-13 11:12:58 +0200
commit3272a1974190e0238da63052b8d26f53aea8e03f (patch)
treef056c178a0989c470479fea20377cb05f0dcd5b5 /storage/innobase
parent96c4b9d49f76eebb3dda9fa1524da394bd67b0ae (diff)
downloadmariadb-git-3272a1974190e0238da63052b8d26f53aea8e03f.tar.gz
MDEV-11782 preparation: Add separate code for validating the 10.1 redo log.
log_crypt_101_read_checkpoint(): Read the encryption information from a MariaDB 10.1 checkpoint page. log_crypt_101_read_block(): Attempt to decrypt a MariaDB 10.1 redo log page. recv_log_format_0_recover(): Only attempt decryption on checksum mismatch. NOTE: With the MariaDB 10.1 innodb_encrypt_log format, we can actually determine from the cleartext portion of the redo log whether the redo log is empty. We do not really have to decrypt the redo log here, if we did not want to determine if the checksum is valid.
Diffstat (limited to 'storage/innobase')
-rw-r--r--storage/innobase/include/log0crypt.h15
-rw-r--r--storage/innobase/log/log0crypt.cc82
-rw-r--r--storage/innobase/log/log0recv.cc7
3 files changed, 98 insertions, 6 deletions
diff --git a/storage/innobase/include/log0crypt.h b/storage/innobase/include/log0crypt.h
index 6b164e90d6e..6762b621155 100644
--- a/storage/innobase/include/log0crypt.h
+++ b/storage/innobase/include/log0crypt.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (C) 2013, 2015, Google Inc. All Rights Reserved.
-Copyright (C) 2014, 2016, MariaDB Corporation. All Rights Reserved.
+Copyright (C) 2014, 2017, MariaDB Corporation. All Rights Reserved.
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
@@ -54,6 +54,19 @@ log_crypt_write_checkpoint_buf(
/*===========================*/
byte* buf); /*!< in/out: checkpoint buffer */
+/** Read the MariaDB 10.1 checkpoint crypto (version, msg and iv) info.
+@param[in] buf checkpoint buffer
+@return whether the operation was successful */
+UNIV_INTERN
+bool
+log_crypt_101_read_checkpoint(const byte* buf);
+
+/** Decrypt a MariaDB 10.1 redo log block.
+@param[in,out] buf log block
+@return whether the decryption was successful */
+bool
+log_crypt_101_read_block(byte* buf);
+
/*********************************************************************//**
Read the crypto (version, msg and iv) info, which has been used for
log blocks with lsn <= this checkpoint's lsn, from a log header's
diff --git a/storage/innobase/log/log0crypt.cc b/storage/innobase/log/log0crypt.cc
index b0a89be8de2..cde9768e78e 100644
--- a/storage/innobase/log/log0crypt.cc
+++ b/storage/innobase/log/log0crypt.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (C) 2013, 2015, Google Inc. All Rights Reserved.
-Copyright (C) 2014, 2016, MariaDB Corporation. All Rights Reserved.
+Copyright (C) 2014, 2017, MariaDB Corporation. All Rights Reserved.
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
@@ -455,6 +455,86 @@ log_decrypt_after_read(
}
}
+/** Read the MariaDB 10.1 checkpoint crypto (version, msg and iv) info.
+@param[in] buf checkpoint buffer
+@return whether the operation was successful */
+UNIV_INTERN
+bool
+log_crypt_101_read_checkpoint(const byte* buf)
+{
+ buf += 20 + 32 * 9;
+
+ const size_t n = *buf++ == 2 ? std::min(unsigned(*buf++), 5U) : 0;
+
+ for (size_t i = 0; i < n; i++) {
+ struct crypt_info_t info;
+ info.checkpoint_no = mach_read_from_4(buf);
+ info.key_version = mach_read_from_4(buf + 4);
+ memcpy(info.crypt_msg, buf + 8, MY_AES_BLOCK_SIZE);
+ memcpy(info.crypt_nonce, buf + 24, MY_AES_BLOCK_SIZE);
+
+ if (!add_crypt_info(&info, true)) {
+ return false;
+ }
+ buf += 4 + 4 + 2 * MY_AES_BLOCK_SIZE;
+ }
+
+ return true;
+}
+
+/** Decrypt a MariaDB 10.1 redo log block.
+@param[in,out] buf log block
+@return whether the decryption was successful */
+UNIV_INTERN
+bool
+log_crypt_101_read_block(byte* buf)
+{
+ ut_ad(log_block_calc_checksum_format_0(buf)
+ != log_block_get_checksum(buf));
+ const crypt_info_t* info = get_crypt_info(buf);
+
+ if (!info || info->key_version == 0) {
+ return false;
+ }
+
+ byte dst[OS_FILE_LOG_BLOCK_SIZE];
+ uint dst_len;
+ byte aes_ctr_counter[MY_AES_BLOCK_SIZE];
+
+ const uint src_len = OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_HDR_SIZE;
+
+ ulint log_block_no = log_block_get_hdr_no(buf);
+ lsn_t log_block_start_lsn = log_block_get_start_lsn(
+ srv_start_lsn, log_block_no);
+
+ /* The log block header is not encrypted. */
+ memcpy(dst, buf, LOG_BLOCK_HDR_SIZE);
+
+ memcpy(aes_ctr_counter, info->crypt_nonce, 3);
+ mach_write_to_8(aes_ctr_counter + 3, log_block_start_lsn);
+ mach_write_to_4(aes_ctr_counter + 11, log_block_no);
+ aes_ctr_counter[15] = 0;
+
+ int rc = encryption_crypt(buf + LOG_BLOCK_HDR_SIZE, src_len,
+ dst + LOG_BLOCK_HDR_SIZE, &dst_len,
+ const_cast<byte*>(info->crypt_key),
+ MY_AES_BLOCK_SIZE,
+ aes_ctr_counter, MY_AES_BLOCK_SIZE,
+ ENCRYPTION_FLAG_DECRYPT
+ | ENCRYPTION_FLAG_NOPAD,
+ LOG_DEFAULT_ENCRYPTION_KEY,
+ info->key_version);
+
+ if (rc != MY_AES_OK || dst_len != src_len
+ || log_block_calc_checksum_format_0(dst)
+ != log_block_get_checksum(dst)) {
+ return false;
+ }
+
+ memcpy(buf, dst, sizeof dst);
+ return true;
+}
+
/*********************************************************************//**
Writes the crypto (version, msg and iv) info, which has been used for
log blocks with lsn <= this checkpoint's lsn, to a log header's
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc
index 3c141b744ce..8c6080d4d7e 100644
--- a/storage/innobase/log/log0recv.cc
+++ b/storage/innobase/log/log0recv.cc
@@ -798,7 +798,7 @@ recv_find_max_checkpoint_0(
checkpoint_no = mach_read_from_8(
buf + LOG_CHECKPOINT_NO);
- if (!log_crypt_read_checkpoint_buf(buf)) {
+ if (!log_crypt_101_read_checkpoint(buf)) {
ib::warn() << "Decrypting checkpoint failed";
continue;
}
@@ -859,10 +859,9 @@ recv_log_format_0_recover(lsn_t lsn)
% univ_page_size.physical()),
OS_FILE_LOG_BLOCK_SIZE, buf, NULL);
- log_decrypt_after_read(buf, OS_FILE_LOG_BLOCK_SIZE);
-
if (log_block_calc_checksum_format_0(buf)
- != log_block_get_checksum(buf)) {
+ != log_block_get_checksum(buf)
+ && !log_crypt_101_read_block(buf)) {
ib::error() << NO_UPGRADE_RECOVERY_MSG
<< ", and it appears corrupted"
<< NO_UPGRADE_RTFM_MSG;