Coverage Report

Created: 2026-05-16 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/crypto/certificate.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Certificate Handling
4
 *
5
 * Copyright 2011 Jiten Pathy
6
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
7
 * Copyright 2015 Thincast Technologies GmbH
8
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
9
 * Copyright 2023 Armin Novak <anovak@thincast.com>
10
 * Copyright 2023 Thincast Technologies GmbH
11
 *
12
 * Licensed under the Apache License, Version 2.0 (the "License");
13
 * you may not use this file except in compliance with the License.
14
 * You may obtain a copy of the License at
15
 *
16
 *     http://www.apache.org/licenses/LICENSE-2.0
17
 *
18
 * Unless required by applicable law or agreed to in writing, software
19
 * distributed under the License is distributed on an "AS IS" BASIS,
20
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
 * See the License for the specific language governing permissions and
22
 * limitations under the License.
23
 */
24
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
87
  do                         \
68
87
  {                          \
69
87
  } while (0)
70
#endif
71
72
#define TSSK_KEY_LENGTH 64
73
74
struct rdp_CertBlob
75
{
76
  UINT32 length;
77
  BYTE* data;
78
};
79
typedef struct rdp_CertBlob rdpCertBlob;
80
81
struct rdp_X509CertChain
82
{
83
  UINT32 count;
84
  rdpCertBlob* array;
85
};
86
typedef struct rdp_X509CertChain rdpX509CertChain;
87
88
struct rdp_certificate
89
{
90
  X509* x509;
91
  STACK_OF(X509) * chain;
92
93
  rdpCertInfo cert_info;
94
  rdpX509CertChain x509_cert_chain;
95
};
96
97
/**
98
 *
99
 * X.509 Certificate Structure
100
 *
101
 * Certificate ::= SEQUENCE
102
 * {
103
 *  tbsCertificate      TBSCertificate,
104
 *  signatureAlgorithm    AlgorithmIdentifier,
105
 *  signatureValue      BIT_STRING
106
 * }
107
 *
108
 * TBSCertificate ::= SEQUENCE
109
 * {
110
 *  version     [0] EXPLICIT Version DEFAULT v1,
111
 *  serialNumber      CertificateSerialNumber,
112
 *  signature     AlgorithmIdentifier,
113
 *  issuer        Name,
114
 *  validity      Validity,
115
 *  subject       Name,
116
 *  subjectPublicKeyInfo    SubjectPublicKeyInfo,
117
 *  issuerUniqueID    [1] IMPLICIT UniqueIdentifier OPTIONAL,
118
 *  subjectUniqueId   [2] IMPLICIT UniqueIdentifier OPTIONAL,
119
 *  extensions    [3] EXPLICIT Extensions OPTIONAL
120
 * }
121
 *
122
 * Version ::= INTEGER { v1(0), v2(1), v3(2) }
123
 *
124
 * CertificateSerialNumber ::= INTEGER
125
 *
126
 * AlgorithmIdentifier ::= SEQUENCE
127
 * {
128
 *  algorithm     OBJECT_IDENTIFIER,
129
 *  parameters      ANY DEFINED BY algorithm OPTIONAL
130
 * }
131
 *
132
 * Name ::= CHOICE { RDNSequence }
133
 *
134
 * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
135
 *
136
 * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
137
 *
138
 * AttributeTypeAndValue ::= SEQUENCE
139
 * {
140
 *  type        AttributeType,
141
 *  value       AttributeValue
142
 * }
143
 *
144
 * AttributeType ::= OBJECT_IDENTIFIER
145
 *
146
 * AttributeValue ::= ANY DEFINED BY AttributeType
147
 *
148
 * Validity ::= SEQUENCE
149
 * {
150
 *  notBefore     Time,
151
 *  notAfter      Time
152
 * }
153
 *
154
 * Time ::= CHOICE
155
 * {
156
 *  utcTime       UTCTime,
157
 *  generalTime     GeneralizedTime
158
 * }
159
 *
160
 * UniqueIdentifier ::= BIT_STRING
161
 *
162
 * SubjectPublicKeyInfo ::= SEQUENCE
163
 * {
164
 *  algorithm     AlgorithmIdentifier,
165
 *  subjectPublicKey    BIT_STRING
166
 * }
167
 *
168
 * RSAPublicKey ::= SEQUENCE
169
 * {
170
 *  modulus       INTEGER
171
 *  publicExponent      INTEGER
172
 * }
173
 *
174
 * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
175
 *
176
 * Extension ::= SEQUENCE
177
 * {
178
 *  extnID        OBJECT_IDENTIFIER
179
 *  critical      BOOLEAN DEFAULT FALSE,
180
 *  extnValue     OCTET_STRING
181
 * }
182
 *
183
 */
184
185
static const char rsa_magic[4] = { 'R', 'S', 'A', '1' };
186
187
static 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
207
static 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)
215
static const BYTE tssk_exponent[] = { 0x5b, 0x7b, 0x88, 0xc0 };
216
#endif
217
218
static void certificate_free_int(rdpCertificate* certificate);
219
static 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
 */
225
static BOOL cert_blob_copy(rdpCertBlob* dst, const rdpCertBlob* src);
226
static void cert_blob_free(rdpCertBlob* blob);
227
static BOOL cert_blob_write(const rdpCertBlob* blob, wStream* s);
228
static BOOL cert_blob_read(rdpCertBlob* blob, wStream* s);
229
230
BOOL cert_blob_read(rdpCertBlob* blob, wStream* s)
231
18
{
232
18
  UINT32 certLength = 0;
233
18
  WINPR_ASSERT(blob);
234
18
  cert_blob_free(blob);
235
236
18
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
237
1
    goto fail;
238
239
17
  Stream_Read_UINT32(s, certLength);
240
241
17
  if (!Stream_CheckAndLogRequiredLength(TAG, s, certLength))
242
3
    goto fail;
243
244
14
  DEBUG_CERTIFICATE("X.509 Certificate length:%" PRIu32 "", certLength);
245
14
  blob->data = (BYTE*)malloc(certLength);
246
247
14
  if (!blob->data)
248
0
    goto fail;
249
250
14
  Stream_Read(s, blob->data, certLength);
251
14
  blob->length = certLength;
252
253
14
  return TRUE;
254
255
4
fail:
256
4
  cert_blob_free(blob);
257
4
  return FALSE;
258
14
}
259
260
BOOL cert_blob_write(const rdpCertBlob* blob, wStream* s)
261
0
{
262
0
  WINPR_ASSERT(blob);
263
264
0
  if (!Stream_EnsureRemainingCapacity(s, 4 + blob->length))
265
0
    return FALSE;
266
267
0
  Stream_Write_UINT32(s, blob->length);
268
0
  Stream_Write(s, blob->data, blob->length);
269
0
  return TRUE;
270
0
}
271
272
void cert_blob_free(rdpCertBlob* blob)
273
40
{
274
40
  if (!blob)
275
0
    return;
276
40
  free(blob->data);
277
40
  blob->data = nullptr;
278
40
  blob->length = 0;
279
40
}
280
281
/**
282
 * Read X.509 Certificate
283
 */
