1 /*****************************************************************************
2 Copyright (C) 2013, 2015, Google Inc. All Rights Reserved.
3 Copyright (c) 2015, 2018, MariaDB Corporation.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************//**
20 @file include/fil0crypt.h
21 The low-level file system encryption support functions
22 
23 Created 04/01/2015 Jan Lindström
24 *******************************************************/
25 
26 #ifndef fil0crypt_h
27 #define fil0crypt_h
28 
29 #ifndef UNIV_INNOCHECKSUM
30 #include "os0event.h"
31 #include "my_crypt.h"
32 #include "fil0fil.h"
33 #endif /*! UNIV_INNOCHECKSUM */
34 
35 /**
36 * Magic pattern in start of crypt data on page 0
37 */
38 #define MAGIC_SZ 6
39 
40 static const unsigned char CRYPT_MAGIC[MAGIC_SZ] = {
41 	's', 0xE, 0xC, 'R', 'E', 't' };
42 
43 /* This key will be used if nothing else is given */
44 #define FIL_DEFAULT_ENCRYPTION_KEY ENCRYPTION_KEY_SYSTEM_DATA
45 
46 extern os_event_t fil_crypt_threads_event;
47 
48 /**
49  * CRYPT_SCHEME_UNENCRYPTED
50  *
51  * Used as intermediate state when convering a space from unencrypted
52  * to encrypted
53  */
54 /**
55  * CRYPT_SCHEME_1
56  *
57  * xxx is AES_CTR or AES_CBC (or another block cypher with the same key and iv lengths)
58  *  L = AES_ECB(KEY, IV)
59  *  CRYPT(PAGE) = xxx(KEY=L, IV=C, PAGE)
60  */
61 
62 #define CRYPT_SCHEME_1 1
63 #define CRYPT_SCHEME_1_IV_LEN 16
64 #define CRYPT_SCHEME_UNENCRYPTED 0
65 
66 /* Cached L or key for given key_version */
67 struct key_struct
68 {
69 	uint key_version;			/*!< Version of the key */
70 	uint key_length;			/*!< Key length */
71 	unsigned char key[MY_AES_MAX_KEY_LENGTH]; /*!< Cached key
72                                                 (that is L in CRYPT_SCHEME_1) */
73 };
74 
75 /** is encryption enabled */
76 extern ulong	srv_encrypt_tables;
77 
78 /** Mutex helper for crypt_data->scheme
79 @param[in, out]	schme	encryption scheme
80 @param[in]	exit	should we exit or enter mutex ? */
81 void
82 crypt_data_scheme_locker(
83 	st_encryption_scheme*	scheme,
84 	int			exit);
85 
86 struct fil_space_rotate_state_t
87 {
88 	time_t start_time;	/*!< time when rotation started */
89 	ulint active_threads;	/*!< active threads in space */
90 	ulint next_offset;	/*!< next "free" offset */
91 	ulint max_offset;	/*!< max offset needing to be rotated */
92 	uint  min_key_version_found; /*!< min key version found but not
93 				     rotated */
94 	lsn_t end_lsn;		/*!< max lsn created when rotating this
95 				space */
96 	bool starting;		/*!< initial write of IV */
97 	bool flushing;		/*!< space is being flushed at end of rotate */
98 	struct {
99 		bool is_active; /*!< is scrubbing active in this space */
100 		time_t last_scrub_completed; /*!< when was last scrub
101 					     completed */
102 	} scrubbing;
103 };
104 
105 #ifndef UNIV_INNOCHECKSUM
106 
107 struct fil_space_crypt_t : st_encryption_scheme
108 {
109  public:
110 	/** Constructor. Does not initialize the members!
111 	The object is expected to be placed in a buffer that
112 	has been zero-initialized. */
fil_space_crypt_tfil_space_crypt_t113 	fil_space_crypt_t(
114 		uint new_type,
115 		uint new_min_key_version,
116 		uint new_key_id,
117 		fil_encryption_t new_encryption)
118 		: st_encryption_scheme(),
119 		min_key_version(new_min_key_version),
120 		page0_offset(0),
121 		encryption(new_encryption),
122 		key_found(0),
123 		rotate_state()
124 	{
125 		key_id = new_key_id;
126 		my_random_bytes(iv, sizeof(iv));
127 		mutex_create(LATCH_ID_FIL_CRYPT_DATA_MUTEX, &mutex);
128 		locker = crypt_data_scheme_locker;
129 		type = new_type;
130 
131 		if (new_encryption == FIL_ENCRYPTION_OFF ||
132 			(!srv_encrypt_tables &&
133 			 new_encryption == FIL_ENCRYPTION_DEFAULT)) {
134 			type = CRYPT_SCHEME_UNENCRYPTED;
135 		} else {
136 			type = CRYPT_SCHEME_1;
137 			min_key_version = key_get_latest_version();
138 		}
139 
140 		key_found = min_key_version;
141 	}
142 
143 	/** Destructor */
~fil_space_crypt_tfil_space_crypt_t144 	~fil_space_crypt_t()
145 	{
146 		mutex_free(&mutex);
147 	}
148 
149 	/** Get latest key version from encryption plugin
150 	@retval key_version or
151 	@retval ENCRYPTION_KEY_VERSION_INVALID if used key_id
152 	is not found from encryption plugin. */
153 	uint key_get_latest_version(void);
154 
155 	/** Returns true if key was found from encryption plugin
156 	and false if not. */
is_key_foundfil_space_crypt_t157 	bool is_key_found() const {
158 		return key_found != ENCRYPTION_KEY_VERSION_INVALID;
159 	}
160 
161 	/** Returns true if tablespace should be encrypted */
should_encryptfil_space_crypt_t162 	bool should_encrypt() const {
163 		return ((encryption == FIL_ENCRYPTION_ON) ||
164 			(srv_encrypt_tables &&
165 				encryption == FIL_ENCRYPTION_DEFAULT));
166 	}
167 
168 	/** Return true if tablespace is encrypted. */
is_encryptedfil_space_crypt_t169 	bool is_encrypted() const {
170 		return (encryption != FIL_ENCRYPTION_OFF);
171 	}
172 
173 	/** Return true if default tablespace encryption is used, */
is_default_encryptionfil_space_crypt_t174 	bool is_default_encryption() const {
175 		return (encryption == FIL_ENCRYPTION_DEFAULT);
176 	}
177 
178 	/** Return true if tablespace is not encrypted. */
not_encryptedfil_space_crypt_t179 	bool not_encrypted() const {
180 		return (encryption == FIL_ENCRYPTION_OFF);
181 	}
182 
183 	/** Fill crypt data information to the give page.
184 	It should be called during ibd file creation.
185 	@param[in]	flags	tablespace flags
186 	@param[in,out]	page	first page of the tablespace */
187 	void fill_page0(ulint flags, byte* page);
188 
189 	/** Write crypt data to a page (0)
190 	@param[in]	space	tablespace
191 	@param[in,out]	page0	first page of the tablespace
192 	@param[in,out]	mtr	mini-transaction */
193 	void write_page0(const fil_space_t* space, byte* page0, mtr_t* mtr);
194 
195 	uint min_key_version; // min key version for this space
196 	ulint page0_offset;   // byte offset on page 0 for crypt data
197 	fil_encryption_t encryption; // Encryption setup
198 
199 	ib_mutex_t mutex;   // mutex protecting following variables
200 
201 	/** Return code from encryption_key_get_latest_version.
202         If ENCRYPTION_KEY_VERSION_INVALID encryption plugin
203 	could not find the key and there is no need to call
204 	get_latest_key_version again as keys are read only
205 	at startup. */
206 	uint key_found;
207 
208 	fil_space_rotate_state_t rotate_state;
209 };
210 
211 /** Status info about encryption */
212 struct fil_space_crypt_status_t {
213 	ulint space;             /*!< tablespace id */
214 	ulint scheme;            /*!< encryption scheme */
215 	uint  min_key_version;   /*!< min key version */
216 	uint  current_key_version;/*!< current key version */
217 	uint  keyserver_requests;/*!< no of key requests to key server */
218 	uint key_id;            /*!< current key_id */
219 	bool rotating;           /*!< is key rotation ongoing */
220 	bool flushing;           /*!< is flush at end of rotation ongoing */
221 	ulint rotate_next_page_number; /*!< next page if key rotating */
222 	ulint rotate_max_page_number;  /*!< max page if key rotating */
223 };
224 
225 /** Statistics about encryption key rotation */
226 struct fil_crypt_stat_t {
227 	ulint pages_read_from_cache;
228 	ulint pages_read_from_disk;
229 	ulint pages_modified;
230 	ulint pages_flushed;
231 	ulint estimated_iops;
232 };
233 
234 /** Status info about scrubbing */
235 struct fil_space_scrub_status_t {
236 	ulint space;             /*!< tablespace id */
237 	bool compressed;        /*!< is space compressed  */
238 	time_t last_scrub_completed;  /*!< when was last scrub completed */
239 	bool scrubbing;               /*!< is scrubbing ongoing */
240 	time_t current_scrub_started; /*!< when started current scrubbing */
241 	ulint current_scrub_active_threads; /*!< current scrub active threads */
242 	ulint current_scrub_page_number; /*!< current scrub page no */
243 	ulint current_scrub_max_page_number; /*!< current scrub max page no */
244 };
245 
246 /*********************************************************************
247 Init space crypt */
248 UNIV_INTERN
249 void
250 fil_space_crypt_init();
251 
252 /*********************************************************************
253 Cleanup space crypt */
254 UNIV_INTERN
255 void
256 fil_space_crypt_cleanup();
257 
258 /**
259 Create a fil_space_crypt_t object
260 @param[in]	encrypt_mode	FIL_ENCRYPTION_DEFAULT or
261 				FIL_ENCRYPTION_ON or
262 				FIL_ENCRYPTION_OFF
263 
264 @param[in]	key_id		Encryption key id
265 @return crypt object */
266 UNIV_INTERN
267 fil_space_crypt_t*
268 fil_space_create_crypt_data(
269 	fil_encryption_t	encrypt_mode,
270 	uint			key_id)
271 	MY_ATTRIBUTE((warn_unused_result));
272 
273 /******************************************************************
274 Merge fil_space_crypt_t object
275 @param[in,out]	dst		Destination cryp data
276 @param[in]	src		Source crypt data */
277 UNIV_INTERN
278 void
279 fil_space_merge_crypt_data(
280 	fil_space_crypt_t* dst,
281 	const fil_space_crypt_t* src);
282 
283 /** Initialize encryption parameters from a tablespace header page.
284 @param[in]	page_size	page size of the tablespace
285 @param[in]	page		first page of the tablespace
286 @return crypt data from page 0
287 @retval	NULL	if not present or not valid */
288 UNIV_INTERN
289 fil_space_crypt_t*
290 fil_space_read_crypt_data(const page_size_t& page_size, const byte* page)
291 	MY_ATTRIBUTE((nonnull, warn_unused_result));
292 
293 /**
294 Free a crypt data object
295 @param[in,out] crypt_data	crypt data to be freed */
296 UNIV_INTERN
297 void
298 fil_space_destroy_crypt_data(
299 	fil_space_crypt_t **crypt_data);
300 
301 /******************************************************************
302 Parse a MLOG_FILE_WRITE_CRYPT_DATA log entry
303 @param[in]	ptr		Log entry start
304 @param[in]	end_ptr		Log entry end
305 @param[out]	err		DB_SUCCESS or DB_DECRYPTION_FAILED
306 @return position on log buffer */
307 UNIV_INTERN
308 byte*
309 fil_parse_write_crypt_data(
310 	byte*			ptr,
311 	const byte*		end_ptr,
312 	dberr_t*		err)
313 	MY_ATTRIBUTE((warn_unused_result));
314 
315 /** Encrypt a buffer.
316 @param[in,out]		crypt_data	Crypt data
317 @param[in]		space		space_id
318 @param[in]		offset		Page offset
319 @param[in]		lsn		Log sequence number
320 @param[in]		src_frame	Page to encrypt
321 @param[in]		page_size	Page size
322 @param[in,out]		dst_frame	Output buffer
323 @return encrypted buffer or NULL */
324 byte*
325 fil_encrypt_buf(
326 	fil_space_crypt_t*	crypt_data,
327 	ulint			space,
328 	ulint			offset,
329 	lsn_t			lsn,
330 	const byte*		src_frame,
331 	const page_size_t&	page_size,
332 	byte*			dst_frame)
333 	MY_ATTRIBUTE((warn_unused_result));
334 
335 /**
336 Encrypt a page.
337 
338 @param[in]		space		Tablespace
339 @param[in]		offset		Page offset
340 @param[in]		lsn		Log sequence number
341 @param[in]		src_frame	Page to encrypt
342 @param[in,out]		dst_frame	Output buffer
343 @return encrypted buffer or NULL */
344 UNIV_INTERN
345 byte*
346 fil_space_encrypt(
347 	const fil_space_t* space,
348 	ulint		offset,
349 	lsn_t		lsn,
350 	byte*		src_frame,
351 	byte*		dst_frame)
352 	MY_ATTRIBUTE((warn_unused_result));
353 
354 /**
355 Decrypt a page.
356 @param[in,out]	crypt_data		crypt_data
357 @param[in]	tmp_frame		Temporary buffer
358 @param[in]	page_size		Page size
359 @param[in,out]	src_frame		Page to decrypt
360 @return DB_SUCCESS or error */
361 UNIV_INTERN
362 dberr_t
363 fil_space_decrypt(
364 	fil_space_crypt_t*	crypt_data,
365 	byte*			tmp_frame,
366 	const page_size_t&	page_size,
367 	byte*			src_frame);
368 
369 /******************************************************************
370 Decrypt a page
371 @param[in]	space			Tablespace
372 @param[in]	tmp_frame		Temporary buffer used for decrypting
373 @param[in,out]	src_frame		Page to decrypt
374 @return decrypted page, or original not encrypted page if decryption is
375 not needed.*/
376 UNIV_INTERN
377 byte*
378 fil_space_decrypt(
379 	const fil_space_t* space,
380 	byte*		tmp_frame,
381 	byte*		src_frame)
382 	MY_ATTRIBUTE((warn_unused_result));
383 
384 /******************************************************************
385 Calculate post encryption checksum
386 @param[in]	page_size	page size
387 @param[in]	dst_frame	Block where checksum is calculated
388 @return page checksum or BUF_NO_CHECKSUM_MAGIC
389 not needed. */
390 UNIV_INTERN
391 uint32_t
392 fil_crypt_calculate_checksum(
393 	const page_size_t&	page_size,
394 	const byte*		dst_frame)
395 	MY_ATTRIBUTE((warn_unused_result));
396 
397 /*********************************************************************
398 Adjust thread count for key rotation
399 @param[in]	enw_cnt		Number of threads to be used */
400 UNIV_INTERN
401 void
402 fil_crypt_set_thread_cnt(
403 	uint	new_cnt);
404 
405 /*********************************************************************
406 Adjust max key age
407 @param[in]	val		New max key age */
408 UNIV_INTERN
409 void
410 fil_crypt_set_rotate_key_age(
411 	uint	val);
412 
413 /*********************************************************************
414 Adjust rotation iops
415 @param[in]	val		New max roation iops */
416 UNIV_INTERN
417 void
418 fil_crypt_set_rotation_iops(
419 	uint val);
420 
421 /*********************************************************************
422 Adjust encrypt tables
423 @param[in]	val		New setting for innodb-encrypt-tables */
424 UNIV_INTERN
425 void
426 fil_crypt_set_encrypt_tables(
427 	uint val);
428 
429 /*********************************************************************
430 Init threads for key rotation */
431 UNIV_INTERN
432 void
433 fil_crypt_threads_init();
434 
435 /*********************************************************************
436 Clean up key rotation threads resources */
437 UNIV_INTERN
438 void
439 fil_crypt_threads_cleanup();
440 
441 /*********************************************************************
442 Wait for crypt threads to stop accessing space
443 @param[in]	space		Tablespace */
444 UNIV_INTERN
445 void
446 fil_space_crypt_close_tablespace(
447 	const fil_space_t*	space);
448 
449 /*********************************************************************
450 Get crypt status for a space (used by information_schema)
451 @param[in]	space		Tablespace
452 @param[out]	status		Crypt status
453 return 0 if crypt data present */
454 UNIV_INTERN
455 void
456 fil_space_crypt_get_status(
457 	const fil_space_t*			space,
458 	struct fil_space_crypt_status_t*	status);
459 
460 /*********************************************************************
461 Return crypt statistics
462 @param[out]	stat		Crypt statistics */
463 UNIV_INTERN
464 void
465 fil_crypt_total_stat(
466 	fil_crypt_stat_t *stat);
467 
468 /**
469 Get scrub status for a space (used by information_schema)
470 
471 @param[in]	space		Tablespace
472 @param[out]	status		Scrub status
473 return 0 if data found */
474 UNIV_INTERN
475 void
476 fil_space_get_scrub_status(
477 	const fil_space_t*		space,
478 	fil_space_scrub_status_t*	status);
479 
480 #include "fil0crypt.inl"
481 #endif /* !UNIV_INNOCHECKSUM */
482 
483 /**
484 Verify that post encryption checksum match calculated checksum.
485 This function should be called only if tablespace contains crypt_data
486 metadata (this is strong indication that tablespace is encrypted).
487 Function also verifies that traditional checksum does not match
488 calculated checksum as if it does page could be valid unencrypted,
489 encrypted, or corrupted.
490 
491 @param[in,out]	page		page frame (checksum is temporarily modified)
492 @param[in]	page_size	page size
493 @return true if page is encrypted AND OK, false otherwise */
494 bool
495 fil_space_verify_crypt_checksum(const byte* page, const page_size_t& page_size)
496 	MY_ATTRIBUTE((warn_unused_result));
497 
498 /** Add the tablespace to the rotation list if
499 innodb_encrypt_rotate_key_age is 0 or encryption plugin does
500 not do key version rotation
501 @return whether the tablespace should be added to rotation list */
502 bool fil_crypt_must_default_encrypt();
503 
504 #endif /* fil0crypt_h */
505