FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
schannel_openssl.c
1
20#include <winpr/config.h>
21
22#include "schannel_openssl.h"
23
24#ifdef WITH_OPENSSL
25
26#include <winpr/crt.h>
27#include <winpr/sspi.h>
28#include <winpr/ssl.h>
29#include <winpr/print.h>
30#include <winpr/crypto.h>
31
32#include <openssl/ssl.h>
33#include <openssl/err.h>
34#include <openssl/bio.h>
35
36#define LIMIT_INTMAX(a) ((a) > INT32_MAX) ? INT32_MAX : (int)(a)
37
38struct S_SCHANNEL_OPENSSL
39{
40 SSL* ssl;
41 SSL_CTX* ctx;
42 BOOL connected;
43 BIO* bioRead;
44 BIO* bioWrite;
45 BYTE* ReadBuffer;
46 BYTE* WriteBuffer;
47};
48
49#include "../../log.h"
50#define TAG WINPR_TAG("sspi.schannel")
51
52static char* openssl_get_ssl_error_string(int ssl_error)
53{
54 switch (ssl_error)
55 {
56 case SSL_ERROR_ZERO_RETURN:
57 return "SSL_ERROR_ZERO_RETURN";
58
59 case SSL_ERROR_WANT_READ:
60 return "SSL_ERROR_WANT_READ";
61
62 case SSL_ERROR_WANT_WRITE:
63 return "SSL_ERROR_WANT_WRITE";
64
65 case SSL_ERROR_SYSCALL:
66 return "SSL_ERROR_SYSCALL";
67
68 case SSL_ERROR_SSL:
69 return "SSL_ERROR_SSL";
70 default:
71 break;
72 }
73
74 return "SSL_ERROR_UNKNOWN";
75}
76
77static void schannel_context_cleanup(SCHANNEL_OPENSSL* context)
78{
79 WINPR_ASSERT(context);
80
81 free(context->ReadBuffer);
82 context->ReadBuffer = NULL;
83
84 if (context->bioWrite)
85 BIO_free_all(context->bioWrite);
86 context->bioWrite = NULL;
87
88 if (context->bioRead)
89 BIO_free_all(context->bioRead);
90 context->bioRead = NULL;
91
92 if (context->ssl)
93 SSL_free(context->ssl);
94 context->ssl = NULL;
95
96 if (context->ctx)
97 SSL_CTX_free(context->ctx);
98 context->ctx = NULL;
99}
100
101static const SSL_METHOD* get_method(BOOL server)
102{
103 if (server)
104 {
105#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
106 return SSLv23_server_method();
107#else
108 return TLS_server_method();
109#endif
110 }
111 else
112 {
113#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
114 return SSLv23_client_method();
115#else
116 return TLS_client_method();
117#endif
118 }
119}
120int schannel_openssl_client_init(SCHANNEL_OPENSSL* context)
121{
122 int status = 0;
123 long options = 0;
124 context->ctx = SSL_CTX_new(get_method(FALSE));
125
126 if (!context->ctx)
127 {
128 WLog_ERR(TAG, "SSL_CTX_new failed");
129 return -1;
130 }
131
141#ifdef SSL_OP_NO_COMPRESSION
142 options |= SSL_OP_NO_COMPRESSION;
143#endif
150 options |= SSL_OP_TLS_BLOCK_PADDING_BUG;
157 options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
158 SSL_CTX_set_options(context->ctx, WINPR_ASSERTING_INT_CAST(uint64_t, options));
159 context->ssl = SSL_new(context->ctx);
160
161 if (!context->ssl)
162 {
163 WLog_ERR(TAG, "SSL_new failed");
164 goto fail;
165 }
166
167 context->bioRead = BIO_new(BIO_s_mem());
168
169 if (!context->bioRead)
170 {
171 WLog_ERR(TAG, "BIO_new failed");
172 goto fail;
173 }
174
175 status = BIO_set_write_buf_size(context->bioRead, SCHANNEL_CB_MAX_TOKEN);
176
177 if (status != 1)
178 {
179 WLog_ERR(TAG, "BIO_set_write_buf_size on bioRead failed");
180 goto fail;
181 }
182
183 context->bioWrite = BIO_new(BIO_s_mem());
184
185 if (!context->bioWrite)
186 {
187 WLog_ERR(TAG, "BIO_new failed");
188 goto fail;
189 }
190
191 status = BIO_set_write_buf_size(context->bioWrite, SCHANNEL_CB_MAX_TOKEN);
192
193 if (status != 1)
194 {
195 WLog_ERR(TAG, "BIO_set_write_buf_size on bioWrite failed");
196 goto fail;
197 }
198
199 status = BIO_make_bio_pair(context->bioRead, context->bioWrite);
200
201 if (status != 1)
202 {
203 WLog_ERR(TAG, "BIO_make_bio_pair failed");
204 goto fail;
205 }
206
207 SSL_set_bio(context->ssl, context->bioRead, context->bioWrite);
208 context->ReadBuffer = (BYTE*)malloc(SCHANNEL_CB_MAX_TOKEN);
209
210 if (!context->ReadBuffer)
211 {
212 WLog_ERR(TAG, "Failed to allocate ReadBuffer");
213 goto fail;
214 }
215
216 context->WriteBuffer = (BYTE*)malloc(SCHANNEL_CB_MAX_TOKEN);
217
218 if (!context->WriteBuffer)
219 {
220 WLog_ERR(TAG, "Failed to allocate ReadBuffer");
221 goto fail;
222 }
223
224 return 0;
225fail:
226 schannel_context_cleanup(context);
227 return -1;
228}
229
230int schannel_openssl_server_init(SCHANNEL_OPENSSL* context)
231{
232 int status = 0;
233 unsigned long options = 0;
234
235 context->ctx = SSL_CTX_new(get_method(TRUE));
236
237 if (!context->ctx)
238 {
239 WLog_ERR(TAG, "SSL_CTX_new failed");
240 return -1;
241 }
242
243 /*
244 * SSL_OP_NO_SSLv2:
245 *
246 * We only want SSLv3 and TLSv1, so disable SSLv2.
247 * SSLv3 is used by, eg. Microsoft RDC for Mac OS X.
248 */
249 options |= SSL_OP_NO_SSLv2;
259#ifdef SSL_OP_NO_COMPRESSION
260 options |= SSL_OP_NO_COMPRESSION;
261#endif
268 options |= SSL_OP_TLS_BLOCK_PADDING_BUG;
275 options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
276 SSL_CTX_set_options(context->ctx, options);
277
278#if defined(WITH_DEBUG_SCHANNEL)
279 if (SSL_CTX_use_RSAPrivateKey_file(context->ctx, "/tmp/localhost.key", SSL_FILETYPE_PEM) <= 0)
280 {
281 WLog_ERR(TAG, "SSL_CTX_use_RSAPrivateKey_file failed");
282 goto fail;
283 }
284#endif
285
286 context->ssl = SSL_new(context->ctx);
287
288 if (!context->ssl)
289 {
290 WLog_ERR(TAG, "SSL_new failed");
291 goto fail;
292 }
293
294 if (SSL_use_certificate_file(context->ssl, "/tmp/localhost.crt", SSL_FILETYPE_PEM) <= 0)
295 {
296 WLog_ERR(TAG, "SSL_use_certificate_file failed");
297 goto fail;
298 }
299
300 context->bioRead = BIO_new(BIO_s_mem());
301
302 if (!context->bioRead)
303 {
304 WLog_ERR(TAG, "BIO_new failed");
305 goto fail;
306 }
307
308 status = BIO_set_write_buf_size(context->bioRead, SCHANNEL_CB_MAX_TOKEN);
309
310 if (status != 1)
311 {
312 WLog_ERR(TAG, "BIO_set_write_buf_size failed for bioRead");
313 goto fail;
314 }
315
316 context->bioWrite = BIO_new(BIO_s_mem());
317
318 if (!context->bioWrite)
319 {
320 WLog_ERR(TAG, "BIO_new failed");
321 goto fail;
322 }
323
324 status = BIO_set_write_buf_size(context->bioWrite, SCHANNEL_CB_MAX_TOKEN);
325
326 if (status != 1)
327 {
328 WLog_ERR(TAG, "BIO_set_write_buf_size failed for bioWrite");
329 goto fail;
330 }
331
332 status = BIO_make_bio_pair(context->bioRead, context->bioWrite);
333
334 if (status != 1)
335 {
336 WLog_ERR(TAG, "BIO_make_bio_pair failed");
337 goto fail;
338 }
339
340 SSL_set_bio(context->ssl, context->bioRead, context->bioWrite);
341 context->ReadBuffer = (BYTE*)malloc(SCHANNEL_CB_MAX_TOKEN);
342
343 if (!context->ReadBuffer)
344 {
345 WLog_ERR(TAG, "Failed to allocate memory for ReadBuffer");
346 goto fail;
347 }
348
349 context->WriteBuffer = (BYTE*)malloc(SCHANNEL_CB_MAX_TOKEN);
350
351 if (!context->WriteBuffer)
352 {
353 WLog_ERR(TAG, "Failed to allocate memory for WriteBuffer");
354 goto fail;
355 }
356
357 return 0;
358fail:
359 schannel_context_cleanup(context);
360 return -1;
361}
362
363SECURITY_STATUS schannel_openssl_client_process_tokens(SCHANNEL_OPENSSL* context,
364 PSecBufferDesc pInput,
365 PSecBufferDesc pOutput)
366{
367 int status = 0;
368 int ssl_error = 0;
369 PSecBuffer pBuffer = NULL;
370
371 if (!context->connected)
372 {
373 if (pInput)
374 {
375 if (pInput->cBuffers < 1)
376 return SEC_E_INVALID_TOKEN;
377
378 pBuffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
379
380 if (!pBuffer)
381 return SEC_E_INVALID_TOKEN;
382
383 ERR_clear_error();
384 status =
385 BIO_write(context->bioRead, pBuffer->pvBuffer, LIMIT_INTMAX(pBuffer->cbBuffer));
386 if (status < 0)
387 return SEC_E_INVALID_TOKEN;
388 }
389
390 status = SSL_connect(context->ssl);
391
392 if (status < 0)
393 {
394 ssl_error = SSL_get_error(context->ssl, status);
395 WLog_ERR(TAG, "SSL_connect error: %s", openssl_get_ssl_error_string(ssl_error));
396 }
397
398 if (status == 1)
399 context->connected = TRUE;
400
401 ERR_clear_error();
402 status = BIO_read(context->bioWrite, context->ReadBuffer, SCHANNEL_CB_MAX_TOKEN);
403
404 if (pOutput->cBuffers < 1)
405 return SEC_E_INVALID_TOKEN;
406
407 pBuffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
408
409 if (!pBuffer)
410 return SEC_E_INVALID_TOKEN;
411
412 if (status > 0)
413 {
414 if (pBuffer->cbBuffer < WINPR_ASSERTING_INT_CAST(uint32_t, status))
415 return SEC_E_INSUFFICIENT_MEMORY;
416
417 CopyMemory(pBuffer->pvBuffer, context->ReadBuffer,
418 WINPR_ASSERTING_INT_CAST(uint32_t, status));
419 pBuffer->cbBuffer = WINPR_ASSERTING_INT_CAST(uint32_t, status);
420 return (context->connected) ? SEC_E_OK : SEC_I_CONTINUE_NEEDED;
421 }
422 else
423 {
424 pBuffer->cbBuffer = 0;
425 return (context->connected) ? SEC_E_OK : SEC_I_CONTINUE_NEEDED;
426 }
427 }
428
429 return SEC_E_OK;
430}
431
432SECURITY_STATUS schannel_openssl_server_process_tokens(SCHANNEL_OPENSSL* context,
433 PSecBufferDesc pInput,
434 PSecBufferDesc pOutput)
435{
436 int status = 0;
437 int ssl_error = 0;
438 PSecBuffer pBuffer = NULL;
439
440 if (!context->connected)
441 {
442 if (pInput->cBuffers < 1)
443 return SEC_E_INVALID_TOKEN;
444
445 pBuffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
446
447 if (!pBuffer)
448 return SEC_E_INVALID_TOKEN;
449
450 ERR_clear_error();
451 status = BIO_write(context->bioRead, pBuffer->pvBuffer, LIMIT_INTMAX(pBuffer->cbBuffer));
452 if (status >= 0)
453 status = SSL_accept(context->ssl);
454
455 if (status < 0)
456 {
457 ssl_error = SSL_get_error(context->ssl, status);
458 WLog_ERR(TAG, "SSL_accept error: %s", openssl_get_ssl_error_string(ssl_error));
459 return SEC_E_INVALID_TOKEN;
460 }
461
462 if (status == 1)
463 context->connected = TRUE;
464
465 ERR_clear_error();
466 status = BIO_read(context->bioWrite, context->ReadBuffer, SCHANNEL_CB_MAX_TOKEN);
467 if (status < 0)
468 {
469 ssl_error = SSL_get_error(context->ssl, status);
470 WLog_ERR(TAG, "BIO_read: %s", openssl_get_ssl_error_string(ssl_error));
471 return SEC_E_INVALID_TOKEN;
472 }
473
474 if (pOutput->cBuffers < 1)
475 return SEC_E_INVALID_TOKEN;
476
477 pBuffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
478
479 if (!pBuffer)
480 return SEC_E_INVALID_TOKEN;
481
482 if (status > 0)
483 {
484 if (pBuffer->cbBuffer < WINPR_ASSERTING_INT_CAST(uint32_t, status))
485 return SEC_E_INSUFFICIENT_MEMORY;
486
487 CopyMemory(pBuffer->pvBuffer, context->ReadBuffer,
488 WINPR_ASSERTING_INT_CAST(uint32_t, status));
489 pBuffer->cbBuffer = WINPR_ASSERTING_INT_CAST(uint32_t, status);
490 return (context->connected) ? SEC_E_OK : SEC_I_CONTINUE_NEEDED;
491 }
492 else
493 {
494 pBuffer->cbBuffer = 0;
495 return (context->connected) ? SEC_E_OK : SEC_I_CONTINUE_NEEDED;
496 }
497 }
498
499 return SEC_E_OK;
500}
501
502SECURITY_STATUS schannel_openssl_encrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage)
503{
504 int status = 0;
505 int ssl_error = 0;
506 PSecBuffer pStreamBodyBuffer = NULL;
507 PSecBuffer pStreamHeaderBuffer = NULL;
508 PSecBuffer pStreamTrailerBuffer = NULL;
509 pStreamHeaderBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_STREAM_HEADER);
510 pStreamBodyBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_DATA);
511 pStreamTrailerBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_STREAM_TRAILER);
512
513 if ((!pStreamHeaderBuffer) || (!pStreamBodyBuffer) || (!pStreamTrailerBuffer))
514 return SEC_E_INVALID_TOKEN;
515
516 status = SSL_write(context->ssl, pStreamBodyBuffer->pvBuffer,
517 LIMIT_INTMAX(pStreamBodyBuffer->cbBuffer));
518
519 if (status < 0)
520 {
521 ssl_error = SSL_get_error(context->ssl, status);
522 WLog_ERR(TAG, "SSL_write: %s", openssl_get_ssl_error_string(ssl_error));
523 }
524
525 ERR_clear_error();
526 status = BIO_read(context->bioWrite, context->ReadBuffer, SCHANNEL_CB_MAX_TOKEN);
527
528 if (status > 0)
529 {
530 size_t ustatus = (size_t)status;
531 size_t length = 0;
532 size_t offset = 0;
533
534 length =
535 (pStreamHeaderBuffer->cbBuffer > ustatus) ? ustatus : pStreamHeaderBuffer->cbBuffer;
536 CopyMemory(pStreamHeaderBuffer->pvBuffer, &context->ReadBuffer[offset], length);
537 ustatus -= length;
538 offset += length;
539 length = (pStreamBodyBuffer->cbBuffer > ustatus) ? ustatus : pStreamBodyBuffer->cbBuffer;
540 CopyMemory(pStreamBodyBuffer->pvBuffer, &context->ReadBuffer[offset], length);
541 ustatus -= length;
542 offset += length;
543 length =
544 (pStreamTrailerBuffer->cbBuffer > ustatus) ? ustatus : pStreamTrailerBuffer->cbBuffer;
545 CopyMemory(pStreamTrailerBuffer->pvBuffer, &context->ReadBuffer[offset], length);
546 }
547
548 return SEC_E_OK;
549}
550
551SECURITY_STATUS schannel_openssl_decrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage)
552{
553 int status = 0;
554 int length = 0;
555 BYTE* buffer = NULL;
556 int ssl_error = 0;
557 PSecBuffer pBuffer = NULL;
558 pBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_DATA);
559
560 if (!pBuffer)
561 return SEC_E_INVALID_TOKEN;
562
563 ERR_clear_error();
564 status = BIO_write(context->bioRead, pBuffer->pvBuffer, LIMIT_INTMAX(pBuffer->cbBuffer));
565 if (status > 0)
566 status = SSL_read(context->ssl, pBuffer->pvBuffer, LIMIT_INTMAX(pBuffer->cbBuffer));
567
568 if (status < 0)
569 {
570 ssl_error = SSL_get_error(context->ssl, status);
571 WLog_ERR(TAG, "SSL_read: %s", openssl_get_ssl_error_string(ssl_error));
572 }
573
574 length = status;
575 buffer = pBuffer->pvBuffer;
576 pMessage->pBuffers[0].BufferType = SECBUFFER_STREAM_HEADER;
577 pMessage->pBuffers[0].cbBuffer = 5;
578 pMessage->pBuffers[1].BufferType = SECBUFFER_DATA;
579 pMessage->pBuffers[1].pvBuffer = buffer;
580 pMessage->pBuffers[1].cbBuffer = WINPR_ASSERTING_INT_CAST(uint32_t, length);
581 pMessage->pBuffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
582 pMessage->pBuffers[2].cbBuffer = 36;
583 pMessage->pBuffers[3].BufferType = SECBUFFER_EMPTY;
584 pMessage->pBuffers[3].cbBuffer = 0;
585 return SEC_E_OK;
586}
587
588SCHANNEL_OPENSSL* schannel_openssl_new(void)
589{
590 SCHANNEL_OPENSSL* context = NULL;
591 context = (SCHANNEL_OPENSSL*)calloc(1, sizeof(SCHANNEL_OPENSSL));
592
593 if (context != NULL)
594 {
595 winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
596 context->connected = FALSE;
597 }
598
599 return context;
600}
601
602void schannel_openssl_free(SCHANNEL_OPENSSL* context)
603{
604 if (context)
605 {
606 free(context->ReadBuffer);
607 free(context->WriteBuffer);
608 free(context);
609 }
610}
611
612#else
613
614int schannel_openssl_client_init(SCHANNEL_OPENSSL* context)
615{
616 return 0;
617}
618
619int schannel_openssl_server_init(SCHANNEL_OPENSSL* context)
620{
621 return 0;
622}
623
624SECURITY_STATUS schannel_openssl_client_process_tokens(SCHANNEL_OPENSSL* context,
625 PSecBufferDesc pInput,
626 PSecBufferDesc pOutput)
627{
628 return SEC_E_OK;
629}
630
631SECURITY_STATUS schannel_openssl_server_process_tokens(SCHANNEL_OPENSSL* context,
632 PSecBufferDesc pInput,
633 PSecBufferDesc pOutput)
634{
635 return SEC_E_OK;
636}
637
638SECURITY_STATUS schannel_openssl_encrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage)
639{
640 return SEC_E_OK;
641}
642
643SECURITY_STATUS schannel_openssl_decrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage)
644{
645 return SEC_E_OK;
646}
647
648SCHANNEL_OPENSSL* schannel_openssl_new(void)
649{
650 return NULL;
651}
652
653void schannel_openssl_free(SCHANNEL_OPENSSL* context)
654{
655}
656
657#endif