1/* Copyright (C) 2015 MariaDB
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
15
16#include <my_global.h>
17#include <my_sys.h>
18#include <my_crypt.h>
19#include <tap.h>
20
21/*** tweaks and stubs for encryption code to compile ***************/
22#define KEY_SIZE (128/8)
23
24my_bool encrypt_tmp_files;
25int init_io_cache_encryption();
26
27uint encryption_key_get_latest_version_func(uint)
28{
29 return 1;
30}
31
32uint encryption_key_id_exists_func(uint)
33{
34 return 1;
35}
36
37uint encryption_key_version_exists_func(uint, uint)
38{
39 return 1;
40}
41
42uint encryption_key_get_func(uint, uint, uchar* key, uint* size)
43{
44 if (*size < KEY_SIZE)
45 {
46 *size= KEY_SIZE;
47 return ENCRYPTION_KEY_BUFFER_TOO_SMALL;
48 }
49 memset(key, KEY_SIZE, *size= KEY_SIZE);
50 return 0;
51}
52
53#ifdef HAVE_EncryptAes128Gcm
54enum my_aes_mode aes_mode= MY_AES_GCM;
55#else
56enum my_aes_mode aes_mode= MY_AES_CBC;
57#endif
58
59int encryption_ctx_init_func(void *ctx, const unsigned char* key, unsigned int klen,
60 const unsigned char* iv, unsigned int ivlen,
61 int flags, unsigned int key_id,
62 unsigned int key_version)
63{
64 return my_aes_crypt_init(ctx, aes_mode, flags, key, klen, iv, ivlen);
65}
66
67uint encryption_encrypted_length_func(unsigned int slen, unsigned int key_id, unsigned int key_version)
68{
69 return my_aes_get_size(aes_mode, slen);
70}
71
72struct encryption_service_st encryption_handler=
73{
74 encryption_key_get_latest_version_func,
75 encryption_key_get_func,
76 (uint (*)(unsigned int, unsigned int))my_aes_ctx_size,
77 encryption_ctx_init_func,
78 my_aes_crypt_update,
79 my_aes_crypt_finish,
80 encryption_encrypted_length_func
81};
82
83void sql_print_information(const char *format, ...)
84{
85}
86
87void sql_print_error(const char *format, ...)
88{
89}
90
91/*** end of encryption tweaks and stubs ****************************/
92
93IO_CACHE info;
94#define CACHE_SIZE 16384
95
96#define INFO_TAIL ", pos_in_file = %llu, pos_in_mem = %lu", \
97 info.pos_in_file, (ulong) ((info.type == READ_CACHE ? info.read_pos : info.write_pos) - info.request_pos)
98
99#define FILL 0x5A
100
101int data_bad(const uchar *buf, size_t len)
102{
103 const uchar *end= buf + len;
104 while (buf < end)
105 if (*buf++ != FILL)
106 return 1;
107 return 0;
108}
109
110void temp_io_cache()
111{
112 int res;
113 uchar buf[CACHE_SIZE + 200];
114 memset(buf, FILL, sizeof(buf));
115
116 diag("temp io_cache with%s encryption", encrypt_tmp_files?"":"out");
117
118 init_io_cache_encryption();
119
120 res= open_cached_file(&info, 0, 0, CACHE_SIZE, 0);
121 ok(res == 0, "open_cached_file" INFO_TAIL);
122
123 res= my_b_write(&info, buf, 100);
124 ok(res == 0 && info.pos_in_file == 0, "small write" INFO_TAIL );
125
126 res= my_b_write(&info, buf, sizeof(buf));
127 ok(res == 0 && info.pos_in_file == CACHE_SIZE, "large write" INFO_TAIL);
128
129 res= reinit_io_cache(&info, WRITE_CACHE, 250, 0, 0);
130 ok(res == 0, "reinit with rewind" INFO_TAIL);
131
132 res= my_b_write(&info, buf, sizeof(buf));
133 ok(res == 0, "large write" INFO_TAIL);
134
135 res= my_b_flush_io_cache(&info, 1);
136 ok(res == 0, "flush" INFO_TAIL);
137
138 res= reinit_io_cache(&info, READ_CACHE, 0, 0, 0);
139 ok(res == 0, "reinit READ_CACHE" INFO_TAIL);
140
141 res= (int)my_pread(info.file, buf, 50, 50, MYF(MY_NABP));
142 ok(res == 0 && data_bad(buf, 50) == encrypt_tmp_files,
143 "file must be %sreadable", encrypt_tmp_files ?"un":"");
144
145 res= my_b_read(&info, buf, 50) || data_bad(buf, 50);
146 ok(res == 0 && info.pos_in_file == 0, "small read" INFO_TAIL);
147
148 res= my_b_read(&info, buf, sizeof(buf)) || data_bad(buf, sizeof(buf));
149 ok(res == 0 && info.pos_in_file == CACHE_SIZE, "large read" INFO_TAIL);
150
151 close_cached_file(&info);
152}
153
154void mdev9044()
155{
156 int res;
157 uchar buf[CACHE_SIZE + 200];
158
159 diag("MDEV-9044 Binlog corruption in Galera");
160
161 res= open_cached_file(&info, 0, 0, CACHE_SIZE, 0);
162 ok(res == 0, "open_cached_file" INFO_TAIL);
163
164 res= my_b_write(&info, USTRING_WITH_LEN("first write\0"));
165 ok(res == 0, "first write" INFO_TAIL);
166
167 res= my_b_flush_io_cache(&info, 1);
168 ok(res == 0, "flush" INFO_TAIL);
169
170 res= reinit_io_cache(&info, WRITE_CACHE, 0, 0, 0);
171 ok(res == 0, "reinit WRITE_CACHE" INFO_TAIL);
172
173 res= my_b_write(&info, USTRING_WITH_LEN("second write\0"));
174 ok(res == 0, "second write" INFO_TAIL );
175
176 res= reinit_io_cache(&info, READ_CACHE, 0, 0, 0);
177 ok(res == 0, "reinit READ_CACHE" INFO_TAIL);
178
179 res= (int)my_b_fill(&info);
180 ok(res == 0, "fill" INFO_TAIL);
181
182 res= reinit_io_cache(&info, READ_CACHE, 0, 0, 0);
183 ok(res == 0, "reinit READ_CACHE" INFO_TAIL);
184
185 res= my_b_read(&info, buf, sizeof(buf));
186 ok(res == 1 && strcmp((char*)buf, "second write") == 0, "read '%s'", buf);
187
188 close_cached_file(&info);
189}
190
191int main(int argc __attribute__((unused)),char *argv[])
192{
193 MY_INIT(argv[0]);
194 plan(29);
195
196 /* temp files with and without encryption */
197 encrypt_tmp_files= 1;
198 temp_io_cache();
199
200 encrypt_tmp_files= 0;
201 temp_io_cache();
202
203 /* regression tests */
204 mdev9044();
205
206 my_end(0);
207 return exit_status();
208}
209
210