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 CERTIFICATE_TAG FREERDP_TAG("core.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] = "RSA1";
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, 4 + 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 = NULL;
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 = { 0 };
297 wStream* s = NULL;
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, NULL)) /* 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 rdpX509CertChain certificate_new_x509_certificate_chain(UINT32 count)
443{
444 rdpX509CertChain x509_cert_chain = { 0 };
445
446 x509_cert_chain.array = (rdpCertBlob*)calloc(count, sizeof(rdpCertBlob));
447
448 if (x509_cert_chain.array)
449 x509_cert_chain.count = count;
450
451 return x509_cert_chain;
452}
453
459static void certificate_free_x509_certificate_chain(rdpX509CertChain* x509_cert_chain)
460{
461 if (!x509_cert_chain)
462 return;
463
464 if (x509_cert_chain->array)
465 {
466 for (UINT32 i = 0; i < x509_cert_chain->count; i++)
467 {
468 rdpCertBlob* element = &x509_cert_chain->array[i];
469 cert_blob_free(element);
470 }
471 }
472
473 free(x509_cert_chain->array);
474 x509_cert_chain->array = NULL;
475 x509_cert_chain->count = 0;
476}
477
478#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
479static OSSL_PARAM* get_params(const BIGNUM* e, const BIGNUM* mod)
480{
481 WINPR_ASSERT(e);
482 WINPR_ASSERT(mod);
483
484 OSSL_PARAM* parameters = NULL;
485 OSSL_PARAM_BLD* param = OSSL_PARAM_BLD_new();
486 if (!param)
487 {
488 WLog_ERR(TAG, "OSSL_PARAM_BLD_new() failed");
489 return NULL;
490 }
491
492 const int bits = BN_num_bits(e);
493 if ((bits < 0) || (bits > 32))
494 {
495 WLog_ERR(TAG, "BN_num_bits(e) out of range: 0 <= %d <= 32", bits);
496 goto fail;
497 }
498
499 UINT ie = 0;
500 const int ne = BN_bn2nativepad(e, (BYTE*)&ie, sizeof(ie));
501 if ((ne < 0) || (ne > 4))
502 {
503 WLog_ERR(TAG, "BN_bn2nativepad(e, (BYTE*)&ie, sizeof(ie)) out of range: 0<= %d <= 4", ne);
504 goto fail;
505 }
506 if (OSSL_PARAM_BLD_push_BN(param, OSSL_PKEY_PARAM_RSA_N, mod) != 1)
507 {
508 WLog_ERR(TAG, "OSSL_PARAM_BLD_push_BN(param, OSSL_PKEY_PARAM_RSA_N, mod) failed");
509 goto fail;
510 }
511 if (OSSL_PARAM_BLD_push_uint(param, OSSL_PKEY_PARAM_RSA_E, ie) != 1)
512 {
513 WLog_ERR(TAG, "OSSL_PARAM_BLD_push_uint(param, OSSL_PKEY_PARAM_RSA_E, ie) failed");
514 goto fail;
515 }
516
517 parameters = OSSL_PARAM_BLD_to_param(param);
518 if (!parameters)
519 WLog_ERR(TAG, "OSSL_PARAM_BLD_to_param(param) failed");
520fail:
521 OSSL_PARAM_BLD_free(param);
522
523 return parameters;
524}
525#endif
526
527static BOOL update_x509_from_info(rdpCertificate* cert)
528{
529 BOOL rc = FALSE;
530
531 WINPR_ASSERT(cert);
532
533 X509_free(cert->x509);
534 cert->x509 = NULL;
535
536 rdpCertInfo* info = &cert->cert_info;
537
538 BIGNUM* e = BN_new();
539 BIGNUM* mod = BN_new();
540#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
541 RSA* rsa = RSA_new();
542 if (!rsa)
543 {
544 WLog_ERR(TAG, "RSA_new() failed");
545 goto fail;
546 }
547#endif
548
549 if (!mod || !e)
550 {
551 WLog_ERR(TAG, "failure: mod=%p, e=%p", mod, e);
552 goto fail;
553 }
554
555 WINPR_ASSERT(info->ModulusLength <= INT_MAX);
556 if (!BN_bin2bn(info->Modulus, (int)info->ModulusLength, mod))
557 {
558 WLog_ERR(TAG, "BN_bin2bn(info->Modulus, (int)info->ModulusLength, mod) failed");
559 goto fail;
560 }
561
562 if (!BN_bin2bn(info->exponent, (int)sizeof(info->exponent), e))
563 {
564 WLog_ERR(TAG, "BN_bin2bn(info->exponent, (int)sizeof(info->exponent), e) failed");
565 goto fail;
566 }
567
568#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
569 const int rec = RSA_set0_key(rsa, mod, e, NULL);
570 if (rec != 1)
571 {
572 WLog_ERR(TAG, "RSA_set0_key(rsa, mod, e, NULL) failed");
573 goto fail;
574 }
575
576 cert->x509 = x509_from_rsa(rsa);
577#else
578 EVP_PKEY* pkey = NULL;
579 EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
580 if (!ctx)
581 {
582 WLog_ERR(TAG, "EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL) failed");
583 goto fail2;
584 }
585 const int xx = EVP_PKEY_fromdata_init(ctx);
586 if (xx != 1)
587 {
588 WLog_ERR(TAG, "EVP_PKEY_fromdata_init(ctx) failed");
589 goto fail2;
590 }
591
592 OSSL_PARAM* parameters = get_params(e, mod);
593 if (!parameters)
594 goto fail2;
595
596 const int rc2 = EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, parameters);
597 OSSL_PARAM_free(parameters);
598 if (rc2 <= 0)
599 {
600 WLog_ERR(TAG, "EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, parameters) failed");
601 goto fail2;
602 }
603
604 cert->x509 = X509_new();
605 if (!cert->x509)
606 {
607 WLog_ERR(TAG, "X509_new() failed");
608 goto fail2;
609 }
610
611 if (X509_set_pubkey(cert->x509, pkey) != 1)
612 {
613 WLog_ERR(TAG, "X509_set_pubkey(cert->x509, pkey) failed");
614 X509_free(cert->x509);
615 cert->x509 = NULL;
616 }
617fail2:
618 EVP_PKEY_free(pkey);
619 EVP_PKEY_CTX_free(ctx);
620#endif
621 if (!cert->x509)
622 goto fail;
623
624 rc = TRUE;
625
626fail:
627 if (!rc)
628 WLog_ERR(TAG, "failed to update x509 from rdpCertInfo");
629
630#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
631 if (rsa)
632 RSA_free(rsa);
633 else
634#endif
635 {
636 BN_free(mod);
637 BN_free(e);
638 }
639 return rc;
640}
641
642static BOOL certificate_process_server_public_key(rdpCertificate* cert, wStream* s,
643 WINPR_ATTR_UNUSED UINT32 length)
644{
645 char magic[sizeof(rsa_magic)] = { 0 };
646 UINT32 keylen = 0;
647 UINT32 bitlen = 0;
648 UINT32 datalen = 0;
649
650 WINPR_ASSERT(cert);
651 WINPR_ASSERT(s);
652
653 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
654 return FALSE;
655
656 Stream_Read(s, magic, sizeof(magic));
657
658 if (memcmp(magic, rsa_magic, sizeof(magic)) != 0)
659 {
660 WLog_ERR(TAG, "invalid RSA magic bytes");
661 return FALSE;
662 }
663
664 rdpCertInfo* info = &cert->cert_info;
665 cert_info_free(info);
666
667 Stream_Read_UINT32(s, keylen);
668 Stream_Read_UINT32(s, bitlen);
669 Stream_Read_UINT32(s, datalen);
670 Stream_Read(s, info->exponent, 4);
671
672 if (keylen <= 8)
673 {
674 WLog_ERR(TAG, "Invalid RSA keylen=%" PRIu32 " <= 8", keylen);
675 return FALSE;
676 }
677 if (!Stream_CheckAndLogRequiredLength(TAG, s, keylen))
678 return FALSE;
679 if (keylen != (bitlen / 8ull) + 8ull)
680 {
681 WLog_ERR(TAG, "Invalid RSA key bitlen %" PRIu32 ", expected %" PRIu32, bitlen,
682 (keylen - 8) * 8);
683 return FALSE;
684 }
685 if (datalen != (bitlen / 8ull) - 1ull)
686 {
687 WLog_ERR(TAG, "Invalid RSA key datalen %" PRIu32 ", expected %" PRIu32, datalen,
688 (bitlen / 8ull) - 1ull);
689 return FALSE;
690 }
691 info->ModulusLength = keylen - 8;
692 BYTE* tmp = realloc(info->Modulus, info->ModulusLength);
693
694 if (!tmp)
695 {
696 WLog_ERR(TAG, "Failed to reallocate modulus of length %" PRIu32, info->ModulusLength);
697 return FALSE;
698 }
699 info->Modulus = tmp;
700
701 Stream_Read(s, info->Modulus, info->ModulusLength);
702 Stream_Seek(s, 8); /* 8 bytes of zero padding */
703 return update_x509_from_info(cert);
704}
705
706static BOOL certificate_process_server_public_signature(rdpCertificate* certificate,
707 const BYTE* sigdata, size_t sigdatalen,
708 wStream* s, UINT32 siglen)
709{
710 WINPR_ASSERT(certificate);
711#if defined(CERT_VALIDATE_RSA)
712 BYTE sig[TSSK_KEY_LENGTH];
713#endif
714 BYTE encsig[TSSK_KEY_LENGTH + 8];
715#if defined(CERT_VALIDATE_MD5) && defined(CERT_VALIDATE_RSA)
716 BYTE md5hash[WINPR_MD5_DIGEST_LENGTH];
717#endif
718#if !defined(CERT_VALIDATE_MD5) || !defined(CERT_VALIDATE_RSA)
719 (void)sigdata;
720 (void)sigdatalen;
721#endif
722 (void)certificate;
723 /* Do not bother with validation of server proprietary certificate. The use of MD5 here is not
724 * allowed under FIPS. Since the validation is not protecting against anything since the
725 * private/public keys are well known and documented in MS-RDPBCGR section 5.3.3.1, we are not
726 * gaining any security by using MD5 for signature comparison. Rather then use MD5
727 * here we just don't do the validation to avoid its use. Historically, freerdp has been ignoring
728 * a failed validation anyways. */
729#if defined(CERT_VALIDATE_MD5)
730
731 if (!winpr_Digest(WINPR_MD_MD5, sigdata, sigdatalen, md5hash, sizeof(md5hash)))
732 return FALSE;
733
734#endif
735 Stream_Read(s, encsig, siglen);
736
737 if (siglen < 8)
738 return FALSE;
739
740 /* Last 8 bytes shall be all zero. */
741#if defined(CERT_VALIDATE_PADDING)
742 {
743 size_t sum = 0;
744 for (size_t i = sizeof(encsig) - 8; i < sizeof(encsig); i++)
745 sum += encsig[i];
746
747 if (sum != 0)
748 {
749 WLog_ERR(TAG, "invalid signature");
750 return FALSE;
751 }
752 }
753#endif
754#if defined(CERT_VALIDATE_RSA)
755
756 if (crypto_rsa_public_decrypt(encsig, siglen - 8, TSSK_KEY_LENGTH, tssk_modulus, tssk_exponent,
757 sig) <= 0)
758 {
759 WLog_ERR(TAG, "invalid RSA decrypt");
760 return FALSE;
761 }
762
763 /* Verify signature. */
764 /* Do not bother with validation of server proprietary certificate as described above. */
765#if defined(CERT_VALIDATE_MD5)
766
767 if (memcmp(md5hash, sig, sizeof(md5hash)) != 0)
768 {
769 WLog_ERR(TAG, "invalid signature");
770 return FALSE;
771 }
772
773#endif
774 /*
775 * Verify rest of decrypted data:
776 * The 17th byte is 0x00.
777 * The 18th through 62nd bytes are each 0xFF.
778 * The 63rd byte is 0x01.
779 */
780 {
781 size_t sum = 0;
782 for (size_t i = 17; i < 62; i++)
783 sum += sig[i];
784
785 if (sig[16] != 0x00 || sum != 0xFF * (62 - 17) || sig[62] != 0x01)
786 {
787 WLog_ERR(TAG, "invalid signature");
788 return FALSE;
789 }
790 }
791#endif
792 return TRUE;
793}
794
795static BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate, wStream* s)
796{
797 UINT32 dwSigAlgId = 0;
798 UINT32 dwKeyAlgId = 0;
799 UINT16 wPublicKeyBlobType = 0;
800 UINT16 wPublicKeyBlobLen = 0;
801 UINT16 wSignatureBlobType = 0;
802 UINT16 wSignatureBlobLen = 0;
803 size_t sigdatalen = 0;
804
805 WINPR_ASSERT(certificate);
806 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
807 return FALSE;
808
809 /* -4, because we need to include dwVersion */
810 const BYTE* sigdata = Stream_PointerAs(s, const BYTE) - 4;
811 Stream_Read_UINT32(s, dwSigAlgId);
812 Stream_Read_UINT32(s, dwKeyAlgId);
813
814 if (!((dwSigAlgId == SIGNATURE_ALG_RSA) && (dwKeyAlgId == KEY_EXCHANGE_ALG_RSA)))
815 {
816 WLog_ERR(TAG,
817 "unsupported signature or key algorithm, dwSigAlgId=%" PRIu32
818 " dwKeyAlgId=%" PRIu32 "",
819 dwSigAlgId, dwKeyAlgId);
820 return FALSE;
821 }
822
823 Stream_Read_UINT16(s, wPublicKeyBlobType);
824
825 if (wPublicKeyBlobType != BB_RSA_KEY_BLOB)
826 {
827 WLog_ERR(TAG, "unsupported public key blob type %" PRIu16 "", wPublicKeyBlobType);
828 return FALSE;
829 }
830
831 Stream_Read_UINT16(s, wPublicKeyBlobLen);
832
833 if (!Stream_CheckAndLogRequiredLength(TAG, s, wPublicKeyBlobLen))
834 return FALSE;
835
836 if (!certificate_process_server_public_key(certificate, s, wPublicKeyBlobLen))
837 return FALSE;
838
839 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
840 return FALSE;
841
842 sigdatalen = WINPR_ASSERTING_INT_CAST(size_t, Stream_PointerAs(s, const BYTE) - sigdata);
843 Stream_Read_UINT16(s, wSignatureBlobType);
844
845 if (wSignatureBlobType != BB_RSA_SIGNATURE_BLOB)
846 {
847 WLog_ERR(TAG, "unsupported blob signature %" PRIu16 "", wSignatureBlobType);
848 return FALSE;
849 }
850
851 Stream_Read_UINT16(s, wSignatureBlobLen);
852
853 if (!Stream_CheckAndLogRequiredLength(TAG, s, wSignatureBlobLen))
854 return FALSE;
855
856 if (wSignatureBlobLen != 72)
857 {
858 WLog_ERR(TAG, "invalid signature length (got %" PRIu16 ", expected 72)", wSignatureBlobLen);
859 return FALSE;
860 }
861
862 if (!certificate_process_server_public_signature(certificate, sigdata, sigdatalen, s,
863 wSignatureBlobLen))
864 {
865 WLog_ERR(TAG, "unable to parse server public signature");
866 return FALSE;
867 }
868 return TRUE;
869}
870
871/* [MS-RDPBCGR] 2.2.1.4.3.1.1.1 RSA Public Key (RSA_PUBLIC_KEY) */
872static BOOL cert_write_rsa_public_key(wStream* s, const rdpCertificate* cert)
873{
874 WINPR_ASSERT(cert);
875 WINPR_ASSERT(freerdp_certificate_is_rsa(cert));
876
877 const rdpCertInfo* info = &cert->cert_info;
878
879 const UINT32 keyLen = info->ModulusLength + 8;
880 const UINT32 bitLen = info->ModulusLength * 8;
881 const UINT32 dataLen = (bitLen / 8) - 1;
882 const size_t pubExpLen = sizeof(info->exponent);
883 const BYTE* pubExp = info->exponent;
884 const BYTE* modulus = info->Modulus;
885
886 const size_t wPublicKeyBlobLen = 16 + pubExpLen + keyLen;
887 WINPR_ASSERT(wPublicKeyBlobLen <= UINT16_MAX);
888 if (!Stream_EnsureRemainingCapacity(s, 2 + wPublicKeyBlobLen))
889 return FALSE;
890 Stream_Write_UINT16(s, (UINT16)wPublicKeyBlobLen);
891 Stream_Write(s, rsa_magic, sizeof(rsa_magic));
892 Stream_Write_UINT32(s, keyLen);
893 Stream_Write_UINT32(s, bitLen);
894 Stream_Write_UINT32(s, dataLen);
895 Stream_Write(s, pubExp, pubExpLen);
896 Stream_Write(s, modulus, info->ModulusLength);
897 Stream_Zero(s, 8);
898 return TRUE;
899}
900
901static BOOL cert_write_rsa_signature(wStream* s, const void* sigData, size_t sigDataLen)
902{
903 BYTE encryptedSignature[TSSK_KEY_LENGTH] = { 0 };
904 BYTE signature[sizeof(initial_signature)] = { 0 };
905
906 memcpy(signature, initial_signature, sizeof(initial_signature));
907 if (!winpr_Digest(WINPR_MD_MD5, sigData, sigDataLen, signature, sizeof(signature)))
908 return FALSE;
909
910 crypto_rsa_private_encrypt(signature, sizeof(signature), priv_key_tssk, encryptedSignature,
911 sizeof(encryptedSignature));
912
913 if (!Stream_EnsureRemainingCapacity(s, 2 * sizeof(UINT16) + sizeof(encryptedSignature) + 8))
914 return FALSE;
915 Stream_Write_UINT16(s, BB_RSA_SIGNATURE_BLOB);
916 Stream_Write_UINT16(s, sizeof(encryptedSignature) + 8); /* wSignatureBlobLen */
917 Stream_Write(s, encryptedSignature, sizeof(encryptedSignature));
918 Stream_Zero(s, 8);
919 return TRUE;
920}
921
922/* [MS-RDPBCGR] 2.2.1.4.3.1.1 Server Proprietary Certificate (PROPRIETARYSERVERCERTIFICATE) */
923static BOOL cert_write_server_certificate_v1(wStream* s, const rdpCertificate* certificate)
924{
925 const size_t start = Stream_GetPosition(s);
926 const BYTE* sigData = Stream_PointerAs(s, const BYTE) - sizeof(UINT32);
927
928 WINPR_ASSERT(start >= 4);
929 if (!Stream_EnsureRemainingCapacity(s, 10))
930 return FALSE;
931 Stream_Write_UINT32(s, SIGNATURE_ALG_RSA);
932 Stream_Write_UINT32(s, KEY_EXCHANGE_ALG_RSA);
933 Stream_Write_UINT16(s, BB_RSA_KEY_BLOB);
934 if (!cert_write_rsa_public_key(s, certificate))
935 return FALSE;
936
937 const size_t end = Stream_GetPosition(s);
938 return cert_write_rsa_signature(s, sigData, end - start + sizeof(UINT32));
939}
940
941static BOOL cert_write_server_certificate_v2(wStream* s, const rdpCertificate* certificate)
942{
943 WINPR_ASSERT(certificate);
944
945 const rdpX509CertChain* chain = &certificate->x509_cert_chain;
946 const size_t padding = 8ull + 4ull * chain->count;
947
948 if (!Stream_EnsureRemainingCapacity(s, sizeof(UINT32)))
949 return FALSE;
950
951 Stream_Write_UINT32(s, chain->count);
952 for (UINT32 x = 0; x < chain->count; x++)
953 {
954 const rdpCertBlob* cert = &chain->array[x];
955 if (!cert_blob_write(cert, s))
956 return FALSE;
957 }
958
959 if (!Stream_EnsureRemainingCapacity(s, padding))
960 return FALSE;
961 Stream_Zero(s, padding);
962 return TRUE;
963}
964
965SSIZE_T freerdp_certificate_write_server_cert(const rdpCertificate* certificate, UINT32 dwVersion,
966 wStream* s)
967{
968 if (!certificate)
969 return -1;
970
971 const size_t start = Stream_GetPosition(s);
972 if (!Stream_EnsureRemainingCapacity(s, 4))
973 return -1;
974 Stream_Write_UINT32(s, dwVersion);
975
976 switch (dwVersion & CERT_CHAIN_VERSION_MASK)
977 {
978 case CERT_CHAIN_VERSION_1:
979 if (!cert_write_server_certificate_v1(s, certificate))
980 return -1;
981 break;
982 case CERT_CHAIN_VERSION_2:
983 if (!cert_write_server_certificate_v2(s, certificate))
984 return -1;
985 break;
986 default:
987 WLog_ERR(TAG, "invalid certificate chain version:%" PRIu32 "",
988 dwVersion & CERT_CHAIN_VERSION_MASK);
989 return -1;
990 }
991
992 const size_t end = Stream_GetPosition(s);
993 if (start > end)
994 return -1;
995
996 const size_t diff = end - start;
997 WINPR_ASSERT(diff <= SSIZE_MAX);
998 return (SSIZE_T)diff;
999}
1000
1008static BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* cert, wStream* s)
1009{
1010 UINT32 numCertBlobs = 0;
1011 DEBUG_CERTIFICATE("Server X.509 Certificate Chain");
1012
1013 WINPR_ASSERT(cert);
1014 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
1015 return FALSE;
1016
1017 Stream_Read_UINT32(s, numCertBlobs); /* numCertBlobs */
1018 certificate_free_x509_certificate_chain(&cert->x509_cert_chain);
1019 cert->x509_cert_chain = certificate_new_x509_certificate_chain(numCertBlobs);
1020
1021 for (UINT32 i = 0; i < cert->x509_cert_chain.count; i++)
1022 {
1023 rdpCertBlob* blob = &cert->x509_cert_chain.array[i];
1024 if (!cert_blob_read(blob, s))
1025 return FALSE;
1026
1027 if (numCertBlobs - i == 1)
1028 {
1029 DEBUG_CERTIFICATE("Terminal Server Certificate");
1030
1031 BOOL res = certificate_read_x509_certificate(blob, &cert->cert_info);
1032
1033 if (res)
1034 {
1035 if (!update_x509_from_info(cert))
1036 res = FALSE;
1037 }
1038
1039 if (!res)
1040 {
1041 WLog_ERR(TAG, "Failed to read x509 certificate");
1042 return FALSE;
1043 }
1044
1045 DEBUG_CERTIFICATE("modulus length:%" PRIu32 "", cert->cert_info.ModulusLength);
1046 }
1047 }
1048
1049 return update_x509_from_info(cert);
1050}
1051
1059BOOL freerdp_certificate_read_server_cert(rdpCertificate* certificate, const BYTE* server_cert,
1060 size_t length)
1061{
1062 BOOL ret = FALSE;
1063 wStream* s = NULL;
1064 wStream sbuffer;
1065 UINT32 dwVersion = 0;
1066
1067 WINPR_ASSERT(certificate);
1068 if (length < 4) /* NULL certificate is not an error see #1795 */
1069 {
1070 WLog_DBG(TAG, "Received empty certificate, ignoring...");
1071 return TRUE;
1072 }
1073
1074 WINPR_ASSERT(server_cert);
1075 s = Stream_StaticConstInit(&sbuffer, server_cert, length);
1076
1077 if (!s)
1078 {
1079 WLog_ERR(TAG, "Stream_New failed!");
1080 return FALSE;
1081 }
1082
1083 Stream_Read_UINT32(s, dwVersion); /* dwVersion (4 bytes) */
1084
1085 switch (dwVersion & CERT_CHAIN_VERSION_MASK)
1086 {
1087 case CERT_CHAIN_VERSION_1:
1088 ret = certificate_read_server_proprietary_certificate(certificate, s);
1089 break;
1090
1091 case CERT_CHAIN_VERSION_2:
1092 ret = certificate_read_server_x509_certificate_chain(certificate, s);
1093 break;
1094
1095 default:
1096 WLog_ERR(TAG, "invalid certificate chain version:%" PRIu32 "",
1097 dwVersion & CERT_CHAIN_VERSION_MASK);
1098 ret = FALSE;
1099 break;
1100 }
1101
1102 return ret;
1103}
1104
1105static BOOL cert_blob_copy(rdpCertBlob* dst, const rdpCertBlob* src)
1106{
1107 WINPR_ASSERT(dst);
1108 WINPR_ASSERT(src);
1109
1110 cert_blob_free(dst);
1111 if (src->length > 0)
1112 {
1113 dst->data = malloc(src->length);
1114 if (!dst->data)
1115 return FALSE;
1116 dst->length = src->length;
1117 memcpy(dst->data, src->data, src->length);
1118 }
1119
1120 return TRUE;
1121}
1122
1123static BOOL cert_x509_chain_copy(rdpX509CertChain* cert, const rdpX509CertChain* src)
1124{
1125 WINPR_ASSERT(cert);
1126
1127 certificate_free_x509_certificate_chain(cert);
1128 if (!src)
1129 return TRUE;
1130
1131 if (src->count > 0)
1132 {
1133 cert->array = calloc(src->count, sizeof(rdpCertBlob));
1134 if (!cert->array)
1135 {
1136 return FALSE;
1137 }
1138 cert->count = src->count;
1139
1140 for (UINT32 x = 0; x < cert->count; x++)
1141 {
1142 const rdpCertBlob* srcblob = &src->array[x];
1143 rdpCertBlob* dstblob = &cert->array[x];
1144
1145 if (!cert_blob_copy(dstblob, srcblob))
1146 {
1147 certificate_free_x509_certificate_chain(cert);
1148 return FALSE;
1149 }
1150 }
1151 }
1152
1153 return TRUE;
1154}
1155
1156BOOL cert_clone_int(rdpCertificate* dst, const rdpCertificate* src)
1157{
1158 WINPR_ASSERT(dst);
1159 WINPR_ASSERT(src);
1160
1161 if (!cert_info_clone(&dst->cert_info, &src->cert_info))
1162 return FALSE;
1163
1164 if (src->x509)
1165 {
1166 dst->x509 = X509_dup(src->x509);
1167 if (!dst->x509)
1168 {
1169 /* Workaround for SSL deprecation issues:
1170 * some security modes use weak RSA ciphers where X509_dup fails.
1171 * In that case recreate the X509 from the raw RSA data
1172 */
1173 if (!update_x509_from_info(dst))
1174 {
1175 WLog_ERR(TAG, "X509_dup failed, SSL configuration bug?");
1176 return FALSE;
1177 }
1178 }
1179 }
1180
1181 if (src->chain)
1182 {
1183 if (dst->chain)
1184 sk_X509_pop_free(dst->chain, X509_free);
1185
1186 dst->chain = sk_X509_deep_copy(src->chain, X509_const_dup, X509_free);
1187 }
1188 return cert_x509_chain_copy(&dst->x509_cert_chain, &src->x509_cert_chain);
1189}
1190
1191rdpCertificate* freerdp_certificate_clone(const rdpCertificate* certificate)
1192{
1193 if (!certificate)
1194 return NULL;
1195
1196 rdpCertificate* _certificate = freerdp_certificate_new();
1197
1198 if (!_certificate)
1199 return NULL;
1200
1201 if (!cert_clone_int(_certificate, certificate))
1202 goto out_fail;
1203
1204 return _certificate;
1205out_fail:
1206
1207 freerdp_certificate_free(_certificate);
1208 return NULL;
1209}
1210
1216rdpCertificate* freerdp_certificate_new(void)
1217{
1218 return (rdpCertificate*)calloc(1, sizeof(rdpCertificate));
1219}
1220
1221void certificate_free_int(rdpCertificate* cert)
1222{
1223 WINPR_ASSERT(cert);
1224
1225 if (cert->x509)
1226 X509_free(cert->x509);
1227 if (cert->chain)
1228 sk_X509_pop_free(cert->chain, X509_free);
1229
1230 certificate_free_x509_certificate_chain(&cert->x509_cert_chain);
1231 cert_info_free(&cert->cert_info);
1232}
1233
1239void freerdp_certificate_free(rdpCertificate* cert)
1240{
1241 if (!cert)
1242 return;
1243
1244 certificate_free_int(cert);
1245 free(cert);
1246}
1247
1248static BOOL freerdp_rsa_from_x509(rdpCertificate* cert)
1249{
1250 BOOL rc = FALSE;
1251
1252 WINPR_ASSERT(cert);
1253
1254 if (!freerdp_certificate_is_rsa(cert))
1255 return TRUE;
1256
1257#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1258 RSA* rsa = NULL;
1259 const BIGNUM* rsa_n = NULL;
1260 const BIGNUM* rsa_e = NULL;
1261#else
1262 BIGNUM* rsa_n = NULL;
1263 BIGNUM* rsa_e = NULL;
1264#endif
1265 EVP_PKEY* pubkey = X509_get0_pubkey(cert->x509);
1266 if (!pubkey)
1267 goto fail;
1268
1269#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1270 rsa = EVP_PKEY_get1_RSA(pubkey);
1271
1272 /* If this is not a RSA key return success */
1273 rc = TRUE;
1274 if (!rsa)
1275 goto fail;
1276
1277 /* Now we return failure again if something is wrong. */
1278 rc = FALSE;
1279
1280 RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
1281#else
1282 if (!EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_E, &rsa_e))
1283 goto fail;
1284 if (!EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_N, &rsa_n))
1285 goto fail;
1286#endif
1287 if (!rsa_n || !rsa_e)
1288 goto fail;
1289 if (!cert_info_create(&cert->cert_info, rsa_n, rsa_e))
1290 goto fail;
1291 rc = TRUE;
1292fail:
1293#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1294 RSA_free(rsa);
1295#else
1296 BN_free(rsa_n);
1297 BN_free(rsa_e);
1298#endif
1299 return rc;
1300}
1301
1302rdpCertificate* freerdp_certificate_new_from_der(const BYTE* data, size_t length)
1303{
1304 rdpCertificate* cert = freerdp_certificate_new();
1305
1306 if (!cert || !data || (length == 0) || (length > INT_MAX))
1307 goto fail;
1308 const BYTE* ptr = data;
1309 cert->x509 = d2i_X509(NULL, &ptr, (int)length);
1310 if (!cert->x509)
1311 goto fail;
1312 if (!freerdp_rsa_from_x509(cert))
1313 goto fail;
1314 return cert;
1315fail:
1316 freerdp_certificate_free(cert);
1317 return NULL;
1318}
1319
1320rdpCertificate* freerdp_certificate_new_from_x509(const X509* xcert, const STACK_OF(X509) * chain)
1321{
1322 WINPR_ASSERT(xcert);
1323
1324 rdpCertificate* cert = freerdp_certificate_new();
1325 if (!cert)
1326 return NULL;
1327
1328 X509* wcert = WINPR_CAST_CONST_PTR_AWAY(xcert, X509*);
1329 cert->x509 = X509_dup(wcert);
1330 if (!cert->x509)
1331 goto fail;
1332
1333 if (!freerdp_rsa_from_x509(cert))
1334 goto fail;
1335
1336 if (chain)
1337 cert->chain = sk_X509_deep_copy(chain, X509_const_dup, X509_free);
1338
1339 return cert;
1340fail:
1341 freerdp_certificate_free(cert);
1342 return NULL;
1343}
1344
1345static STACK_OF(X509) * extract_chain_from_pem(const char* pem, BOOL isFile)
1346{
1347 if (!pem)
1348 {
1349 return NULL;
1350 }
1351
1352 BIO* bio = NULL;
1353 if (isFile)
1354 bio = BIO_new_file(pem, "rb");
1355 else
1356 {
1357 const size_t len = strlen(pem);
1358 bio = BIO_new_mem_buf(pem, WINPR_ASSERTING_INT_CAST(int, len));
1359 }
1360
1361 if (!bio)
1362 {
1363 return NULL;
1364 }
1365
1366 X509* leaf = PEM_read_bio_X509(bio, NULL, NULL, NULL);
1367 if (!leaf)
1368 {
1369 BIO_free(bio);
1370 return NULL;
1371 }
1372
1373 STACK_OF(X509)* chain = sk_X509_new_null();
1374 if (!chain)
1375 {
1376 X509_free(leaf);
1377 BIO_free(bio);
1378 return NULL;
1379 }
1380
1381 X509* cert = NULL;
1382 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL)
1383 {
1384 sk_X509_push(chain, cert);
1385 }
1386
1387 X509_free(leaf);
1388 BIO_free(bio);
1389 return chain;
1390}
1391
1392static rdpCertificate* freerdp_certificate_new_from(const char* file, BOOL isFile)
1393{
1394 X509* x509 = x509_utils_from_pem(file, strlen(file), isFile);
1395 if (!x509)
1396 return NULL;
1397 STACK_OF(X509)* chain = extract_chain_from_pem(file, isFile);
1398 rdpCertificate* cert = freerdp_certificate_new_from_x509(x509, chain);
1399 if (chain)
1400 sk_X509_pop_free(chain, X509_free);
1401 X509_free(x509);
1402 return cert;
1403}
1404
1405rdpCertificate* freerdp_certificate_new_from_file(const char* file)
1406{
1407 return freerdp_certificate_new_from(file, TRUE);
1408}
1409
1410rdpCertificate* freerdp_certificate_new_from_pem(const char* pem)
1411{
1412 return freerdp_certificate_new_from(pem, FALSE);
1413}
1414
1415const rdpCertInfo* freerdp_certificate_get_info(const rdpCertificate* cert)
1416{
1417 WINPR_ASSERT(cert);
1418 if (!freerdp_certificate_is_rsa(cert))
1419 return NULL;
1420 return &cert->cert_info;
1421}
1422
1423char* freerdp_certificate_get_fingerprint(const rdpCertificate* cert)
1424{
1425 return freerdp_certificate_get_fingerprint_by_hash(cert, "sha256");
1426}
1427
1428char* freerdp_certificate_get_fingerprint_by_hash(const rdpCertificate* cert, const char* hash)
1429{
1430 return freerdp_certificate_get_fingerprint_by_hash_ex(cert, hash, TRUE);
1431}
1432
1433char* freerdp_certificate_get_fingerprint_by_hash_ex(const rdpCertificate* cert, const char* hash,
1434 BOOL separator)
1435{
1436 size_t fp_len = 0;
1437 size_t pos = 0;
1438 size_t size = 0;
1439 BYTE* fp = NULL;
1440 char* fp_buffer = NULL;
1441 if (!cert || !cert->x509)
1442 {
1443 WLog_ERR(TAG, "Invalid certificate [%p, %p]", cert, cert ? cert->x509 : NULL);
1444 return NULL;
1445 }
1446 if (!hash)
1447 {
1448 WLog_ERR(TAG, "Invalid certificate hash %p", hash);
1449 return NULL;
1450 }
1451 fp = x509_utils_get_hash(cert->x509, hash, &fp_len);
1452 if (!fp)
1453 return NULL;
1454
1455 if (fp_len < 1)
1456 goto fail;
1457
1458 size = fp_len * 3 + 1;
1459 fp_buffer = calloc(size, sizeof(char));
1460 if (!fp_buffer)
1461 goto fail;
1462
1463 pos = 0;
1464
1465 size_t i = 0;
1466 for (; i < (fp_len - 1); i++)
1467 {
1468 int rc = 0;
1469 char* p = &fp_buffer[pos];
1470 if (separator)
1471 rc = sprintf_s(p, size - pos, "%02" PRIx8 ":", fp[i]);
1472 else
1473 rc = sprintf_s(p, size - pos, "%02" PRIx8, fp[i]);
1474 if (rc <= 0)
1475 goto fail;
1476 pos += (size_t)rc;
1477 }
1478
1479 (void)sprintf_s(&fp_buffer[pos], size - pos, "%02" PRIx8 "", fp[i]);
1480
1481 free(fp);
1482
1483 return fp_buffer;
1484fail:
1485 free(fp);
1486 free(fp_buffer);
1487 return NULL;
1488}
1489
1490static BOOL bio_read_pem(BIO* bio, char** ppem, size_t* plength)
1491{
1492 BOOL rc = FALSE;
1493
1494 WINPR_ASSERT(bio);
1495 WINPR_ASSERT(ppem);
1496
1497 const size_t blocksize = 2048;
1498 size_t offset = 0;
1499 size_t length = blocksize;
1500 char* pem = NULL;
1501
1502 *ppem = NULL;
1503 if (plength)
1504 *plength = 0;
1505
1506 while (offset < length)
1507 {
1508 char* tmp = realloc(pem, length + 1);
1509 if (!tmp)
1510 goto fail;
1511 pem = tmp;
1512
1513 ERR_clear_error();
1514
1515 const int status = BIO_read(bio, &pem[offset], (int)(length - offset));
1516 if (status < 0)
1517 {
1518 WLog_ERR(TAG, "failed to read certificate");
1519 goto fail;
1520 }
1521
1522 if (status == 0)
1523 break;
1524
1525 offset += (size_t)status;
1526 if (length - offset > 0)
1527 break;
1528 length += blocksize;
1529 }
1530
1531 if (pem)
1532 {
1533 if (offset >= length)
1534 goto fail;
1535 pem[offset] = '\0';
1536 }
1537 *ppem = pem;
1538 if (plength)
1539 *plength = offset;
1540 rc = TRUE;
1541fail:
1542 if (!rc)
1543 free(pem);
1544
1545 return rc;
1546}
1547
1548char* freerdp_certificate_get_pem(const rdpCertificate* cert, size_t* pLength)
1549{
1550 return freerdp_certificate_get_pem_ex(cert, pLength, TRUE);
1551}
1552
1553char* freerdp_certificate_get_pem_ex(const rdpCertificate* cert, size_t* pLength,
1554 BOOL withCertChain)
1555{
1556 WINPR_ASSERT(cert);
1557
1558 if (!cert->x509)
1559 return NULL;
1560
1565 BIO* bio = BIO_new(BIO_s_mem());
1566
1567 if (!bio)
1568 {
1569 WLog_ERR(TAG, "BIO_new() failure");
1570 return NULL;
1571 }
1572
1573 char* pem = NULL;
1574
1575 const int status = PEM_write_bio_X509(bio, cert->x509);
1576 if (status < 0)
1577 {
1578 WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", status);
1579 goto fail;
1580 }
1581
1582 if (cert->chain && withCertChain)
1583 {
1584 const int count = sk_X509_num(cert->chain);
1585 for (int x = 0; x < count; x++)
1586 {
1587 X509* c = sk_X509_value(cert->chain, x);
1588 const int rc = PEM_write_bio_X509(bio, c);
1589 if (rc < 0)
1590 {
1591 WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", rc);
1592 goto fail;
1593 }
1594 }
1595 }
1596
1597 (void)bio_read_pem(bio, &pem, pLength);
1598
1599fail:
1600 BIO_free_all(bio);
1601 return pem;
1602}
1603
1604char* freerdp_certificate_get_subject(const rdpCertificate* cert)
1605{
1606 WINPR_ASSERT(cert);
1607 return x509_utils_get_subject(cert->x509);
1608}
1609
1610char* freerdp_certificate_get_issuer(const rdpCertificate* cert)
1611{
1612 WINPR_ASSERT(cert);
1613 return x509_utils_get_issuer(cert->x509);
1614}
1615
1616char* freerdp_certificate_get_upn(const rdpCertificate* cert)
1617{
1618 WINPR_ASSERT(cert);
1619 return x509_utils_get_upn(cert->x509);
1620}
1621
1622char* freerdp_certificate_get_email(const rdpCertificate* cert)
1623{
1624 WINPR_ASSERT(cert);
1625 return x509_utils_get_email(cert->x509);
1626}
1627
1628char* freerdp_certificate_get_validity(const rdpCertificate* cert, BOOL startDate)
1629{
1630 WINPR_ASSERT(cert);
1631 return x509_utils_get_date(cert->x509, startDate);
1632}
1633
1634BOOL freerdp_certificate_check_eku(const rdpCertificate* cert, int nid)
1635{
1636 WINPR_ASSERT(cert);
1637 return x509_utils_check_eku(cert->x509, nid);
1638}
1639
1640BOOL freerdp_certificate_get_public_key(const rdpCertificate* cert, BYTE** PublicKey,
1641 DWORD* PublicKeyLength)
1642{
1643 BYTE* ptr = NULL;
1644 BYTE* optr = NULL;
1645 int length = 0;
1646 BOOL status = FALSE;
1647 EVP_PKEY* pkey = NULL;
1648
1649 WINPR_ASSERT(cert);
1650
1651 pkey = X509_get0_pubkey(cert->x509);
1652
1653 if (!pkey)
1654 {
1655 WLog_ERR(TAG, "X509_get_pubkey() failed");
1656 goto exit;
1657 }
1658
1659 length = i2d_PublicKey(pkey, NULL);
1660
1661 if (length < 1)
1662 {
1663 WLog_ERR(TAG, "i2d_PublicKey() failed");
1664 goto exit;
1665 }
1666
1667 *PublicKey = optr = ptr = (BYTE*)calloc(WINPR_ASSERTING_INT_CAST(size_t, length), sizeof(BYTE));
1668
1669 if (!ptr)
1670 goto exit;
1671
1672 const int length2 = i2d_PublicKey(pkey, &ptr);
1673 if (length != length2)
1674 goto exit;
1675 *PublicKeyLength = (DWORD)length2;
1676 status = TRUE;
1677exit:
1678
1679 if (!status)
1680 free(optr);
1681
1682 return status;
1683}
1684
1685BOOL freerdp_certificate_verify(const rdpCertificate* cert, const char* certificate_store_path)
1686{
1687 WINPR_ASSERT(cert);
1688 return x509_utils_verify(cert->x509, cert->chain, certificate_store_path);
1689}
1690
1691char** freerdp_certificate_get_dns_names(const rdpCertificate* cert, size_t* pcount,
1692 size_t** pplengths)
1693{
1694 WINPR_ASSERT(cert);
1695 return x509_utils_get_dns_names(cert->x509, pcount, pplengths);
1696}
1697
1698char* freerdp_certificate_get_common_name(const rdpCertificate* cert, size_t* plength)
1699{
1700 WINPR_ASSERT(cert);
1701 return x509_utils_get_common_name(cert->x509, plength);
1702}
1703
1704WINPR_MD_TYPE freerdp_certificate_get_signature_alg(const rdpCertificate* cert)
1705{
1706 WINPR_ASSERT(cert);
1707 return x509_utils_get_signature_alg(cert->x509);
1708}
1709
1710void freerdp_certificate_free_dns_names(size_t count, size_t* lengths, char** names)
1711{
1712 x509_utils_dns_names_free(count, lengths, names);
1713}
1714
1715char* freerdp_certificate_get_hash(const rdpCertificate* cert, const char* hash, size_t* plength)
1716{
1717 WINPR_ASSERT(cert);
1718 return (char*)x509_utils_get_hash(cert->x509, hash, plength);
1719}
1720
1721X509* freerdp_certificate_get_x509(rdpCertificate* cert)
1722{
1723 WINPR_ASSERT(cert);
1724 return cert->x509;
1725}
1726
1727BOOL freerdp_certificate_publickey_encrypt(const rdpCertificate* cert, const BYTE* input,
1728 size_t cbInput, BYTE** poutput, size_t* pcbOutput)
1729{
1730 WINPR_ASSERT(cert);
1731 WINPR_ASSERT(input);
1732 WINPR_ASSERT(poutput);
1733 WINPR_ASSERT(pcbOutput);
1734
1735 BOOL ret = FALSE;
1736 BYTE* output = NULL;
1737 EVP_PKEY* pkey = X509_get0_pubkey(cert->x509);
1738 if (!pkey)
1739 return FALSE;
1740
1741 EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, NULL);
1742 if (!ctx)
1743 return FALSE;
1744
1745 size_t outputSize = WINPR_ASSERTING_INT_CAST(size_t, EVP_PKEY_size(pkey));
1746 output = malloc(outputSize);
1747 if (output == NULL)
1748 goto out;
1749 *pcbOutput = outputSize;
1750
1751 if (EVP_PKEY_encrypt_init(ctx) != 1 ||
1752 EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) != 1 ||
1753 EVP_PKEY_encrypt(ctx, output, pcbOutput, input, cbInput) != 1)
1754 {
1755 WLog_ERR(TAG, "error when setting up public key");
1756 goto out;
1757 }
1758
1759 *poutput = output;
1760 output = NULL;
1761 ret = TRUE;
1762out:
1763 EVP_PKEY_CTX_free(ctx);
1764 free(output);
1765 return ret;
1766}
1767
1768#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1769static RSA* freerdp_certificate_get_RSA(const rdpCertificate* cert)
1770{
1771 WINPR_ASSERT(cert);
1772
1773 if (!freerdp_certificate_is_rsa(cert))
1774 return NULL;
1775
1776 EVP_PKEY* pubkey = X509_get0_pubkey(cert->x509);
1777 if (!pubkey)
1778 return NULL;
1779
1780 return EVP_PKEY_get1_RSA(pubkey);
1781}
1782#endif
1783
1784BYTE* freerdp_certificate_get_der(const rdpCertificate* cert, size_t* pLength)
1785{
1786 WINPR_ASSERT(cert);
1787
1788 if (pLength)
1789 *pLength = 0;
1790
1791 const int rc = i2d_X509(cert->x509, NULL);
1792 if (rc <= 0)
1793 return NULL;
1794
1795 BYTE* ptr = calloc(WINPR_ASSERTING_INT_CAST(size_t, rc) + 1, sizeof(BYTE));
1796 if (!ptr)
1797 return NULL;
1798 BYTE* i2d_ptr = ptr;
1799
1800 const int rc2 = i2d_X509(cert->x509, &i2d_ptr);
1801 if (rc2 <= 0)
1802 {
1803 free(ptr);
1804 return NULL;
1805 }
1806
1807 if (pLength)
1808 *pLength = (size_t)rc2;
1809 return ptr;
1810}
1811
1812BOOL freerdp_certificate_is_rsa(const rdpCertificate* cert)
1813{
1814 WINPR_ASSERT(cert);
1815 return is_rsa_key(cert->x509);
1816}
1817
1818BOOL freerdp_certificate_is_rdp_security_compatible(const rdpCertificate* cert)
1819{
1820 const rdpCertInfo* info = freerdp_certificate_get_info(cert);
1821 if (!freerdp_certificate_is_rsa(cert) || !info || (info->ModulusLength != 2048 / 8))
1822 {
1823 WLog_INFO(TAG, "certificate is not RSA 2048, RDP security not supported.");
1824 return FALSE;
1825 }
1826 return TRUE;
1827}
1828
1829char* freerdp_certificate_get_param(const rdpCertificate* cert, enum FREERDP_CERT_PARAM what,
1830 size_t* psize)
1831{
1832 WINPR_ASSERT(cert);
1833 WINPR_ASSERT(psize);
1834
1835 *psize = 0;
1836
1837#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1838 const BIGNUM* bn = NULL;
1839 RSA* rsa = freerdp_certificate_get_RSA(cert);
1840 switch (what)
1841 {
1842 case FREERDP_CERT_RSA_E:
1843 RSA_get0_key(rsa, NULL, &bn, NULL);
1844 break;
1845 case FREERDP_CERT_RSA_N:
1846 RSA_get0_key(rsa, &bn, NULL, NULL);
1847 break;
1848 default:
1849 RSA_free(rsa);
1850 return NULL;
1851 }
1852 RSA_free(rsa);
1853#else
1854 EVP_PKEY* pkey = X509_get0_pubkey(cert->x509);
1855 if (!pkey)
1856 return NULL;
1857
1858 BIGNUM* bn = NULL;
1859 switch (what)
1860 {
1861 case FREERDP_CERT_RSA_E:
1862 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &bn))
1863 return NULL;
1864 break;
1865 case FREERDP_CERT_RSA_N:
1866 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &bn))
1867 return NULL;
1868 break;
1869 default:
1870 return NULL;
1871 }
1872#endif
1873
1874 const size_t bnsize = WINPR_ASSERTING_INT_CAST(size_t, BN_num_bytes(bn));
1875 char* rc = calloc(bnsize + 1, sizeof(char));
1876 if (!rc)
1877 goto fail;
1878 BN_bn2bin(bn, (BYTE*)rc);
1879 *psize = bnsize;
1880
1881fail:
1882#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR < 3)
1883 BN_free(bn);
1884#endif
1885 return rc;
1886}
1887
1888size_t freerdp_certificate_get_chain_len(rdpCertificate* certificate)
1889{
1890 WINPR_ASSERT(certificate);
1891 if (!certificate->chain)
1892 return 0;
1893
1894 return WINPR_ASSERTING_INT_CAST(size_t, sk_X509_num(certificate->chain));
1895}
1896
1897X509* freerdp_certificate_get_chain_at(rdpCertificate* certificate, size_t offset)
1898{
1899 WINPR_ASSERT(certificate);
1900 WINPR_ASSERT(freerdp_certificate_get_chain_len(certificate) > offset);
1901 const int ioff = WINPR_ASSERTING_INT_CAST(int, offset);
1902 return sk_X509_value(certificate->chain, ioff);
1903}