FreeRDP
Loading...
Searching...
No Matches
certificate.c
1
25#include <freerdp/config.h>
26
27#include <errno.h>
28#include <stdio.h>
29#include <string.h>
30
31#include <winpr/assert.h>
32#include <winpr/wtypes.h>
33#include <winpr/crt.h>
34#include <winpr/file.h>
35#include <winpr/print.h>
36#include <winpr/crypto.h>
37
38#include <freerdp/crypto/certificate.h>
39
40#include <openssl/err.h>
41#include <openssl/pem.h>
42#include <openssl/rsa.h>
43#include <openssl/bn.h>
44
45#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
46#include <openssl/core_names.h>
47#include <openssl/param_build.h>
48#include <openssl/evp.h>
49#include <openssl/x509.h>
50#endif
51
52#include "certificate.h"
53#include "cert_common.h"
54#include "crypto.h"
55
56#include "x509_utils.h"
57#include "privatekey.h"
58#include "opensslcompat.h"
59
60#define TAG FREERDP_TAG("core")
61
62#ifdef WITH_DEBUG_CERTIFICATE
63#define DEBUG_CERTIFICATE(...) WLog_DBG(TAG, __VA_ARGS__)
64#else
65#define DEBUG_CERTIFICATE(...) \
66 do \
67 { \
68 } while (0)
69#endif
70
71#define TSSK_KEY_LENGTH 64
72
73struct rdp_CertBlob
74{
75 UINT32 length;
76 BYTE* data;
77};
78typedef struct rdp_CertBlob rdpCertBlob;
79
80struct rdp_X509CertChain
81{
82 UINT32 count;
83 rdpCertBlob* array;
84};
85typedef struct rdp_X509CertChain rdpX509CertChain;
86
87struct rdp_certificate
88{
89 X509* x509;
90 STACK_OF(X509) * chain;
91
92 rdpCertInfo cert_info;
93 rdpX509CertChain x509_cert_chain;
94};
95
184static const char rsa_magic[4] = { 'R', 'S', 'A', '1' };
185
186static const char* certificate_read_errors[] = { "Certificate tag",
187 "TBSCertificate",
188 "Explicit Contextual Tag [0]",
189 "version",
190 "CertificateSerialNumber",
191 "AlgorithmIdentifier",
192 "Issuer Name",
193 "Validity",
194 "Subject Name",
195 "SubjectPublicKeyInfo Tag",
196 "subjectPublicKeyInfo::AlgorithmIdentifier",
197 "subjectPublicKeyInfo::subjectPublicKey",
198 "RSAPublicKey Tag",
199 "modulusLength",
200 "zero padding",
201 "modulusLength",
202 "modulus",
203 "publicExponent length",
204 "publicExponent" };
205
206static const BYTE initial_signature[] = {
207 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
208 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
209 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
210 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01
211};
212
213#if defined(CERT_VALIDATE_RSA)
214static const BYTE tssk_exponent[] = { 0x5b, 0x7b, 0x88, 0xc0 };
215#endif
216
217static void certificate_free_int(rdpCertificate* certificate);
218static BOOL cert_clone_int(rdpCertificate* dst, const rdpCertificate* src);
219
220/* [MS-RDPBCGR] 5.3.3.2 X.509 Certificate Chains:
221 *
222 * More detail[MS-RDPELE] section 2.2.1.4.2.
223 */
224static BOOL cert_blob_copy(rdpCertBlob* dst, const rdpCertBlob* src);
225static void cert_blob_free(rdpCertBlob* blob);
226static BOOL cert_blob_write(const rdpCertBlob* blob, wStream* s);
227static BOOL cert_blob_read(rdpCertBlob* blob, wStream* s);
228
229BOOL cert_blob_read(rdpCertBlob* blob, wStream* s)
230{
231 UINT32 certLength = 0;
232 WINPR_ASSERT(blob);
233 cert_blob_free(blob);
234
235 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
236 goto fail;
237
238 Stream_Read_UINT32(s, certLength);
239
240 if (!Stream_CheckAndLogRequiredLength(TAG, s, certLength))
241 goto fail;
242
243 DEBUG_CERTIFICATE("X.509 Certificate length:%" PRIu32 "", certLength);
244 blob->data = (BYTE*)malloc(certLength);
245
246 if (!blob->data)
247 goto fail;
248
249 Stream_Read(s, blob->data, certLength);
250 blob->length = certLength;
251
252 return TRUE;
253
254fail:
255 cert_blob_free(blob);
256 return FALSE;
257}
258
259BOOL cert_blob_write(const rdpCertBlob* blob, wStream* s)
260{
261 WINPR_ASSERT(blob);
262
263 if (!Stream_EnsureRemainingCapacity(s, 4ull + blob->length))
264 return FALSE;
265
266 Stream_Write_UINT32(s, blob->length);
267 Stream_Write(s, blob->data, blob->length);
268 return TRUE;
269}
270
271void cert_blob_free(rdpCertBlob* blob)
272{
273 if (!blob)
274 return;
275 free(blob->data);
276 blob->data = nullptr;
277 blob->length = 0;
278}
279
284static BOOL is_rsa_key(const X509* x509)
285{
286 EVP_PKEY* evp = X509_get0_pubkey(x509);
287 if (!evp)
288 return FALSE;
289
290 return (EVP_PKEY_id(evp) == EVP_PKEY_RSA);
291}
292
293static BOOL certificate_read_x509_certificate(const rdpCertBlob* cert, rdpCertInfo* info)
294{
295 wStream sbuffer = WINPR_C_ARRAY_INIT;
296 wStream* s = nullptr;
297 size_t length = 0;
298 BYTE padding = 0;
299 UINT32 version = 0;
300 size_t modulus_length = 0;
301 size_t exponent_length = 0;
302 int error = 0;
303
304 WINPR_ASSERT(cert);
305 WINPR_ASSERT(info);
306
307 cert_info_free(info);
308
309 s = Stream_StaticConstInit(&sbuffer, cert->data, cert->length);
310
311 if (!s)
312 return FALSE;
313
314 if (!ber_read_sequence_tag(s, &length)) /* Certificate (SEQUENCE) */
315 goto error;
316
317 error++;
318
319 if (!ber_read_sequence_tag(s, &length)) /* TBSCertificate (SEQUENCE) */
320 goto error;
321
322 error++;
323
324 if (!ber_read_contextual_tag(s, 0, &length, TRUE)) /* Explicit Contextual Tag [0] */
325 goto error;
326
327 error++;
328
329 if (!ber_read_integer(s, &version)) /* version (INTEGER) */
330 goto error;
331
332 error++;
333 version++;
334
335 /* serialNumber */
336 if (!ber_read_integer(s, nullptr)) /* CertificateSerialNumber (INTEGER) */
337 goto error;
338
339 error++;
340
341 /* signature */
342 if (!ber_read_sequence_tag(s, &length) ||
343 !Stream_SafeSeek(s, length)) /* AlgorithmIdentifier (SEQUENCE) */
344 goto error;
345
346 error++;
347
348 /* issuer */
349 if (!ber_read_sequence_tag(s, &length) || !Stream_SafeSeek(s, length)) /* Name (SEQUENCE) */
350 goto error;
351
352 error++;
353
354 /* validity */
355 if (!ber_read_sequence_tag(s, &length) || !Stream_SafeSeek(s, length)) /* Validity (SEQUENCE) */
356 goto error;
357
358 error++;
359
360 /* subject */
361 if (!ber_read_sequence_tag(s, &length) || !Stream_SafeSeek(s, length)) /* Name (SEQUENCE) */
362 goto error;
363
364 error++;
365
366 /* subjectPublicKeyInfo */
367 if (!ber_read_sequence_tag(s, &length)) /* SubjectPublicKeyInfo (SEQUENCE) */
368 goto error;
369
370 error++;
371
372 /* subjectPublicKeyInfo::AlgorithmIdentifier */
373 if (!ber_read_sequence_tag(s, &length) ||
374 !Stream_SafeSeek(s, length)) /* AlgorithmIdentifier (SEQUENCE) */
375 goto error;
376
377 error++;
378
379 /* subjectPublicKeyInfo::subjectPublicKey */
380 if (!ber_read_bit_string(s, &length, &padding)) /* BIT_STRING */
381 goto error;
382
383 error++;
384
385 /* RSAPublicKey (SEQUENCE) */
386 if (!ber_read_sequence_tag(s, &length)) /* SEQUENCE */
387 goto error;
388
389 error++;
390
391 if (!ber_read_integer_length(s, &modulus_length)) /* modulus (INTEGER) */
392 goto error;
393
394 error++;
395
396 /* skip zero padding, if any */
397 do
398 {
399 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
400 goto error;
401
402 Stream_Peek_UINT8(s, padding);
403
404 if (padding == 0)
405 {
406 if (!Stream_SafeSeek(s, 1))
407 goto error;
408
409 modulus_length--;
410 }
411 } while (padding == 0);
412
413 error++;
414
415 if (!cert_info_read_modulus(info, modulus_length, s))
416 goto error;
417
418 error++;
419
420 if (!ber_read_integer_length(s, &exponent_length)) /* publicExponent (INTEGER) */
421 goto error;
422
423 error++;
424
425 if (!cert_info_read_exponent(info, exponent_length, s))
426 goto error;
427 return TRUE;
428error:
429 WLog_ERR(TAG, "error reading when reading certificate: part=%s error=%d",
430 certificate_read_errors[error], error);
431 cert_info_free(info);
432 return FALSE;
433}
434
441static BOOL certificate_new_x509_certificate_chain(UINT32 count, wStream* s,
442 rdpX509CertChain* chain)
443{
444 WINPR_ASSERT(chain);
445
446 rdpX509CertChain x509_cert_chain = WINPR_C_ARRAY_INIT;
447 *chain = x509_cert_chain;
448
449 if (!Stream_CheckAndLogRequiredCapacityOfSize(TAG, s, count, sizeof(rdpCertBlob)))
450 return FALSE;
451
452 if (count == 0)
453 return TRUE;
454
455 x509_cert_chain.array = (rdpCertBlob*)calloc(count, sizeof(rdpCertBlob));
456 if (!x509_cert_chain.array)
457 return FALSE;
458
459 x509_cert_chain.count = count;
460
461 *chain = x509_cert_chain;
462 return TRUE;
463}
464
470static void certificate_free_x509_certificate_chain(rdpX509CertChain* x509_cert_chain)
471{
472 if (!x509_cert_chain)
473 return;
474
475 if (x509_cert_chain->array)
476 {
477 for (UINT32 i = 0; i < x509_cert_chain->count; i++)
478 {
479 rdpCertBlob* element = &x509_cert_chain->array[i];
480 cert_blob_free(element);
481 }
482 }
483
484 free(x509_cert_chain->array);
485 x509_cert_chain->array = nullptr;
486 x509_cert_chain->count = 0;
487}
488
489#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
490static OSSL_PARAM* get_params(const BIGNUM* e, const BIGNUM* mod)
491{
492 WINPR_ASSERT(e);
493 WINPR_ASSERT(mod);
494
495 OSSL_PARAM* parameters = nullptr;
496 OSSL_PARAM_BLD* param = OSSL_PARAM_BLD_new();
497 if (!param)
498 {
499 WLog_ERR(TAG, "OSSL_PARAM_BLD_new() failed");
500 return nullptr;
501 }
502
503 const int bits = BN_num_bits(e);
504 if ((bits < 0) || (bits > 32))
505 {
506 WLog_ERR(TAG, "BN_num_bits(e) out of range: 0 <= %d <= 32", bits);
507 goto fail;
508 }
509
510 {
511 UINT ie = 0;
512 {
513 const int ne = BN_bn2nativepad(e, (BYTE*)&ie, sizeof(ie));
514 if ((ne < 0) || (ne > 4))
515 {
516 WLog_ERR(TAG,
517 "BN_bn2nativepad(e, (BYTE*)&ie, sizeof(ie)) out of range: 0<= %d <= 4",
518 ne);
519 goto fail;
520 }
521 }
522
523 if (OSSL_PARAM_BLD_push_BN(param, OSSL_PKEY_PARAM_RSA_N, mod) != 1)
524 {
525 WLog_ERR(TAG, "OSSL_PARAM_BLD_push_BN(param, OSSL_PKEY_PARAM_RSA_N, mod) failed");
526 goto fail;
527 }
528 if (OSSL_PARAM_BLD_push_uint(param, OSSL_PKEY_PARAM_RSA_E, ie) != 1)
529 {
530 WLog_ERR(TAG, "OSSL_PARAM_BLD_push_uint(param, OSSL_PKEY_PARAM_RSA_E, ie) failed");
531 goto fail;
532 }
533 }
534
535 parameters = OSSL_PARAM_BLD_to_param(param);
536 if (!parameters)
537 WLog_ERR(TAG, "OSSL_PARAM_BLD_to_param(param) failed");
538fail:
539 OSSL_PARAM_BLD_free(param);
540
541 return parameters;
542}
543#endif
544
545static BOOL update_x509_from_info(rdpCertificate* cert)
546{
547 BOOL rc = FALSE;
548
549 WINPR_ASSERT(cert);
550
551 X509_free(cert->x509);
552 cert->x509 = nullptr;
553
554 rdpCertInfo* info = &cert->cert_info;
555
556 BIGNUM* e = BN_new();
557 BIGNUM* mod = BN_new();
558#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
559 RSA* rsa = RSA_new();
560 if (!rsa)
561 {
562 WLog_ERR(TAG, "RSA_new() failed");
563 goto fail;
564 }
565#endif
566
567 if (!mod || !e)
568 {
569 WLog_ERR(TAG, "failure: mod=%p, e=%p", WINPR_CXX_COMPAT_CAST(const void*, mod),
570 WINPR_CXX_COMPAT_CAST(const void*, e));
571 goto fail;
572 }
573
574 WINPR_ASSERT(info->ModulusLength <= INT_MAX);
575 if (!BN_bin2bn(info->Modulus, (int)info->ModulusLength, mod))
576 {
577 WLog_ERR(TAG, "BN_bin2bn(info->Modulus, (int)info->ModulusLength, mod) failed");
578 goto fail;
579 }
580
581 if (!BN_bin2bn(info->exponent, (int)sizeof(info->exponent), e))
582 {
583 WLog_ERR(TAG, "BN_bin2bn(info->exponent, (int)sizeof(info->exponent), e) failed");
584 goto fail;
585 }
586
587#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
588 const int rec = RSA_set0_key(rsa, mod, e, nullptr);
589 if (rec != 1)
590 {
591 WLog_ERR(TAG, "RSA_set0_key(rsa, mod, e, nullptr) failed");
592 goto fail;
593 }
594
595 cert->x509 = x509_from_rsa(rsa);
596#else
597 {
598 EVP_PKEY* pkey = nullptr;
599 EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr);
600 if (!ctx)
601 {
602 WLog_ERR(TAG, "EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr) failed");
603 goto fail2;
604 }
605
606 {
607 const int xx = EVP_PKEY_fromdata_init(ctx);
608 if (xx != 1)
609 {
610 WLog_ERR(TAG, "EVP_PKEY_fromdata_init(ctx) failed");
611 goto fail2;
612 }
613 }
614
615 {
616 OSSL_PARAM* parameters = get_params(e, mod);
617 if (!parameters)
618 goto fail2;
619
620 {
621 const int rc2 = EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, parameters);
622 OSSL_PARAM_free(parameters);
623 if (rc2 <= 0)
624 {
625 WLog_ERR(
626 TAG,
627 "EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, parameters) failed");
628 goto fail2;
629 }
630 }
631 }
632
633 cert->x509 = X509_new();
634 if (!cert->x509)
635 {
636 WLog_ERR(TAG, "X509_new() failed");
637 goto fail2;
638 }
639
640 if (X509_set_pubkey(cert->x509, pkey) != 1)
641 {
642 WLog_ERR(TAG, "X509_set_pubkey(cert->x509, pkey) failed");
643 X509_free(cert->x509);
644 cert->x509 = nullptr;
645 }
646 fail2:
647 EVP_PKEY_free(pkey);
648 EVP_PKEY_CTX_free(ctx);
649 }
650#endif
651 if (!cert->x509)
652 goto fail;
653
654 rc = TRUE;
655
656fail:
657 if (!rc)
658 WLog_ERR(TAG, "failed to update x509 from rdpCertInfo");
659
660#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
661 if (rsa)
662 RSA_free(rsa);
663 else
664#endif
665 {
666 BN_free(mod);
667 BN_free(e);
668 }
669 return rc;
670}
671
672static BOOL certificate_process_server_public_key(rdpCertificate* cert, wStream* s,
673 WINPR_ATTR_UNUSED UINT32 length)
674{
675 char magic[sizeof(rsa_magic)] = WINPR_C_ARRAY_INIT;
676 UINT32 keylen = 0;
677 UINT32 bitlen = 0;
678 UINT32 datalen = 0;
679
680 WINPR_ASSERT(cert);
681 WINPR_ASSERT(s);
682
683 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
684 return FALSE;
685
686 Stream_Read(s, magic, sizeof(magic));
687
688 if (memcmp(magic, rsa_magic, sizeof(magic)) != 0)
689 {
690 WLog_ERR(TAG, "invalid RSA magic bytes");
691 return FALSE;
692 }
693
694 rdpCertInfo* info = &cert->cert_info;
695 cert_info_free(info);
696
697 Stream_Read_UINT32(s, keylen);
698 Stream_Read_UINT32(s, bitlen);
699 Stream_Read_UINT32(s, datalen);
700 Stream_Read(s, info->exponent, 4);
701
702 if (keylen <= 8)
703 {
704 WLog_ERR(TAG, "Invalid RSA keylen=%" PRIu32 " <= 8", keylen);
705 return FALSE;
706 }
707 if (!Stream_CheckAndLogRequiredLength(TAG, s, keylen))
708 return FALSE;
709 if (keylen != (bitlen / 8ull) + 8ull)
710 {
711 WLog_ERR(TAG, "Invalid RSA key bitlen %" PRIu32 ", expected %" PRIu32, bitlen,
712 (keylen - 8) * 8);
713 return FALSE;
714 }
715 if (datalen != (bitlen / 8ull) - 1ull)
716 {
717 WLog_ERR(TAG, "Invalid RSA key datalen %" PRIu32 ", expected %llu", datalen,
718 (1ull * bitlen / 8ull) - 1ull);
719 return FALSE;
720 }
721 info->ModulusLength = keylen - 8;
722 BYTE* tmp = realloc(info->Modulus, info->ModulusLength);
723
724 if (!tmp)
725 {
726 WLog_ERR(TAG, "Failed to reallocate modulus of length %" PRIu32, info->ModulusLength);
727 return FALSE;
728 }
729 info->Modulus = tmp;
730
731 Stream_Read(s, info->Modulus, info->ModulusLength);
732 Stream_Seek(s, 8); /* 8 bytes of zero padding */
733 return update_x509_from_info(cert);
734}
735
736static BOOL certificate_process_server_public_signature(rdpCertificate* certificate,
737 const BYTE* sigdata, size_t sigdatalen,
738 wStream* s, UINT32 siglen)
739{
740 WINPR_ASSERT(certificate);
741#if defined(CERT_VALIDATE_RSA)
742 BYTE sig[TSSK_KEY_LENGTH];
743#endif
744 BYTE encsig[TSSK_KEY_LENGTH + 8];
745#if defined(CERT_VALIDATE_MD5) && defined(CERT_VALIDATE_RSA)
746 BYTE md5hash[WINPR_MD5_DIGEST_LENGTH];
747#endif
748#if !defined(CERT_VALIDATE_MD5) || !defined(CERT_VALIDATE_RSA)
749 (void)sigdata;
750 (void)sigdatalen;
751#endif
752 (void)certificate;
753 /* Do not bother with validation of server proprietary certificate. The use of MD5 here is not
754 * allowed under FIPS. Since the validation is not protecting against anything since the
755 * private/public keys are well known and documented in MS-RDPBCGR section 5.3.3.1, we are not
756 * gaining any security by using MD5 for signature comparison. Rather then use MD5
757 * here we just don't do the validation to avoid its use. Historically, freerdp has been
758 * ignoring a failed validation anyways. */
759#if defined(CERT_VALIDATE_MD5)
760
761 if (!winpr_Digest(WINPR_MD_MD5, sigdata, sigdatalen, md5hash, sizeof(md5hash)))
762 return FALSE;
763
764#endif
765 Stream_Read(s, encsig, siglen);
766
767 if (siglen < 8)
768 {
769 WLog_WARN(TAG, "public signature too short: %" PRIu32, siglen);
770 return FALSE;
771 }
772
773 /* Last 8 bytes shall be all zero. */
774#if defined(CERT_VALIDATE_PADDING)
775 {
776 size_t sum = 0;
777 for (size_t i = sizeof(encsig) - 8; i < sizeof(encsig); i++)
778 sum += encsig[i];
779
780 if (sum != 0)
781 {
782 WLog_ERR(TAG, "invalid signature");
783 return FALSE;
784 }
785 }
786#endif
787#if defined(CERT_VALIDATE_RSA)
788
789 if (crypto_rsa_public_decrypt(encsig, siglen - 8, TSSK_KEY_LENGTH, tssk_modulus, tssk_exponent,
790 sig) <= 0)
791 {
792 WLog_ERR(TAG, "invalid RSA decrypt");
793 return FALSE;
794 }
795
796 /* Verify signature. */
797 /* Do not bother with validation of server proprietary certificate as described above. */
798#if defined(CERT_VALIDATE_MD5)
799
800 if (memcmp(md5hash, sig, sizeof(md5hash)) != 0)
801 {
802 WLog_ERR(TAG, "invalid signature");
803 return FALSE;
804 }
805
806#endif
807 /*
808 * Verify rest of decrypted data:
809 * The 17th byte is 0x00.
810 * The 18th through 62nd bytes are each 0xFF.
811 * The 63rd byte is 0x01.
812 */
813 {
814 size_t sum = 0;
815 for (size_t i = 17; i < 62; i++)
816 sum += sig[i];
817
818 if (sig[16] != 0x00 || sum != 0xFF * (62 - 17) || sig[62] != 0x01)
819 {
820 WLog_ERR(TAG, "invalid signature");
821 return FALSE;
822 }
823 }
824#endif
825 return TRUE;
826}
827
828static BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate, wStream* s)
829{
830 UINT32 dwSigAlgId = 0;
831 UINT32 dwKeyAlgId = 0;
832 UINT16 wPublicKeyBlobType = 0;
833 UINT16 wPublicKeyBlobLen = 0;
834 UINT16 wSignatureBlobType = 0;
835 UINT16 wSignatureBlobLen = 0;
836 size_t sigdatalen = 0;
837
838 WINPR_ASSERT(certificate);
839 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
840 return FALSE;
841
842 /* -4, because we need to include dwVersion */
843 const BYTE* sigdata = Stream_PointerAs(s, const BYTE) - 4;
844 Stream_Read_UINT32(s, dwSigAlgId);
845 Stream_Read_UINT32(s, dwKeyAlgId);
846
847 if (!((dwSigAlgId == SIGNATURE_ALG_RSA) && (dwKeyAlgId == KEY_EXCHANGE_ALG_RSA)))
848 {
849 WLog_ERR(TAG,
850 "unsupported signature or key algorithm, dwSigAlgId=%" PRIu32
851 " dwKeyAlgId=%" PRIu32 "",
852 dwSigAlgId, dwKeyAlgId);
853 return FALSE;
854 }
855
856 Stream_Read_UINT16(s, wPublicKeyBlobType);
857
858 if (wPublicKeyBlobType != BB_RSA_KEY_BLOB)
859 {
860 WLog_ERR(TAG, "unsupported public key blob type %" PRIu16 "", wPublicKeyBlobType);
861 return FALSE;
862 }
863
864 Stream_Read_UINT16(s, wPublicKeyBlobLen);
865
866 if (!Stream_CheckAndLogRequiredLength(TAG, s, wPublicKeyBlobLen))
867 return FALSE;
868
869 if (!certificate_process_server_public_key(certificate, s, wPublicKeyBlobLen))
870 return FALSE;
871
872 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
873 return FALSE;
874
875 sigdatalen = WINPR_ASSERTING_INT_CAST(size_t, Stream_PointerAs(s, const BYTE) - sigdata);
876 Stream_Read_UINT16(s, wSignatureBlobType);
877
878 if (wSignatureBlobType != BB_RSA_SIGNATURE_BLOB)
879 {
880 WLog_ERR(TAG, "unsupported blob signature %" PRIu16 "", wSignatureBlobType);
881 return FALSE;
882 }
883
884 Stream_Read_UINT16(s, wSignatureBlobLen);
885
886 if (!Stream_CheckAndLogRequiredLength(TAG, s, wSignatureBlobLen))
887 return FALSE;
888
889 if (wSignatureBlobLen != 72)
890 {
891 WLog_ERR(TAG, "invalid signature length (got %" PRIu16 ", expected 72)", wSignatureBlobLen);
892 return FALSE;
893 }
894
895 if (!certificate_process_server_public_signature(certificate, sigdata, sigdatalen, s,
896 wSignatureBlobLen))
897 {
898 WLog_ERR(TAG, "unable to parse server public signature");
899 return FALSE;
900 }
901 return TRUE;
902}
903
904/* [MS-RDPBCGR] 2.2.1.4.3.1.1.1 RSA Public Key (RSA_PUBLIC_KEY) */
905static BOOL cert_write_rsa_public_key(wStream* s, const rdpCertificate* cert)
906{
907 WINPR_ASSERT(cert);
908 WINPR_ASSERT(freerdp_certificate_is_rsa(cert));
909
910 const rdpCertInfo* info = &cert->cert_info;
911
912 const UINT32 keyLen = info->ModulusLength + 8;
913 const UINT32 bitLen = info->ModulusLength * 8;
914 const UINT32 dataLen = (bitLen / 8) - 1;
915 const size_t pubExpLen = sizeof(info->exponent);
916 const BYTE* pubExp = info->exponent;
917 const BYTE* modulus = info->Modulus;
918
919 const size_t wPublicKeyBlobLen = 16 + pubExpLen + keyLen;
920 WINPR_ASSERT(wPublicKeyBlobLen <= UINT16_MAX);
921 if (!Stream_EnsureRemainingCapacity(s, 2ull + wPublicKeyBlobLen))
922 return FALSE;
923 Stream_Write_UINT16(s, (UINT16)wPublicKeyBlobLen);
924 Stream_Write(s, rsa_magic, sizeof(rsa_magic));
925 Stream_Write_UINT32(s, keyLen);
926 Stream_Write_UINT32(s, bitLen);
927 Stream_Write_UINT32(s, dataLen);
928 Stream_Write(s, pubExp, pubExpLen);
929 Stream_Write(s, modulus, info->ModulusLength);
930 Stream_Zero(s, 8);
931 return TRUE;
932}
933
934static BOOL cert_write_rsa_signature(wStream* s, const void* sigData, size_t sigDataLen)
935{
936 BYTE encryptedSignature[TSSK_KEY_LENGTH] = WINPR_C_ARRAY_INIT;
937 BYTE signature[sizeof(initial_signature)] = WINPR_C_ARRAY_INIT;
938
939 memcpy(signature, initial_signature, sizeof(initial_signature));
940 if (!winpr_Digest(WINPR_MD_MD5, sigData, sigDataLen, signature, sizeof(signature)))
941 return FALSE;
942
943 if (crypto_rsa_private_encrypt(signature, sizeof(signature), priv_key_tssk, encryptedSignature,
944 sizeof(encryptedSignature)) < 0)
945 return FALSE;
946
947 if (!Stream_EnsureRemainingCapacity(s,
948 2ull * sizeof(UINT16) + sizeof(encryptedSignature) + 8ull))
949 return FALSE;
950 Stream_Write_UINT16(s, BB_RSA_SIGNATURE_BLOB);
951 Stream_Write_UINT16(s, sizeof(encryptedSignature) + 8); /* wSignatureBlobLen */
952 Stream_Write(s, encryptedSignature, sizeof(encryptedSignature));
953 Stream_Zero(s, 8);
954 return TRUE;
955}
956
957/* [MS-RDPBCGR] 2.2.1.4.3.1.1 Server Proprietary Certificate (PROPRIETARYSERVERCERTIFICATE) */
958static BOOL cert_write_server_certificate_v1(wStream* s, const rdpCertificate* certificate)
959{
960 const size_t start = Stream_GetPosition(s);
961 const BYTE* sigData = Stream_PointerAs(s, const BYTE) - sizeof(UINT32);
962
963 WINPR_ASSERT(start >= 4);
964 if (!Stream_EnsureRemainingCapacity(s, 10))
965 return FALSE;
966 Stream_Write_UINT32(s, SIGNATURE_ALG_RSA);
967 Stream_Write_UINT32(s, KEY_EXCHANGE_ALG_RSA);
968 Stream_Write_UINT16(s, BB_RSA_KEY_BLOB);
969 if (!cert_write_rsa_public_key(s, certificate))
970 return FALSE;
971
972 const size_t end = Stream_GetPosition(s);
973 return cert_write_rsa_signature(s, sigData, end - start + sizeof(UINT32));
974}
975
976static BOOL cert_write_server_certificate_v2(wStream* s, const rdpCertificate* certificate)
977{
978 WINPR_ASSERT(certificate);
979
980 const rdpX509CertChain* chain = &certificate->x509_cert_chain;
981 const size_t padding = 8ull + 4ull * chain->count;
982
983 if (!Stream_EnsureRemainingCapacity(s, sizeof(UINT32)))
984 return FALSE;
985
986 Stream_Write_UINT32(s, chain->count);
987 for (UINT32 x = 0; x < chain->count; x++)
988 {
989 const rdpCertBlob* cert = &chain->array[x];
990 if (!cert_blob_write(cert, s))
991 return FALSE;
992 }
993
994 if (!Stream_EnsureRemainingCapacity(s, padding))
995 return FALSE;
996 Stream_Zero(s, padding);
997 return TRUE;
998}
999
1000SSIZE_T freerdp_certificate_write_server_cert(const rdpCertificate* certificate, UINT32 dwVersion,
1001 wStream* s)
1002{
1003 if (!certificate)
1004 return -1;
1005
1006 const size_t start = Stream_GetPosition(s);
1007 if (!Stream_EnsureRemainingCapacity(s, 4))
1008 return -1;
1009 Stream_Write_UINT32(s, dwVersion);
1010
1011 switch (dwVersion & CERT_CHAIN_VERSION_MASK)
1012 {
1013 case CERT_CHAIN_VERSION_1:
1014 if (!cert_write_server_certificate_v1(s, certificate))
1015 return -1;
1016 break;
1017 case CERT_CHAIN_VERSION_2:
1018 if (!cert_write_server_certificate_v2(s, certificate))
1019 return -1;
1020 break;
1021 default:
1022 WLog_ERR(TAG, "invalid certificate chain version:%" PRIu32 "",
1023 dwVersion & CERT_CHAIN_VERSION_MASK);
1024 return -1;
1025 }
1026
1027 const size_t end = Stream_GetPosition(s);
1028 if (start > end)
1029 return -1;
1030
1031 const size_t diff = end - start;
1032 WINPR_ASSERT(diff <= SSIZE_MAX);
1033 return (SSIZE_T)diff;
1034}
1035
1043static BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* cert, wStream* s)
1044{
1045 UINT32 numCertBlobs = 0;
1046 DEBUG_CERTIFICATE("Server X.509 Certificate Chain");
1047
1048 WINPR_ASSERT(cert);
1049 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
1050 return FALSE;
1051
1052 Stream_Read_UINT32(s, numCertBlobs); /* numCertBlobs */
1053 certificate_free_x509_certificate_chain(&cert->x509_cert_chain);
1054 if (!certificate_new_x509_certificate_chain(numCertBlobs, s, &cert->x509_cert_chain))
1055 return FALSE;
1056
1057 for (UINT32 i = 0; i < cert->x509_cert_chain.count; i++)
1058 {
1059 rdpCertBlob* blob = &cert->x509_cert_chain.array[i];
1060 if (!cert_blob_read(blob, s))
1061 return FALSE;
1062
1063 if (numCertBlobs - i == 1)
1064 {
1065 DEBUG_CERTIFICATE("Terminal Server Certificate");
1066
1067 BOOL res = certificate_read_x509_certificate(blob, &cert->cert_info);
1068
1069 if (res)
1070 {
1071 if (!update_x509_from_info(cert))
1072 res = FALSE;
1073 }
1074
1075 if (!res)
1076 {
1077 WLog_ERR(TAG, "Failed to read x509 certificate");
1078 return FALSE;
1079 }
1080
1081 DEBUG_CERTIFICATE("modulus length:%" PRIu32 "", cert->cert_info.ModulusLength);
1082 }
1083 }
1084
1085 return update_x509_from_info(cert);
1086}
1087
1095BOOL freerdp_certificate_read_server_cert(rdpCertificate* certificate, const BYTE* server_cert,
1096 size_t length)
1097{
1098 BOOL ret = FALSE;
1099 wStream* s = nullptr;
1100 wStream sbuffer;
1101 UINT32 dwVersion = 0;
1102
1103 WINPR_ASSERT(certificate);
1104 if (length < 4) /* nullptr certificate is not an error see #1795 */
1105 {
1106 WLog_DBG(TAG, "Received empty certificate, ignoring...");
1107 return TRUE;
1108 }
1109
1110 WINPR_ASSERT(server_cert);
1111 s = Stream_StaticConstInit(&sbuffer, server_cert, length);
1112
1113 if (!s)
1114 {
1115 WLog_ERR(TAG, "Stream_New failed!");
1116 return FALSE;
1117 }
1118
1119 Stream_Read_UINT32(s, dwVersion); /* dwVersion (4 bytes) */
1120
1121 switch (dwVersion & CERT_CHAIN_VERSION_MASK)
1122 {
1123 case CERT_CHAIN_VERSION_1:
1124 ret = certificate_read_server_proprietary_certificate(certificate, s);
1125 break;
1126
1127 case CERT_CHAIN_VERSION_2:
1128 ret = certificate_read_server_x509_certificate_chain(certificate, s);
1129 break;
1130
1131 default:
1132 WLog_ERR(TAG, "invalid certificate chain version:%" PRIu32 "",
1133 dwVersion & CERT_CHAIN_VERSION_MASK);
1134 ret = FALSE;
1135 break;
1136 }
1137
1138 return ret;
1139}
1140
1141static BOOL cert_blob_copy(rdpCertBlob* dst, const rdpCertBlob* src)
1142{
1143 WINPR_ASSERT(dst);
1144 WINPR_ASSERT(src);
1145
1146 cert_blob_free(dst);
1147 if (src->length > 0)
1148 {
1149 dst->data = malloc(src->length);
1150 if (!dst->data)
1151 return FALSE;
1152 dst->length = src->length;
1153 memcpy(dst->data, src->data, src->length);
1154 }
1155
1156 return TRUE;
1157}
1158
1159static BOOL cert_x509_chain_copy(rdpX509CertChain* cert, const rdpX509CertChain* src)
1160{
1161 WINPR_ASSERT(cert);
1162
1163 certificate_free_x509_certificate_chain(cert);
1164 if (!src)
1165 return TRUE;
1166
1167 if (src->count > 0)
1168 {
1169 cert->array = calloc(src->count, sizeof(rdpCertBlob));
1170 if (!cert->array)
1171 {
1172 return FALSE;
1173 }
1174 cert->count = src->count;
1175
1176 for (UINT32 x = 0; x < cert->count; x++)
1177 {
1178 const rdpCertBlob* srcblob = &src->array[x];
1179 rdpCertBlob* dstblob = &cert->array[x];
1180
1181 if (!cert_blob_copy(dstblob, srcblob))
1182 {
1183 certificate_free_x509_certificate_chain(cert);
1184 return FALSE;
1185 }
1186 }
1187 }
1188
1189 return TRUE;
1190}
1191
1192BOOL cert_clone_int(rdpCertificate* dst, const rdpCertificate* src)
1193{
1194 WINPR_ASSERT(dst);
1195 WINPR_ASSERT(src);
1196
1197 if (!cert_info_clone(&dst->cert_info, &src->cert_info))
1198 return FALSE;
1199
1200 if (src->x509)
1201 {
1202 dst->x509 = X509_dup(src->x509);
1203 if (!dst->x509)
1204 {
1205 /* Workaround for SSL deprecation issues:
1206 * some security modes use weak RSA ciphers where X509_dup fails.
1207 * In that case recreate the X509 from the raw RSA data
1208 */
1209 if (!update_x509_from_info(dst))
1210 {
1211 WLog_ERR(TAG, "X509_dup failed, SSL configuration bug?");
1212 return FALSE;
1213 }
1214 }
1215 }
1216
1217 if (src->chain)
1218 {
1219 if (dst->chain)
1220 sk_X509_pop_free(dst->chain, X509_free);
1221
1222 dst->chain = sk_X509_deep_copy(src->chain, X509_const_dup, X509_free);
1223 }
1224 return cert_x509_chain_copy(&dst->x509_cert_chain, &src->x509_cert_chain);
1225}
1226
1227rdpCertificate* freerdp_certificate_clone(const rdpCertificate* certificate)
1228{
1229 if (!certificate)
1230 return nullptr;
1231
1232 rdpCertificate* _certificate = freerdp_certificate_new();
1233
1234 if (!_certificate)
1235 return nullptr;
1236
1237 if (!cert_clone_int(_certificate, certificate))
1238 goto out_fail;
1239
1240 return _certificate;
1241out_fail:
1242
1243 freerdp_certificate_free(_certificate);
1244 return nullptr;
1245}
1246
1252rdpCertificate* freerdp_certificate_new(void)
1253{
1254 return (rdpCertificate*)calloc(1, sizeof(rdpCertificate));
1255}
1256
1257void certificate_free_int(rdpCertificate* cert)
1258{
1259 WINPR_ASSERT(cert);
1260
1261 if (cert->x509)
1262 X509_free(cert->x509);
1263 if (cert->chain)
1264 sk_X509_pop_free(cert->chain, X509_free);
1265
1266 certificate_free_x509_certificate_chain(&cert->x509_cert_chain);
1267 cert_info_free(&cert->cert_info);
1268}
1269
1275void freerdp_certificate_free(rdpCertificate* cert)
1276{
1277 if (!cert)
1278 return;
1279
1280 certificate_free_int(cert);
1281 free(cert);
1282}
1283
1284static BOOL freerdp_rsa_from_x509(rdpCertificate* cert)
1285{
1286 BOOL rc = FALSE;
1287
1288 WINPR_ASSERT(cert);
1289
1290 if (!freerdp_certificate_is_rsa(cert))
1291 return TRUE;
1292
1293#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1294 RSA* rsa = nullptr;
1295 const BIGNUM* rsa_n = nullptr;
1296 const BIGNUM* rsa_e = nullptr;
1297#else
1298 BIGNUM* rsa_n = nullptr;
1299 BIGNUM* rsa_e = nullptr;
1300#endif
1301 EVP_PKEY* pubkey = X509_get0_pubkey(cert->x509);
1302 if (!pubkey)
1303 goto fail;
1304
1305#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1306 rsa = EVP_PKEY_get1_RSA(pubkey);
1307
1308 /* If this is not a RSA key return success */
1309 rc = TRUE;
1310 if (!rsa)
1311 goto fail;
1312
1313 /* Now we return failure again if something is wrong. */
1314 rc = FALSE;
1315
1316 RSA_get0_key(rsa, &rsa_n, &rsa_e, nullptr);
1317#else
1318 if (!EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_E, &rsa_e))
1319 goto fail;
1320 if (!EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_N, &rsa_n))
1321 goto fail;
1322#endif
1323 if (!rsa_n || !rsa_e)
1324 goto fail;
1325 if (!cert_info_create(&cert->cert_info, rsa_n, rsa_e))
1326 goto fail;
1327 rc = TRUE;
1328fail:
1329#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1330 RSA_free(rsa);
1331#else
1332 BN_free(rsa_n);
1333 BN_free(rsa_e);
1334#endif
1335 return rc;
1336}
1337
1338rdpCertificate* freerdp_certificate_new_from_der(const BYTE* data, size_t length)
1339{
1340 rdpCertificate* cert = freerdp_certificate_new();
1341
1342 if (!cert || !data || (length == 0) || (length > INT_MAX))
1343 goto fail;
1344
1345 {
1346 const BYTE* ptr = data;
1347 cert->x509 = d2i_X509(nullptr, &ptr, (int)length);
1348 }
1349
1350 if (!cert->x509)
1351 goto fail;
1352 if (!freerdp_rsa_from_x509(cert))
1353 goto fail;
1354 return cert;
1355fail:
1356 freerdp_certificate_free(cert);
1357 return nullptr;
1358}
1359
1360rdpCertificate* freerdp_certificate_new_from_x509(const X509* xcert, const STACK_OF(X509) * chain)
1361{
1362 WINPR_ASSERT(xcert);
1363
1364 rdpCertificate* cert = freerdp_certificate_new();
1365 if (!cert)
1366 return nullptr;
1367
1368 X509* wcert = WINPR_CAST_CONST_PTR_AWAY(xcert, X509*);
1369 cert->x509 = X509_dup(wcert);
1370 if (!cert->x509)
1371 goto fail;
1372
1373 if (!freerdp_rsa_from_x509(cert))
1374 goto fail;
1375
1376 if (chain)
1377 cert->chain = sk_X509_deep_copy(chain, X509_const_dup, X509_free);
1378
1379 return cert;
1380fail:
1381 freerdp_certificate_free(cert);
1382 return nullptr;
1383}
1384
1385static STACK_OF(X509) * extract_chain_from_pem(const char* pem, BOOL isFile)
1386{
1387 if (!pem)
1388 {
1389 return nullptr;
1390 }
1391
1392 BIO* bio = nullptr;
1393 if (isFile)
1394 bio = BIO_new_file(pem, "rb");
1395 else
1396 {
1397 const size_t len = strlen(pem);
1398 bio = BIO_new_mem_buf(pem, WINPR_ASSERTING_INT_CAST(int, len));
1399 }
1400
1401 if (!bio)
1402 {
1403 return nullptr;
1404 }
1405
1406 X509* leaf = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
1407 if (!leaf)
1408 {
1409 BIO_free(bio);
1410 return nullptr;
1411 }
1412
1413 STACK_OF(X509)* chain = sk_X509_new_null();
1414 if (!chain)
1415 {
1416 X509_free(leaf);
1417 BIO_free(bio);
1418 return nullptr;
1419 }
1420
1421 X509* cert = nullptr;
1422 while ((cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr)) != nullptr)
1423 {
1424 sk_X509_push(chain, cert);
1425 }
1426
1427 X509_free(leaf);
1428 BIO_free(bio);
1429 return chain;
1430}
1431
1432static rdpCertificate* freerdp_certificate_new_from(const char* file, BOOL isFile)
1433{
1434 X509* x509 = x509_utils_from_pem(file, strlen(file), isFile);
1435 if (!x509)
1436 return nullptr;
1437 STACK_OF(X509)* chain = extract_chain_from_pem(file, isFile);
1438 rdpCertificate* cert = freerdp_certificate_new_from_x509(x509, chain);
1439 if (chain)
1440 sk_X509_pop_free(chain, X509_free);
1441 X509_free(x509);
1442 return cert;
1443}
1444
1445rdpCertificate* freerdp_certificate_new_from_file(const char* file)
1446{
1447 return freerdp_certificate_new_from(file, TRUE);
1448}
1449
1450rdpCertificate* freerdp_certificate_new_from_pem(const char* pem)
1451{
1452 return freerdp_certificate_new_from(pem, FALSE);
1453}
1454
1455const rdpCertInfo* freerdp_certificate_get_info(const rdpCertificate* cert)
1456{
1457 WINPR_ASSERT(cert);
1458 if (!freerdp_certificate_is_rsa(cert))
1459 return nullptr;
1460 return &cert->cert_info;
1461}
1462
1463char* freerdp_certificate_get_fingerprint(const rdpCertificate* cert)
1464{
1465 return freerdp_certificate_get_fingerprint_by_hash(cert, "sha256");
1466}
1467
1468char* freerdp_certificate_get_fingerprint_by_hash(const rdpCertificate* cert, const char* hash)
1469{
1470 return freerdp_certificate_get_fingerprint_by_hash_ex(cert, hash, TRUE);
1471}
1472
1473char* freerdp_certificate_get_fingerprint_by_hash_ex(const rdpCertificate* cert, const char* hash,
1474 BOOL separator)
1475{
1476 size_t fp_len = 0;
1477 size_t pos = 0;
1478 size_t size = 0;
1479 BYTE* fp = nullptr;
1480 char* fp_buffer = nullptr;
1481 if (!cert || !cert->x509)
1482 {
1483 WLog_ERR(TAG, "Invalid certificate [%p, %p]", WINPR_CXX_COMPAT_CAST(const void*, cert),
1484 WINPR_CXX_COMPAT_CAST(const void*, cert ? cert->x509 : nullptr));
1485 return nullptr;
1486 }
1487 if (!hash)
1488 {
1489 WLog_ERR(TAG, "Invalid certificate hash %p", WINPR_CXX_COMPAT_CAST(const void*, hash));
1490 return nullptr;
1491 }
1492 fp = x509_utils_get_hash(cert->x509, hash, &fp_len);
1493 if (!fp)
1494 return nullptr;
1495
1496 if (fp_len < 1)
1497 goto fail;
1498
1499 size = fp_len * 3 + 1;
1500 fp_buffer = calloc(size, sizeof(char));
1501 if (!fp_buffer)
1502 goto fail;
1503
1504 pos = 0;
1505
1506 {
1507 size_t i = 0;
1508 for (; i < (fp_len - 1); i++)
1509 {
1510 int rc = 0;
1511 char* p = &fp_buffer[pos];
1512 if (separator)
1513 rc = sprintf_s(p, size - pos, "%02" PRIx8 ":", fp[i]);
1514 else
1515 rc = sprintf_s(p, size - pos, "%02" PRIx8, fp[i]);
1516 if (rc <= 0)
1517 goto fail;
1518 pos += (size_t)rc;
1519 }
1520
1521 (void)sprintf_s(&fp_buffer[pos], size - pos, "%02" PRIx8 "", fp[i]);
1522 }
1523
1524 free(fp);
1525
1526 return fp_buffer;
1527fail:
1528 free(fp);
1529 free(fp_buffer);
1530 return nullptr;
1531}
1532
1533char* freerdp_certificate_get_pem(const rdpCertificate* cert, size_t* pLength)
1534{
1535 return freerdp_certificate_get_pem_ex(cert, pLength, TRUE);
1536}
1537
1538char* freerdp_certificate_get_pem_ex(const rdpCertificate* cert, size_t* pLength,
1539 BOOL withCertChain)
1540{
1541 WINPR_ASSERT(cert);
1542
1543 if (!cert->x509)
1544 return nullptr;
1545
1550 BIO* bio = BIO_new(BIO_s_mem());
1551
1552 if (!bio)
1553 {
1554 WLog_ERR(TAG, "BIO_new() failure");
1555 return nullptr;
1556 }
1557
1558 char* pem = nullptr;
1559
1560 const int status = PEM_write_bio_X509(bio, cert->x509);
1561 if (status < 0)
1562 {
1563 WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", status);
1564 goto fail;
1565 }
1566
1567 if (cert->chain && withCertChain)
1568 {
1569 const int count = sk_X509_num(cert->chain);
1570 for (int x = 0; x < count; x++)
1571 {
1572 X509* c = sk_X509_value(cert->chain, x);
1573 const int rc = PEM_write_bio_X509(bio, c);
1574 if (rc < 0)
1575 {
1576 WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", rc);
1577 goto fail;
1578 }
1579 }
1580 }
1581
1582 pem = x509_utils_bio_read(bio, pLength);
1583
1584fail:
1585 BIO_free_all(bio);
1586 return pem;
1587}
1588
1589char* freerdp_certificate_get_subject(const rdpCertificate* cert)
1590{
1591 WINPR_ASSERT(cert);
1592 return x509_utils_get_subject(cert->x509);
1593}
1594
1595char* freerdp_certificate_get_issuer(const rdpCertificate* cert)
1596{
1597 WINPR_ASSERT(cert);
1598 return x509_utils_get_issuer(cert->x509);
1599}
1600
1601char* freerdp_certificate_get_upn(const rdpCertificate* cert)
1602{
1603 WINPR_ASSERT(cert);
1604 return x509_utils_get_upn(cert->x509);
1605}
1606
1607char* freerdp_certificate_get_email(const rdpCertificate* cert)
1608{
1609 WINPR_ASSERT(cert);
1610 return x509_utils_get_email(cert->x509);
1611}
1612
1613char* freerdp_certificate_get_validity(const rdpCertificate* cert, BOOL startDate)
1614{
1615 WINPR_ASSERT(cert);
1616 return x509_utils_get_date(cert->x509, startDate);
1617}
1618
1619BOOL freerdp_certificate_check_eku(const rdpCertificate* cert, int nid)
1620{
1621 WINPR_ASSERT(cert);
1622 return x509_utils_check_eku(cert->x509, nid);
1623}
1624
1625BOOL freerdp_certificate_get_public_key(const rdpCertificate* cert, BYTE** PublicKey,
1626 DWORD* PublicKeyLength)
1627{
1628 BYTE* ptr = nullptr;
1629 BYTE* optr = nullptr;
1630 int length = 0;
1631 BOOL status = FALSE;
1632 EVP_PKEY* pkey = nullptr;
1633
1634 WINPR_ASSERT(cert);
1635
1636 pkey = X509_get0_pubkey(cert->x509);
1637
1638 if (!pkey)
1639 {
1640 WLog_ERR(TAG, "X509_get_pubkey() failed");
1641 goto exit;
1642 }
1643
1644 length = i2d_PublicKey(pkey, nullptr);
1645
1646 if (length < 1)
1647 {
1648 WLog_ERR(TAG, "i2d_PublicKey() failed");
1649 goto exit;
1650 }
1651
1652 *PublicKey = optr = ptr = (BYTE*)calloc(WINPR_ASSERTING_INT_CAST(size_t, length), sizeof(BYTE));
1653
1654 if (!ptr)
1655 goto exit;
1656
1657 {
1658 const int length2 = i2d_PublicKey(pkey, &ptr);
1659 if (length != length2)
1660 goto exit;
1661 *PublicKeyLength = (DWORD)length2;
1662 }
1663 status = TRUE;
1664exit:
1665
1666 if (!status)
1667 free(optr);
1668
1669 return status;
1670}
1671
1672BOOL freerdp_certificate_verify(const rdpCertificate* cert, const char* certificate_store_path)
1673{
1674 WINPR_ASSERT(cert);
1675 return x509_utils_verify(cert->x509, cert->chain, certificate_store_path);
1676}
1677
1678char** freerdp_certificate_get_dns_names(const rdpCertificate* cert, size_t* pcount,
1679 size_t** pplengths)
1680{
1681 WINPR_ASSERT(cert);
1682 return x509_utils_get_dns_names(cert->x509, pcount, pplengths);
1683}
1684
1685char* freerdp_certificate_get_common_name(const rdpCertificate* cert, size_t* plength)
1686{
1687 WINPR_ASSERT(cert);
1688 return x509_utils_get_common_name(cert->x509, plength);
1689}
1690
1691WINPR_MD_TYPE freerdp_certificate_get_signature_alg(const rdpCertificate* cert)
1692{
1693 WINPR_ASSERT(cert);
1694 return x509_utils_get_signature_alg(cert->x509);
1695}
1696
1697void freerdp_certificate_free_dns_names(size_t count, size_t* lengths, char** names)
1698{
1699 x509_utils_dns_names_free(count, lengths, names);
1700}
1701
1702char* freerdp_certificate_get_hash(const rdpCertificate* cert, const char* hash, size_t* plength)
1703{
1704 WINPR_ASSERT(cert);
1705 return (char*)x509_utils_get_hash(cert->x509, hash, plength);
1706}
1707
1708X509* freerdp_certificate_get_x509(rdpCertificate* cert)
1709{
1710 WINPR_ASSERT(cert);
1711 return cert->x509;
1712}
1713
1714BOOL freerdp_certificate_publickey_encrypt(const rdpCertificate* cert, const BYTE* input,
1715 size_t cbInput, BYTE** poutput, size_t* pcbOutput)
1716{
1717 WINPR_ASSERT(cert);
1718 WINPR_ASSERT(input);
1719 WINPR_ASSERT(poutput);
1720 WINPR_ASSERT(pcbOutput);
1721
1722 BOOL ret = FALSE;
1723 BYTE* output = nullptr;
1724 EVP_PKEY* pkey = X509_get0_pubkey(cert->x509);
1725 if (!pkey)
1726 return FALSE;
1727
1728 EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, nullptr);
1729 if (!ctx)
1730 return FALSE;
1731
1732 size_t outputSize = WINPR_ASSERTING_INT_CAST(size_t, EVP_PKEY_size(pkey));
1733 output = malloc(outputSize);
1734 if (output == nullptr)
1735 goto out;
1736 *pcbOutput = outputSize;
1737
1738 if (EVP_PKEY_encrypt_init(ctx) != 1 ||
1739 EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) != 1 ||
1740 EVP_PKEY_encrypt(ctx, output, pcbOutput, input, cbInput) != 1)
1741 {
1742 WLog_ERR(TAG, "error when setting up public key");
1743 goto out;
1744 }
1745
1746 *poutput = output;
1747 output = nullptr;
1748 ret = TRUE;
1749out:
1750 EVP_PKEY_CTX_free(ctx);
1751 free(output);
1752 return ret;
1753}
1754
1755#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1756static RSA* freerdp_certificate_get_RSA(const rdpCertificate* cert)
1757{
1758 WINPR_ASSERT(cert);
1759
1760 if (!freerdp_certificate_is_rsa(cert))
1761 return nullptr;
1762
1763 EVP_PKEY* pubkey = X509_get0_pubkey(cert->x509);
1764 if (!pubkey)
1765 return nullptr;
1766
1767 return EVP_PKEY_get1_RSA(pubkey);
1768}
1769#endif
1770
1771BYTE* freerdp_certificate_get_der(const rdpCertificate* cert, size_t* pLength)
1772{
1773 WINPR_ASSERT(cert);
1774
1775 if (pLength)
1776 *pLength = 0;
1777
1778 const int rc = i2d_X509(cert->x509, nullptr);
1779 if (rc <= 0)
1780 return nullptr;
1781
1782 BYTE* ptr = calloc(WINPR_ASSERTING_INT_CAST(size_t, rc) + 1, sizeof(BYTE));
1783 if (!ptr)
1784 return nullptr;
1785 BYTE* i2d_ptr = ptr;
1786
1787 const int rc2 = i2d_X509(cert->x509, &i2d_ptr);
1788 if (rc2 <= 0)
1789 {
1790 free(ptr);
1791 return nullptr;
1792 }
1793
1794 if (pLength)
1795 *pLength = (size_t)rc2;
1796 return ptr;
1797}
1798
1799BOOL freerdp_certificate_is_rsa(const rdpCertificate* cert)
1800{
1801 WINPR_ASSERT(cert);
1802 return is_rsa_key(cert->x509);
1803}
1804
1805BOOL freerdp_certificate_is_rdp_security_compatible(const rdpCertificate* cert)
1806{
1807 const rdpCertInfo* info = freerdp_certificate_get_info(cert);
1808 if (!freerdp_certificate_is_rsa(cert) || !info || (info->ModulusLength != 2048 / 8))
1809 {
1810 WLog_INFO(TAG, "certificate is not RSA 2048, RDP security not supported.");
1811 return FALSE;
1812 }
1813 return TRUE;
1814}
1815
1816char* freerdp_certificate_get_param(const rdpCertificate* cert, enum FREERDP_CERT_PARAM what,
1817 size_t* psize)
1818{
1819 WINPR_ASSERT(cert);
1820 WINPR_ASSERT(psize);
1821
1822 *psize = 0;
1823
1824#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1825 const BIGNUM* bn = nullptr;
1826 RSA* rsa = freerdp_certificate_get_RSA(cert);
1827 switch (what)
1828 {
1829 case FREERDP_CERT_RSA_E:
1830 RSA_get0_key(rsa, nullptr, &bn, nullptr);
1831 break;
1832 case FREERDP_CERT_RSA_N:
1833 RSA_get0_key(rsa, &bn, nullptr, nullptr);
1834 break;
1835 default:
1836 RSA_free(rsa);
1837 return nullptr;
1838 }
1839 RSA_free(rsa);
1840#else
1841 EVP_PKEY* pkey = X509_get0_pubkey(cert->x509);
1842 if (!pkey)
1843 return nullptr;
1844
1845 BIGNUM* bn = nullptr;
1846 switch (what)
1847 {
1848 case FREERDP_CERT_RSA_E:
1849 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &bn))
1850 return nullptr;
1851 break;
1852 case FREERDP_CERT_RSA_N:
1853 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &bn))
1854 return nullptr;
1855 break;
1856 default:
1857 return nullptr;
1858 }
1859#endif
1860
1861 const size_t bnsize = WINPR_ASSERTING_INT_CAST(size_t, BN_num_bytes(bn));
1862 char* rc = calloc(bnsize + 1, sizeof(char));
1863 if (!rc)
1864 goto fail;
1865 BN_bn2bin(bn, (BYTE*)rc);
1866 *psize = bnsize;
1867
1868fail:
1869#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR < 3)
1870 BN_free(bn);
1871#endif
1872 return rc;
1873}
1874
1875size_t freerdp_certificate_get_chain_len(rdpCertificate* certificate)
1876{
1877 WINPR_ASSERT(certificate);
1878 if (!certificate->chain)
1879 return 0;
1880
1881 return WINPR_ASSERTING_INT_CAST(size_t, sk_X509_num(certificate->chain));
1882}
1883
1884X509* freerdp_certificate_get_chain_at(rdpCertificate* certificate, size_t offset)
1885{
1886 WINPR_ASSERT(certificate);
1887 WINPR_ASSERT(freerdp_certificate_get_chain_len(certificate) > offset);
1888 const int ioff = WINPR_ASSERTING_INT_CAST(int, offset);
1889 return sk_X509_value(certificate->chain, ioff);
1890}