284
285
static BOOL is_rsa_key(const X509* x509)
286
105
{
287
105
  EVP_PKEY* evp = X509_get0_pubkey(x509);
288
105
  if (!evp)
289
69
    return FALSE;
290
291
36
  return (EVP_PKEY_id(evp) == EVP_PKEY_RSA);
292
105
}
293
294
static BOOL certificate_read_x509_certificate(const rdpCertBlob* cert, rdpCertInfo* info)
295
10
{
296
10
  wStream sbuffer = WINPR_C_ARRAY_INIT;
297
10
  wStream* s = nullptr;
298
10
  size_t length = 0;
299
10
  BYTE padding = 0;
300
10
  UINT32 version = 0;
301
10
  size_t modulus_length = 0;
302
10
  size_t exponent_length = 0;
303
10
  int error = 0;
304
305
10
  WINPR_ASSERT(cert);
306
10
  WINPR_ASSERT(info);
307
308
10
  cert_info_free(info);
309
310
10
  s = Stream_StaticConstInit(&sbuffer, cert->data, cert->length);
311
312
10
  if (!s)
313
0
    return FALSE;
314
315
10
  if (!ber_read_sequence_tag(s, &length)) /* Certificate (SEQUENCE) */
316
5
    goto error;
317
318
5
  error++;
319
320
5
  if (!ber_read_sequence_tag(s, &length)) /* TBSCertificate (SEQUENCE) */
321
1
    goto error;
322
323
4
  error++;
324
325
4
  if (!ber_read_contextual_tag(s, 0, &length, TRUE)) /* Explicit Contextual Tag [0] */
326
2
    goto error;
327
328
2
  error++;
329
330
2
  if (!ber_read_integer(s, &version)) /* version (INTEGER) */
331
1
    goto error;
332
333
1
  error++;
334
1
  version++;
335
336
  /* serialNumber */
337
1
  if (!ber_read_integer(s, nullptr)) /* CertificateSerialNumber (INTEGER) */
338
1
    goto error;
339
340
0
  error++;
341
342
  /* signature */
343
0
  if (!ber_read_sequence_tag(s, &length) ||
344
0
      !Stream_SafeSeek(s, length)) /* AlgorithmIdentifier (SEQUENCE) */
345
0
    goto error;
346
347
0
  error++;
348
349
  /* issuer */
350
0
  if (!ber_read_sequence_tag(s, &length) || !Stream_SafeSeek(s, length)) /* Name (SEQUENCE) */
351
0
    goto error;
352
353
0
  error++;
354
355
  /* validity */
356
0
  if (!ber_read_sequence_tag(s, &length) || !Stream_SafeSeek(s, length)) /* Validity (SEQUENCE) */
357
0
    goto error;
358
359
0
  error++;
360
361
  /* subject */
362
0
  if (!ber_read_sequence_tag(s, &length) || !Stream_SafeSeek(s, length)) /* Name (SEQUENCE) */
363
0
    goto error;
364
365
0
  error++;
366
367
  /* subjectPublicKeyInfo */
368
0
  if (!ber_read_sequence_tag(s, &length)) /* SubjectPublicKeyInfo (SEQUENCE) */
369
0
    goto error;
370
371
0
  error++;
372
373
  /* subjectPublicKeyInfo::AlgorithmIdentifier */
374
0
  if (!ber_read_sequence_tag(s, &length) ||
375
0
      !Stream_SafeSeek(s, length)) /* AlgorithmIdentifier (SEQUENCE) */
376
0
    goto error;
377
378
0
  error++;
379
380
  /* subjectPublicKeyInfo::subjectPublicKey */
381
0
  if (!ber_read_bit_string(s, &length, &padding)) /* BIT_STRING */
382
0
    goto error;
383
384
0
  error++;
385
386
  /* RSAPublicKey (SEQUENCE) */
387
0
  if (!ber_read_sequence_tag(s, &length)) /* SEQUENCE */
388
0
    goto error;
389
390
0
  error++;
391
392
0
  if (!ber_read_integer_length(s, &modulus_length)) /* modulus (INTEGER) */
393
0
    goto error;
394
395
0
  error++;
396
397
  /* skip zero padding, if any */
398
0
  do
399
0
  {
400
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
401
0
      goto error;
402
403
0
    Stream_Peek_UINT8(s, padding);
404
405
0
    if (padding == 0)
406
0
    {
407
0
      if (!Stream_SafeSeek(s, 1))
408
0
        goto error;
409
410
0
      modulus_length--;
411
0
    }
412
0
  } while (padding == 0);
413
414
0
  error++;
415
416
0
  if (!cert_info_read_modulus(info, modulus_length, s))
417
0
    goto error;
418
419
0
  error++;
420
421
0
  if (!ber_read_integer_length(s, &exponent_length)) /* publicExponent (INTEGER) */
422
0
    goto error;
423
424
0
  error++;
425
426
0
  if (!cert_info_read_exponent(info, exponent_length, s))
427
0
    goto error;
428
0
  return TRUE;
429
10
error:
430
10
  WLog_ERR(TAG, "error reading when reading certificate: part=%s error=%d",
431
10
           certificate_read_errors[error], error);
432
10
  cert_info_free(info);
433
10
  return FALSE;
434
0
}
435
436
/**
437
 * Instantiate new X.509 Certificate Chain.
438
 * @param count certificate chain count
439
 * @return new X.509 certificate chain
440
 */
441
442
static BOOL certificate_new_x509_certificate_chain(UINT32 count, wStream* s,
443
                                                   rdpX509CertChain* chain)
444
61
{
445
61
  WINPR_ASSERT(chain);
446
447
61
  rdpX509CertChain x509_cert_chain = WINPR_C_ARRAY_INIT;
448
61
  *chain = x509_cert_chain;
449
450
61
  if (!Stream_CheckAndLogRequiredCapacityOfSize(TAG, s, count, sizeof(rdpCertBlob)))
451
45
    return FALSE;
452
453
16
  if (count == 0)
454
2
    return TRUE;
455
456
14
  x509_cert_chain.array = (rdpCertBlob*)calloc(count, sizeof(rdpCertBlob));
457
14
  if (!x509_cert_chain.array)
458
0
    return FALSE;
459
460
14
  x509_cert_chain.count = count;
461
462
14
  *chain = x509_cert_chain;
463
14
  return TRUE;
464
14
}
465
466
/**
467
 * Free X.509 Certificate Chain.
468
 * @param x509_cert_chain X.509 certificate chain to be freed
469
 */
470
471
static void certificate_free_x509_certificate_chain(rdpX509CertChain* x509_cert_chain)
472
126k
{
473
126k
  if (!x509_cert_chain)
474
0
    return;
475
476
126k
  if (x509_cert_chain->array)
477
14
  {
478
32
    for (UINT32 i = 0; i < x509_cert_chain->count; i++)
479
18
    {
480
18
      rdpCertBlob* element = &x509_cert_chain->array[i];
481
18
      cert_blob_free(element);
482
18
    }
483
14
  }
484
485
126k
  free(x509_cert_chain->array);
486
126k
  x509_cert_chain->array = nullptr;
487
126k
  x509_cert_chain->count = 0;
488
126k
}
489
490
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
491
static 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");
539
fail:
540
  OSSL_PARAM_BLD_free(param);
541
542
  return parameters;
543
}
544
#endif
545
546
static BOOL update_x509_from_info(rdpCertificate* cert)
547
2
{
548
2
  BOOL rc = FALSE;
549
550
2
  WINPR_ASSERT(cert);
551
552
2
  X509_free(cert->x509);
553
2
  cert->x509 = nullptr;
554
555
2
  rdpCertInfo* info = &cert->cert_info;
556
557
2
  BIGNUM* e = BN_new();
558
2
  BIGNUM* mod = BN_new();
559
2
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
560
2
  RSA* rsa = RSA_new();
561
2
  if (!rsa)
562
0
  {
563
0
    WLog_ERR(TAG, "RSA_new() failed");
564
0
    goto fail;
565
0
  }
566
2
#endif
567
568
2
  if (!mod || !e)
569
0
  {
570
0
    WLog_ERR(TAG, "failure: mod=%p, e=%p", WINPR_CXX_COMPAT_CAST(const void*, mod),
571
0
             WINPR_CXX_COMPAT_CAST(const void*, e));
572
0
    goto fail;
573
0
  }
574
575
2
  WINPR_ASSERT(info->ModulusLength <= INT_MAX);
576
2
  if (!BN_bin2bn(info->Modulus, (int)info->ModulusLength, mod))
577
0
  {
578
0
    WLog_ERR(TAG, "BN_bin2bn(info->Modulus, (int)info->ModulusLength, mod) failed");
579
0
    goto fail;
580
0
  }
581
582
2
  if (!BN_bin2bn(info->exponent, (int)sizeof(info->exponent), e))
583
0
  {
584
0
    WLog_ERR(TAG, "BN_bin2bn(info->exponent, (int)sizeof(info->exponent), e) failed");
585
0
    goto fail;
586
0
  }
587
588
2
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
589
2
  const int rec = RSA_set0_key(rsa, mod, e, nullptr);
590
2
  if (rec != 1)
591
0
  {
592
0
    WLog_ERR(TAG, "RSA_set0_key(rsa, mod, e, nullptr) failed");
593
0
    goto fail;
594
0
  }
595
596
2
  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
2
  if (!cert->x509)
653
0
    goto fail;
654
655
2
  rc = TRUE;
656
657
2
fail:
658
2
  if (!rc)
659
0
    WLog_ERR(TAG, "failed to update x509 from rdpCertInfo");
660
661
2
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
662
2
  if (rsa)
663
2
    RSA_free(rsa);
664
0
  else
665
0
#endif
666
0
  {
667
0
    BN_free(mod);
668
0
    BN_free(e);
669
0
  }
670
2
  return rc;
671
2
}
672
673
static BOOL certificate_process_server_public_key(rdpCertificate* cert, wStream* s,
674
                                                  WINPR_ATTR_UNUSED UINT32 length)
