"Fossies" - the Fresh Open Source Software Archive 
Member "mariadb-connector-c-3.0.9-src/plugins/auth/sha256_pw.c" (8 Feb 2019, 8849 Bytes) of package /linux/misc/mariadb-connector-c-3.0.9-src.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
See also the latest
Fossies "Diffs" side-by-side code changes report for "sha256_pw.c":
3.0.8_vs_3.0.9.
1 /************************************************************************************
2 Copyright (C) 2017 MariaDB Corporation AB
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with this library; if not see <http://www.gnu.org/licenses>
16 or write to the Free Software Foundation, Inc.,
17 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
18 *************************************************************************************/
19 #ifndef _WIN32
20 #define _GNU_SOURCE 1
21 #endif
22
23 #ifdef _WIN32
24 #if !defined(HAVE_OPENSSL)
25 #define HAVE_WINCRYPT
26 #endif
27 #endif
28
29 #if defined(HAVE_OPENSSL) || defined(HAVE_WINCRYPT)
30
31 #include <ma_global.h>
32 #include <mysql.h>
33 #include <mysql/client_plugin.h>
34 #include <string.h>
35 #include <memory.h>
36 #include <errmsg.h>
37 #include <ma_global.h>
38 #include <ma_sys.h>
39 #include <ma_common.h>
40
41 #ifndef WIN32
42 #include <dlfcn.h>
43 #endif
44
45 #if defined(HAVE_OPENSSL)
46 #include <openssl/rsa.h>
47 #include <openssl/pem.h>
48 #include <openssl/err.h>
49 #elif defined(HAVE_WINCRYPT)
50 #include <wincrypt.h>
51 #endif
52
53 #define MAX_PW_LEN 1024
54
55 /* function prototypes */
56 static int auth_sha256_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
57 static int auth_sha256_init(char *unused1,
58 size_t unused2,
59 int unused3,
60 va_list);
61
62
63 #ifndef PLUGIN_DYNAMIC
64 struct st_mysql_client_plugin_AUTHENTICATION sha256_password_client_plugin=
65 #else
66 struct st_mysql_client_plugin_AUTHENTICATION _mysql_client_plugin_declaration_ =
67 #endif
68 {
69 MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
70 MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
71 "sha256_password",
72 "Georg Richter",
73 "SHA256 Authentication Plugin",
74 {0,1,0},
75 "LGPL",
76 NULL,
77 auth_sha256_init,
78 NULL,
79 NULL,
80 auth_sha256_client
81 };
82
83 #ifdef HAVE_WINCRYPT
84 static LPBYTE ma_load_pem(const char *buffer, DWORD *buffer_len)
85 {
86 LPBYTE der_buffer= NULL;
87 DWORD der_buffer_length;
88
89 if (buffer_len == NULL || *buffer_len == 0)
90 return NULL;
91 /* calculate the length of DER binary */
92 if (!CryptStringToBinaryA(buffer, *buffer_len, CRYPT_STRING_BASE64HEADER,
93 NULL, &der_buffer_length, NULL, NULL))
94 goto end;
95 /* allocate DER binary buffer */
96 if (!(der_buffer= (LPBYTE)LocalAlloc(0, der_buffer_length)))
97 goto end;
98 /* convert to DER binary */
99 if (!CryptStringToBinaryA(buffer, *buffer_len, CRYPT_STRING_BASE64HEADER,
100 der_buffer, &der_buffer_length, NULL, NULL))
101 goto end;
102
103 *buffer_len= der_buffer_length;
104
105 return der_buffer;
106
107 end:
108 if (der_buffer)
109 LocalFree(der_buffer);
110 *buffer_len= 0;
111 return NULL;
112 }
113 #endif
114
115 static char *load_pub_key_file(const char *filename, int *pub_key_size)
116 {
117 FILE *fp= NULL;
118 char *buffer= NULL;
119 unsigned char error= 1;
120 size_t bytes_read= 0;
121 long fsize= 0;
122
123 if (!pub_key_size)
124 return NULL;
125
126 if (!(fp= fopen(filename, "r")))
127 goto end;
128
129 if (fseek(fp, 0, SEEK_END))
130 goto end;
131
132 fsize= ftell(fp);
133 if (fsize < 0)
134 goto end;
135
136 rewind(fp);
137
138 if (!(buffer= malloc(fsize + 1)))
139 goto end;
140
141 bytes_read= fread(buffer, 1, (size_t)fsize, fp);
142 if (bytes_read < (size_t)fsize)
143 goto end;
144
145 *pub_key_size= (int)bytes_read;
146
147 error= 0;
148
149 end:
150 if (fp)
151 fclose(fp);
152 if (error && buffer)
153 {
154 free(buffer);
155 buffer= NULL;
156 }
157 return buffer;
158 }
159
160
161 static int auth_sha256_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
162 {
163 unsigned char *packet;
164 int packet_length;
165 int rc= CR_ERROR;
166 char passwd[MAX_PW_LEN];
167 unsigned char rsa_enc_pw[MAX_PW_LEN];
168 unsigned int rsa_size;
169 unsigned int pwlen, i;
170
171 #if defined(HAVE_OPENSSL)
172 RSA *pubkey= NULL;
173 BIO *bio;
174 #elif defined(HAVE_WINCRYPT)
175 HCRYPTKEY pubkey= 0;
176 HCRYPTPROV hProv= 0;
177 LPBYTE der_buffer= NULL;
178 DWORD der_buffer_len= 0;
179 CERT_PUBLIC_KEY_INFO *publicKeyInfo= NULL;
180 DWORD ParamSize= sizeof(DWORD);
181 int publicKeyInfoLen;
182 #endif
183 char *filebuffer= NULL;
184
185 /* read error */
186 if ((packet_length= vio->read_packet(vio, &packet)) < 0)
187 return CR_ERROR;
188
189 if (packet_length != SCRAMBLE_LENGTH + 1)
190 return CR_SERVER_HANDSHAKE_ERR;
191
192 memmove(mysql->scramble_buff, packet, SCRAMBLE_LENGTH);
193 mysql->scramble_buff[SCRAMBLE_LENGTH]= 0;
194
195 /* if a tls session is active we need to send plain password */
196 if (mysql->client_flag & CLIENT_SSL)
197 {
198 if (vio->write_packet(vio, (unsigned char *)mysql->passwd, (int)strlen(mysql->passwd) + 1))
199 return CR_ERROR;
200 return CR_OK;
201 }
202
203 /* send empty packet if no password was provided */
204 if (!mysql->passwd || !mysql->passwd[0])
205 {
206 if (vio->write_packet(vio, 0, 0))
207 return CR_ERROR;
208 return CR_OK;
209 }
210
211 /* read public key file (if specified) */
212 if (mysql->options.extension &&
213 mysql->options.extension->server_public_key)
214 {
215 filebuffer= load_pub_key_file(mysql->options.extension->server_public_key,
216 &packet_length);
217 }
218
219 /* if no public key file was specified or if we couldn't read the file,
220 we ask server to send public key */
221 if (!filebuffer)
222 {
223 unsigned char buf= 1;
224 if (vio->write_packet(vio, &buf, 1))
225 return CR_ERROR;
226 if ((packet_length=vio->read_packet(vio, &packet)) == -1)
227 return CR_ERROR;
228 }
229 #if defined(HAVE_OPENSSL)
230 bio= BIO_new_mem_buf(filebuffer ? (unsigned char *)filebuffer : packet,
231 packet_length);
232 if ((pubkey= PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL)))
233 rsa_size= RSA_size(pubkey);
234 BIO_free(bio);
235 ERR_clear_error();
236 #elif defined(HAVE_WINCRYPT)
237 der_buffer_len= packet_length;
238 /* Load pem and convert it to binary object. New length will be returned
239 in der_buffer_len */
240 if (!(der_buffer= ma_load_pem(filebuffer ? filebuffer : (char *)packet, &der_buffer_len)))
241 goto error;
242
243 /* Create context and load public key */
244 if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO,
245 der_buffer, der_buffer_len,
246 CRYPT_DECODE_ALLOC_FLAG, NULL,
247 &publicKeyInfo, (DWORD *)&publicKeyInfoLen))
248 goto error;
249 LocalFree(der_buffer);
250
251 if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
252 CRYPT_VERIFYCONTEXT))
253 goto error;
254 if (!CryptImportPublicKeyInfo(hProv, X509_ASN_ENCODING,
255 publicKeyInfo, &pubkey))
256 goto error;
257
258 /* Get rsa_size */
259 CryptGetKeyParam(pubkey, KP_KEYLEN, (BYTE *)&rsa_size, &ParamSize, 0);
260 rsa_size /= 8;
261 #endif
262 if (!pubkey)
263 return CR_ERROR;
264
265 pwlen= (unsigned int)strlen(mysql->passwd) + 1; /* include terminating zero */
266 if (pwlen > MAX_PW_LEN)
267 goto error;
268 memcpy(passwd, mysql->passwd, pwlen);
269
270 /* xor password with scramble */
271 for (i=0; i < pwlen; i++)
272 passwd[i]^= *(mysql->scramble_buff + i % SCRAMBLE_LENGTH);
273
274 /* encrypt scrambled password */
275 #if defined(HAVE_OPENSSL)
276 if (RSA_public_encrypt(pwlen, (unsigned char *)passwd, rsa_enc_pw, pubkey, RSA_PKCS1_OAEP_PADDING) < 0)
277 goto error;
278 #elif defined(HAVE_WINCRYPT)
279 if (!CryptEncrypt(pubkey, 0, TRUE, CRYPT_OAEP, (BYTE *)passwd, (DWORD *)&pwlen, MAX_PW_LEN))
280 goto error;
281 /* Windows encrypts as little-endian, while server (openssl) expects
282 big-endian, so we have to revert the string */
283 for (i= 0; i < rsa_size / 2; i++)
284 {
285 rsa_enc_pw[i]= passwd[rsa_size - 1 - i];
286 rsa_enc_pw[rsa_size - 1 - i]= passwd[i];
287 }
288 #endif
289 if (vio->write_packet(vio, rsa_enc_pw, rsa_size))
290 goto error;
291
292 rc= CR_OK;
293 error:
294 #if defined(HAVE_OPENSSL)
295 if (pubkey)
296 RSA_free(pubkey);
297 #elif defined(HAVE_WINCRYPT)
298 CryptReleaseContext(hProv, 0);
299 if (publicKeyInfo)
300 LocalFree(publicKeyInfo);
301 #endif
302 free(filebuffer);
303 return rc;
304 }
305 /* }}} */
306
307 /* {{{ static int auth_sha256_init */
308 /*
309 Initialization routine
310
311 SYNOPSIS
312 auth_sha256_init
313 unused1
314 unused2
315 unused3
316 unused4
317
318 DESCRIPTION
319 Init function checks if the caller provides own dialog function.
320 The function name must be mariadb_auth_dialog or
321 mysql_authentication_dialog_ask. If the function cannot be found,
322 we will use owr own simple command line input.
323
324 RETURN
325 0 success
326 */
327 static int auth_sha256_init(char *unused1 __attribute__((unused)),
328 size_t unused2 __attribute__((unused)),
329 int unused3 __attribute__((unused)),
330 va_list unused4 __attribute__((unused)))
331 {
332 return 0;
333 }
334 /* }}} */
335
336 #endif /* defined(HAVE_OPENSSL) || defined(HAVE_WINCRYPT) */