1 /*****************************************************************************
2 Copyright (C) 2013, 2015, Google Inc. All Rights Reserved.
3 Copyright (c) 2015, 2020, 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 	uint32_t next_offset;	/*!< next "free" offset */
89 	uint32_t 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 };
97 
98 #ifndef UNIV_INNOCHECKSUM
99 
100 struct fil_space_crypt_t : st_encryption_scheme
101 {
102  public:
103 	/** Constructor. Does not initialize the members!
104 	The object is expected to be placed in a buffer that
105 	has been zero-initialized. */
fil_space_crypt_tfil_space_crypt_t106 	fil_space_crypt_t(
107 		uint new_type,
108 		uint new_min_key_version,
109 		uint new_key_id,
110 		fil_encryption_t new_encryption)
111 		: st_encryption_scheme(),
112 		min_key_version(new_min_key_version),
113 		encryption(new_encryption),
114 		key_found(0),
115 		rotate_state()
116 	{
117 		key_id = new_key_id;
118 		my_random_bytes(iv, sizeof(iv));
119 		mutex_create(LATCH_ID_FIL_CRYPT_DATA_MUTEX, &mutex);
120 		locker = crypt_data_scheme_locker;
121 		type = new_type;
122 
123 		if (new_encryption == FIL_ENCRYPTION_OFF ||
124 			(!srv_encrypt_tables &&
125 			 new_encryption == FIL_ENCRYPTION_DEFAULT)) {
126 			type = CRYPT_SCHEME_UNENCRYPTED;
127 		} else {
128 			type = CRYPT_SCHEME_1;
129 			min_key_version = key_get_latest_version();
130 		}
131 
132 		key_found = min_key_version;
133 	}
134 
135 	/** Destructor */
~fil_space_crypt_tfil_space_crypt_t136 	~fil_space_crypt_t()
137 	{
138 		mutex_free(&mutex);
139 	}
140 
141 	/** Get latest key version from encryption plugin
142 	@retval key_version or
143 	@retval ENCRYPTION_KEY_VERSION_INVALID if used key_id
144 	is not found from encryption plugin. */
145 	uint key_get_latest_version(void);
146 
147 	/** Returns true if key was found from encryption plugin
148 	and false if not. */
is_key_foundfil_space_crypt_t149 	bool is_key_found() const {
150 		return key_found != ENCRYPTION_KEY_VERSION_INVALID;
151 	}
152 
153 	/** Returns true if tablespace should be encrypted */
should_encryptfil_space_crypt_t154 	bool should_encrypt() const {
155 		return ((encryption == FIL_ENCRYPTION_ON) ||
156 			(srv_encrypt_tables &&
157 				encryption == FIL_ENCRYPTION_DEFAULT));
158 	}
159 
160 	/** Return true if tablespace is encrypted. */
is_encryptedfil_space_crypt_t161 	bool is_encrypted() const {
162 		return (encryption != FIL_ENCRYPTION_OFF);
163 	}
164 
165 	/** Return true if default tablespace encryption is used, */
is_default_encryptionfil_space_crypt_t166 	bool is_default_encryption() const {
167 		return (encryption == FIL_ENCRYPTION_DEFAULT);
168 	}
169 
170 	/** Return true if tablespace is not encrypted. */
not_encryptedfil_space_crypt_t171 	bool not_encrypted() const {
172 		return (encryption == FIL_ENCRYPTION_OFF);
173 	}
174 
175 	/** Fill crypt data information to the give page.
176 	It should be called during ibd file creation.
177 	@param[in]	flags	tablespace flags
178 	@param[in,out]	page	first page of the tablespace */
179 	void fill_page0(ulint flags, byte* page);
180 
181 	/** Write encryption metadata to the first page.
182 	@param[in,out]	block	first page of the tablespace
183 	@param[in,out]	mtr	mini-transaction */
184 	void write_page0(buf_block_t* block, mtr_t* mtr);
185 
186 	uint min_key_version; // min key version for this space
187 	fil_encryption_t encryption; // Encryption setup
188 
189 	ib_mutex_t mutex;   // mutex protecting following variables
190 
191 	/** Return code from encryption_key_get_latest_version.
192         If ENCRYPTION_KEY_VERSION_INVALID encryption plugin
193 	could not find the key and there is no need to call
194 	get_latest_key_version again as keys are read only
195 	at startup. */
196 	uint key_found;
197 
198 	fil_space_rotate_state_t rotate_state;
199 };
200 
201 /** Status info about encryption */
202 struct fil_space_crypt_status_t {
203 	ulint space;             /*!< tablespace id */
204 	ulint scheme;            /*!< encryption scheme */
205 	uint  min_key_version;   /*!< min key version */
206 	uint  current_key_version;/*!< current key version */
207 	uint  keyserver_requests;/*!< no of key requests to key server */
208 	uint key_id;            /*!< current key_id */
209 	bool rotating;           /*!< is key rotation ongoing */
210 	bool flushing;           /*!< is flush at end of rotation ongoing */
211 	ulint rotate_next_page_number; /*!< next page if key rotating */
212 	ulint rotate_max_page_number;  /*!< max page if key rotating */
213 };
214 
215 /** Statistics about encryption key rotation */
216 struct fil_crypt_stat_t {
217 	ulint pages_read_from_cache;
218 	ulint pages_read_from_disk;
219 	ulint pages_modified;
220 	ulint pages_flushed;
221 	ulint estimated_iops;
222 };
223 
224 /*********************************************************************
225 Init space crypt */
226 UNIV_INTERN
227 void
228 fil_space_crypt_init();
229 
230 /*********************************************************************
231 Cleanup space crypt */
232 UNIV_INTERN
233 void
234 fil_space_crypt_cleanup();
235 
236 /**
237 Create a fil_space_crypt_t object
238 @param[in]	encrypt_mode	FIL_ENCRYPTION_DEFAULT or
239 				FIL_ENCRYPTION_ON or
240 				FIL_ENCRYPTION_OFF
241 
242 @param[in]	key_id		Encryption key id
243 @return crypt object */
244 UNIV_INTERN
245 fil_space_crypt_t*
246 fil_space_create_crypt_data(
247 	fil_encryption_t	encrypt_mode,
248 	uint			key_id)
249 	MY_ATTRIBUTE((warn_unused_result));
250 
251 /******************************************************************
252 Merge fil_space_crypt_t object
253 @param[in,out]	dst		Destination cryp data
254 @param[in]	src		Source crypt data */
255 UNIV_INTERN
256 void
257 fil_space_merge_crypt_data(
258 	fil_space_crypt_t* dst,
259 	const fil_space_crypt_t* src);
260 
261 /** Initialize encryption parameters from a tablespace header page.
262 @param[in]	zip_size	ROW_FORMAT=COMPRESSED page size, or 0
263 @param[in]	page		first page of the tablespace
264 @return crypt data from page 0
265 @retval	NULL	if not present or not valid */
266 fil_space_crypt_t* fil_space_read_crypt_data(ulint zip_size, const byte* page)
267 	MY_ATTRIBUTE((nonnull, warn_unused_result));
268 
269 /**
270 Free a crypt data object
271 @param[in,out] crypt_data	crypt data to be freed */
272 UNIV_INTERN
273 void
274 fil_space_destroy_crypt_data(
275 	fil_space_crypt_t **crypt_data);
276 
277 /** Amend encryption information from redo log.
278 @param[in]	space	tablespace
279 @param[in]	data	encryption metadata */
280 void fil_crypt_parse(fil_space_t* space, const byte* data);
281 
282 /** Encrypt a buffer.
283 @param[in,out]		crypt_data		Crypt data
284 @param[in]		space			space_id
285 @param[in]		offset			Page offset
286 @param[in]		src_frame		Page to encrypt
287 @param[in]		zip_size		ROW_FORMAT=COMPRESSED page size, or 0
288 @param[in,out]		dst_frame		Output buffer
289 @param[in]		use_full_checksum	full crc32 algo is used
290 @return encrypted buffer or NULL */
291 UNIV_INTERN
292 byte*
293 fil_encrypt_buf(
294 	fil_space_crypt_t*	crypt_data,
295 	ulint			space,
296 	ulint			offset,
297 	const byte*		src_frame,
298 	ulint			zip_size,
299 	byte*			dst_frame,
300 	bool			use_full_checksum)
301 	MY_ATTRIBUTE((warn_unused_result));
302 
303 /**
304 Encrypt a page.
305 
306 @param[in]		space		Tablespace
307 @param[in]		offset		Page offset
308 @param[in]		src_frame	Page to encrypt
309 @param[in,out]		dst_frame	Output buffer
310 @return encrypted buffer or NULL */
311 byte* fil_space_encrypt(
312 	const fil_space_t* space,
313 	ulint		offset,
314 	byte*		src_frame,
315 	byte*		dst_frame)
316 	MY_ATTRIBUTE((warn_unused_result));
317 
318 
319 /** Decrypt a page.
320 @param]in]	space_id		space id
321 @param[in]	crypt_data		crypt_data
322 @param[in]	tmp_frame		Temporary buffer
323 @param[in]	physical_size		page size
324 @param[in]	fsp_flags		Tablespace flags
325 @param[in,out]	src_frame		Page to decrypt
326 @return DB_SUCCESS or error */
327 UNIV_INTERN
328 dberr_t
329 fil_space_decrypt(
330 	ulint			space_id,
331 	fil_space_crypt_t*	crypt_data,
332 	byte*			tmp_frame,
333 	ulint			physical_size,
334 	ulint			fsp_flags,
335 	byte*			src_frame);
336 
337 /******************************************************************
338 Decrypt a page
339 @param[in]	space			Tablespace
340 @param[in]	tmp_frame		Temporary buffer used for decrypting
341 @param[in,out]	src_frame		Page to decrypt
342 @return decrypted page, or original not encrypted page if decryption is
343 not needed.*/
344 UNIV_INTERN
345 byte*
346 fil_space_decrypt(
347 	const fil_space_t* space,
348 	byte*		tmp_frame,
349 	byte*		src_frame)
350 	MY_ATTRIBUTE((warn_unused_result));
351 
352 /**
353 Calculate post encryption checksum
354 @param[in]	zip_size	ROW_FORMAT=COMPRESSED page size, or 0
355 @param[in]	dst_frame	Block where checksum is calculated
356 @return page checksum
357 not needed. */
358 uint32_t
359 fil_crypt_calculate_checksum(ulint zip_size, const byte* dst_frame)
360 	MY_ATTRIBUTE((warn_unused_result));
361 
362 /*********************************************************************
363 Adjust thread count for key rotation
364 @param[in]	enw_cnt		Number of threads to be used */
365 UNIV_INTERN
366 void
367 fil_crypt_set_thread_cnt(
368 	uint	new_cnt);
369 
370 /*********************************************************************
371 Adjust max key age
372 @param[in]	val		New max key age */
373 UNIV_INTERN
374 void
375 fil_crypt_set_rotate_key_age(
376 	uint	val);
377 
378 /*********************************************************************
379 Adjust rotation iops
380 @param[in]	val		New max roation iops */
381 UNIV_INTERN
382 void
383 fil_crypt_set_rotation_iops(
384 	uint val);
385 
386 /*********************************************************************
387 Adjust encrypt tables
388 @param[in]	val		New setting for innodb-encrypt-tables */
389 void fil_crypt_set_encrypt_tables(ulong val);
390 
391 /*********************************************************************
392 Init threads for key rotation */
393 UNIV_INTERN
394 void
395 fil_crypt_threads_init();
396 
397 /*********************************************************************
398 Clean up key rotation threads resources */
399 UNIV_INTERN
400 void
401 fil_crypt_threads_cleanup();
402 
403 /*********************************************************************
404 Wait for crypt threads to stop accessing space
405 @param[in]	space		Tablespace */
406 UNIV_INTERN
407 void
408 fil_space_crypt_close_tablespace(
409 	const fil_space_t*	space);
410 
411 /*********************************************************************
412 Get crypt status for a space (used by information_schema)
413 @param[in]	space		Tablespace
414 @param[out]	status		Crypt status
415 return 0 if crypt data present */
416 UNIV_INTERN
417 void
418 fil_space_crypt_get_status(
419 	const fil_space_t*			space,
420 	struct fil_space_crypt_status_t*	status);
421 
422 /*********************************************************************
423 Return crypt statistics
424 @param[out]	stat		Crypt statistics */
425 UNIV_INTERN
426 void
427 fil_crypt_total_stat(
428 	fil_crypt_stat_t *stat);
429 
430 #include "fil0crypt.inl"
431 #endif /* !UNIV_INNOCHECKSUM */
432 
433 /**
434 Verify that post encryption checksum match calculated checksum.
435 This function should be called only if tablespace contains crypt_data
436 metadata (this is strong indication that tablespace is encrypted).
437 Function also verifies that traditional checksum does not match
438 calculated checksum as if it does page could be valid unencrypted,
439 encrypted, or corrupted.
440 
441 @param[in,out]	page		page frame (checksum is temporarily modified)
442 @param[in]	zip_size	ROW_FORMAT=COMPRESSED page size, or 0
443 @return true if page is encrypted AND OK, false otherwise */
444 bool fil_space_verify_crypt_checksum(const byte* page, ulint zip_size)
445 	MY_ATTRIBUTE((warn_unused_result));
446 
447 /** Add the tablespace to the rotation list if
448 innodb_encrypt_rotate_key_age is 0 or encryption plugin does
449 not do key version rotation
450 @return whether the tablespace should be added to rotation list */
451 bool fil_crypt_must_default_encrypt();
452 
453 #endif /* fil0crypt_h */
454