675
1
{
676
1
  char magic[sizeof(rsa_magic)] = WINPR_C_ARRAY_INIT;
677
1
  UINT32 keylen = 0;
678
1
  UINT32 bitlen = 0;
679
1
  UINT32 datalen = 0;
680
681
1
  WINPR_ASSERT(cert);
682
1
  WINPR_ASSERT(s);
683
684
1
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
685
1
    return FALSE;
686
687
0
  Stream_Read(s, magic, sizeof(magic));
688
689
0
  if (memcmp(magic, rsa_magic, sizeof(magic)) != 0)
690
0
  {
691
0
    WLog_ERR(TAG, "invalid RSA magic bytes");
692
0
    return FALSE;
693
0
  }
694
695
0
  rdpCertInfo* info = &cert->cert_info;
696
0
  cert_info_free(info);
697
698
0
  Stream_Read_UINT32(s, keylen);
699
0
  Stream_Read_UINT32(s, bitlen);
700
0
  Stream_Read_UINT32(s, datalen);
701
0
  Stream_Read(s, info->exponent, 4);
702
703
0
  if (keylen <= 8)
704
0
  {
705
0
    WLog_ERR(TAG, "Invalid RSA keylen=%" PRIu32 " <= 8", keylen);
706
0
    return FALSE;
707
0
  }
708
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, keylen))
709
0
    return FALSE;
710
0
  if (keylen != (bitlen / 8ull) + 8ull)
711
0
  {
712
0
    WLog_ERR(TAG, "Invalid RSA key bitlen %" PRIu32 ", expected %" PRIu32, bitlen,
713
0
             (keylen - 8) * 8);
714
0
    return FALSE;
715
0
  }
716
0
  if (datalen != (bitlen / 8ull) - 1ull)
717
0
  {
718
0
    WLog_ERR(TAG, "Invalid RSA key datalen %" PRIu32 ", expected %llu", datalen,
719
0
             (1ull * bitlen / 8ull) - 1ull);
720
0
    return FALSE;
721
0
  }
722
0
  info->ModulusLength = keylen - 8;
723
0
  BYTE* tmp = realloc(info->Modulus, info->ModulusLength);
724
725
0
  if (!tmp)
726
0
  {
727
0
    WLog_ERR(TAG, "Failed to reallocate modulus of length %" PRIu32, info->ModulusLength);
728
0
    return FALSE;
729
0
  }
730
0
  info->Modulus = tmp;
731
732
0
  Stream_Read(s, info->Modulus, info->ModulusLength);
733
0
  Stream_Seek(s, 8); /* 8 bytes of zero padding */
734
0
  return update_x509_from_info(cert);
735
0
}
736
737
static BOOL certificate_process_server_public_signature(rdpCertificate* certificate,
738
                                                        const BYTE* sigdata, size_t sigdatalen,
739
                                                        wStream* s, UINT32 siglen)
740
0
{
741
0
  WINPR_ASSERT(certificate);
742
#if defined(CERT_VALIDATE_RSA)
743
  BYTE sig[TSSK_KEY_LENGTH];
744
#endif
745
0
  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
0
#if !defined(CERT_VALIDATE_MD5) || !defined(CERT_VALIDATE_RSA)
750
0
  (void)sigdata;
751
0
  (void)sigdatalen;
752
0
#endif
753
0
  (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
0
  Stream_Read(s, encsig, siglen);
767
768
0
  if (siglen < 8)
769
0
  {
770
0
    WLog_WARN(TAG, "public signature too short: %" PRIu32, siglen);
771
0
    return FALSE;
772
0
  }
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
0
  return TRUE;
827
0
}
828
829
static BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate, wStream* s)
830
124
{
831
124
  UINT32 dwSigAlgId = 0;
832
124
  UINT32 dwKeyAlgId = 0;
833
124
  UINT16 wPublicKeyBlobType = 0;
834
124
  UINT16 wPublicKeyBlobLen = 0;
835
124
  UINT16 wSignatureBlobType = 0;
836
124
  UINT16 wSignatureBlobLen = 0;
837
124
  size_t sigdatalen = 0;
838
839
124
  WINPR_ASSERT(certificate);
840
124
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
841
2
    return FALSE;
842
843
  /* -4, because we need to include dwVersion */
844
122
  const BYTE* sigdata = Stream_PointerAs(s, const BYTE) - 4;
845
122
  Stream_Read_UINT32(s, dwSigAlgId);
846
122
  Stream_Read_UINT32(s, dwKeyAlgId);
847
848
122
  if (!((dwSigAlgId == SIGNATURE_ALG_RSA) && (dwKeyAlgId == KEY_EXCHANGE_ALG_RSA)))
849
117
  {
850
117
    WLog_ERR(TAG,
851
117
             "unsupported signature or key algorithm, dwSigAlgId=%" PRIu32
852
117
             " dwKeyAlgId=%" PRIu32 "",
853
117
             dwSigAlgId, dwKeyAlgId);
854
117
    return FALSE;
855
117
  }
856
857
5
  Stream_Read_UINT16(s, wPublicKeyBlobType);
858
859
5
  if (wPublicKeyBlobType != BB_RSA_KEY_BLOB)
860
3
  {
861
3
    WLog_ERR(TAG, "unsupported public key blob type %" PRIu16 "", wPublicKeyBlobType);
862
3
    return FALSE;
863
3
  }
864
865
2
  Stream_Read_UINT16(s, wPublicKeyBlobLen);
866
867
2
  if (!Stream_CheckAndLogRequiredLength(TAG, s, wPublicKeyBlobLen))
868
1
    return FALSE;
869
870
1
  if (!certificate_process_server_public_key(certificate, s, wPublicKeyBlobLen))
871
1
    return FALSE;
872
873
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
874
0
    return FALSE;
875
876
0
  sigdatalen = WINPR_ASSERTING_INT_CAST(size_t, Stream_PointerAs(s, const BYTE) - sigdata);
877
0
  Stream_Read_UINT16(s, wSignatureBlobType);
878
879
0
  if (wSignatureBlobType != BB_RSA_SIGNATURE_BLOB)
880
0
  {
881
0
    WLog_ERR(TAG, "unsupported blob signature %" PRIu16 "", wSignatureBlobType);
882
0
    return FALSE;
883
0
  }
884
885
0
  Stream_Read_UINT16(s, wSignatureBlobLen);
886
887
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, wSignatureBlobLen))
888
0
    return FALSE;
889
890
0
  if (wSignatureBlobLen != 72)
891
0
  {
892
0
    WLog_ERR(TAG, "invalid signature length (got %" PRIu16 ", expected 72)", wSignatureBlobLen);
893
0
    return FALSE;
894
0
  }
895
896
0
  if (!certificate_process_server_public_signature(certificate, sigdata, sigdatalen, s,
897
0
                                                   wSignatureBlobLen))
898
0
  {
899
0
    WLog_ERR(TAG, "unable to parse server public signature");
900
0
    return FALSE;
901
0
  }
902
0
  return TRUE;
