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