1 /*****************************************************************************
2 Copyright (C) 2013, 2015, Google Inc. All Rights Reserved.
3 Copyright (c) 2015, 2019, 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 #include "os0event.h"
30 #include "my_crypt.h"
31 #include "fil0fil.h"
32 
33 /**
34 * Magic pattern in start of crypt data on page 0
35 */
36 #define MAGIC_SZ 6
37 
38 static const unsigned char CRYPT_MAGIC[MAGIC_SZ] = {
39 	's', 0xE, 0xC, 'R', 'E', 't' };
40 
41 /* This key will be used if nothing else is given */
42 #define FIL_DEFAULT_ENCRYPTION_KEY ENCRYPTION_KEY_SYSTEM_DATA
43 
44 extern os_event_t fil_crypt_threads_event;
45 
46 /**
47  * CRYPT_SCHEME_UNENCRYPTED
48  *
49  * Used as intermediate state when convering a space from unencrypted
50  * to encrypted
51  */
52 /**
53  * CRYPT_SCHEME_1
54  *
55  * xxx is AES_CTR or AES_CBC (or another block cypher with the same key and iv lengths)
56  *  L = AES_ECB(KEY, IV)
57  *  CRYPT(PAGE) = xxx(KEY=L, IV=C, PAGE)
58  */
59 
60 #define CRYPT_SCHEME_1 1
61 #define CRYPT_SCHEME_1_IV_LEN 16
62 #define CRYPT_SCHEME_UNENCRYPTED 0
63 
64 /* Cached L or key for given key_version */
65 struct key_struct
66 {
67 	uint key_version;			/*!< Version of the key */
68 	uint key_length;			/*!< Key length */
69 	unsigned char key[MY_AES_MAX_KEY_LENGTH]; /*!< Cached key
70                                                 (that is L in CRYPT_SCHEME_1) */
71 };
72 
73 /** is encryption enabled */
74 extern ulong	srv_encrypt_tables;
75 
76 /** Mutex helper for crypt_data->scheme
77 @param[in, out]	schme	encryption scheme
78 @param[in]	exit	should we exit or enter mutex ? */
79 void
80 crypt_data_scheme_locker(
81 	st_encryption_scheme*	scheme,
82 	int			exit);
83 
84 struct fil_space_rotate_state_t
85 {
86 	time_t start_time;	/*!< time when rotation started */
87 	ulint active_threads;	/*!< active threads in space */
88 	ulint next_offset;	/*!< next "free" offset */
89 	ulint max_offset;	/*!< max offset needing to be rotated */
90 	uint  min_key_version_found; /*!< min key version found but not
91 				     rotated */
92 	lsn_t end_lsn;		/*!< max lsn created when rotating this
93 				space */
94 	bool starting;		/*!< initial write of IV */
95 	bool flushing;		/*!< space is being flushed at end of rotate */
96 	struct {
97 		bool is_active; /*!< is scrubbing active in this space */
98 		time_t last_scrub_completed; /*!< when was last scrub
99 					     completed */
100 	} scrubbing;
101 };
102 
103 #ifndef UNIV_INNOCHECKSUM
104 
105 struct fil_space_crypt_t : st_encryption_scheme
106 {
107  public:
108 	/** Constructor. Does not initialize the members!
109 	The object is expected to be placed in a buffer that
110 	has been zero-initialized. */
fil_space_crypt_tfil_space_crypt_t111 	fil_space_crypt_t(
112 		uint new_type,
113 		uint new_min_key_version,
114 		uint new_key_id,
115 		fil_encryption_t new_encryption)
116 		: st_encryption_scheme(),
117 		min_key_version(new_min_key_version),
118 		page0_offset(0),
119 		encryption(new_encryption),
120 		key_found(0),
121 		rotate_state()
122 	{
123 		key_id = new_key_id;
124 		my_random_bytes(iv, sizeof(iv));
125 		mutex_create(LATCH_ID_FIL_CRYPT_DATA_MUTEX, &mutex);
126 		locker = crypt_data_scheme_locker;
127 		type = new_type;
128 
129 		if (new_encryption == FIL_ENCRYPTION_OFF ||
130 			(!srv_encrypt_tables &&
131 			 new_encryption == FIL_ENCRYPTION_DEFAULT)) {
132 			type = CRYPT_SCHEME_UNENCRYPTED;
133 		} else {
134 			type = CRYPT_SCHEME_1;
135 			min_key_version = key_get_latest_version();
136 		}
137 
138 		key_found = min_key_version;
139 	}
140 
141 	/** Destructor */
~fil_space_crypt_tfil_space_crypt_t142 	~fil_space_crypt_t()
143 	{
144 		mutex_free(&mutex);
145 	}
146 
147 	/** Get latest key version from encryption plugin
148 	@retval key_version or
149 	@retval ENCRYPTION_KEY_VERSION_INVALID if used key_id
150 	is not found from encryption plugin. */
151 	uint key_get_latest_version(void);
152 
153 	/** Returns true if key was found from encryption plugin
154 	and false if not. */
is_key_foundfil_space_crypt_t155 	bool is_key_found() const {
156 		return key_found != ENCRYPTION_KEY_VERSION_INVALID;
157 	}
158 
159 	/** Returns true if tablespace should be encrypted */
should_encryptfil_space_crypt_t160 	bool should_encrypt() const {
161 		return ((encryption == FIL_ENCRYPTION_ON) ||
162 			(srv_encrypt_tables &&
163 				encryption == FIL_ENCRYPTION_DEFAULT));
164 	}
165 
166 	/** Return true if tablespace is encrypted. */
is_encryptedfil_space_crypt_t167 	bool is_encrypted() const {
168 		return (encryption != FIL_ENCRYPTION_OFF);
169 	}
170 
171 	/** Return true if default tablespace encryption is used, */
is_default_encryptionfil_space_crypt_t172 	bool is_default_encryption() const {
173 		return (encryption == FIL_ENCRYPTION_DEFAULT);
174 	}
175 
176 	/** Return true if tablespace is not encrypted. */
not_encryptedfil_space_crypt_t177 	bool not_encrypted() const {
178 		return (encryption == FIL_ENCRYPTION_OFF);
179 	}
180 
181 	/** Fill crypt data information to the give page.
182 	It should be called during ibd file creation.
183 	@param[in]	flags	tablespace flags
184 	@param[in,out]	page	first page of the tablespace */
185 	void fill_page0(ulint flags, byte* page);
186 
187 	/** Write crypt data to a page (0)
188 	@param[in]	space	tablespace
189 	@param[in,out]	page0	first page of the tablespace
190 	@param[in,out]	mtr	mini-transaction */
191 	void write_page0(const fil_space_t* space, byte* page0, mtr_t* mtr);
192 
193 	uint min_key_version; // min key version for this space
194 	ulint page0_offset;   // byte offset on page 0 for crypt data
195 	fil_encryption_t encryption; // Encryption setup
196 
197 	ib_mutex_t mutex;   // mutex protecting following variables
198 
199 	/** Return code from encryption_key_get_latest_version.
200         If ENCRYPTION_KEY_VERSION_INVALID encryption plugin
201 	could not find the key and there is no need to call
202 	get_latest_key_version again as keys are read only
203 	at startup. */
204 	uint key_found;
205 
206 	fil_space_rotate_state_t rotate_state;
207 };
208 
209 /** Status info about encryption */
210 struct fil_space_crypt_status_t {
211 	ulint space;             /*!< tablespace id */
212 	ulint scheme;            /*!< encryption scheme */
213 	uint  min_key_version;   /*!< min key version */
214 	uint  current_key_version;/*!< current key version */
215 	uint  keyserver_requests;/*!< no of key requests to key server */
216 	uint key_id;            /*!< current key_id */
217 	bool rotating;           /*!< is key rotation ongoing */
218 	bool flushing;           /*!< is flush at end of rotation ongoing */
219 	ulint rotate_next_page_number; /*!< next page if key rotating */
220 	ulint rotate_max_page_number;  /*!< max page if key rotating */
221 };
222 
223 /** Statistics about encryption key rotation */
224 struct fil_crypt_stat_t {
225 	ulint pages_read_from_cache;
226 	ulint pages_read_from_disk;
227 	ulint pages_modified;
228 	ulint pages_flushed;
229 	ulint estimated_iops;
230 };
231 
232 /** Status info about scrubbing */
233 struct fil_space_scrub_status_t {
234 	ulint space;             /*!< tablespace id */
235 	bool compressed;        /*!< is space compressed  */
236 	time_t last_scrub_completed;  /*!< when was last scrub completed */
237 	bool scrubbing;               /*!< is scrubbing ongoing */
238 	time_t current_scrub_started; /*!< when started current scrubbing */
239 	ulint current_scrub_active_threads; /*!< current scrub active threads */
240 	ulint current_scrub_page_number; /*!< current scrub page no */
241 	ulint current_scrub_max_page_number; /*!< current scrub max page no */
242 };
243 
244 /*********************************************************************
245 Init space crypt */
246 UNIV_INTERN
247 void
248 fil_space_crypt_init();
249 
250 /*********************************************************************
251 Cleanup space crypt */
252 UNIV_INTERN
253 void
254 fil_space_crypt_cleanup();
255 
256 /**
257 Create a fil_space_crypt_t object
258 @param[in]	encrypt_mode	FIL_ENCRYPTION_DEFAULT or
259 				FIL_ENCRYPTION_ON or
260 				FIL_ENCRYPTION_OFF
261 
262 @param[in]	key_id		Encryption key id
263 @return crypt object */
264 UNIV_INTERN
265 fil_space_crypt_t*
266 fil_space_create_crypt_data(
267 	fil_encryption_t	encrypt_mode,
268 	uint			key_id)
269 	MY_ATTRIBUTE((warn_unused_result));
270 
271 /******************************************************************
272 Merge fil_space_crypt_t object
273 @param[in,out]	dst		Destination cryp data
274 @param[in]	src		Source crypt data */
275 UNIV_INTERN
276 void
277 fil_space_merge_crypt_data(
278 	fil_space_crypt_t* dst,
279 	const fil_space_crypt_t* src);
280 
281 /** Initialize encryption parameters from a tablespace header page.
282 @param[in]	zip_size	ROW_FORMAT=COMPRESSED page size, or 0
283 @param[in]	page		first page of the tablespace
284 @return crypt data from page 0
285 @retval	NULL	if not present or not valid */
286 fil_space_crypt_t* fil_space_read_crypt_data(ulint zip_size, const byte* page)
287 	MY_ATTRIBUTE((nonnull, warn_unused_result));
288 
289 /**
290 Free a crypt data object
291 @param[in,out] crypt_data	crypt data to be freed */
292 UNIV_INTERN
293 void
294 fil_space_destroy_crypt_data(
295 	fil_space_crypt_t **crypt_data);
296 
297 /******************************************************************
298 Parse a MLOG_FILE_WRITE_CRYPT_DATA log entry
299 @param[in]	ptr		Log entry start
300 @param[in]	end_ptr		Log entry end
301 @param[out]	err		DB_SUCCESS or DB_DECRYPTION_FAILED
302 @return position on log buffer */
303 UNIV_INTERN
304 byte*
305 fil_parse_write_crypt_data(
306 	byte*			ptr,
307 	const byte*		end_ptr,
308 	dberr_t*		err)
309 	MY_ATTRIBUTE((warn_unused_result));
310 
311 /** Encrypt a buffer.
312 @param[in,out]		crypt_data		Crypt data
313 @param[in]		space			space_id
314 @param[in]		offset			Page offset
315 @param[in]		lsn			Log sequence number
316 @param[in]		src_frame		Page to encrypt
317 @param[in]		zip_size		ROW_FORMAT=COMPRESSED page size, or 0
318 @param[in,out]		dst_frame		Output buffer
319 @param[in]		use_full_checksum	full crc32 algo is used
320 @return encrypted buffer or NULL */
321 UNIV_INTERN
322 byte*
323 fil_encrypt_buf(
324 	fil_space_crypt_t*	crypt_data,
325 	ulint			space,
326 	ulint			offset,
327 	lsn_t			lsn,
328 	const byte*		src_frame,
329 	ulint			zip_size,
330 	byte*			dst_frame,
331 	bool			use_full_checksum)
332 	MY_ATTRIBUTE((warn_unused_result));
333 
334 /**
335 Encrypt a page.
336 
337 @param[in]		space		Tablespace
338 @param[in]		offset		Page offset
339 @param[in]		lsn		Log sequence number
340 @param[in]		src_frame	Page to encrypt
341 @param[in,out]		dst_frame	Output buffer
342 @return encrypted buffer or NULL */
343 UNIV_INTERN
344 byte*
345 fil_space_encrypt(
346 	const fil_space_t* space,
347 	ulint		offset,
348 	lsn_t		lsn,
349 	byte*		src_frame,
350 	byte*		dst_frame)
351 	MY_ATTRIBUTE((warn_unused_result));
352 
353 
354 /** Decrypt a page.
355 @param]in]	space_id		space id
356 @param[in]	crypt_data		crypt_data
357 @param[in]	tmp_frame		Temporary buffer
358 @param[in]	physical_size		page size
359 @param[in]	fsp_flags		Tablespace flags
360 @param[in,out]	src_frame		Page to decrypt
361 @return DB_SUCCESS or error */
362 UNIV_INTERN
363 dberr_t
364 fil_space_decrypt(
365 	ulint			space_id,
366 	fil_space_crypt_t*	crypt_data,
367 	byte*			tmp_frame,
368 	ulint			physical_size,
369 	ulint			fsp_flags,
370 	byte*			src_frame);
371 
372 /******************************************************************
373 Decrypt a page
374 @param[in]	space			Tablespace
375 @param[in]	tmp_frame		Temporary buffer used for decrypting
376 @param[in,out]	src_frame		Page to decrypt
377 @return decrypted page, or original not encrypted page if decryption is
378 not needed.*/
379 UNIV_INTERN
380 byte*
381 fil_space_decrypt(
382 	const fil_space_t* space,
383 	byte*		tmp_frame,
384 	byte*		src_frame)
385 	MY_ATTRIBUTE((warn_unused_result));
386 
387 /**
388 Calculate post encryption checksum
389 @param[in]	zip_size	ROW_FORMAT=COMPRESSED page size, or 0
390 @param[in]	dst_frame	Block where checksum is calculated
391 @return page checksum
392 not needed. */
393 uint32_t
394 fil_crypt_calculate_checksum(ulint zip_size, 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]	zip_size	ROW_FORMAT=COMPRESSED page size, or 0
493 @return true if page is encrypted AND OK, false otherwise */
494 bool fil_space_verify_crypt_checksum(const byte* page, ulint zip_size)
495 	MY_ATTRIBUTE((warn_unused_result));
496 
497 /** Add the tablespace to the rotation list if
498 innodb_encrypt_rotate_key_age is 0 or encryption plugin does
499 not do key version rotation
500 @return whether the tablespace should be added to rotation list */
501 bool fil_crypt_must_default_encrypt();
502 
503 #endif /* fil0crypt_h */
504