903
0
}
904
905
/* [MS-RDPBCGR] 2.2.1.4.3.1.1.1 RSA Public Key (RSA_PUBLIC_KEY) */
906
static BOOL cert_write_rsa_public_key(wStream* s, const rdpCertificate* cert)
907
0
{
908
0
  WINPR_ASSERT(cert);
909
0
  WINPR_ASSERT(freerdp_certificate_is_rsa(cert));
910
911
0
  const rdpCertInfo* info = &cert->cert_info;
912
913
0
  const UINT32 keyLen = info->ModulusLength + 8;
914
0
  const UINT32 bitLen = info->ModulusLength * 8;
915
0
  const UINT32 dataLen = (bitLen / 8) - 1;
916
0
  const size_t pubExpLen = sizeof(info->exponent);
917
0
  const BYTE* pubExp = info->exponent;
918
0
  const BYTE* modulus = info->Modulus;
919
920
0
  const size_t wPublicKeyBlobLen = 16 + pubExpLen + keyLen;
921
0
  WINPR_ASSERT(wPublicKeyBlobLen <= UINT16_MAX);
922
0
  if (!Stream_EnsureRemainingCapacity(s, 2 + wPublicKeyBlobLen))
923
0
    return FALSE;
924
0
  Stream_Write_UINT16(s, (UINT16)wPublicKeyBlobLen);
925
0
  Stream_Write(s, rsa_magic, sizeof(rsa_magic));
926
0
  Stream_Write_UINT32(s, keyLen);
927
0
  Stream_Write_UINT32(s, bitLen);
928
0
  Stream_Write_UINT32(s, dataLen);
929
0
  Stream_Write(s, pubExp, pubExpLen);
930
0
  Stream_Write(s, modulus, info->ModulusLength);
931
0
  Stream_Zero(s, 8);
932
0
  return TRUE;
933
0
}
934
935
static BOOL cert_write_rsa_signature(wStream* s, const void* sigData, size_t sigDataLen)
936
0
{
937
0
  BYTE encryptedSignature[TSSK_KEY_LENGTH] = WINPR_C_ARRAY_INIT;
938
0
  BYTE signature[sizeof(initial_signature)] = WINPR_C_ARRAY_INIT;
939
940
0
  memcpy(signature, initial_signature, sizeof(initial_signature));
941
0
  if (!winpr_Digest(WINPR_MD_MD5, sigData, sigDataLen, signature, sizeof(signature)))
942
0
    return FALSE;
943
944
0
  if (crypto_rsa_private_encrypt(signature, sizeof(signature), priv_key_tssk, encryptedSignature,
945
0
                                 sizeof(encryptedSignature)) < 0)
946
0
    return FALSE;
947
948
0
  if (!Stream_EnsureRemainingCapacity(s, 2 * sizeof(UINT16) + sizeof(encryptedSignature) + 8))
949
0
    return FALSE;
950
0
  Stream_Write_UINT16(s, BB_RSA_SIGNATURE_BLOB);
951
0
  Stream_Write_UINT16(s, sizeof(encryptedSignature) + 8); /* wSignatureBlobLen */
952
0
  Stream_Write(s, encryptedSignature, sizeof(encryptedSignature));
953
0
  Stream_Zero(s, 8);
954
0
  return TRUE;
955
0
}
956
957
/* [MS-RDPBCGR] 2.2.1.4.3.1.1 Server Proprietary Certificate (PROPRIETARYSERVERCERTIFICATE) */
958
static BOOL cert_write_server_certificate_v1(wStream* s, const rdpCertificate* certificate)
959
0
{
960
0
  const size_t start = Stream_GetPosition(s);
961
0
  const BYTE* sigData = Stream_PointerAs(s, const BYTE) - sizeof(UINT32);
962
963
0
  WINPR_ASSERT(start >= 4);
964
0
  if (!Stream_EnsureRemainingCapacity(s, 10))
965
0
    return FALSE;
966
0
  Stream_Write_UINT32(s, SIGNATURE_ALG_RSA);
967
0
  Stream_Write_UINT32(s, KEY_EXCHANGE_ALG_RSA);
968
0
  Stream_Write_UINT16(s, BB_RSA_KEY_BLOB);
969
0
  if (!cert_write_rsa_public_key(s, certificate))
970
0
    return FALSE;
971
972
0
  const size_t end = Stream_GetPosition(s);
973
0
  return cert_write_rsa_signature(s, sigData, end - start + sizeof(UINT32));
974
0
}
975
976
static BOOL cert_write_server_certificate_v2(wStream* s, const rdpCertificate* certificate)
977
0
{
978
0
  WINPR_ASSERT(certificate);
979
980
0
  const rdpX509CertChain* chain = &certificate->x509_cert_chain;
981
0
  const size_t padding = 8ull + 4ull * chain->count;
982
983
0
  if (!Stream_EnsureRemainingCapacity(s, sizeof(UINT32)))
984
0
    return FALSE;
985
986
0
  Stream_Write_UINT32(s, chain->count);
987
0
  for (UINT32 x = 0; x < chain->count; x++)
988
0
  {
989
0
    const rdpCertBlob* cert = &chain->array[x];
990
0
    if (!cert_blob_write(cert, s))
991
0
      return FALSE;
992
0
  }
993
994
0
  if (!Stream_EnsureRemainingCapacity(s, padding))
995
0
    return FALSE;
996
0
  Stream_Zero(s, padding);
997
0
  return TRUE;
998
0
}
999
1000
SSIZE_T freerdp_certificate_write_server_cert(const rdpCertificate* certificate, UINT32 dwVersion,
1001
                                              wStream* s)
1002
0
{
1003
0
  if (!certificate)
1004
0
    return -1;
1005
1006
0
  const size_t start = Stream_GetPosition(s);
1007
0
  if (!Stream_EnsureRemainingCapacity(s, 4))
1008
0
    return -1;
1009
0
  Stream_Write_UINT32(s, dwVersion);
1010
1011
0
  switch (dwVersion & CERT_CHAIN_VERSION_MASK)
1012
0
  {
1013
0
    case CERT_CHAIN_VERSION_1:
1014
0
      if (!cert_write_server_certificate_v1(s, certificate))
1015
0
        return -1;
1016
0
      break;
1017
0
    case CERT_CHAIN_VERSION_2:
1018
0
      if (!cert_write_server_certificate_v2(s, certificate))
1019
0
        return -1;
1020
0
      break;
1021
0
    default:
1022
0
      WLog_ERR(TAG, "invalid certificate chain version:%" PRIu32 "",
1023
0
               dwVersion & CERT_CHAIN_VERSION_MASK);
1024
0
      return -1;
1025
0
  }
1026
1027
0
  const size_t end = Stream_GetPosition(s);
1028
0
  if (start > end)
1029
0
    return -1;
1030
1031
0
  const size_t diff = end - start;
1032
0
  WINPR_ASSERT(diff <= SSIZE_MAX);
1033
0
  return (SSIZE_T)diff;
1034
0
}
1035
1036
/**
1037
 * Read an X.509 Certificate Chain.
1038
 * @param cert certificate module
1039
 * @param s stream
1040
 * @return \b TRUE for success, \b FALSE otherwise.
1041
 */
