Encryption Context and Encryption Setup have been added
Encryption Context and Encryption Setup structures have been added to ROUTER_INSTANCE Replication doesn’t start if binlog file has START_ENCRYPTION_EVENT but router_option ‘encrypt_binlog’ is Off
This commit is contained in:
@ -60,6 +60,9 @@
|
||||
#define BINLOG_EVENT_HDR_LEN 19
|
||||
#define BINLOG_EVENT_CRC_ALGO_TYPE 1
|
||||
#define BINLOG_EVENT_CRC_SIZE 4
|
||||
#define BINLOG_EVENT_LEN_OFFSET 9
|
||||
#define BINLOG_ENCRYPTION_ALGORYTM_NAME_LEN 13
|
||||
#define BINLOG_FATAL_ERROR_READING 1236
|
||||
|
||||
/**
|
||||
* Binlog event types
|
||||
@ -457,6 +460,16 @@ typedef struct
|
||||
int fde_len; /*< Length of fde_event */
|
||||
} MASTER_RESPONSES;
|
||||
|
||||
/**
|
||||
* The binlog encryption setup
|
||||
*/
|
||||
typedef struct binlog_encryption_setup
|
||||
{
|
||||
bool enabled;
|
||||
char encryption_algorithm[BINLOG_ENCRYPTION_ALGORYTM_NAME_LEN];
|
||||
char *key_management_filename;
|
||||
uint8_t *keys;
|
||||
} BINLOG_ENCRYPTION_SETUP;
|
||||
/**
|
||||
* The per instance data for the router.
|
||||
*/
|
||||
@ -541,7 +554,8 @@ typedef struct router_instance
|
||||
char *ssl_version; /*< config TLS Version for Master SSL connection */
|
||||
bool request_semi_sync; /*< Request Semi-Sync replication to master */
|
||||
int master_semi_sync; /*< Semi-Sync replication status of master server */
|
||||
int encrypt_binlog; /*< Encrypt binlog files */
|
||||
BINLOG_ENCRYPTION_SETUP encryption; /*< Binlog encryption setup */
|
||||
void *encryption_ctx; /*< Encryption context */
|
||||
struct router_instance *next;
|
||||
} ROUTER_INSTANCE;
|
||||
|
||||
|
||||
@ -295,7 +295,12 @@ createInstance(SERVICE *service, char **options)
|
||||
/* Semi-Sync support */
|
||||
inst->request_semi_sync = false;
|
||||
inst->master_semi_sync = 0;
|
||||
inst->encrypt_binlog = 0;
|
||||
|
||||
/* Binlog encryption */
|
||||
inst->encryption.enabled = 0;
|
||||
|
||||
/* Encryption CTX */
|
||||
inst->encryption_ctx = NULL;
|
||||
|
||||
/* Generate UUID for the router instance */
|
||||
uuid_generate_time(defuuid);
|
||||
@ -433,7 +438,7 @@ createInstance(SERVICE *service, char **options)
|
||||
}
|
||||
else if (strcmp(options[i], "encrypt_binlog") == 0)
|
||||
{
|
||||
inst->encrypt_binlog = config_truth_value(value);
|
||||
inst->encryption.enabled = config_truth_value(value);
|
||||
}
|
||||
else if (strcmp(options[i], "lowwater") == 0)
|
||||
{
|
||||
@ -805,7 +810,7 @@ createInstance(SERVICE *service, char **options)
|
||||
}
|
||||
|
||||
/* Log whether the binlog encryption option value is on */
|
||||
if (inst->encrypt_binlog)
|
||||
if (inst->encryption.enabled)
|
||||
{
|
||||
MXS_NOTICE("%s: Service has binlog encryption set to ON",
|
||||
service->name);
|
||||
@ -820,21 +825,34 @@ createInstance(SERVICE *service, char **options)
|
||||
MXS_NOTICE("Validating binlog file '%s' ...",
|
||||
inst->binlog_name);
|
||||
|
||||
if (inst->trx_safe && !blr_check_binlog(inst))
|
||||
if (!blr_check_binlog(inst))
|
||||
{
|
||||
/* Don't start replication, just return */
|
||||
return (ROUTER *)inst;
|
||||
if (inst->trx_safe)
|
||||
{
|
||||
/* Don't start replication, just return */
|
||||
return (ROUTER *)inst;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inst->trx_safe)
|
||||
/* Report current pos in binlog file and last seen transaction pos */
|
||||
MXS_INFO("Current binlog file is %s, safe pos %lu, current pos is %lu\n",
|
||||
inst->binlog_name, inst->binlog_position, inst->current_pos);
|
||||
|
||||
/* Don't start replication if binlog has START_ENCRYPTION_EVENT but binlog encryption is off */
|
||||
if (!inst->encryption.enabled && inst->encryption_ctx)
|
||||
{
|
||||
MXS_INFO("Current binlog file is %s, current pos is %lu\n",
|
||||
inst->binlog_name, inst->binlog_position);
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_INFO("Current binlog file is %s, safe pos %lu, current pos is %lu\n",
|
||||
inst->binlog_name, inst->binlog_position, inst->current_pos);
|
||||
MXS_ERROR("Found START_ENCRYPTION_EVENT but "
|
||||
"binlog ecryption option is currently Off. Replication can't start right now. "
|
||||
"Please restart maxScale with option set to On");
|
||||
|
||||
/* Force STOPPED state */
|
||||
inst->master_state = BLRM_SLAVE_STOPPED;
|
||||
/* Set mysql_errno and error message */
|
||||
inst->m_errno = BINLOG_FATAL_ERROR_READING;
|
||||
inst->m_errmsg = mxs_strdup("HY000 Binlog encryption is Off but binlog file has "
|
||||
"the START_ENCRYPTION_EVENT");
|
||||
|
||||
return (ROUTER *)inst;
|
||||
}
|
||||
|
||||
/* Start replication from master server */
|
||||
|
||||
@ -140,6 +140,20 @@ typedef struct start_encryption_event
|
||||
uint8_t nonce[BLRM_NONCE_LENGTH];
|
||||
} START_ENCRYPTION_EVENT;
|
||||
|
||||
/**
|
||||
* Binlog encryption context of current binlog file
|
||||
*
|
||||
* nonce for current binlog
|
||||
* key version
|
||||
* crypto_scheme
|
||||
*/
|
||||
typedef struct binlog_encryption_ctx
|
||||
{
|
||||
uint8_t binlog_crypto_scheme;
|
||||
uint32_t binlog_key_version;
|
||||
uint8_t nonce[BLRM_NONCE_LENGTH];
|
||||
} BINLOG_ENCRYPTION_CTX;
|
||||
|
||||
/**
|
||||
* Initialise the binlog file for this instance. MaxScale will look
|
||||
* for all the binlogs that it has on local disk, determine the next
|
||||
@ -435,7 +449,6 @@ blr_write_binlog_record(ROUTER_INSTANCE *router, REP_HEADER *hdr, uint32_t size,
|
||||
* Fill the gap with a self generated ignorable event
|
||||
* Binlog file position is incremented by blr_write_special_event()
|
||||
*/
|
||||
|
||||
if (hdr->next_pos && (hdr->next_pos > (file_offset + size)))
|
||||
{
|
||||
uint64_t hole_size = hdr->next_pos - file_offset - size;
|
||||
@ -445,6 +458,43 @@ blr_write_binlog_record(ROUTER_INSTANCE *router, REP_HEADER *hdr, uint32_t size,
|
||||
}
|
||||
}
|
||||
|
||||
if (router->encryption_ctx != NULL)
|
||||
{
|
||||
BINLOG_ENCRYPTION_CTX *tmp_encryption_ctx = (BINLOG_ENCRYPTION_CTX *)(router->encryption_ctx);
|
||||
uint8_t iv[BLRM_IV_LENGTH];
|
||||
uint64_t file_offset = router->current_pos;
|
||||
char iv_hex[AES_BLOCK_SIZE * 2 + 1] = "";
|
||||
char nonce_hex[BLRM_NONCE_LENGTH * 2 + 1] = "";
|
||||
|
||||
/* Encryption IV is 12 bytes nonce + 4 bytes event position */
|
||||
memcpy(iv, tmp_encryption_ctx->nonce, BLRM_NONCE_LENGTH);
|
||||
gw_mysql_set_byte4(iv + BLRM_NONCE_LENGTH, (unsigned long)file_offset);
|
||||
/* Human readable versions */
|
||||
gw_bin2hex(iv_hex, iv, BLRM_IV_LENGTH);
|
||||
gw_bin2hex(nonce_hex, tmp_encryption_ctx->nonce, BLRM_NONCE_LENGTH);
|
||||
|
||||
MXS_DEBUG("Writing Encrypted event type %d, size %lu. IV is %s, nonce %s, enc scheme %d, key ver %u",
|
||||
hdr->event_type,
|
||||
(unsigned long)size,
|
||||
iv_hex,
|
||||
nonce_hex,
|
||||
tmp_encryption_ctx->binlog_crypto_scheme,
|
||||
tmp_encryption_ctx->binlog_key_version);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* save event size (buf + 9, 4 bytes)
|
||||
* move first 4 bytes of buf to buf + 9 ...
|
||||
* encrypt buf starting from buf + 4 (so it will be event_size - 4)
|
||||
* move encrypted_data + 9, (4 bytesi), to encrypted_data[0]
|
||||
* write saved_event_size 4 bytes into encrypted_data + 9
|
||||
* write encrypted_data
|
||||
*
|
||||
* First task is the data move only in current 'buf', no encryption at all.
|
||||
*/
|
||||
|
||||
/* Write current received event from master */
|
||||
if ((n = pwrite(router->binlog_fd, buf, size,
|
||||
router->last_written)) != size)
|
||||
@ -474,10 +524,14 @@ blr_write_binlog_record(ROUTER_INSTANCE *router, REP_HEADER *hdr, uint32_t size,
|
||||
spinlock_release(&router->binlog_lock);
|
||||
|
||||
/* Check whether adding the Start Encryption event into current binlog */
|
||||
if (router->encrypt_binlog && write_begin_encryption)
|
||||
if (router->encryption.enabled && write_begin_encryption)
|
||||
{
|
||||
uint64_t event_size = router->master_chksum ? 40 : 36;
|
||||
uint64_t event_size = sizeof(START_ENCRYPTION_EVENT);
|
||||
uint64_t file_offset = router->current_pos;
|
||||
if (router->master_chksum)
|
||||
{
|
||||
event_size += BINLOG_EVENT_CRC_SIZE;
|
||||
}
|
||||
if (!blr_write_special_event(router, file_offset, event_size, hdr, BLRM_START_ENCRYPTION))
|
||||
{
|
||||
return 0;
|
||||
@ -1298,6 +1352,48 @@ blr_read_events_all_events(ROUTER_INSTANCE *router, int fix, int debug)
|
||||
}
|
||||
}
|
||||
|
||||
if (start_encryption_seen)
|
||||
{
|
||||
uint8_t iv[AES_BLOCK_SIZE + 1] = "";
|
||||
char iv_hex[AES_BLOCK_SIZE * 2 + 1] = "";
|
||||
uint32_t event_size = EXTRACT32(hdbuf + BINLOG_EVENT_LEN_OFFSET);
|
||||
|
||||
/**
|
||||
* Events are encrypted.
|
||||
*
|
||||
* The routine doesn't decrypt them but follows
|
||||
* next event based on the event_size (4 bytes) that is af offset
|
||||
* of BINLOG_EVENT_LEN_OFFSET (9) and it's in clear.
|
||||
*
|
||||
* This version prints to DEBUG the encryption event IV.
|
||||
*/
|
||||
|
||||
/* Get binlog file "nonce" and other data from router encryption_ctx */
|
||||
BINLOG_ENCRYPTION_CTX *enc_ctx = router->encryption_ctx;
|
||||
|
||||
/* Encryption IV is 12 bytes nonce + 4 bytes event position */
|
||||
memcpy(iv, enc_ctx->nonce, BLRM_NONCE_LENGTH);
|
||||
gw_mysql_set_byte4(iv + BLRM_NONCE_LENGTH, (unsigned long)pos);
|
||||
|
||||
/* Human readable version */
|
||||
gw_bin2hex(iv_hex, iv, BLRM_IV_LENGTH);
|
||||
|
||||
MXS_DEBUG("** Encrypted Event @ %lu: the IV is %s, size is %lu, next pos is %lu\n",
|
||||
(unsigned long)pos,
|
||||
iv_hex, (unsigned long)event_size,
|
||||
(unsigned long)(pos + event_size));
|
||||
|
||||
/* Next event pos is ps + event size */
|
||||
pos = pos + event_size;
|
||||
|
||||
/* Update other offsets as well */
|
||||
router->binlog_position = pos;
|
||||
router->current_safe_event = pos;
|
||||
router->current_pos = pos;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* fill replication header struct */
|
||||
hdr.timestamp = EXTRACT32(hdbuf);
|
||||
hdr.event_type = hdbuf[4];
|
||||
@ -1586,51 +1682,64 @@ blr_read_events_all_events(ROUTER_INSTANCE *router, int fix, int debug)
|
||||
/* Detect possible Start Encryption Event */
|
||||
if (hdr.event_type == MARIADB10_START_ENCRYPTION_EVENT)
|
||||
{
|
||||
START_ENCRYPTION_EVENT ste_event = {};
|
||||
char nonce_hex[12 * 2 + 1] = "";
|
||||
/* The start encryption event data is 17 bytes long:
|
||||
* Scheme = 1
|
||||
* Key Version: 4
|
||||
* nonce = 12
|
||||
*/
|
||||
char nonce_hex[12 * 2 + 1] = "";
|
||||
BINLOG_ENCRYPTION_CTX *new_encryption_ctx = MXS_CALLOC(1, sizeof(BINLOG_ENCRYPTION_CTX));
|
||||
START_ENCRYPTION_EVENT ste_event = {};
|
||||
|
||||
/* Fill the event content, after the event header */
|
||||
ste_event.binlog_crypto_scheme = ptr[0];
|
||||
ste_event.binlog_key_version = extract_field(ptr + 1, 32);
|
||||
memcpy(ste_event.nonce, ptr + 1 + 4, BLRM_NONCE_LENGTH);
|
||||
/* The start encryption event data is 17 bytes long:
|
||||
* Scheme = 1
|
||||
* Key Version: 4
|
||||
* nonce = 12
|
||||
*/
|
||||
|
||||
if (debug)
|
||||
/* Fill the event content, after the event header */
|
||||
ste_event.binlog_crypto_scheme = ptr[0];
|
||||
ste_event.binlog_key_version = extract_field(ptr + 1, 32);
|
||||
memcpy(ste_event.nonce, ptr + 1 + 4, BLRM_NONCE_LENGTH);
|
||||
|
||||
/* Fill the encryption_ctx */
|
||||
memcpy(new_encryption_ctx->nonce, ste_event.nonce, BLRM_NONCE_LENGTH);
|
||||
new_encryption_ctx->binlog_crypto_scheme = ste_event.binlog_crypto_scheme;
|
||||
memcpy(&new_encryption_ctx->binlog_key_version,
|
||||
&ste_event.binlog_key_version, BLRM_KEY_VERSION_LENGTH);
|
||||
|
||||
if (debug)
|
||||
{
|
||||
char *cksum_format = ", crc32 0x";
|
||||
char hex_checksum[BINLOG_EVENT_CRC_SIZE * 2 + strlen(cksum_format) + 1];
|
||||
uint8_t cksum_data[BINLOG_EVENT_CRC_SIZE];
|
||||
hex_checksum[0]='\0';
|
||||
|
||||
/* Hex representation of nonce */
|
||||
gw_bin2hex(nonce_hex, ste_event.nonce, BLRM_NONCE_LENGTH);
|
||||
|
||||
/* Hex representation of checksum */
|
||||
cksum_data[3] = *(ptr + hdr.event_size - 4 - BINLOG_EVENT_HDR_LEN);
|
||||
cksum_data[2] = *(ptr + hdr.event_size - 3 - BINLOG_EVENT_HDR_LEN);
|
||||
cksum_data[1] = *(ptr + hdr.event_size - 2 - BINLOG_EVENT_HDR_LEN);
|
||||
cksum_data[0] = *(ptr + hdr.event_size - 1 - BINLOG_EVENT_HDR_LEN);
|
||||
|
||||
if (found_chksum)
|
||||
{
|
||||
char *cksum_format = ", crc32 0x";
|
||||
char hex_checksum[BINLOG_EVENT_CRC_SIZE * 2 + strlen(cksum_format) + 1];
|
||||
uint8_t cksum_data[BINLOG_EVENT_CRC_SIZE];
|
||||
hex_checksum[0]='\0';
|
||||
|
||||
/* Hex representation of nonce */
|
||||
gw_bin2hex(nonce_hex, ste_event.nonce, BLRM_NONCE_LENGTH);
|
||||
|
||||
/* Hex representation of checksum */
|
||||
cksum_data[3] = *(ptr + hdr.event_size - 4 - BINLOG_EVENT_HDR_LEN);
|
||||
cksum_data[2] = *(ptr + hdr.event_size - 3 - BINLOG_EVENT_HDR_LEN);
|
||||
cksum_data[1] = *(ptr + hdr.event_size - 2 - BINLOG_EVENT_HDR_LEN);
|
||||
cksum_data[0] = *(ptr + hdr.event_size - 1 - BINLOG_EVENT_HDR_LEN);
|
||||
|
||||
if (found_chksum)
|
||||
{
|
||||
strcpy(hex_checksum, cksum_format);
|
||||
gw_bin2hex(hex_checksum + strlen(cksum_format) , cksum_data, BINLOG_EVENT_CRC_SIZE);
|
||||
}
|
||||
|
||||
MXS_DEBUG("- START_ENCRYPTION event @ %llu, size %lu, next pos is @ %lu, flags %u%s",
|
||||
pos, (unsigned long)hdr.event_size, (unsigned long)hdr.next_pos, hdr.flags,
|
||||
hex_checksum);
|
||||
|
||||
MXS_DEBUG(" Encryption scheme: %u, key_version: %u,"
|
||||
" nonce: %s\n", ste_event.binlog_crypto_scheme,
|
||||
ste_event.binlog_key_version, nonce_hex);
|
||||
strcpy(hex_checksum, cksum_format);
|
||||
gw_bin2hex(hex_checksum + strlen(cksum_format) , cksum_data, BINLOG_EVENT_CRC_SIZE);
|
||||
}
|
||||
|
||||
start_encryption_seen = 1;
|
||||
MXS_DEBUG("- START_ENCRYPTION event @ %llu, size %lu, next pos is @ %lu, flags %u%s",
|
||||
pos, (unsigned long)hdr.event_size, (unsigned long)hdr.next_pos, hdr.flags,
|
||||
hex_checksum);
|
||||
|
||||
MXS_DEBUG(" Encryption scheme: %u, key_version: %u,"
|
||||
" nonce: %s\n", ste_event.binlog_crypto_scheme,
|
||||
ste_event.binlog_key_version, nonce_hex);
|
||||
}
|
||||
|
||||
start_encryption_seen = 1;
|
||||
|
||||
/* Update the router encryption context */
|
||||
MXS_FREE(router->encryption_ctx);
|
||||
router->encryption_ctx = NULL;
|
||||
router->encryption_ctx = new_encryption_ctx;
|
||||
}
|
||||
|
||||
/* set last event time, pos and type */
|
||||
@ -2375,6 +2484,7 @@ blr_create_start_encryption_event(ROUTER_INSTANCE *router, uint32_t event_pos, b
|
||||
{
|
||||
uint8_t *new_event;
|
||||
uint8_t event_size = sizeof(START_ENCRYPTION_EVENT);
|
||||
BINLOG_ENCRYPTION_CTX *new_encryption_ctx = MXS_CALLOC(1, sizeof(BINLOG_ENCRYPTION_CTX));
|
||||
|
||||
/* Add 4 bytes to event size with crc32 */
|
||||
if (do_checksum)
|
||||
@ -2424,6 +2534,22 @@ blr_create_start_encryption_event(ROUTER_INSTANCE *router, uint32_t event_pos, b
|
||||
encode_value(new_event + event_size - BINLOG_EVENT_CRC_SIZE, chksum, 32);
|
||||
}
|
||||
|
||||
/* Update the encryption context */
|
||||
uint8_t *nonce_ptr = &(new_event[BINLOG_EVENT_HDR_LEN + 4 + 1]);
|
||||
|
||||
spinlock_acquire(&router->binlog_lock);
|
||||
|
||||
memcpy(new_encryption_ctx->nonce, nonce_ptr, BLRM_NONCE_LENGTH);
|
||||
new_encryption_ctx->binlog_crypto_scheme = new_event[BINLOG_EVENT_HDR_LEN];
|
||||
memcpy(&new_encryption_ctx->binlog_key_version,
|
||||
&new_event[BINLOG_EVENT_HDR_LEN + 1], BLRM_KEY_VERSION_LENGTH);
|
||||
|
||||
MXS_FREE(router->encryption_ctx);
|
||||
router->encryption_ctx = NULL;
|
||||
router->encryption_ctx = new_encryption_ctx;
|
||||
|
||||
spinlock_release(&router->binlog_lock);
|
||||
|
||||
return new_event;
|
||||
}
|
||||
|
||||
|
||||
@ -1250,8 +1250,9 @@ blr_handle_binlog_record(ROUTER_INSTANCE *router, GWBUF *pkt)
|
||||
|
||||
spinlock_release(&router->lock);
|
||||
#ifdef SHOW_EVENTS
|
||||
printf("blr: len %lu, event type 0x%02x, flags 0x%04x, "
|
||||
printf("blr @ %lu: len %lu, event type 0x%02x, flags 0x%04x, "
|
||||
"event size %d, event timestamp %lu\n",
|
||||
router->current_pos,
|
||||
(unsigned long)len - 4,
|
||||
hdr.event_type,
|
||||
hdr.flags,
|
||||
|
||||
@ -28,6 +28,12 @@
|
||||
* Currently MariadDB 10 starting transactions
|
||||
* are detected checking GTID event
|
||||
* with flags = 0
|
||||
* 26/04/16 Massimiliano Pinto MariaDB 10.1 GTID flags are properly parsed
|
||||
* 23/09/16 Massimiliano Pinto MariaDB 10.1 encrypted binlog compatible:
|
||||
* the output shows the START_ENCRYPTION_EVENT and follows
|
||||
* binlog positions without dectypting events.
|
||||
*
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
|
||||
@ -55,7 +61,7 @@ static struct option long_options[] =
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
char *binlog_check_version = "1.1.0";
|
||||
char *binlog_check_version = "1.2.0";
|
||||
|
||||
int
|
||||
maxscale_uptime()
|
||||
|
||||
Reference in New Issue
Block a user