1 /************************************************************************************
2   Copyright (C) 2014 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  *************************************************************************************/
20 #include "ma_schannel.h"
21 #include "schannel_certs.h"
22 #include <string.h>
23 
24 extern my_bool ma_tls_initialized;
25 char tls_library_version[] = "Schannel";
26 
27 #define PROT_SSL3 1
28 #define PROT_TLS1_0 2
29 #define PROT_TLS1_2 4
30 #define PROT_TLS1_3 8
31 
32 static struct
33 {
34   DWORD cipher_id;
35   DWORD protocol;
36   const char *iana_name;
37   const char *openssl_name;
38   ALG_ID algs[4]; /* exchange, encryption, hash, signature */
39 }
40 cipher_map[] =
41 {
42   {
43     0x0002,
44     PROT_TLS1_0 |  PROT_TLS1_2 | PROT_SSL3,
45     "TLS_RSA_WITH_NULL_SHA", "NULL-SHA",
46     { CALG_RSA_KEYX, 0, CALG_SHA1, CALG_RSA_SIGN }
47   },
48   {
49     0x0004,
50     PROT_TLS1_0 |  PROT_TLS1_2 | PROT_SSL3,
51     "TLS_RSA_WITH_RC4_128_MD5", "RC4-MD5",
52     { CALG_RSA_KEYX, CALG_RC4, CALG_MD5, CALG_RSA_SIGN }
53   },
54   {
55     0x0005,
56     PROT_TLS1_0 |  PROT_TLS1_2 | PROT_SSL3,
57     "TLS_RSA_WITH_RC4_128_SHA", "RC4-SHA",
58     { CALG_RSA_KEYX, CALG_RC4, CALG_SHA1, CALG_RSA_SIGN }
59   },
60   {
61     0x000A,
62     PROT_SSL3,
63     "TLS_RSA_WITH_3DES_EDE_CBC_SHA", "DES-CBC3-SHA",
64     {CALG_RSA_KEYX, CALG_3DES, CALG_SHA1, CALG_DSS_SIGN}
65   },
66   {
67     0x0013,
68     PROT_TLS1_0 |  PROT_TLS1_2 | PROT_SSL3,
69     "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", "EDH-DSS-DES-CBC3-SHA",
70     { CALG_DH_EPHEM, CALG_3DES, CALG_SHA1, CALG_DSS_SIGN }
71   },
72   {
73     0x002F,
74     PROT_SSL3 | PROT_TLS1_0 | PROT_TLS1_2,
75     "TLS_RSA_WITH_AES_128_CBC_SHA", "AES128-SHA",
76     { CALG_RSA_KEYX, CALG_AES_128, CALG_SHA, CALG_RSA_SIGN}
77   },
78   {
79     0x0032,
80     PROT_TLS1_0 |  PROT_TLS1_2,
81     "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "DHE-DSS-AES128-SHA",
82     { CALG_DH_EPHEM, CALG_AES_128, CALG_SHA1, CALG_RSA_SIGN }
83   },
84   {
85     0x0033,
86     PROT_TLS1_0 |  PROT_TLS1_2,
87     "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "DHE-RSA-AES128-SHA",
88     { CALG_DH_EPHEM, CALG_AES_128, CALG_SHA1, CALG_RSA_SIGN }
89   },
90   {
91     0x0035,
92     PROT_TLS1_0 |  PROT_TLS1_2,
93     "TLS_RSA_WITH_AES_256_CBC_SHA", "AES256-SHA",
94     { CALG_RSA_KEYX, CALG_AES_256, CALG_SHA1, CALG_RSA_SIGN }
95   },
96   {
97     0x0038,
98     PROT_TLS1_0 |  PROT_TLS1_2,
99     "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "DHE-DSS-AES256-SHA",
100     { CALG_DH_EPHEM, CALG_AES_256, CALG_SHA1, CALG_DSS_SIGN }
101   },
102   {
103     0x0039,
104     PROT_TLS1_0 |  PROT_TLS1_2,
105     "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "DHE-RSA-AES256-SHA",
106     { CALG_DH_EPHEM, CALG_AES_256, CALG_SHA1, CALG_RSA_SIGN }
107   },
108   {
109     0x003B,
110     PROT_TLS1_2,
111     "TLS_RSA_WITH_NULL_SHA256", "NULL-SHA256",
112     { CALG_RSA_KEYX, 0, CALG_SHA_256, CALG_RSA_SIGN }
113   },
114   {
115     0x003C,
116     PROT_TLS1_2,
117     "TLS_RSA_WITH_AES_128_CBC_SHA256", "AES128-SHA256",
118     { CALG_RSA_KEYX, CALG_AES_128, CALG_SHA_256, CALG_RSA_SIGN }
119   },
120   {
121     0x003D,
122     PROT_TLS1_2,
123     "TLS_RSA_WITH_AES_256_CBC_SHA256", "AES256-SHA256",
124     { CALG_RSA_KEYX, CALG_AES_256, CALG_SHA_256, CALG_RSA_SIGN }
125   },
126   {
127     0x0040,
128     PROT_TLS1_2,
129     "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "DHE-DSS-AES128-SHA256",
130     { CALG_DH_EPHEM, CALG_AES_128, CALG_SHA_256, CALG_DSS_SIGN }
131   },
132   {
133     0x009C,
134     PROT_TLS1_2,
135     "TLS_RSA_WITH_AES_128_GCM_SHA256", "AES128-GCM-SHA256",
136     { CALG_RSA_KEYX, CALG_AES_128, CALG_SHA_256, CALG_RSA_SIGN }
137   },
138   {
139     0x009D,
140     PROT_TLS1_2,
141     "TLS_RSA_WITH_AES_256_GCM_SHA384", "AES256-GCM-SHA384",
142     { CALG_RSA_KEYX, CALG_AES_256, CALG_SHA_384, CALG_RSA_SIGN }
143   },
144   {
145     0x009E,
146     PROT_TLS1_2,
147     "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "DHE-RSA-AES128-GCM-SHA256",
148     { CALG_DH_EPHEM, CALG_AES_128, CALG_SHA_256, CALG_RSA_SIGN }
149   },
150   {
151     0x009F,
152     PROT_TLS1_2,
153     "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "DHE-RSA-AES256-GCM-SHA384",
154     { CALG_DH_EPHEM, CALG_AES_256, CALG_SHA_384, CALG_RSA_SIGN }
155   },
156   {
157     0xC027,
158     PROT_TLS1_2,
159     "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "ECDHE-RSA-AES128-SHA256",
160     { CALG_ECDH, CALG_AES_128, CALG_SHA_256, CALG_RSA_SIGN }
161   },
162   {
163     0xC028,
164     PROT_TLS1_2,
165     "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "ECDHE-RSA-AES256-SHA384",
166     { CALG_ECDH, CALG_AES_256, CALG_SHA_384, CALG_RSA_SIGN }
167   }
168 };
169 
170 #define MAX_ALG_ID 50
171 
172 extern void ma_schannel_set_sec_error(MARIADB_PVIO *pvio, DWORD ErrorNo);
173 
174 /*
175   Initializes SSL and allocate global
176   context SSL_context
177 
178   SYNOPSIS
179     ma_tls_start
180 
181   RETURN VALUES
182     0  success
183     1  error
184 */
ma_tls_start(char * errmsg,size_t errmsg_len)185 int ma_tls_start(char *errmsg, size_t errmsg_len)
186 {
187   ma_tls_initialized = TRUE;
188   return 0;
189 }
190 
191 /*
192    Release SSL and free resources
193    Will be automatically executed by
194    mysql_server_end() function
195 
196    SYNOPSIS
197      ma_tls_end()
198        void
199 
200    RETURN VALUES
201      void
202 */
ma_tls_end()203 void ma_tls_end()
204 {
205   return;
206 }
207 
208 /* {{{ static int ma_tls_set_client_certs(MARIADB_TLS *ctls) */
ma_tls_set_client_certs(MARIADB_TLS * ctls,const CERT_CONTEXT ** cert_ctx)209 static int ma_tls_set_client_certs(MARIADB_TLS *ctls,const CERT_CONTEXT **cert_ctx)
210 {
211   MYSQL *mysql= ctls->pvio->mysql;
212   char *certfile= mysql->options.ssl_cert,
213        *keyfile= mysql->options.ssl_key;
214   MARIADB_PVIO *pvio= ctls->pvio;
215   char errmsg[256];
216 
217   if (!certfile && keyfile)
218     certfile= keyfile;
219   if (!keyfile && certfile)
220     keyfile= certfile;
221 
222   if (!certfile)
223     return 0;
224 
225   *cert_ctx = schannel_create_cert_context(certfile, keyfile, errmsg, sizeof(errmsg));
226   if (!*cert_ctx)
227   {
228     pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: %s", errmsg);
229     return 1;
230   }
231 
232   return 0;
233 }
234 /* }}} */
235 
236 /* {{{ void *ma_tls_init(MARIADB_TLS *ctls, MYSQL *mysql) */
ma_tls_init(MYSQL * mysql)237 void *ma_tls_init(MYSQL *mysql)
238 {
239   SC_CTX *sctx = (SC_CTX *)LocalAlloc(LMEM_ZEROINIT, sizeof(SC_CTX));
240   if (sctx)
241   {
242     SecInvalidateHandle(&sctx->CredHdl);
243     SecInvalidateHandle(&sctx->hCtxt);
244   }
245   return sctx;
246 }
247 /* }}} */
248 
249 
250 /*
251   Maps between openssl suite names and schannel alg_ids.
252   Every suite has 4 algorithms (for exchange, encryption, hash and signing).
253 
254   The input string is a set of suite names (openssl),  separated
255   by ':'
256 
257   The output is written into the array 'arr' of size 'arr_size'
258   The function returns number of elements written to the 'arr'.
259 */
260 
261 static struct _tls_version {
262   const char *tls_version;
263   DWORD protocol;
264 } tls_version[]= {
265     {"TLSv1.0", PROT_TLS1_0},
266     {"TLSv1.2", PROT_TLS1_2},
267     {"TLSv1.3", PROT_TLS1_3},
268     {"SSLv3",   PROT_SSL3}
269 };
270 
271 /* The following list was produced with OpenSSL 1.1.1j
272    by executing `openssl ciphers -V`.  */
273 static struct {
274   DWORD dwCipherSuite;
275   const char *openssl_name;
276 } openssl_ciphers[] = {
277   {0x002F, "AES128-SHA"},
278   {0x0033, "DHE-RSA-AES128-SHA"},
279   {0x0035, "AES256-SHA"},
280   {0x0039, "DHE-RSA-AES256-SHA"},
281   {0x003C, "AES128-SHA256"},
282   {0x003D, "AES256-SHA256"},
283   {0x0067, "DHE-RSA-AES128-SHA256"},
284   {0x006B, "DHE-RSA-AES256-SHA256"},
285   {0x008C, "PSK-AES128-CBC-SHA"},
286   {0x008D, "PSK-AES256-CBC-SHA"},
287   {0x0090, "DHE-PSK-AES128-CBC-SHA"},
288   {0x0091, "DHE-PSK-AES256-CBC-SHA"},
289   {0x0094, "RSA-PSK-AES128-CBC-SHA"},
290   {0x0095, "RSA-PSK-AES256-CBC-SHA"},
291   {0x009C, "AES128-GCM-SHA256"},
292   {0x009D, "AES256-GCM-SHA384"},
293   {0x009E, "DHE-RSA-AES128-GCM-SHA256"},
294   {0x009F, "DHE-RSA-AES256-GCM-SHA384"},
295   {0x00A8, "PSK-AES128-GCM-SHA256"},
296   {0x00A9, "PSK-AES256-GCM-SHA384"},
297   {0x00AA, "DHE-PSK-AES128-GCM-SHA256"},
298   {0x00AB, "DHE-PSK-AES256-GCM-SHA384"},
299   {0x00AC, "RSA-PSK-AES128-GCM-SHA256"},
300   {0x00AD, "RSA-PSK-AES256-GCM-SHA384"},
301   {0x00AE, "PSK-AES128-CBC-SHA256"},
302   {0x00AF, "PSK-AES256-CBC-SHA384"},
303   {0x00B2, "DHE-PSK-AES128-CBC-SHA256"},
304   {0x00B3, "DHE-PSK-AES256-CBC-SHA384"},
305   {0x00B6, "RSA-PSK-AES128-CBC-SHA256"},
306   {0x00B7, "RSA-PSK-AES256-CBC-SHA384"},
307   {0x1301, "TLS_AES_128_GCM_SHA256"},
308   {0x1302, "TLS_AES_256_GCM_SHA384"},
309   {0x1303, "TLS_CHACHA20_POLY1305_SHA256"},
310   {0xC009, "ECDHE-ECDSA-AES128-SHA"},
311   {0xC00A, "ECDHE-ECDSA-AES256-SHA"},
312   {0xC013, "ECDHE-RSA-AES128-SHA"},
313   {0xC014, "ECDHE-RSA-AES256-SHA"},
314   {0xC01D, "SRP-AES-128-CBC-SHA"},
315   {0xC01E, "SRP-RSA-AES-128-CBC-SHA"},
316   {0xC020, "SRP-AES-256-CBC-SHA"},
317   {0xC021, "SRP-RSA-AES-256-CBC-SHA"},
318   {0xC023, "ECDHE-ECDSA-AES128-SHA256"},
319   {0xC024, "ECDHE-ECDSA-AES256-SHA384"},
320   {0xC027, "ECDHE-RSA-AES128-SHA256"},
321   {0xC028, "ECDHE-RSA-AES256-SHA384"},
322   {0xC02B, "ECDHE-ECDSA-AES128-GCM-SHA256"},
323   {0xC02C, "ECDHE-ECDSA-AES256-GCM-SHA384"},
324   {0xC02F, "ECDHE-RSA-AES128-GCM-SHA256"},
325   {0xC030, "ECDHE-RSA-AES256-GCM-SHA384"},
326   {0xC035, "ECDHE-PSK-AES128-CBC-SHA"},
327   {0xC036, "ECDHE-PSK-AES256-CBC-SHA"},
328   {0xC037, "ECDHE-PSK-AES128-CBC-SHA256"},
329   {0xC038, "ECDHE-PSK-AES256-CBC-SHA384"},
330   {0xCCA8, "ECDHE-RSA-CHACHA20-POLY1305"},
331   {0xCCA9, "ECDHE-ECDSA-CHACHA20-POLY1305"},
332   {0xCCAA, "DHE-RSA-CHACHA20-POLY1305"},
333   {0xCCAB, "PSK-CHACHA20-POLY1305"},
334   {0xCCAC, "ECDHE-PSK-CHACHA20-POLY1305"},
335   {0xCCAD, "DHE-PSK-CHACHA20-POLY1305"},
336   {0xCCAE, "RSA-PSK-CHACHA20-POLY1305"}
337 };
338 
set_cipher(char * cipher_str,DWORD protocol,ALG_ID * arr,size_t arr_size)339 static size_t set_cipher(char * cipher_str, DWORD protocol, ALG_ID *arr , size_t arr_size)
340 {
341   char *token = strtok(cipher_str, ":");
342   size_t pos = 0;
343 
344   while (token)
345   {
346     size_t i;
347 
348     for(i = 0; i < sizeof(cipher_map)/sizeof(cipher_map[0]) ; i++)
349     {
350       if((pos + 4 < arr_size && strcmp(cipher_map[i].openssl_name, token) == 0) ||
351         (cipher_map[i].protocol <= protocol))
352       {
353         memcpy(arr + pos, cipher_map[i].algs, sizeof(ALG_ID)* 4);
354         pos += 4;
355         break;
356       }
357     }
358     token = strtok(NULL, ":");
359   }
360   return pos;
361 }
362 
ma_tls_connect(MARIADB_TLS * ctls)363 my_bool ma_tls_connect(MARIADB_TLS *ctls)
364 {
365   MYSQL *mysql;
366   SCHANNEL_CRED Cred = {0};
367   MARIADB_PVIO *pvio;
368   my_bool rc= 1;
369   SC_CTX *sctx;
370   SECURITY_STATUS sRet;
371   ALG_ID AlgId[MAX_ALG_ID];
372   size_t i;
373   DWORD protocol = 0;
374   int verify_certs;
375   const CERT_CONTEXT* cert_context = NULL;
376 
377   if (!ctls)
378     return 1;
379 
380   pvio= ctls->pvio;
381   sctx= (SC_CTX *)ctls->ssl;
382   if (!pvio || !sctx)
383     return 1;
384 
385   mysql= pvio->mysql;
386   if (!mysql)
387     return 1;
388 
389   /* Set cipher */
390   if (mysql->options.ssl_cipher)
391   {
392 
393    /* check if a protocol was specified as a cipher:
394      * In this case don't allow cipher suites which belong to newer protocols
395      * Please note: There are no cipher suites for TLS1.1
396      */
397     for (i = 0; i < sizeof(tls_version) / sizeof(tls_version[0]); i++)
398     {
399       if (!_stricmp(mysql->options.ssl_cipher, tls_version[i].tls_version))
400         protocol |= tls_version[i].protocol;
401     }
402     memset(AlgId, 0, sizeof(AlgId));
403     Cred.cSupportedAlgs = (DWORD)set_cipher(mysql->options.ssl_cipher, protocol, AlgId, MAX_ALG_ID);
404     if (Cred.cSupportedAlgs)
405     {
406       Cred.palgSupportedAlgs = AlgId;
407     }
408     else if (!protocol)
409     {
410       ma_schannel_set_sec_error(pvio, SEC_E_ALGORITHM_MISMATCH);
411       goto end;
412     }
413   }
414 
415   Cred.dwVersion= SCHANNEL_CRED_VERSION;
416 
417   Cred.dwFlags = SCH_CRED_NO_SERVERNAME_CHECK | SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION;
418 
419   if (mysql->options.extension && mysql->options.extension->tls_version)
420   {
421     if (strstr(mysql->options.extension->tls_version, "TLSv1.0"))
422       Cred.grbitEnabledProtocols|= SP_PROT_TLS1_0_CLIENT;
423     if (strstr(mysql->options.extension->tls_version, "TLSv1.1"))
424       Cred.grbitEnabledProtocols|= SP_PROT_TLS1_1_CLIENT;
425     if (strstr(mysql->options.extension->tls_version, "TLSv1.2"))
426       Cred.grbitEnabledProtocols|= SP_PROT_TLS1_2_CLIENT;
427   }
428   if (!Cred.grbitEnabledProtocols)
429     Cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT;
430 
431 
432   if (ma_tls_set_client_certs(ctls, &cert_context))
433     goto end;
434 
435   if (cert_context)
436   {
437     Cred.cCreds = 1;
438     Cred.paCred = &cert_context;
439   }
440   sRet= AcquireCredentialsHandleA(NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND,
441                                        NULL, &Cred, NULL, NULL, &sctx->CredHdl, NULL);
442   if (sRet)
443   {
444     ma_schannel_set_sec_error(pvio, sRet);
445     goto end;
446   }
447   if (ma_schannel_client_handshake(ctls) != SEC_E_OK)
448     goto end;
449 
450    verify_certs =  mysql->options.ssl_ca || mysql->options.ssl_capath ||
451      (mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT);
452 
453   if (verify_certs)
454   {
455     if (!ma_schannel_verify_certs(ctls, (mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT)))
456       goto end;
457   }
458 
459   rc = 0;
460 
461 end:
462   if (cert_context)
463     schannel_free_cert_context(cert_context);
464   return rc;
465 }
466 
ma_tls_read(MARIADB_TLS * ctls,const uchar * buffer,size_t length)467 ssize_t ma_tls_read(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
468 {
469   SC_CTX *sctx= (SC_CTX *)ctls->ssl;
470   MARIADB_PVIO *pvio= ctls->pvio;
471   DWORD dlength= 0;
472   SECURITY_STATUS status = ma_schannel_read_decrypt(pvio, &sctx->hCtxt, &dlength, (uchar *)buffer, (DWORD)length);
473   if (status == SEC_I_CONTEXT_EXPIRED)
474     return 0; /* other side shut down the connection. */
475   if (status == SEC_I_RENEGOTIATE)
476     return -1; /* Do not handle renegotiate yet */
477 
478   return (status == SEC_E_OK)? (ssize_t)dlength : -1;
479 }
480 
ma_tls_write(MARIADB_TLS * ctls,const uchar * buffer,size_t length)481 ssize_t ma_tls_write(MARIADB_TLS *ctls, const uchar* buffer, size_t length)
482 {
483   MARIADB_PVIO *pvio= ctls->pvio;
484   ssize_t rc, wlength= 0;
485   ssize_t remain= length;
486 
487   while (remain > 0)
488   {
489     if ((rc= ma_schannel_write_encrypt(pvio, (uchar *)buffer + wlength, remain)) <= 0)
490       return rc;
491     wlength+= rc;
492     remain-= rc;
493   }
494   return length;
495 }
496 
497 /* {{{ my_bool ma_tls_close(MARIADB_PVIO *pvio) */
ma_tls_close(MARIADB_TLS * ctls)498 my_bool ma_tls_close(MARIADB_TLS *ctls)
499 {
500   SC_CTX *sctx= (SC_CTX *)ctls->ssl;
501 
502   if (sctx)
503   {
504     LocalFree(sctx->IoBuffer);
505 
506     if (SecIsValidHandle(&sctx->CredHdl))
507       FreeCredentialHandle(&sctx->CredHdl);
508 
509     if (SecIsValidHandle(&sctx->hCtxt))
510       DeleteSecurityContext(&sctx->hCtxt);
511   }
512   LocalFree(sctx);
513   return 0;
514 }
515 /* }}} */
516 
ma_tls_verify_server_cert(MARIADB_TLS * ctls)517 int ma_tls_verify_server_cert(MARIADB_TLS *ctls)
518 {
519   /* Done elsewhere */
520   return 0;
521 }
522 
cipher_name(const SecPkgContext_CipherInfo * CipherInfo)523 static const char *cipher_name(const SecPkgContext_CipherInfo *CipherInfo)
524 {
525   size_t i;
526 
527   for(i = 0; i < sizeof(openssl_ciphers)/sizeof(openssl_ciphers[0]) ; i++)
528   {
529     if (CipherInfo->dwCipherSuite == openssl_ciphers[i].dwCipherSuite)
530       return openssl_ciphers[i].openssl_name;
531   }
532   return "";
533 };
534 
ma_tls_get_cipher(MARIADB_TLS * ctls)535 const char *ma_tls_get_cipher(MARIADB_TLS *ctls)
536 {
537   SecPkgContext_CipherInfo CipherInfo = { SECPKGCONTEXT_CIPHERINFO_V1 };
538   SECURITY_STATUS sRet;
539   SC_CTX *sctx;
540 
541   if (!ctls || !ctls->ssl)
542     return NULL;
543 
544   sctx= (SC_CTX *)ctls->ssl;
545   sRet= QueryContextAttributesA(&sctx->hCtxt, SECPKG_ATTR_CIPHER_INFO, (PVOID)&CipherInfo);
546 
547   if (sRet != SEC_E_OK)
548     return NULL;
549 
550   return cipher_name(&CipherInfo);
551 }
552 
ma_tls_get_finger_print(MARIADB_TLS * ctls,char * fp,unsigned int len)553 unsigned int ma_tls_get_finger_print(MARIADB_TLS *ctls, char *fp, unsigned int len)
554 {
555   SC_CTX *sctx= (SC_CTX *)ctls->ssl;
556   PCCERT_CONTEXT pRemoteCertContext = NULL;
557   if (QueryContextAttributes(&sctx->hCtxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pRemoteCertContext) != SEC_E_OK)
558     return 0;
559   CertGetCertificateContextProperty(pRemoteCertContext, CERT_HASH_PROP_ID, fp, (DWORD *)&len);
560   CertFreeCertificateContext(pRemoteCertContext);
561   return len;
562 }
563