1042
1043
static BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* cert, wStream* s)
1044
63
{
1045
63
  UINT32 numCertBlobs = 0;
1046
63
  DEBUG_CERTIFICATE("Server X.509 Certificate Chain");
1047
1048
63
  WINPR_ASSERT(cert);
1049
63
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
1050
2
    return FALSE;
1051
1052
61
  Stream_Read_UINT32(s, numCertBlobs); /* numCertBlobs */
1053
61
  certificate_free_x509_certificate_chain(&cert->x509_cert_chain);
1054
61
  if (!certificate_new_x509_certificate_chain(numCertBlobs, s, &cert->x509_cert_chain))
1055
45
    return FALSE;
1056
1057
20
  for (UINT32 i = 0; i < cert->x509_cert_chain.count; i++)
1058
18
  {
1059
18
    rdpCertBlob* blob = &cert->x509_cert_chain.array[i];
1060
18
    if (!cert_blob_read(blob, s))
1061
4
      return FALSE;
1062
1063
14
    if (numCertBlobs - i == 1)
1064
10
    {
1065
10
      DEBUG_CERTIFICATE("Terminal Server Certificate");
1066
1067
10
      BOOL res = certificate_read_x509_certificate(blob, &cert->cert_info);
1068
1069
10
      if (res)
1070
0
      {
1071
0
        if (!update_x509_from_info(cert))
1072
0
          res = FALSE;
1073
0
      }
1074
1075
10
      if (!res)
1076
10
      {
1077
10
        WLog_ERR(TAG, "Failed to read x509 certificate");
1078
10
        return FALSE;
1079
10
      }
1080
1081
0
      DEBUG_CERTIFICATE("modulus length:%" PRIu32 "", cert->cert_info.ModulusLength);
1082
0
    }
1083
14
  }
1084
1085
2
  return update_x509_from_info(cert);
1086
16
}
1087
1088
/**
1089
 * Read a Server Certificate.
1090
 * @param certificate certificate module
1091
 * @param server_cert server certificate
1092
 * @param length certificate length
1093
 */
1094
1095
BOOL freerdp_certificate_read_server_cert(rdpCertificate* certificate, const BYTE* server_cert,
1096
                                          size_t length)
1097
210
{
1098
210
  BOOL ret = FALSE;
1099
210
  wStream* s = nullptr;
1100
210
  wStream sbuffer;
1101
210
  UINT32 dwVersion = 0;
1102
1103
210
  WINPR_ASSERT(certificate);
1104
210
  if (length < 4) /* nullptr certificate is not an error see #1795 */
1105
17
  {
1106
17
    WLog_DBG(TAG, "Received empty certificate, ignoring...");
1107
17
    return TRUE;
1108
17
  }
1109
1110
193
  WINPR_ASSERT(server_cert);
1111
193
  s = Stream_StaticConstInit(&sbuffer, server_cert, length);
1112
1113
193
  if (!s)
1114
0
  {
1115
0
    WLog_ERR(TAG, "Stream_New failed!");
1116
0
    return FALSE;
1117
0
  }
1118
1119
193
  Stream_Read_UINT32(s, dwVersion); /* dwVersion (4 bytes) */
1120
1121
193
  switch (dwVersion & CERT_CHAIN_VERSION_MASK)
1122
193
  {
1123
124
    case CERT_CHAIN_VERSION_1:
1124
124
      ret = certificate_read_server_proprietary_certificate(certificate, s);
1125
124
      break;
1126
1127
63
    case CERT_CHAIN_VERSION_2:
1128
63
      ret = certificate_read_server_x509_certificate_chain(certificate, s);
1129
63
      break;
1130
1131
6
    default:
1132
6
      WLog_ERR(TAG, "invalid certificate chain version:%" PRIu32 "",
1133
6
               dwVersion & CERT_CHAIN_VERSION_MASK);
1134
6
      ret = FALSE;
1135
6
      break;
1136
193
  }
1137
1138
193
  return ret;
1139
193
}
1140
1141
static BOOL cert_blob_copy(rdpCertBlob* dst, const rdpCertBlob* src)
1142
0
{
1143
0
  WINPR_ASSERT(dst);
1144
0
  WINPR_ASSERT(src);
1145
1146
0
  cert_blob_free(dst);
1147
0
  if (src->length > 0)
1148
0
  {
1149
0
    dst->data = malloc(src->length);
1150
0
    if (!dst->data)
1151
0
      return FALSE;
1152
0
    dst->length = src->length;
1153
0
    memcpy(dst->data, src->data, src->length);
1154
0
  }
1155
1156
0
  return TRUE;
1157
0
}
1158
1159
static BOOL cert_x509_chain_copy(rdpX509CertChain* cert, const rdpX509CertChain* src)
1160
17.9k
{
1161
17.9k
  WINPR_ASSERT(cert);
1162
1163
17.9k
  certificate_free_x509_certificate_chain(cert);
1164
17.9k
  if (!src)
1165
0
    return TRUE;
1166
1167
17.9k
  if (src->count > 0)
1168
0
  {
1169
0
    cert->array = calloc(src->count, sizeof(rdpCertBlob));
1170
0
    if (!cert->array)
1171
0
    {
1172
0
      return FALSE;
1173
0
    }
1174
0
    cert->count = src->count;
1175
1176
0
    for (UINT32 x = 0; x < cert->count; x++)
1177
0
    {
1178
0
      const rdpCertBlob* srcblob = &src->array[x];
1179
0
      rdpCertBlob* dstblob = &cert->array[x];
1180
1181
0
      if (!cert_blob_copy(dstblob, srcblob))
1182
0
      {
1183
0
        certificate_free_x509_certificate_chain(cert);
1184
0
        return FALSE;
1185
0
      }
1186
0
    }
1187
0
  }
1188
1189
17.9k
  return TRUE;
1190
17.9k
}
1191
1192
BOOL cert_clone_int(rdpCertificate* dst, const rdpCertificate* src)
1193
17.9k
{
1194
17.9k
  WINPR_ASSERT(dst);
1195
17.9k
  WINPR_ASSERT(src);
1196
1197
17.9k
  if (!cert_info_clone(&dst->cert_info, &src->cert_info))
1198
0
    return FALSE;
1199
1200
17.9k
  if (src->x509)
1201
0
  {
1202
0
    dst->x509 = X509_dup(src->x509);
1203
0
    if (!dst->x509)
1204
0
    {
1205
      /* Workaround for SSL deprecation issues:
1206
       * some security modes use weak RSA ciphers where X509_dup fails.
1207
       * In that case recreate the X509 from the raw RSA data
1208
       */
1209
0
      if (!update_x509_from_info(dst))
1210
0
      {
1211
0
        WLog_ERR(TAG, "X509_dup failed, SSL configuration bug?");
1212
0
        return FALSE;
1213
0
      }
1214
0
    }
1215
0
  }
1216
1217
17.9k
  if (src->chain)
1218
0
  {
1219
0
    if (dst->chain)
1220
0
      sk_X509_pop_free(dst->chain, X509_free);
1221
1222
0
    dst->chain = sk_X509_deep_copy(src->chain, X509_const_dup, X509_free);
1223
0
  }
1224
17.9k
  return cert_x509_chain_copy(&dst->x509_cert_chain, &src->x509_cert_chain);
1225
17.9k
}
1226
1227
rdpCertificate* freerdp_certificate_clone(const rdpCertificate* certificate)
1228
17.9k
{
1229
17.9k
  if (!certificate)
1230
0
    return nullptr;
1231
1232
17.9k
  rdpCertificate* _certificate = freerdp_certificate_new();
1233
1234
17.9k
  if (!_certificate)
1235
0
    return nullptr;
1236
1237
17.9k
  if (!cert_clone_int(_certificate, certificate))
1238
0
    goto out_fail;
1239
1240
17.9k
  return _certificate;
1241
0
out_fail:
1242
1243
0
  freerdp_certificate_free(_certificate);
1244
0
  return nullptr;
1245
17.9k
}
1246
1247
/**
1248
 * Instantiate new certificate module.
1249
 * @return new certificate module
1250
 */
1251
1252
rdpCertificate* freerdp_certificate_new(void)
1253
108k
{
1254
108k
  return (rdpCertificate*)calloc(1, sizeof(rdpCertificate));
1255
108k
}
1256
1257
void certificate_free_int(rdpCertificate* cert)
1258
108k
{
1259
108k
  WINPR_ASSERT(cert);
1260
1261
108k
  if (cert->x509)
1262
107
    X509_free(cert->x509);
1263
108k
  if (cert->chain)
1264
91
    sk_X509_pop_free(cert->chain, X509_free);
1265
1266
108k
  certificate_free_x509_certificate_chain(&cert->x509_cert_chain);
1267
108k
  cert_info_free(&cert->cert_info);
1268
108k
}
1269
1270
/**
1271
 * Free certificate module.
1272
 * @param cert certificate module to be freed
1273
 */
