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, 4 + 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, 2 + 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, 2 * sizeof(UINT16) + sizeof(encryptedSignature) + 8))
948 return FALSE;
949 Stream_Write_UINT16(s, BB_RSA_SIGNATURE_BLOB);
950 Stream_Write_UINT16(s, sizeof(encryptedSignature) + 8); /* wSignatureBlobLen */
951 Stream_Write(s, encryptedSignature, sizeof(encryptedSignature));
952 Stream_Zero(s, 8);
953 return TRUE;
954}
955
956/* [MS-RDPBCGR] 2.2.1.4.3.1.1 Server Proprietary Certificate (PROPRIETARYSERVERCERTIFICATE) */
957static BOOL cert_write_server_certificate_v1(wStream* s, const rdpCertificate* certificate)
958{
959 const size_t start = Stream_GetPosition(s);
960 const BYTE* sigData = Stream_PointerAs(s, const BYTE) - sizeof(UINT32);
961
962 WINPR_ASSERT(start >= 4);
963 if (!Stream_EnsureRemainingCapacity(s, 10))
964 return FALSE;
965 Stream_Write_UINT32(s, SIGNATURE_ALG_RSA);
966 Stream_Write_UINT32(s, KEY_EXCHANGE_ALG_RSA);
967 Stream_Write_UINT16(s, BB_RSA_KEY_BLOB);
968 if (!cert_write_rsa_public_key(s, certificate))
969 return FALSE;
970
971 const size_t end = Stream_GetPosition(s);
972 return cert_write_rsa_signature(s, sigData, end - start + sizeof(UINT32));
973}
974
975static BOOL cert_write_server_certificate_v2(wStream* s, const rdpCertificate* certificate)
976{
977 WINPR_ASSERT(certificate);
978
979 const rdpX509CertChain* chain = &certificate->x509_cert_chain;
980 const size_t padding = 8ull + 4ull * chain->count;
981
982 if (!Stream_EnsureRemainingCapacity(s, sizeof(UINT32)))
983 return FALSE;
984
985 Stream_Write_UINT32(s, chain->count);
986 for (UINT32 x = 0; x < chain->count; x++)
987 {
988 const rdpCertBlob* cert = &chain->array[x];
989 if (!cert_blob_write(cert, s))
990 return FALSE;
991 }
992
993 if (!Stream_EnsureRemainingCapacity(s, padding))
994 return FALSE;
995 Stream_Zero(s, padding);
996 return TRUE;
997}
998
999SSIZE_T freerdp_certificate_write_server_cert(const rdpCertificate* certificate, UINT32 dwVersion,
1000 wStream* s)
1001{
1002 if (!certificate)
1003 return -1;
1004
1005 const size_t start = Stream_GetPosition(s);
1006 if (!Stream_EnsureRemainingCapacity(s, 4))
1007 return -1;
1008 Stream_Write_UINT32(s, dwVersion);
1009
1010 switch (dwVersion & CERT_CHAIN_VERSION_MASK)
1011 {
1012 case CERT_CHAIN_VERSION_1:
1013 if (!cert_write_server_certificate_v1(s, certificate))
1014 return -1;
1015 break;
1016 case CERT_CHAIN_VERSION_2:
1017 if (!cert_write_server_certificate_v2(s, certificate))
1018 return -1;
1019 break;
1020 default:
1021 WLog_ERR(TAG, "invalid certificate chain version:%" PRIu32 "",
1022 dwVersion & CERT_CHAIN_VERSION_MASK);
1023 return -1;
1024 }
1025
1026 const size_t end = Stream_GetPosition(s);
1027 if (start > end)
1028 return -1;
1029
1030 const size_t diff = end - start;
1031 WINPR_ASSERT(diff <= SSIZE_MAX);
1032 return (SSIZE_T)diff;
1033}
1034
1042static BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* cert, wStream* s)
1043{
1044 UINT32 numCertBlobs = 0;
1045 DEBUG_CERTIFICATE("Server X.509 Certificate Chain");
1046
1047 WINPR_ASSERT(cert);
1048 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
1049 return FALSE;
1050
1051 Stream_Read_UINT32(s, numCertBlobs); /* numCertBlobs */
1052 certificate_free_x509_certificate_chain(&cert->x509_cert_chain);
1053 if (!certificate_new_x509_certificate_chain(numCertBlobs, s, &cert->x509_cert_chain))
1054 return FALSE;
1055
1056 for (UINT32 i = 0; i < cert->x509_cert_chain.count; i++)
1057 {
1058 rdpCertBlob* blob = &cert->x509_cert_chain.array[i];
1059 if (!cert_blob_read(blob, s))
1060 return FALSE;
1061
1062 if (numCertBlobs - i == 1)
1063 {
1064 DEBUG_CERTIFICATE("Terminal Server Certificate");
1065
1066 BOOL res = certificate_read_x509_certificate(blob, &cert->cert_info);
1067
1068 if (res)
1069 {
1070 if (!update_x509_from_info(cert))
1071 res = FALSE;
1072 }
1073
1074 if (!res)
1075 {
1076 WLog_ERR(TAG, "Failed to read x509 certificate");
1077 return FALSE;
1078 }
1079
1080 DEBUG_CERTIFICATE("modulus length:%" PRIu32 "", cert->cert_info.ModulusLength);
1081 }
1082 }
1083
1084 return update_x509_from_info(cert);
1085}
1086
1094BOOL freerdp_certificate_read_server_cert(rdpCertificate* certificate, const BYTE* server_cert,
1095 size_t length)
1096{
1097 BOOL ret = FALSE;
1098 wStream* s = nullptr;
1099 wStream sbuffer;
1100 UINT32 dwVersion = 0;
1101
1102 WINPR_ASSERT(certificate);
1103 if (length < 4) /* nullptr certificate is not an error see #1795 */
1104 {
1105 WLog_DBG(TAG, "Received empty certificate, ignoring...");
1106 return TRUE;
1107 }
1108
1109 WINPR_ASSERT(server_cert);
1110 s = Stream_StaticConstInit(&sbuffer, server_cert, length);
1111
1112 if (!s)
1113 {
1114 WLog_ERR(TAG, "Stream_New failed!");
1115 return FALSE;
1116 }
1117
1118 Stream_Read_UINT32(s, dwVersion); /* dwVersion (4 bytes) */
1119
1120 switch (dwVersion & CERT_CHAIN_VERSION_MASK)
1121 {
1122 case CERT_CHAIN_VERSION_1:
1123 ret = certificate_read_server_proprietary_certificate(certificate, s);
1124 break;
1125
1126 case CERT_CHAIN_VERSION_2:
1127 ret = certificate_read_server_x509_certificate_chain(certificate, s);
1128 break;
1129
1130 default:
1131 WLog_ERR(TAG, "invalid certificate chain version:%" PRIu32 "",
1132 dwVersion & CERT_CHAIN_VERSION_MASK);
1133 ret = FALSE;
1134 break;
1135 }
1136
1137 return ret;
1138}
1139
1140static BOOL cert_blob_copy(rdpCertBlob* dst, const rdpCertBlob* src)
1141{
1142 WINPR_ASSERT(dst);
1143 WINPR_ASSERT(src);
1144
1145 cert_blob_free(dst);
1146 if (src->length > 0)
1147 {
1148 dst->data = malloc(src->length);
1149 if (!dst->data)
1150 return FALSE;
1151 dst->length = src->length;
1152 memcpy(dst->data, src->data, src->length);
1153 }
1154
1155 return TRUE;
1156}
1157
1158static BOOL cert_x509_chain_copy(rdpX509CertChain* cert, const rdpX509CertChain* src)
1159{
1160 WINPR_ASSERT(cert);
1161
1162 certificate_free_x509_certificate_chain(cert);
1163 if (!src)
1164 return TRUE;
1165
1166 if (src->count > 0)
1167 {
1168 cert->array = calloc(src->count, sizeof(rdpCertBlob));
1169 if (!cert->array)
1170 {
1171 return FALSE;
1172 }
1173 cert->count = src->count;
1174
1175 for (UINT32 x = 0; x < cert->count; x++)
1176 {
1177 const rdpCertBlob* srcblob = &src->array[x];
1178 rdpCertBlob* dstblob = &cert->array[x];
1179
1180 if (!cert_blob_copy(dstblob, srcblob))
1181 {
1182 certificate_free_x509_certificate_chain(cert);
1183 return FALSE;
1184 }
1185 }
1186 }
1187
1188 return TRUE;
1189}
1190
1191BOOL cert_clone_int(rdpCertificate* dst, const rdpCertificate* src)
1192{
1193 WINPR_ASSERT(dst);
1194 WINPR_ASSERT(src);
1195
1196 if (!cert_info_clone(&dst->cert_info, &src->cert_info))
1197 return FALSE;
1198
1199 if (src->x509)
1200 {
1201 dst->x509 = X509_dup(src->x509);
1202 if (!dst->x509)
1203 {
1204 /* Workaround for SSL deprecation issues:
1205 * some security modes use weak RSA ciphers where X509_dup fails.
1206 * In that case recreate the X509 from the raw RSA data
1207 */
1208 if (!update_x509_from_info(dst))
1209 {
1210 WLog_ERR(TAG, "X509_dup failed, SSL configuration bug?");
1211 return FALSE;
1212 }
1213 }
1214 }
1215
1216 if (src->chain)
1217 {
1218 if (dst->chain)
1219 sk_X509_pop_free(dst->chain, X509_free);
1220
1221 dst->chain = sk_X509_deep_copy(src->chain, X509_const_dup, X509_free);
1222 }
1223 return cert_x509_chain_copy(&dst->x509_cert_chain, &src->x509_cert_chain);
1224}
1225
1226rdpCertificate* freerdp_certificate_clone(const rdpCertificate* certificate)
1227{
1228 if (!certificate)
1229 return nullptr;
1230
1231 rdpCertificate* _certificate = freerdp_certificate_new();
1232
1233 if (!_certificate)
1234 return nullptr;
1235
1236 if (!cert_clone_int(_certificate, certificate))
1237 goto out_fail;
1238
1239 return _certificate;
1240out_fail:
1241
1242 freerdp_certificate_free(_certificate);
1243 return nullptr;
1244}
1245
1251rdpCertificate* freerdp_certificate_new(void)
1252{
1253 return (rdpCertificate*)calloc(1, sizeof(rdpCertificate));
1254}
1255
1256void certificate_free_int(rdpCertificate* cert)
1257{
1258 WINPR_ASSERT(cert);
1259
1260 if (cert->x509)
1261 X509_free(cert->x509);
1262 if (cert->chain)
1263 sk_X509_pop_free(cert->chain, X509_free);
1264
1265 certificate_free_x509_certificate_chain(&cert->x509_cert_chain);
1266 cert_info_free(&cert->cert_info);
1267}
1268
1274void freerdp_certificate_free(rdpCertificate* cert)
1275{
1276 if (!cert)
1277 return;
1278
1279 certificate_free_int(cert);
1280 free(cert);
1281}
1282
1283static BOOL freerdp_rsa_from_x509(rdpCertificate* cert)
1284{
1285 BOOL rc = FALSE;
1286
1287 WINPR_ASSERT(cert);
1288
1289 if (!freerdp_certificate_is_rsa(cert))
1290 return TRUE;
1291
1292#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1293 RSA* rsa = nullptr;
1294 const BIGNUM* rsa_n = nullptr;
1295 const BIGNUM* rsa_e = nullptr;
1296#else
1297 BIGNUM* rsa_n = nullptr;
1298 BIGNUM* rsa_e = nullptr;
1299#endif
1300 EVP_PKEY* pubkey = X509_get0_pubkey(cert->x509);
1301 if (!pubkey)
1302 goto fail;
1303
1304#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1305 rsa = EVP_PKEY_get1_RSA(pubkey);
1306
1307 /* If this is not a RSA key return success */
1308 rc = TRUE;
1309 if (!rsa)
1310 goto fail;
1311
1312 /* Now we return failure again if something is wrong. */
1313 rc = FALSE;
1314
1315 RSA_get0_key(rsa, &rsa_n, &rsa_e, nullptr);
1316#else
1317 if (!EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_E, &rsa_e))
1318 goto fail;
1319 if (!EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_N, &rsa_n))
1320 goto fail;
1321#endif
1322 if (!rsa_n || !rsa_e)
1323 goto fail;
1324 if (!cert_info_create(&cert->cert_info, rsa_n, rsa_e))
1325 goto fail;
1326 rc = TRUE;
1327fail:
1328#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1329 RSA_free(rsa);
1330#else
1331 BN_free(rsa_n);
1332 BN_free(rsa_e);
1333#endif
1334 return rc;
1335}
1336
1337rdpCertificate* freerdp_certificate_new_from_der(const BYTE* data, size_t length)
1338{
1339 rdpCertificate* cert = freerdp_certificate_new();
1340
1341 if (!cert || !data || (length == 0) || (length > INT_MAX))
1342 goto fail;
1343
1344 {
1345 const BYTE* ptr = data;
1346 cert->x509 = d2i_X509(nullptr, &ptr, (int)length);
1347 }
1348
1349 if (!cert->x509)
1350 goto fail;
1351 if (!freerdp_rsa_from_x509(cert))
1352 goto fail;
1353 return cert;
1354fail:
1355 freerdp_certificate_free(cert);
1356 return nullptr;
1357}
1358
1359rdpCertificate* freerdp_certificate_new_from_x509(const X509* xcert, const STACK_OF(X509) * chain)
1360{
1361 WINPR_ASSERT(xcert);
1362
1363 rdpCertificate* cert = freerdp_certificate_new();
1364 if (!cert)
1365 return nullptr;
1366
1367 X509* wcert = WINPR_CAST_CONST_PTR_AWAY(xcert, X509*);
1368 cert->x509 = X509_dup(wcert);
1369 if (!cert->x509)
1370 goto fail;
1371
1372 if (!freerdp_rsa_from_x509(cert))
1373 goto fail;
1374
1375 if (chain)
1376 cert->chain = sk_X509_deep_copy(chain, X509_const_dup, X509_free);
1377
1378 return cert;
1379fail:
1380 freerdp_certificate_free(cert);
1381 return nullptr;
1382}
1383
1384static STACK_OF(X509) * extract_chain_from_pem(const char* pem, BOOL isFile)
1385{
1386 if (!pem)
1387 {
1388 return nullptr;
1389 }
1390
1391 BIO* bio = nullptr;
1392 if (isFile)
1393 bio = BIO_new_file(pem, "rb");
1394 else
1395 {
1396 const size_t len = strlen(pem);
1397 bio = BIO_new_mem_buf(pem, WINPR_ASSERTING_INT_CAST(int, len));
1398 }
1399
1400 if (!bio)
1401 {
1402 return nullptr;
1403 }
1404
1405 X509* leaf = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
1406 if (!leaf)
1407 {
1408 BIO_free(bio);
1409 return nullptr;
1410 }
1411
1412 STACK_OF(X509)* chain = sk_X509_new_null();
1413 if (!chain)
1414 {
1415 X509_free(leaf);
1416 BIO_free(bio);
1417 return nullptr;
1418 }
1419
1420 X509* cert = nullptr;
1421 while ((cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr)) != nullptr)
1422 {
1423 sk_X509_push(chain, cert);
1424 }
1425
1426 X509_free(leaf);
1427 BIO_free(bio);
1428 return chain;
1429}
1430
1431static rdpCertificate* freerdp_certificate_new_from(const char* file, BOOL isFile)
1432{
1433 X509* x509 = x509_utils_from_pem(file, strlen(file), isFile);
1434 if (!x509)
1435 return nullptr;
1436 STACK_OF(X509)* chain = extract_chain_from_pem(file, isFile);
1437 rdpCertificate* cert = freerdp_certificate_new_from_x509(x509, chain);
1438 if (chain)
1439 sk_X509_pop_free(chain, X509_free);
1440 X509_free(x509);
1441 return cert;
1442}
1443
1444rdpCertificate* freerdp_certificate_new_from_file(const char* file)
1445{
1446 return freerdp_certificate_new_from(file, TRUE);
1447}
1448
1449rdpCertificate* freerdp_certificate_new_from_pem(const char* pem)
1450{
1451 return freerdp_certificate_new_from(pem, FALSE);
1452}
1453
1454const rdpCertInfo* freerdp_certificate_get_info(const rdpCertificate* cert)
1455{
1456 WINPR_ASSERT(cert);
1457 if (!freerdp_certificate_is_rsa(cert))
1458 return nullptr;
1459 return &cert->cert_info;
1460}
1461
1462char* freerdp_certificate_get_fingerprint(const rdpCertificate* cert)
1463{
1464 return freerdp_certificate_get_fingerprint_by_hash(cert, "sha256");
1465}
1466
1467char* freerdp_certificate_get_fingerprint_by_hash(const rdpCertificate* cert, const char* hash)
1468{
1469 return freerdp_certificate_get_fingerprint_by_hash_ex(cert, hash, TRUE);
1470}
1471
1472char* freerdp_certificate_get_fingerprint_by_hash_ex(const rdpCertificate* cert, const char* hash,
1473 BOOL separator)
1474{
1475 size_t fp_len = 0;
1476 size_t pos = 0;
1477 size_t size = 0;
1478 BYTE* fp = nullptr;
1479 char* fp_buffer = nullptr;
1480 if (!cert || !cert->x509)
1481 {
1482 WLog_ERR(TAG, "Invalid certificate [%p, %p]", WINPR_CXX_COMPAT_CAST(const void*, cert),
1483 WINPR_CXX_COMPAT_CAST(const void*, cert ? cert->x509 : nullptr));
1484 return nullptr;
1485 }
1486 if (!hash)
1487 {
1488 WLog_ERR(TAG, "Invalid certificate hash %p", WINPR_CXX_COMPAT_CAST(const void*, hash));
1489 return nullptr;
1490 }
1491 fp = x509_utils_get_hash(cert->x509, hash, &fp_len);
1492 if (!fp)
1493 return nullptr;
1494
1495 if (fp_len < 1)
1496 goto fail;
1497
1498 size = fp_len * 3 + 1;
1499 fp_buffer = calloc(size, sizeof(char));
1500 if (!fp_buffer)
1501 goto fail;
1502
1503 pos = 0;
1504
1505 {
1506 size_t i = 0;
1507 for (; i < (fp_len - 1); i++)
1508 {
1509 int rc = 0;
1510 char* p = &fp_buffer[pos];
1511 if (separator)
1512 rc = sprintf_s(p, size - pos, "%02" PRIx8 ":", fp[i]);
1513 else
1514 rc = sprintf_s(p, size - pos, "%02" PRIx8, fp[i]);
1515 if (rc <= 0)
1516 goto fail;
1517 pos += (size_t)rc;
1518 }
1519
1520 (void)sprintf_s(&fp_buffer[pos], size - pos, "%02" PRIx8 "", fp[i]);
1521 }
1522
1523 free(fp);
1524
1525 return fp_buffer;
1526fail:
1527 free(fp);
1528 free(fp_buffer);
1529 return nullptr;
1530}
1531
1532char* freerdp_certificate_get_pem(const rdpCertificate* cert, size_t* pLength)
1533{
1534 return freerdp_certificate_get_pem_ex(cert, pLength, TRUE);
1535}
1536
1537char* freerdp_certificate_get_pem_ex(const rdpCertificate* cert, size_t* pLength,
1538 BOOL withCertChain)
1539{
1540 WINPR_ASSERT(cert);
1541
1542 if (!cert->x509)
1543 return nullptr;
1544
1549 BIO* bio = BIO_new(BIO_s_mem());
1550
1551 if (!bio)
1552 {
1553 WLog_ERR(TAG, "BIO_new() failure");
1554 return nullptr;
1555 }
1556
1557 char* pem = nullptr;
1558
1559 const int status = PEM_write_bio_X509(bio, cert->x509);
1560 if (status < 0)
1561 {
1562 WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", status);
1563 goto fail;
1564 }
1565
1566 if (cert->chain && withCertChain)
1567 {
1568 const int count = sk_X509_num(cert->chain);
1569 for (int x = 0; x < count; x++)
1570 {
1571 X509* c = sk_X509_value(cert->chain, x);
1572 const int rc = PEM_write_bio_X509(bio, c);
1573 if (rc < 0)
1574 {
1575 WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", rc);
1576 goto fail;
1577 }
1578 }
1579 }
1580
1581 pem = x509_utils_bio_read(bio, pLength);
1582
1583fail:
1584 BIO_free_all(bio);
1585 return pem;
1586}
1587
1588char* freerdp_certificate_get_subject(const rdpCertificate* cert)
1589{
1590 WINPR_ASSERT(cert);
1591 return x509_utils_get_subject(cert->x509);
1592}
1593
1594char* freerdp_certificate_get_issuer(const rdpCertificate* cert)
1595{
1596 WINPR_ASSERT(cert);
1597 return x509_utils_get_issuer(cert->x509);
1598}
1599
1600char* freerdp_certificate_get_upn(const rdpCertificate* cert)
1601{
1602 WINPR_ASSERT(cert);
1603 return x509_utils_get_upn(cert->x509);
1604}
1605
1606char* freerdp_certificate_get_email(const rdpCertificate* cert)
1607{
1608 WINPR_ASSERT(cert);
1609 return x509_utils_get_email(cert->x509);
1610}
1611
1612char* freerdp_certificate_get_validity(const rdpCertificate* cert, BOOL startDate)
1613{
1614 WINPR_ASSERT(cert);
1615 return x509_utils_get_date(cert->x509, startDate);
1616}
1617
1618BOOL freerdp_certificate_check_eku(const rdpCertificate* cert, int nid)
1619{
1620 WINPR_ASSERT(cert);
1621 return x509_utils_check_eku(cert->x509, nid);
1622}
1623
1624BOOL freerdp_certificate_get_public_key(const rdpCertificate* cert, BYTE** PublicKey,
1625 DWORD* PublicKeyLength)
1626{
1627 BYTE* ptr = nullptr;
1628 BYTE* optr = nullptr;
1629 int length = 0;
1630 BOOL status = FALSE;
1631 EVP_PKEY* pkey = nullptr;
1632
1633 WINPR_ASSERT(cert);
1634
1635 pkey = X509_get0_pubkey(cert->x509);
1636
1637 if (!pkey)
1638 {
1639 WLog_ERR(TAG, "X509_get_pubkey() failed");
1640 goto exit;
1641 }
1642
1643 length = i2d_PublicKey(pkey, nullptr);
1644
1645 if (length < 1)
1646 {
1647 WLog_ERR(TAG, "i2d_PublicKey() failed");
1648 goto exit;
1649 }
1650
1651 *PublicKey = optr = ptr = (BYTE*)calloc(WINPR_ASSERTING_INT_CAST(size_t, length), sizeof(BYTE));
1652
1653 if (!ptr)
1654 goto exit;
1655
1656 {
1657 const int length2 = i2d_PublicKey(pkey, &ptr);
1658 if (length != length2)
1659 goto exit;
1660 *PublicKeyLength = (DWORD)length2;
1661 }
1662 status = TRUE;
1663exit:
1664
1665 if (!status)
1666 free(optr);
1667
1668 return status;
1669}
1670
1671BOOL freerdp_certificate_verify(const rdpCertificate* cert, const char* certificate_store_path)
1672{
1673 WINPR_ASSERT(cert);
1674 return x509_utils_verify(cert->x509, cert->chain, certificate_store_path);
1675}
1676
1677char** freerdp_certificate_get_dns_names(const rdpCertificate* cert, size_t* pcount,
1678 size_t** pplengths)
1679{
1680 WINPR_ASSERT(cert);
1681 return x509_utils_get_dns_names(cert->x509, pcount, pplengths);
1682}
1683
1684char* freerdp_certificate_get_common_name(const rdpCertificate* cert, size_t* plength)
1685{
1686 WINPR_ASSERT(cert);
1687 return x509_utils_get_common_name(cert->x509, plength);
1688}
1689
1690WINPR_MD_TYPE freerdp_certificate_get_signature_alg(const rdpCertificate* cert)
1691{
1692 WINPR_ASSERT(cert);
1693 return x509_utils_get_signature_alg(cert->x509);
1694}
1695
1696void freerdp_certificate_free_dns_names(size_t count, size_t* lengths, char** names)
1697{
1698 x509_utils_dns_names_free(count, lengths, names);
1699}
1700
1701char* freerdp_certificate_get_hash(const rdpCertificate* cert, const char* hash, size_t* plength)
1702{
1703 WINPR_ASSERT(cert);
1704 return (char*)x509_utils_get_hash(cert->x509, hash, plength);
1705}
1706
1707X509* freerdp_certificate_get_x509(rdpCertificate* cert)
1708{
1709 WINPR_ASSERT(cert);
1710 return cert->x509;
1711}
1712
1713BOOL freerdp_certificate_publickey_encrypt(const rdpCertificate* cert, const BYTE* input,
1714 size_t cbInput, BYTE** poutput, size_t* pcbOutput)
1715{
1716 WINPR_ASSERT(cert);
1717 WINPR_ASSERT(input);
1718 WINPR_ASSERT(poutput);
1719 WINPR_ASSERT(pcbOutput);
1720
1721 BOOL ret = FALSE;
1722 BYTE* output = nullptr;
1723 EVP_PKEY* pkey = X509_get0_pubkey(cert->x509);
1724 if (!pkey)
1725 return FALSE;
1726
1727 EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, nullptr);
1728 if (!ctx)
1729 return FALSE;
1730
1731 size_t outputSize = WINPR_ASSERTING_INT_CAST(size_t, EVP_PKEY_size(pkey));
1732 output = malloc(outputSize);
1733 if (output == nullptr)
1734 goto out;
1735 *pcbOutput = outputSize;
1736
1737 if (EVP_PKEY_encrypt_init(ctx) != 1 ||
1738 EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) != 1 ||
1739 EVP_PKEY_encrypt(ctx, output, pcbOutput, input, cbInput) != 1)
1740 {
1741 WLog_ERR(TAG, "error when setting up public key");
1742 goto out;
1743 }
1744
1745 *poutput = output;
1746 output = nullptr;
1747 ret = TRUE;
1748out:
1749 EVP_PKEY_CTX_free(ctx);
1750 free(output);
1751 return ret;
1752}
1753
1754#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1755static RSA* freerdp_certificate_get_RSA(const rdpCertificate* cert)
1756{
1757 WINPR_ASSERT(cert);
1758
1759 if (!freerdp_certificate_is_rsa(cert))
1760 return nullptr;
1761
1762 EVP_PKEY* pubkey = X509_get0_pubkey(cert->x509);
1763 if (!pubkey)
1764 return nullptr;
1765
1766 return EVP_PKEY_get1_RSA(pubkey);
1767}
1768#endif
1769
1770BYTE* freerdp_certificate_get_der(const rdpCertificate* cert, size_t* pLength)
1771{
1772 WINPR_ASSERT(cert);
1773
1774 if (pLength)
1775 *pLength = 0;
1776
1777 const int rc = i2d_X509(cert->x509, nullptr);
1778 if (rc <= 0)
1779 return nullptr;
1780
1781 BYTE* ptr = calloc(WINPR_ASSERTING_INT_CAST(size_t, rc) + 1, sizeof(BYTE));
1782 if (!ptr)
1783 return nullptr;
1784 BYTE* i2d_ptr = ptr;
1785
1786 const int rc2 = i2d_X509(cert->x509, &i2d_ptr);
1787 if (rc2 <= 0)
1788 {
1789 free(ptr);
1790 return nullptr;
1791 }
1792
1793 if (pLength)
1794 *pLength = (size_t)rc2;
1795 return ptr;
1796}
1797
1798BOOL freerdp_certificate_is_rsa(const rdpCertificate* cert)
1799{
1800 WINPR_ASSERT(cert);
1801 return is_rsa_key(cert->x509);
1802}
1803
1804BOOL freerdp_certificate_is_rdp_security_compatible(const rdpCertificate* cert)
1805{
1806 const rdpCertInfo* info = freerdp_certificate_get_info(cert);
1807 if (!freerdp_certificate_is_rsa(cert) || !info || (info->ModulusLength != 2048 / 8))
1808 {
1809 WLog_INFO(TAG, "certificate is not RSA 2048, RDP security not supported.");
1810 return FALSE;
1811 }
1812 return TRUE;
1813}
1814
1815char* freerdp_certificate_get_param(const rdpCertificate* cert, enum FREERDP_CERT_PARAM what,
1816 size_t* psize)
1817{
1818 WINPR_ASSERT(cert);
1819 WINPR_ASSERT(psize);
1820
1821 *psize = 0;
1822
1823#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1824 const BIGNUM* bn = nullptr;
1825 RSA* rsa = freerdp_certificate_get_RSA(cert);
1826 switch (what)
1827 {
1828 case FREERDP_CERT_RSA_E:
1829 RSA_get0_key(rsa, nullptr, &bn, nullptr);
1830 break;
1831 case FREERDP_CERT_RSA_N:
1832 RSA_get0_key(rsa, &bn, nullptr, nullptr);
1833 break;
1834 default:
1835 RSA_free(rsa);
1836 return nullptr;
1837 }
1838 RSA_free(rsa);
1839#else
1840 EVP_PKEY* pkey = X509_get0_pubkey(cert->x509);
1841 if (!pkey)
1842 return nullptr;
1843
1844 BIGNUM* bn = nullptr;
1845 switch (what)
1846 {
1847 case FREERDP_CERT_RSA_E:
1848 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &bn))
1849 return nullptr;
1850 break;
1851 case FREERDP_CERT_RSA_N:
1852 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &bn))
1853 return nullptr;
1854 break;
1855 default:
1856 return nullptr;
1857 }
1858#endif
1859
1860 const size_t bnsize = WINPR_ASSERTING_INT_CAST(size_t, BN_num_bytes(bn));
1861 char* rc = calloc(bnsize + 1, sizeof(char));
1862 if (!rc)
1863 goto fail;
1864 BN_bn2bin(bn, (BYTE*)rc);
1865 *psize = bnsize;
1866
1867fail:
1868#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR < 3)
1869 BN_free(bn);
1870#endif
1871 return rc;
1872}
1873
1874size_t freerdp_certificate_get_chain_len(rdpCertificate* certificate)
1875{
1876 WINPR_ASSERT(certificate);
1877 if (!certificate->chain)
1878 return 0;
1879
1880 return WINPR_ASSERTING_INT_CAST(size_t, sk_X509_num(certificate->chain));
1881}
1882
1883X509* freerdp_certificate_get_chain_at(rdpCertificate* certificate, size_t offset)
1884{
1885 WINPR_ASSERT(certificate);
1886 WINPR_ASSERT(freerdp_certificate_get_chain_len(certificate) > offset);
1887 const int ioff = WINPR_ASSERTING_INT_CAST(int, offset);
1888 return sk_X509_value(certificate->chain, ioff);
1889}