Coverage Report

Created: 2026-08-31 06:25

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