1274
1275
void freerdp_certificate_free(rdpCertificate* cert)
1276
342k
{
1277
342k
  if (!cert)
1278
234k
    return;
1279
1280
108k
  certificate_free_int(cert);
1281
108k
  free(cert);
1282
108k
}
1283
1284
static BOOL freerdp_rsa_from_x509(rdpCertificate* cert)
1285
105
{
1286
105
  BOOL rc = FALSE;
1287
1288
105
  WINPR_ASSERT(cert);
1289
1290
105
  if (!freerdp_certificate_is_rsa(cert))
1291
73
    return TRUE;
1292
1293
32
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1294
32
  RSA* rsa = nullptr;
1295
32
  const BIGNUM* rsa_n = nullptr;
1296
32
  const BIGNUM* rsa_e = nullptr;
1297
#else
1298
  BIGNUM* rsa_n = nullptr;
1299
  BIGNUM* rsa_e = nullptr;
1300
#endif
1301
32
  EVP_PKEY* pubkey = X509_get0_pubkey(cert->x509);
1302
32
  if (!pubkey)
1303
0
    goto fail;
1304
1305
32
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1306
32
  rsa = EVP_PKEY_get1_RSA(pubkey);
1307
1308
  /* If this is not a RSA key return success */
1309
32
  rc = TRUE;
1310
32
  if (!rsa)
1311
0
    goto fail;
1312
1313
  /* Now we return failure again if something is wrong. */
1314
32
  rc = FALSE;
1315
1316
32
  RSA_get0_key(rsa, &rsa_n, &rsa_e, nullptr);
1317
#else
1318
  if (!EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_E, &rsa_e))
1319
    goto fail;
1320
  if (!EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_N, &rsa_n))
1321
    goto fail;
1322
#endif
1323
32
  if (!rsa_n || !rsa_e)
1324
0
    goto fail;
1325
32
  if (!cert_info_create(&cert->cert_info, rsa_n, rsa_e))
1326
13
    goto fail;
1327
19
  rc = TRUE;
1328
32
fail:
1329
32
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1330
32
  RSA_free(rsa);
1331
#else
1332
  BN_free(rsa_n);
1333
  BN_free(rsa_e);
1334
#endif
1335
32
  return rc;
1336
19
}
1337
1338
rdpCertificate* freerdp_certificate_new_from_der(const BYTE* data, size_t length)
1339
0
{
1340
0
  rdpCertificate* cert = freerdp_certificate_new();
1341
1342
0
  if (!cert || !data || (length == 0) || (length > INT_MAX))
1343
0
    goto fail;
1344
1345
0
  {
1346
0
    const BYTE* ptr = data;
1347
0
    cert->x509 = d2i_X509(nullptr, &ptr, (int)length);
1348
0
  }
1349
1350
0
  if (!cert->x509)
1351
0
    goto fail;
1352
0
  if (!freerdp_rsa_from_x509(cert))
1353
0
    goto fail;
1354
0
  return cert;
1355
0
fail:
1356
0
  freerdp_certificate_free(cert);
1357
0
  return nullptr;
1358
0
}
1359
1360
rdpCertificate* freerdp_certificate_new_from_x509(const X509* xcert, const STACK_OF(X509) * chain)
1361
108
{
1362
108
  WINPR_ASSERT(xcert);
1363
1364
108
  rdpCertificate* cert = freerdp_certificate_new();
1365
108
  if (!cert)
1366
0
    return nullptr;
1367
1368
108
  X509* wcert = WINPR_CAST_CONST_PTR_AWAY(xcert, X509*);
1369
108
  cert->x509 = X509_dup(wcert);
1370
108
  if (!cert->x509)
1371
3
    goto fail;
1372
1373
105
  if (!freerdp_rsa_from_x509(cert))
1374
13
    goto fail;
1375
1376
92
  if (chain)
1377
92
    cert->chain = sk_X509_deep_copy(chain, X509_const_dup, X509_free);
1378
1379
92
  return cert;
1380
16
fail:
1381
16
  freerdp_certificate_free(cert);
1382
16
  return nullptr;
1383
105
}
1384
1385
static STACK_OF(X509) * extract_chain_from_pem(const char* pem, BOOL isFile)
1386
108
{
1387
108
  if (!pem)
1388
0
  {
1389
0
    return nullptr;
1390
0
  }
1391
1392
108
  BIO* bio = nullptr;
1393
108
  if (isFile)
1394
0
    bio = BIO_new_file(pem, "rb");
1395
108
  else
1396
108
  {
1397
108
    const size_t len = strlen(pem);
1398
108
    bio = BIO_new_mem_buf(pem, WINPR_ASSERTING_INT_CAST(int, len));
1399
108
  }
1400
1401
108
  if (!bio)
1402
0
  {
1403
0
    return nullptr;
1404
0
  }
1405
1406
108
  X509* leaf = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
1407
108
  if (!leaf)
1408
0
  {
1409
0
    BIO_free(bio);
1410
0
    return nullptr;
1411
0
  }
1412
1413
108
  STACK_OF(X509)* chain = sk_X509_new_null();
1414
108
  if (!chain)
1415
0
  {
1416
0
    X509_free(leaf);
1417
0
    BIO_free(bio);
1418
0
    return nullptr;
1419
0
  }
1420
1421
108
  X509* cert = nullptr;
1422
8.45k
  while ((cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr)) != nullptr)
1423
8.34k
  {
1424
8.34k
    sk_X509_push(chain, cert);
1425
8.34k
  }
1426
1427
108
  X509_free(leaf);
1428
108
  BIO_free(bio);
1429
108
  return chain;
1430
108
}
1431
1432
static rdpCertificate* freerdp_certificate_new_from(const char* file, BOOL isFile)
1433
1.02k
{
1434
1.02k
  X509* x509 = x509_utils_from_pem(file, strlen(file), isFile);
1435
1.02k
  if (!x509)
1436
917
    return nullptr;
1437
1.02k
  STACK_OF(X509)* chain = extract_chain_from_pem(file, isFile);
1438
108
  rdpCertificate* cert = freerdp_certificate_new_from_x509(x509, chain);
1439
108
  if (chain)
1440
108
    sk_X509_pop_free(chain, X509_free);
1441
108
  X509_free(x509);
1442
108
  return cert;
1443
1.02k
}
1444
1445
rdpCertificate* freerdp_certificate_new_from_file(const char* file)
1446
0
{
1447
0
  return freerdp_certificate_new_from(file, TRUE);
1448
0
}
1449
1450
rdpCertificate* freerdp_certificate_new_from_pem(const char* pem)
1451
1.02k
{
1452
1.02k
  return freerdp_certificate_new_from(pem, FALSE);
1453
1.02k
}
1454
1455
const rdpCertInfo* freerdp_certificate_get_info(const rdpCertificate* cert)
1456
0
{
1457
0
  WINPR_ASSERT(cert);
1458
0
  if (!freerdp_certificate_is_rsa(cert))
1459
0
    return nullptr;
1460
0
  return &cert->cert_info;
1461
0
}
1462
1463
char* freerdp_certificate_get_fingerprint(const rdpCertificate* cert)
1464
92
{
1465
92
  return freerdp_certificate_get_fingerprint_by_hash(cert, "sha256");
1466
92
}
1467
1468
char* freerdp_certificate_get_fingerprint_by_hash(const rdpCertificate* cert, const char* hash)
1469
92
{
1470
92
  return freerdp_certificate_get_fingerprint_by_hash_ex(cert, hash, TRUE);
1471
92
}
1472
1473
char* freerdp_certificate_get_fingerprint_by_hash_ex(const rdpCertificate* cert, const char* hash,
1474
                                                     BOOL separator)
