FreeRDP
Loading...
Searching...
No Matches
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 = nullptr;
83
84 if (context->bioWrite)
85 BIO_free_all(context->bioWrite);
86 context->bioWrite = nullptr;
87
88 if (context->bioRead)
89 BIO_free_all(context->bioRead);
90 context->bioRead = nullptr;
91
92 if (context->ssl)
93 SSL_free(context->ssl);
94 context->ssl = nullptr;
95
96 if (context->ctx)
97 SSL_CTX_free(context->ctx);
98 context->ctx = nullptr;
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 {
280 const char* key = getenv("FREERDP_SCHANNEL_KEY");
281 if (!key)
282 key = "/tmp/localhost.key";
283
284 if (SSL_CTX_use_PrivateKey_file(context->ctx, key, SSL_FILETYPE_PEM) <= 0)
285 {
286 WLog_ERR(TAG, "SSL_CTX_use_RSAPrivateKey_file failed");
287 goto fail;
288 }
289 }
290#endif
291
292 context->ssl = SSL_new(context->ctx);
293
294 if (!context->ssl)
295 {
296 WLog_ERR(TAG, "SSL_new failed");
297 goto fail;
298 }
299
300 if (SSL_use_certificate_file(context->ssl, "/tmp/localhost.crt", SSL_FILETYPE_PEM) <= 0)
301 {
302 WLog_ERR(TAG, "SSL_use_certificate_file failed");
303 goto fail;
304 }
305
306 context->bioRead = BIO_new(BIO_s_mem());
307
308 if (!context->bioRead)
309 {
310 WLog_ERR(TAG, "BIO_new failed");
311 goto fail;
312 }
313
314 status = BIO_set_write_buf_size(context->bioRead, SCHANNEL_CB_MAX_TOKEN);
315
316 if (status != 1)
317 {
318 WLog_ERR(TAG, "BIO_set_write_buf_size failed for bioRead");
319 goto fail;
320 }
321
322 context->bioWrite = BIO_new(BIO_s_mem());
323
324 if (!context->bioWrite)
325 {
326 WLog_ERR(TAG, "BIO_new failed");
327 goto fail;
328 }
329
330 status = BIO_set_write_buf_size(context->bioWrite, SCHANNEL_CB_MAX_TOKEN);
331
332 if (status != 1)
333 {
334 WLog_ERR(TAG, "BIO_set_write_buf_size failed for bioWrite");
335 goto fail;
336 }
337
338 status = BIO_make_bio_pair(context->bioRead, context->bioWrite);
339
340 if (status != 1)
341 {
342 WLog_ERR(TAG, "BIO_make_bio_pair failed");
343 goto fail;
344 }
345
346 SSL_set_bio(context->ssl, context->bioRead, context->bioWrite);
347 context->ReadBuffer = (BYTE*)malloc(SCHANNEL_CB_MAX_TOKEN);
348
349 if (!context->ReadBuffer)
350 {
351 WLog_ERR(TAG, "Failed to allocate memory for ReadBuffer");
352 goto fail;
353 }
354
355 context->WriteBuffer = (BYTE*)malloc(SCHANNEL_CB_MAX_TOKEN);
356
357 if (!context->WriteBuffer)
358 {
359 WLog_ERR(TAG, "Failed to allocate memory for WriteBuffer");
360 goto fail;
361 }
362
363 return 0;
364fail:
365 schannel_context_cleanup(context);
366 return -1;
367}
368
369SECURITY_STATUS schannel_openssl_client_process_tokens(SCHANNEL_OPENSSL* context,
370 PSecBufferDesc pInput,
371 PSecBufferDesc pOutput)
372{
373 int status = 0;
374 int ssl_error = 0;
375 PSecBuffer pBuffer = nullptr;
376
377 if (!context->connected)
378 {
379 if (pInput)
380 {
381 if (pInput->cBuffers < 1)
382 return SEC_E_INVALID_TOKEN;
383
384 pBuffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
385
386 if (!pBuffer)
387 return SEC_E_INVALID_TOKEN;
388
389 ERR_clear_error();
390 status =
391 BIO_write(context->bioRead, pBuffer->pvBuffer, LIMIT_INTMAX(pBuffer->cbBuffer));
392 if (status < 0)
393 return SEC_E_INVALID_TOKEN;
394 }
395
396 status = SSL_connect(context->ssl);
397
398 if (status < 0)
399 {
400 ssl_error = SSL_get_error(context->ssl, status);
401 WLog_ERR(TAG, "SSL_connect error: %s", openssl_get_ssl_error_string(ssl_error));
402 }
403
404 if (status == 1)
405 context->connected = TRUE;
406
407 ERR_clear_error();
408 status = BIO_read(context->bioWrite, context->ReadBuffer, SCHANNEL_CB_MAX_TOKEN);
409
410 if (pOutput->cBuffers < 1)
411 return SEC_E_INVALID_TOKEN;
412
413 pBuffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
414
415 if (!pBuffer)
416 return SEC_E_INVALID_TOKEN;
417
418 if (status > 0)
419 {
420 if (pBuffer->cbBuffer < WINPR_ASSERTING_INT_CAST(uint32_t, status))
421 return SEC_E_INSUFFICIENT_MEMORY;
422
423 CopyMemory(pBuffer->pvBuffer, context->ReadBuffer,
424 WINPR_ASSERTING_INT_CAST(uint32_t, status));
425 pBuffer->cbBuffer = WINPR_ASSERTING_INT_CAST(uint32_t, status);
426 return (context->connected) ? SEC_E_OK : SEC_I_CONTINUE_NEEDED;
427 }
428 else
429 {
430 pBuffer->cbBuffer = 0;
431 return (context->connected) ? SEC_E_OK : SEC_I_CONTINUE_NEEDED;
432 }
433 }
434
435 return SEC_E_OK;
436}
437
438SECURITY_STATUS schannel_openssl_server_process_tokens(SCHANNEL_OPENSSL* context,
439 PSecBufferDesc pInput,
440 PSecBufferDesc pOutput)
441{
442 int status = 0;
443 int ssl_error = 0;
444 PSecBuffer pBuffer = nullptr;
445
446 if (!context->connected)
447 {
448 if (pInput->cBuffers < 1)
449 return SEC_E_INVALID_TOKEN;
450
451 pBuffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
452
453 if (!pBuffer)
454 return SEC_E_INVALID_TOKEN;
455
456 ERR_clear_error();
457 status = BIO_write(context->bioRead, pBuffer->pvBuffer, LIMIT_INTMAX(pBuffer->cbBuffer));
458 if (status >= 0)
459 status = SSL_accept(context->ssl);
460
461 if (status < 0)
462 {
463 ssl_error = SSL_get_error(context->ssl, status);
464 WLog_ERR(TAG, "SSL_accept error: %s", openssl_get_ssl_error_string(ssl_error));
465 return SEC_E_INVALID_TOKEN;
466 }
467
468 if (status == 1)
469 context->connected = TRUE;
470
471 ERR_clear_error();
472 status = BIO_read(context->bioWrite, context->ReadBuffer, SCHANNEL_CB_MAX_TOKEN);
473 if (status < 0)
474 {
475 ssl_error = SSL_get_error(context->ssl, status);
476 WLog_ERR(TAG, "BIO_read: %s", openssl_get_ssl_error_string(ssl_error));
477 return SEC_E_INVALID_TOKEN;
478 }
479
480 if (pOutput->cBuffers < 1)
481 return SEC_E_INVALID_TOKEN;
482
483 pBuffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
484
485 if (!pBuffer)
486 return SEC_E_INVALID_TOKEN;
487
488 if (status > 0)
489 {
490 if (pBuffer->cbBuffer < WINPR_ASSERTING_INT_CAST(uint32_t, status))
491 return SEC_E_INSUFFICIENT_MEMORY;
492
493 CopyMemory(pBuffer->pvBuffer, context->ReadBuffer,
494 WINPR_ASSERTING_INT_CAST(uint32_t, status));
495 pBuffer->cbBuffer = WINPR_ASSERTING_INT_CAST(uint32_t, status);
496 return (context->connected) ? SEC_E_OK : SEC_I_CONTINUE_NEEDED;
497 }
498 else
499 {
500 pBuffer->cbBuffer = 0;
501 return (context->connected) ? SEC_E_OK : SEC_I_CONTINUE_NEEDED;
502 }
503 }
504
505 return SEC_E_OK;
506}
507
508SECURITY_STATUS schannel_openssl_encrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage)
509{
510 int status = 0;
511 int ssl_error = 0;
512 PSecBuffer pStreamBodyBuffer = nullptr;
513 PSecBuffer pStreamHeaderBuffer = nullptr;
514 PSecBuffer pStreamTrailerBuffer = nullptr;
515 pStreamHeaderBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_STREAM_HEADER);
516 pStreamBodyBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_DATA);
517 pStreamTrailerBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_STREAM_TRAILER);
518
519 if ((!pStreamHeaderBuffer) || (!pStreamBodyBuffer) || (!pStreamTrailerBuffer))
520 return SEC_E_INVALID_TOKEN;
521
522 status = SSL_write(context->ssl, pStreamBodyBuffer->pvBuffer,
523 LIMIT_INTMAX(pStreamBodyBuffer->cbBuffer));
524
525 if (status < 0)
526 {
527 ssl_error = SSL_get_error(context->ssl, status);
528 WLog_ERR(TAG, "SSL_write: %s", openssl_get_ssl_error_string(ssl_error));
529 }
530
531 ERR_clear_error();
532 status = BIO_read(context->bioWrite, context->ReadBuffer, SCHANNEL_CB_MAX_TOKEN);
533
534 if (status > 0)
535 {
536 size_t ustatus = (size_t)status;
537 size_t length = 0;
538 size_t offset = 0;
539
540 length =
541 (pStreamHeaderBuffer->cbBuffer > ustatus) ? ustatus : pStreamHeaderBuffer->cbBuffer;
542 CopyMemory(pStreamHeaderBuffer->pvBuffer, &context->ReadBuffer[offset], length);
543 ustatus -= length;
544 offset += length;
545 length = (pStreamBodyBuffer->cbBuffer > ustatus) ? ustatus : pStreamBodyBuffer->cbBuffer;
546 CopyMemory(pStreamBodyBuffer->pvBuffer, &context->ReadBuffer[offset], length);
547 ustatus -= length;
548 offset += length;
549 length =
550 (pStreamTrailerBuffer->cbBuffer > ustatus) ? ustatus : pStreamTrailerBuffer->cbBuffer;
551 CopyMemory(pStreamTrailerBuffer->pvBuffer, &context->ReadBuffer[offset], length);
552 }
553
554 return SEC_E_OK;
555}
556
557SECURITY_STATUS schannel_openssl_decrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage)
558{
559 int status = 0;
560 int length = 0;
561 BYTE* buffer = nullptr;
562 int ssl_error = 0;
563 PSecBuffer pBuffer = nullptr;
564 pBuffer = sspi_FindSecBuffer(pMessage, SECBUFFER_DATA);
565
566 if (!pBuffer)
567 return SEC_E_INVALID_TOKEN;
568
569 ERR_clear_error();
570 status = BIO_write(context->bioRead, pBuffer->pvBuffer, LIMIT_INTMAX(pBuffer->cbBuffer));
571 if (status > 0)
572 status = SSL_read(context->ssl, pBuffer->pvBuffer, LIMIT_INTMAX(pBuffer->cbBuffer));
573
574 if (status < 0)
575 {
576 ssl_error = SSL_get_error(context->ssl, status);
577 WLog_ERR(TAG, "SSL_read: %s", openssl_get_ssl_error_string(ssl_error));
578 }
579
580 length = status;
581 buffer = pBuffer->pvBuffer;
582 pMessage->pBuffers[0].BufferType = SECBUFFER_STREAM_HEADER;
583 pMessage->pBuffers[0].cbBuffer = 5;
584 pMessage->pBuffers[1].BufferType = SECBUFFER_DATA;
585 pMessage->pBuffers[1].pvBuffer = buffer;
586 pMessage->pBuffers[1].cbBuffer = WINPR_ASSERTING_INT_CAST(uint32_t, length);
587 pMessage->pBuffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
588 pMessage->pBuffers[2].cbBuffer = 36;
589 pMessage->pBuffers[3].BufferType = SECBUFFER_EMPTY;
590 pMessage->pBuffers[3].cbBuffer = 0;
591 return SEC_E_OK;
592}
593
594SCHANNEL_OPENSSL* schannel_openssl_new(void)
595{
596 if (!winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT))
597 return nullptr;
598
599 SCHANNEL_OPENSSL* context = (SCHANNEL_OPENSSL*)calloc(1, sizeof(SCHANNEL_OPENSSL));
600
601 if (context != nullptr)
602 {
603 context->connected = FALSE;
604 }
605
606 return context;
607}
608
609void schannel_openssl_free(SCHANNEL_OPENSSL* context)
610{
611 if (context)
612 {
613 free(context->ReadBuffer);
614 free(context->WriteBuffer);
615 free(context);
616 }
617}
618
619#else
620
621int schannel_openssl_client_init(SCHANNEL_OPENSSL* context)
622{
623 return 0;
624}
625
626int schannel_openssl_server_init(SCHANNEL_OPENSSL* context)
627{
628 return 0;
629}
630
631SECURITY_STATUS schannel_openssl_client_process_tokens(SCHANNEL_OPENSSL* context,
632 PSecBufferDesc pInput,
633 PSecBufferDesc pOutput)
634{
635 return SEC_E_OK;
636}
637
638SECURITY_STATUS schannel_openssl_server_process_tokens(SCHANNEL_OPENSSL* context,
639 PSecBufferDesc pInput,
640 PSecBufferDesc pOutput)
641{
642 return SEC_E_OK;
643}
644
645SECURITY_STATUS schannel_openssl_encrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage)
646{
647 return SEC_E_OK;
648}
649
650SECURITY_STATUS schannel_openssl_decrypt_message(SCHANNEL_OPENSSL* context, PSecBufferDesc pMessage)
651{
652 return SEC_E_OK;
653}
654
655SCHANNEL_OPENSSL* schannel_openssl_new(void)
656{
657 return nullptr;
658}
659
660void schannel_openssl_free(SCHANNEL_OPENSSL* context)
661{
662}
663
664#endif