Coverage Report

Created: 2026-02-26 06:54

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