1475
92
{
1476
92
  size_t fp_len = 0;
1477
92
  size_t pos = 0;
1478
92
  size_t size = 0;
1479
92
  BYTE* fp = nullptr;
1480
92
  char* fp_buffer = nullptr;
1481
92
  if (!cert || !cert->x509)
1482
0
  {
1483
0
    WLog_ERR(TAG, "Invalid certificate [%p, %p]", WINPR_CXX_COMPAT_CAST(const void*, cert),
1484
0
             WINPR_CXX_COMPAT_CAST(const void*, cert ? cert->x509 : nullptr));
1485
0
    return nullptr;
1486
0
  }
1487
92
  if (!hash)
1488
0
  {
1489
0
    WLog_ERR(TAG, "Invalid certificate hash %p", WINPR_CXX_COMPAT_CAST(const void*, hash));
1490
0
    return nullptr;
1491
0
  }
1492
92
  fp = x509_utils_get_hash(cert->x509, hash, &fp_len);
1493
92
  if (!fp)
1494
0
    return nullptr;
1495
1496
92
  if (fp_len < 1)
1497
0
    goto fail;
1498
1499
92
  size = fp_len * 3 + 1;
1500
92
  fp_buffer = calloc(size, sizeof(char));
1501
92
  if (!fp_buffer)
1502
0
    goto fail;
1503
1504
92
  pos = 0;
1505
1506
92
  {
1507
92
    size_t i = 0;
1508
2.94k
    for (; i < (fp_len - 1); i++)
1509
2.85k
    {
1510
2.85k
      int rc = 0;
1511
2.85k
      char* p = &fp_buffer[pos];
1512
2.85k
      if (separator)
1513
2.85k
        rc = sprintf_s(p, size - pos, "%02" PRIx8 ":", fp[i]);
1514
0
      else
1515
0
        rc = sprintf_s(p, size - pos, "%02" PRIx8, fp[i]);
1516
2.85k
      if (rc <= 0)
1517
0
        goto fail;
1518
2.85k
      pos += (size_t)rc;
1519
2.85k
    }
1520
1521
92
    (void)sprintf_s(&fp_buffer[pos], size - pos, "%02" PRIx8 "", fp[i]);
1522
92
  }
1523
1524
0
  free(fp);
1525
1526
92
  return fp_buffer;
1527
0
fail:
1528
0
  free(fp);
1529
0
  free(fp_buffer);
1530
0
  return nullptr;
1531
92
}
1532
1533
char* freerdp_certificate_get_pem(const rdpCertificate* cert, size_t* pLength)
1534
0
{
1535
0
  return freerdp_certificate_get_pem_ex(cert, pLength, TRUE);
1536
0
}
1537
1538
char* freerdp_certificate_get_pem_ex(const rdpCertificate* cert, size_t* pLength,
1539
                                     BOOL withCertChain)
1540
184
{
1541
184
  WINPR_ASSERT(cert);
1542
1543
184
  if (!cert->x509)
1544
0
    return nullptr;
1545
1546
  /**
1547
   * Don't manage certificates internally, leave it up entirely to the external client
1548
   * implementation
1549
   */
1550
184
  BIO* bio = BIO_new(BIO_s_mem());
1551
1552
184
  if (!bio)
1553
0
  {
1554
0
    WLog_ERR(TAG, "BIO_new() failure");
1555
0
    return nullptr;
1556
0
  }
1557
1558
184
  char* pem = nullptr;
1559
1560
184
  const int status = PEM_write_bio_X509(bio, cert->x509);
1561
184
  if (status < 0)
1562
0
  {
1563
0
    WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", status);
1564
0
    goto fail;
1565
0
  }
1566
1567
184
  if (cert->chain && withCertChain)
1568
91
  {
1569
91
    const int count = sk_X509_num(cert->chain);
1570
8.43k
    for (int x = 0; x < count; x++)
1571
8.34k
    {
1572
8.34k
      X509* c = sk_X509_value(cert->chain, x);
1573
8.34k
      const int rc = PEM_write_bio_X509(bio, c);
1574
8.34k
      if (rc < 0)
1575
0
      {
1576
0
        WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", rc);
1577
0
        goto fail;
1578
0
      }
1579
8.34k
    }
1580
91
  }
1581
1582
184
  pem = x509_utils_bio_read(bio, pLength);
1583
1584
184
fail:
1585
184
  BIO_free_all(bio);
1586
184
  return pem;
1587
184
}
1588
1589
char* freerdp_certificate_get_subject(const rdpCertificate* cert)
1590
92
{
1591
92
  WINPR_ASSERT(cert);
1592
92
  return x509_utils_get_subject(cert->x509);
1593
92
}
1594
1595
char* freerdp_certificate_get_issuer(const rdpCertificate* cert)
1596
92
{
1597
92
  WINPR_ASSERT(cert);
1598
92
  return x509_utils_get_issuer(cert->x509);
1599
92
}
1600
1601
char* freerdp_certificate_get_upn(const rdpCertificate* cert)
1602
0
{
1603
0
  WINPR_ASSERT(cert);
1604
0
  return x509_utils_get_upn(cert->x509);
1605
0
}
1606
1607
char* freerdp_certificate_get_email(const rdpCertificate* cert)
1608
0
{
1609
0
  WINPR_ASSERT(cert);
1610
0
  return x509_utils_get_email(cert->x509);
1611
0
}
1612
1613
char* freerdp_certificate_get_validity(const rdpCertificate* cert, BOOL startDate)
1614
0
{
1615
0
  WINPR_ASSERT(cert);
1616
0
  return x509_utils_get_date(cert->x509, startDate);
1617
0
}
1618
1619
BOOL freerdp_certificate_check_eku(const rdpCertificate* cert, int nid)
1620
0
{
1621
0
  WINPR_ASSERT(cert);
1622
0
  return x509_utils_check_eku(cert->x509, nid);
1623
0
}
1624
1625
BOOL freerdp_certificate_get_public_key(const rdpCertificate* cert, BYTE** PublicKey,
1626
                                        DWORD* PublicKeyLength)
1627
0
{
1628
0
  BYTE* ptr = nullptr;
1629
0
  BYTE* optr = nullptr;
1630
0
  int length = 0;
1631
0
  BOOL status = FALSE;
1632
0
  EVP_PKEY* pkey = nullptr;
1633
1634
0
  WINPR_ASSERT(cert);
1635
1636
0
  pkey = X509_get0_pubkey(cert->x509);
1637
1638
0
  if (!pkey)
1639
0
  {
1640
0
    WLog_ERR(TAG, "X509_get_pubkey() failed");
1641
0
    goto exit;
1642
0
  }
1643
1644
0
  length = i2d_PublicKey(pkey, nullptr);
1645
1646
0
  if (length < 1)
1647
0
  {
1648
0
    WLog_ERR(TAG, "i2d_PublicKey() failed");
1649
0
    goto exit;
1650
0
  }
1651
1652
0
  *PublicKey = optr = ptr = (BYTE*)calloc(WINPR_ASSERTING_INT_CAST(size_t, length), sizeof(BYTE));
1653
1654
0
  if (!ptr)
1655
0
    goto exit;
1656
1657
0
  {
1658
0
    const int length2 = i2d_PublicKey(pkey, &ptr);
1659
0
    if (length != length2)
1660
0
      goto exit;
1661
0
    *PublicKeyLength = (DWORD)length2;
1662
0
  }
1663
0
  status = TRUE;
1664
0
exit:
1665
1666
0
  if (!status)
1667
0
    free(optr);
1668
1669
0
  return status;
1670
0
}
1671
1672
BOOL freerdp_certificate_verify(const rdpCertificate* cert, const char* certificate_store_path)
1673
0
{
1674
0
  WINPR_ASSERT(cert);
1675
0
  return x509_utils_verify(cert->x509, cert->chain, certificate_store_path);
1676
0
}
1677
1678
char** freerdp_certificate_get_dns_names(const rdpCertificate* cert, size_t* pcount,
1679
                                         size_t** pplengths)
