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 Author: Georg Richter
20
21 *************************************************************************************/
22 #include "ma_schannel.h"
23 #include "schannel_certs.h"
24 #include <assert.h>
25
26 #define SC_IO_BUFFER_SIZE 0x4000
27 #define MAX_SSL_ERR_LEN 100
28
29 #define SCHANNEL_PAYLOAD(A) ((A).cbMaximumMessage + (A).cbHeader + (A).cbTrailer)
30 void ma_schannel_set_win_error(MARIADB_PVIO *pvio, DWORD ErrorNo);
31
32
33
34
35 /* {{{ void ma_schannel_set_sec_error */
ma_schannel_set_sec_error(MARIADB_PVIO * pvio,DWORD ErrorNo)36 void ma_schannel_set_sec_error(MARIADB_PVIO* pvio, DWORD ErrorNo)
37 {
38 MYSQL* mysql = pvio->mysql;
39 if (ErrorNo != SEC_E_OK)
40 mysql->net.extension->extended_errno = ErrorNo;
41 if (ErrorNo == SEC_E_INTERNAL_ERROR && GetLastError())
42 {
43 ma_schannel_set_win_error(pvio, GetLastError());
44 return;
45 }
46 ma_schannel_set_win_error(pvio, ErrorNo);
47 }
48 /* }}} */
49
50 #include "win32_errmsg.h"
51 /* {{{ void ma_schnnel_set_win_error */
ma_schannel_set_win_error(MARIADB_PVIO * pvio,DWORD ErrorNo)52 void ma_schannel_set_win_error(MARIADB_PVIO *pvio, DWORD ErrorNo)
53 {
54 char buffer[256];
55 ma_format_win32_error(buffer, sizeof(buffer), ErrorNo, "SSL connection error: ");
56 pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, buffer);
57 return;
58 }
59 /* }}} */
60
61
62 /* }}} */
63
64 /* {{{ SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRead, SecBuffer *pExtraData) */
65 /*
66 perform handshake loop
67
68 SYNOPSIS
69 ma_schannel_handshake_loop()
70 pvio Pointer to an Communication/IO structure
71 InitialRead TRUE if it's the very first read
72 ExtraData Pointer to an SecBuffer which contains extra data (sent by application)
73
74
75 */
76
ma_schannel_handshake_loop(MARIADB_PVIO * pvio,my_bool InitialRead,SecBuffer * pExtraData)77 SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRead, SecBuffer *pExtraData)
78 {
79 SecBufferDesc OutBuffer, InBuffer;
80 SecBuffer InBuffers[2], OutBuffers;
81 DWORD dwSSPIFlags, dwSSPIOutFlags, cbData, cbIoBuffer;
82 TimeStamp tsExpiry;
83 SECURITY_STATUS rc;
84 PUCHAR IoBuffer;
85 BOOL fDoRead;
86 MARIADB_TLS *ctls= pvio->ctls;
87 SC_CTX *sctx= (SC_CTX *)ctls->ssl;
88
89
90 dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
91 ISC_REQ_REPLAY_DETECT |
92 ISC_REQ_CONFIDENTIALITY |
93 ISC_RET_EXTENDED_ERROR |
94 ISC_REQ_ALLOCATE_MEMORY |
95 ISC_REQ_STREAM;
96
97
98 /* Allocate data buffer */
99 if (!(IoBuffer = LocalAlloc(LMEM_FIXED, SC_IO_BUFFER_SIZE)))
100 return SEC_E_INSUFFICIENT_MEMORY;
101
102 cbIoBuffer = 0;
103 fDoRead = InitialRead;
104
105 /* handshake loop: We will leave if handshake is finished
106 or an error occurs */
107
108 rc = SEC_I_CONTINUE_NEEDED;
109
110 while (rc == SEC_I_CONTINUE_NEEDED ||
111 rc == SEC_E_INCOMPLETE_MESSAGE ||
112 rc == SEC_I_INCOMPLETE_CREDENTIALS )
113 {
114 /* Read data */
115 if (rc == SEC_E_INCOMPLETE_MESSAGE ||
116 !cbIoBuffer)
117 {
118 if(fDoRead)
119 {
120 ssize_t nbytes = pvio->methods->read(pvio, IoBuffer + cbIoBuffer, (size_t)(SC_IO_BUFFER_SIZE - cbIoBuffer));
121 if (nbytes <= 0)
122 {
123 rc = SEC_E_INTERNAL_ERROR;
124 break;
125 }
126 cbData = (DWORD)nbytes;
127 cbIoBuffer += cbData;
128 }
129 else
130 fDoRead = TRUE;
131 }
132
133 /* input buffers
134 First buffer stores data received from server. leftover data
135 will be stored in second buffer with BufferType SECBUFFER_EXTRA */
136
137 InBuffers[0].pvBuffer = IoBuffer;
138 InBuffers[0].cbBuffer = cbIoBuffer;
139 InBuffers[0].BufferType = SECBUFFER_TOKEN;
140
141 InBuffers[1].pvBuffer = NULL;
142 InBuffers[1].cbBuffer = 0;
143 InBuffers[1].BufferType = SECBUFFER_EMPTY;
144
145 InBuffer.cBuffers = 2;
146 InBuffer.pBuffers = InBuffers;
147 InBuffer.ulVersion = SECBUFFER_VERSION;
148
149
150 /* output buffer */
151 OutBuffers.pvBuffer = NULL;
152 OutBuffers.BufferType= SECBUFFER_TOKEN;
153 OutBuffers.cbBuffer = 0;
154
155 OutBuffer.cBuffers = 1;
156 OutBuffer.pBuffers = &OutBuffers;
157 OutBuffer.ulVersion = SECBUFFER_VERSION;
158
159
160 rc = InitializeSecurityContextA(&sctx->CredHdl,
161 &sctx->hCtxt,
162 NULL,
163 dwSSPIFlags,
164 0,
165 SECURITY_NATIVE_DREP,
166 &InBuffer,
167 0,
168 NULL,
169 &OutBuffer,
170 &dwSSPIOutFlags,
171 &tsExpiry );
172
173
174 if (rc == SEC_E_OK ||
175 rc == SEC_I_CONTINUE_NEEDED ||
176 (FAILED(rc) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR)))
177 {
178 if(OutBuffers.cbBuffer && OutBuffers.pvBuffer)
179 {
180 ssize_t nbytes = pvio->methods->write(pvio, (uchar *)OutBuffers.pvBuffer, (size_t)OutBuffers.cbBuffer);
181 if(nbytes <= 0)
182 {
183 FreeContextBuffer(OutBuffers.pvBuffer);
184 DeleteSecurityContext(&sctx->hCtxt);
185 return SEC_E_INTERNAL_ERROR;
186 }
187 cbData= (DWORD)nbytes;
188 /* Free output context buffer */
189 FreeContextBuffer(OutBuffers.pvBuffer);
190 OutBuffers.pvBuffer = NULL;
191 }
192 }
193 /* check if we need to read more data */
194 switch (rc) {
195 case SEC_E_INCOMPLETE_MESSAGE:
196 /* we didn't receive all data, so just continue loop */
197 continue;
198 break;
199 case SEC_E_OK:
200 /* handshake completed, but we need to check if extra
201 data was sent (which contains encrypted application data) */
202 if (InBuffers[1].BufferType == SECBUFFER_EXTRA)
203 {
204 if (!(pExtraData->pvBuffer= LocalAlloc(0, InBuffers[1].cbBuffer)))
205 return SEC_E_INSUFFICIENT_MEMORY;
206
207 MoveMemory(pExtraData->pvBuffer, IoBuffer + (cbIoBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer );
208 pExtraData->BufferType = SECBUFFER_TOKEN;
209 pExtraData->cbBuffer = InBuffers[1].cbBuffer;
210 }
211 else
212 {
213 pExtraData->BufferType= SECBUFFER_EMPTY;
214 pExtraData->pvBuffer= NULL;
215 pExtraData->cbBuffer= 0;
216 }
217 break;
218
219 case SEC_I_INCOMPLETE_CREDENTIALS:
220 /* Provided credentials didn't contain a valid client certificate.
221 We will try to connect anonymously, using current credentials */
222 fDoRead= FALSE;
223 rc= SEC_I_CONTINUE_NEEDED;
224 continue;
225 break;
226 default:
227 if (FAILED(rc))
228 {
229 goto loopend;
230 }
231 break;
232 }
233
234 if ( InBuffers[1].BufferType == SECBUFFER_EXTRA )
235 {
236 MoveMemory( IoBuffer, IoBuffer + (cbIoBuffer - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer );
237 cbIoBuffer = InBuffers[1].cbBuffer;
238 }
239 else
240 cbIoBuffer = 0;
241 }
242 loopend:
243 if (FAILED(rc))
244 {
245 ma_schannel_set_sec_error(pvio, rc);
246 DeleteSecurityContext(&sctx->hCtxt);
247 }
248 LocalFree(IoBuffer);
249
250 return rc;
251 }
252 /* }}} */
253
254 /* {{{ SECURITY_STATUS ma_schannel_client_handshake(MARIADB_TLS *ctls) */
255 /*
256 performs client side handshake
257
258 SYNOPSIS
259 ma_schannel_client_handshake()
260 ctls Pointer to a MARIADB_TLS structure
261
262 DESCRIPTION
263 initiates a client/server handshake. This function can be used
264 by clients only
265
266 RETURN
267 SEC_E_OK on success
268 */
269
ma_schannel_client_handshake(MARIADB_TLS * ctls)270 SECURITY_STATUS ma_schannel_client_handshake(MARIADB_TLS *ctls)
271 {
272 MARIADB_PVIO *pvio;
273 SECURITY_STATUS sRet;
274 DWORD OutFlags;
275 DWORD r;
276 SC_CTX *sctx;
277 SecBuffer ExtraData;
278 DWORD SFlags= ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
279 ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR |
280 ISC_REQ_USE_SUPPLIED_CREDS |
281 ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM;
282
283 SecBufferDesc BufferOut;
284 SecBuffer BuffersOut;
285
286 if (!ctls || !ctls->pvio)
287 return 1;
288
289 pvio= ctls->pvio;
290 sctx= (SC_CTX *)ctls->ssl;
291
292 /* Initialie securifty context */
293 BuffersOut.BufferType= SECBUFFER_TOKEN;
294 BuffersOut.cbBuffer= 0;
295 BuffersOut.pvBuffer= NULL;
296
297
298 BufferOut.cBuffers= 1;
299 BufferOut.pBuffers= &BuffersOut;
300 BufferOut.ulVersion= SECBUFFER_VERSION;
301
302 sRet = InitializeSecurityContext(&sctx->CredHdl,
303 NULL,
304 pvio->mysql->host,
305 SFlags,
306 0,
307 SECURITY_NATIVE_DREP,
308 NULL,
309 0,
310 &sctx->hCtxt,
311 &BufferOut,
312 &OutFlags,
313 NULL);
314
315 if(sRet != SEC_I_CONTINUE_NEEDED)
316 {
317 ma_schannel_set_sec_error(pvio, sRet);
318 return sRet;
319 }
320
321 /* send client hello packaet */
322 if(BuffersOut.cbBuffer != 0 && BuffersOut.pvBuffer != NULL)
323 {
324 ssize_t nbytes = (DWORD)pvio->methods->write(pvio, (uchar *)BuffersOut.pvBuffer, (size_t)BuffersOut.cbBuffer);
325
326 if (nbytes <= 0)
327 {
328 sRet= SEC_E_INTERNAL_ERROR;
329 goto end;
330 }
331 r = (DWORD)nbytes;
332 }
333 sRet= ma_schannel_handshake_loop(pvio, TRUE, &ExtraData);
334
335 /* allocate IO-Buffer for write operations: After handshake
336 was successful, we are able now to calculate payload */
337 if ((sRet = QueryContextAttributes(&sctx->hCtxt, SECPKG_ATTR_STREAM_SIZES, &sctx->Sizes )))
338 goto end;
339
340 sctx->IoBufferSize= SCHANNEL_PAYLOAD(sctx->Sizes);
341 if (!(sctx->IoBuffer= (PUCHAR)LocalAlloc(0, sctx->IoBufferSize)))
342 {
343 sRet= SEC_E_INSUFFICIENT_MEMORY;
344 goto end;
345 }
346
347 return sRet;
348 end:
349 if (BuffersOut.pvBuffer)
350 FreeContextBuffer(BuffersOut.pvBuffer);
351 return sRet;
352 }
353 /* }}} */
354
355 /* {{{ SECURITY_STATUS ma_schannel_read_decrypt(MARIADB_PVIO *pvio, PCredHandle phCreds, CtxtHandle * phContext,
356 DWORD DecryptLength, uchar *ReadBuffer, DWORD ReadBufferSize) */
357 /*
358 Reads encrypted data from a SSL stream and decrypts it.
359
360 SYNOPSIS
361 ma_schannel_read
362 pvio pointer to Communication IO structure
363 phContext a context handle
364 DecryptLength size of decrypted buffer
365 ReadBuffer Buffer for decrypted data
366 ReadBufferSize size of ReadBuffer
367
368
369 DESCRIPTION
370 Reads decrypted data from a SSL stream and encrypts it.
371
372 RETURN
373 SEC_E_OK on success
374 SEC_E_* if an error occurred
375 */
376
ma_schannel_read_decrypt(MARIADB_PVIO * pvio,CtxtHandle * phContext,DWORD * DecryptLength,uchar * ReadBuffer,DWORD ReadBufferSize)377 SECURITY_STATUS ma_schannel_read_decrypt(MARIADB_PVIO *pvio,
378 CtxtHandle * phContext,
379 DWORD *DecryptLength,
380 uchar *ReadBuffer,
381 DWORD ReadBufferSize)
382 {
383 ssize_t nbytes = 0;
384 DWORD dwOffset = 0;
385 SC_CTX *sctx;
386 SECURITY_STATUS sRet = 0;
387 SecBufferDesc Msg;
388 SecBuffer Buffers[4];
389 int i;
390
391 if (!pvio || !pvio->methods || !pvio->methods->read || !pvio->ctls || !DecryptLength)
392 return SEC_E_INTERNAL_ERROR;
393
394 sctx = (SC_CTX *)pvio->ctls->ssl;
395 *DecryptLength = 0;
396
397 if (sctx->dataBuf.cbBuffer)
398 {
399 /* Have unread decrypted data from the last time, copy. */
400 nbytes = MIN(ReadBufferSize, sctx->dataBuf.cbBuffer);
401 memcpy(ReadBuffer, sctx->dataBuf.pvBuffer, nbytes);
402 sctx->dataBuf.pvBuffer = (char *)(sctx->dataBuf.pvBuffer) + nbytes;
403 sctx->dataBuf.cbBuffer -= (DWORD)nbytes;
404 *DecryptLength = (DWORD)nbytes;
405 return SEC_E_OK;
406 }
407
408
409 while (1)
410 {
411 /* Check for any encrypted data returned by last DecryptMessage() in SECBUFFER_EXTRA buffer. */
412 if (sctx->extraBuf.cbBuffer)
413 {
414 memmove(sctx->IoBuffer, sctx->extraBuf.pvBuffer, sctx->extraBuf.cbBuffer);
415 dwOffset = sctx->extraBuf.cbBuffer;
416 sctx->extraBuf.cbBuffer = 0;
417 }
418
419 do {
420 assert(sctx->IoBufferSize > dwOffset);
421 if (dwOffset == 0 || sRet == SEC_E_INCOMPLETE_MESSAGE)
422 {
423 nbytes = pvio->methods->read(pvio, sctx->IoBuffer + dwOffset, (size_t)(sctx->IoBufferSize - dwOffset));
424 if (nbytes <= 0)
425 {
426 /* server closed connection, or an error */
427 // todo: error
428 return SEC_E_INVALID_HANDLE;
429 }
430 dwOffset += (DWORD)nbytes;
431 }
432 ZeroMemory(Buffers, sizeof(SecBuffer) * 4);
433 Buffers[0].pvBuffer = sctx->IoBuffer;
434 Buffers[0].cbBuffer = dwOffset;
435
436 Buffers[0].BufferType = SECBUFFER_DATA;
437 Buffers[1].BufferType = SECBUFFER_EMPTY;
438 Buffers[2].BufferType = SECBUFFER_EMPTY;
439 Buffers[3].BufferType = SECBUFFER_EMPTY;
440
441 Msg.ulVersion = SECBUFFER_VERSION; // Version number
442 Msg.cBuffers = 4;
443 Msg.pBuffers = Buffers;
444
445 sRet = DecryptMessage(phContext, &Msg, 0, NULL);
446
447 } while (sRet == SEC_E_INCOMPLETE_MESSAGE); /* Continue reading until full message arrives */
448
449
450 if (sRet != SEC_E_OK)
451 {
452 ma_schannel_set_sec_error(pvio, sRet);
453 return sRet;
454 }
455
456 sctx->extraBuf.cbBuffer = 0;
457 sctx->dataBuf.cbBuffer = 0;
458 for (i = 0; i < 4; i++)
459 {
460 if (Buffers[i].BufferType == SECBUFFER_DATA)
461 sctx->dataBuf = Buffers[i];
462 if (Buffers[i].BufferType == SECBUFFER_EXTRA)
463 sctx->extraBuf = Buffers[i];
464 }
465
466
467 if (sctx->dataBuf.cbBuffer)
468 {
469 assert(sctx->dataBuf.pvBuffer);
470 /*
471 Copy at most ReadBufferSize bytes to output.
472 Store the rest (if any) to be processed next time.
473 */
474 nbytes = MIN(sctx->dataBuf.cbBuffer, ReadBufferSize);
475 memcpy((char *)ReadBuffer, sctx->dataBuf.pvBuffer, nbytes);
476 sctx->dataBuf.cbBuffer -= (unsigned long)nbytes;
477 sctx->dataBuf.pvBuffer = (char *)sctx->dataBuf.pvBuffer + nbytes;
478
479 *DecryptLength = (DWORD)nbytes;
480 return SEC_E_OK;
481 }
482 // No data buffer, loop
483 }
484 }
485 /* }}} */
486 #include "win32_errmsg.h"
ma_schannel_verify_certs(MARIADB_TLS * ctls,BOOL verify_server_name)487 my_bool ma_schannel_verify_certs(MARIADB_TLS *ctls, BOOL verify_server_name)
488 {
489 SECURITY_STATUS status;
490
491 MARIADB_PVIO *pvio= ctls->pvio;
492 MYSQL *mysql= pvio->mysql;
493 SC_CTX *sctx = (SC_CTX *)ctls->ssl;
494 const char *ca_file= mysql->options.ssl_ca;
495 const char* ca_path = mysql->options.ssl_capath;
496 const char *crl_file= mysql->options.extension ? mysql->options.extension->ssl_crl : NULL;
497 const char* crl_path = mysql->options.extension ? mysql->options.extension->ssl_crlpath : NULL;
498 PCCERT_CONTEXT pServerCert= NULL;
499 char errmsg[256];
500 HCERTSTORE store= NULL;
501 int ret= 0;
502
503 status = schannel_create_store(ca_file, ca_path, crl_file, crl_path, &store, errmsg, sizeof(errmsg));
504 if(status)
505 goto end;
506
507 status = QueryContextAttributesA(&sctx->hCtxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pServerCert);
508 if (status)
509 {
510 ma_format_win32_error(errmsg, sizeof(errmsg), GetLastError(),
511 "QueryContextAttributes(SECPKG_ATTR_REMOTE_CERT_CONTEXT) failed.");
512 goto end;
513 }
514
515 status = schannel_verify_server_certificate(
516 pServerCert,
517 store,
518 crl_file != 0 || crl_path != 0,
519 mysql->host,
520 verify_server_name,
521 errmsg, sizeof(errmsg));
522
523 if (status)
524 goto end;
525
526 ret= 1;
527
528 end:
529 if (!ret)
530 {
531 pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
532 "SSL connection error: %s", errmsg);
533 }
534 if (pServerCert)
535 CertFreeCertificateContext(pServerCert);
536 if(store)
537 schannel_free_store(store);
538 return ret;
539 }
540
541
542 /* {{{ size_t ma_schannel_write_encrypt(MARIADB_PVIO *pvio, PCredHandle phCreds, CtxtHandle * phContext) */
543 /*
544 Decrypts data and write to SSL stream
545 SYNOPSIS
546 ma_schannel_write_decrypt
547 pvio pointer to Communication IO structure
548 phContext a context handle
549 DecryptLength size of decrypted buffer
550 ReadBuffer Buffer for decrypted data
551 ReadBufferSize size of ReadBuffer
552
553 DESCRIPTION
554 Write encrypted data to SSL stream.
555
556 RETURN
557 SEC_E_OK on success
558 SEC_E_* if an error occurred
559 */
ma_schannel_write_encrypt(MARIADB_PVIO * pvio,uchar * WriteBuffer,size_t WriteBufferSize)560 ssize_t ma_schannel_write_encrypt(MARIADB_PVIO *pvio,
561 uchar *WriteBuffer,
562 size_t WriteBufferSize)
563 {
564 SECURITY_STATUS scRet;
565 SecBufferDesc Message;
566 SecBuffer Buffers[4];
567 DWORD cbMessage;
568 PBYTE pbMessage;
569 SC_CTX *sctx= (SC_CTX *)pvio->ctls->ssl;
570 size_t payload;
571 ssize_t nbytes;
572 DWORD write_size;
573
574 payload= MIN(WriteBufferSize, sctx->Sizes.cbMaximumMessage);
575
576 memcpy(&sctx->IoBuffer[sctx->Sizes.cbHeader], WriteBuffer, payload);
577 pbMessage = sctx->IoBuffer + sctx->Sizes.cbHeader;
578 cbMessage = (DWORD)payload;
579
580 Buffers[0].pvBuffer = sctx->IoBuffer;
581 Buffers[0].cbBuffer = sctx->Sizes.cbHeader;
582 Buffers[0].BufferType = SECBUFFER_STREAM_HEADER; // Type of the buffer
583
584 Buffers[1].pvBuffer = &sctx->IoBuffer[sctx->Sizes.cbHeader];
585 Buffers[1].cbBuffer = (DWORD)payload;
586 Buffers[1].BufferType = SECBUFFER_DATA;
587
588 Buffers[2].pvBuffer = &sctx->IoBuffer[sctx->Sizes.cbHeader] + payload;
589 Buffers[2].cbBuffer = sctx->Sizes.cbTrailer;
590 Buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
591
592 Buffers[3].pvBuffer = SECBUFFER_EMPTY; // Pointer to buffer 4
593 Buffers[3].cbBuffer = SECBUFFER_EMPTY; // length of buffer 4
594 Buffers[3].BufferType = SECBUFFER_EMPTY; // Type of the buffer 4
595
596
597 Message.ulVersion = SECBUFFER_VERSION;
598 Message.cBuffers = 4;
599 Message.pBuffers = Buffers;
600 if ((scRet = EncryptMessage(&sctx->hCtxt, 0, &Message, 0))!= SEC_E_OK)
601 return -1;
602 write_size = Buffers[0].cbBuffer + Buffers[1].cbBuffer + Buffers[2].cbBuffer;
603 nbytes = pvio->methods->write(pvio, sctx->IoBuffer, write_size);
604 return nbytes == write_size ? payload : -1;
605 }
606 /* }}} */
607
608 extern char *ssl_protocol_version[5];
609
610 /* {{{ ma_tls_get_protocol_version(MARIADB_TLS *ctls) */
ma_tls_get_protocol_version(MARIADB_TLS * ctls)611 int ma_tls_get_protocol_version(MARIADB_TLS *ctls)
612 {
613 SC_CTX *sctx;
614 SecPkgContext_ConnectionInfo ConnectionInfo;
615 if (!ctls->ssl)
616 return 1;
617
618 sctx= (SC_CTX *)ctls->ssl;
619
620 if (QueryContextAttributes(&sctx->hCtxt, SECPKG_ATTR_CONNECTION_INFO, &ConnectionInfo) != SEC_E_OK)
621 return -1;
622
623 switch(ConnectionInfo.dwProtocol)
624 {
625 case SP_PROT_SSL3_CLIENT:
626 return PROTOCOL_SSLV3;
627 case SP_PROT_TLS1_CLIENT:
628 return PROTOCOL_TLS_1_0;
629 case SP_PROT_TLS1_1_CLIENT:
630 return PROTOCOL_TLS_1_1;
631 case SP_PROT_TLS1_2_CLIENT:
632 return PROTOCOL_TLS_1_2;
633 default:
634 return -1;
635 }
636 }
637 /* }}} */
638