1680
0
{
1681
0
  WINPR_ASSERT(cert);
1682
0
  return x509_utils_get_dns_names(cert->x509, pcount, pplengths);
1683
0
}
1684
1685
char* freerdp_certificate_get_common_name(const rdpCertificate* cert, size_t* plength)
1686
0
{
1687
0
  WINPR_ASSERT(cert);
1688
0
  return x509_utils_get_common_name(cert->x509, plength);
1689
0
}
1690
1691
WINPR_MD_TYPE freerdp_certificate_get_signature_alg(const rdpCertificate* cert)
1692
0
{
1693
0
  WINPR_ASSERT(cert);
1694
0
  return x509_utils_get_signature_alg(cert->x509);
1695
0
}
1696
1697
void freerdp_certificate_free_dns_names(size_t count, size_t* lengths, char** names)
1698
0
{
1699
0
  x509_utils_dns_names_free(count, lengths, names);
1700
0
}
1701
1702
char* freerdp_certificate_get_hash(const rdpCertificate* cert, const char* hash, size_t* plength)
1703
0
{
1704
0
  WINPR_ASSERT(cert);
1705
0
  return (char*)x509_utils_get_hash(cert->x509, hash, plength);
1706
0
}
1707
1708
X509* freerdp_certificate_get_x509(rdpCertificate* cert)
1709
0
{
1710
0
  WINPR_ASSERT(cert);
1711
0
  return cert->x509;
1712
0
}
1713
1714
BOOL freerdp_certificate_publickey_encrypt(const rdpCertificate* cert, const BYTE* input,
1715
                                           size_t cbInput, BYTE** poutput, size_t* pcbOutput)
1716
0
{
1717
0
  WINPR_ASSERT(cert);
1718
0
  WINPR_ASSERT(input);
1719
0
  WINPR_ASSERT(poutput);
1720
0
  WINPR_ASSERT(pcbOutput);
1721
1722
0
  BOOL ret = FALSE;
1723
0
  BYTE* output = nullptr;
1724
0
  EVP_PKEY* pkey = X509_get0_pubkey(cert->x509);
1725
0
  if (!pkey)
1726
0
    return FALSE;
1727
1728
0
  EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, nullptr);
1729
0
  if (!ctx)
1730
0
    return FALSE;
1731
1732
0
  size_t outputSize = WINPR_ASSERTING_INT_CAST(size_t, EVP_PKEY_size(pkey));
1733
0
  output = malloc(outputSize);
1734
0
  if (output == nullptr)
1735
0
    goto out;
1736
0
  *pcbOutput = outputSize;
1737
1738
0
  if (EVP_PKEY_encrypt_init(ctx) != 1 ||
1739
0
      EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) != 1 ||
1740
0
      EVP_PKEY_encrypt(ctx, output, pcbOutput, input, cbInput) != 1)
1741
0
  {
1742
0
    WLog_ERR(TAG, "error when setting up public key");
1743
0
    goto out;
1744
0
  }
1745
1746
0
  *poutput = output;
1747
0
  output = nullptr;
1748
0
  ret = TRUE;
1749
0
out:
1750
0
  EVP_PKEY_CTX_free(ctx);
1751
0
  free(output);
1752
0
  return ret;
1753
0
}
1754
1755
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1756
static RSA* freerdp_certificate_get_RSA(const rdpCertificate* cert)
1757
0
{
1758
0
  WINPR_ASSERT(cert);
1759
1760
0
  if (!freerdp_certificate_is_rsa(cert))
1761
0
    return nullptr;
1762
1763
0
  EVP_PKEY* pubkey = X509_get0_pubkey(cert->x509);
1764
0
  if (!pubkey)
1765
0
    return nullptr;
1766
1767
0
  return EVP_PKEY_get1_RSA(pubkey);
1768
0
}
1769
#endif
1770
1771
BYTE* freerdp_certificate_get_der(const rdpCertificate* cert, size_t* pLength)
1772
0
{
1773
0
  WINPR_ASSERT(cert);
1774
1775
0
  if (pLength)
1776
0
    *pLength = 0;
1777
1778
0
  const int rc = i2d_X509(cert->x509, nullptr);
1779
0
  if (rc <= 0)
1780
0
    return nullptr;
1781
1782
0
  BYTE* ptr = calloc(WINPR_ASSERTING_INT_CAST(size_t, rc) + 1, sizeof(BYTE));
1783
0
  if (!ptr)
1784
0
    return nullptr;
1785
0
  BYTE* i2d_ptr = ptr;
1786
1787
0
  const int rc2 = i2d_X509(cert->x509, &i2d_ptr);
1788
0
  if (rc2 <= 0)
1789
0
  {
1790
0
    free(ptr);
1791
0
    return nullptr;
1792
0
  }
1793
1794
0
  if (pLength)
1795
0
    *pLength = (size_t)rc2;
1796
0
  return ptr;
1797
0
}
1798
1799
BOOL freerdp_certificate_is_rsa(const rdpCertificate* cert)
1800
105
{
1801
105
  WINPR_ASSERT(cert);
1802
105
  return is_rsa_key(cert->x509);
1803
105
}
1804
1805
BOOL freerdp_certificate_is_rdp_security_compatible(const rdpCertificate* cert)
1806
0
{
1807
0
  const rdpCertInfo* info = freerdp_certificate_get_info(cert);
1808
0
  if (!freerdp_certificate_is_rsa(cert) || !info || (info->ModulusLength != 2048 / 8))
1809
0
  {
1810
0
    WLog_INFO(TAG, "certificate is not RSA 2048, RDP security not supported.");
1811
0
    return FALSE;
1812
0
  }
1813
0
  return TRUE;
1814
0
}
1815
1816
char* freerdp_certificate_get_param(const rdpCertificate* cert, enum FREERDP_CERT_PARAM what,
1817
                                    size_t* psize)
1818
0
{
1819
0
  WINPR_ASSERT(cert);
1820
0
  WINPR_ASSERT(psize);
1821
1822
0
  *psize = 0;
1823
1824
0
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1825
0
  const BIGNUM* bn = nullptr;
1826
0
  RSA* rsa = freerdp_certificate_get_RSA(cert);
1827
0
  switch (what)
1828
0
  {
1829
0
    case FREERDP_CERT_RSA_E:
1830
0
      RSA_get0_key(rsa, nullptr, &bn, nullptr);
1831
0
      break;
1832
0
    case FREERDP_CERT_RSA_N:
1833
0
      RSA_get0_key(rsa, &bn, nullptr, nullptr);
1834
0
      break;
1835
0
    default:
1836
0
      RSA_free(rsa);
1837
0
      return nullptr;
1838
0
  }
1839
0
  RSA_free(rsa);
1840
#else
1841
  EVP_PKEY* pkey = X509_get0_pubkey(cert->x509);
1842
  if (!pkey)
1843
    return nullptr;
1844
1845
  BIGNUM* bn = nullptr;
1846
  switch (what)
1847
  {
1848
    case FREERDP_CERT_RSA_E:
1849
      if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &bn))
1850
        return nullptr;
1851
      break;
1852
    case FREERDP_CERT_RSA_N:
1853
      if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &bn))
1854
        return nullptr;
1855
      break;
1856
    default:
1857
      return nullptr;
1858
  }
1859
#endif
1860
1861
0
  const size_t bnsize = WINPR_ASSERTING_INT_CAST(size_t, BN_num_bytes(bn));
1862
0
  char* rc = calloc(bnsize + 1, sizeof(char));
1863
0
  if (!rc)
1864
0
    goto fail;
1865
0
  BN_bn2bin(bn, (BYTE*)rc);
1866
0
  *psize = bnsize;
1867
1868
0
fail:
1869
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR < 3)
1870
  BN_free(bn);
1871
#endif
1872
0
  return rc;
1873
0
}
1874
1875
size_t freerdp_certificate_get_chain_len(rdpCertificate* certificate)
1876
0
{
1877
0
  WINPR_ASSERT(certificate);
1878
0
  if (!certificate->chain)
1879
0
    return 0;
1880
1881
0
  return WINPR_ASSERTING_INT_CAST(size_t, sk_X509_num(certificate->chain));
1882
0
}
1883
1884
X509* freerdp_certificate_get_chain_at(rdpCertificate* certificate, size_t offset)
1885
0
{
1886
0
  WINPR_ASSERT(certificate);
1887
0
  WINPR_ASSERT(freerdp_certificate_get_chain_len(certificate) > offset);
1888
0
  const int ioff = WINPR_ASSERTING_INT_CAST(int, offset);
1889
0
  return sk_X509_value(certificate->chain, ioff);
1890
0
}