Coverage Report

Created: 2026-02-26 06:50

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
0
  do                         \
68
0
  {                          \
69
0
  } 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
0
{
232
0
  UINT32 certLength = 0;
233
0
  WINPR_ASSERT(blob);
234
0
  cert_blob_free(blob);
235
236
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
237
0
    goto fail;
238
239
0
  Stream_Read_UINT32(s, certLength);
240
241
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, certLength))
242
0
    goto fail;
243
244
0
  DEBUG_CERTIFICATE("X.509 Certificate length:%" PRIu32 "", certLength);
245
0
  blob->data = (BYTE*)malloc(certLength);
246
247
0
  if (!blob->data)
248
0
    goto fail;
249
250
0
  Stream_Read(s, blob->data, certLength);
251
0
  blob->length = certLength;
252
253
0
  return TRUE;
254
255
0
fail:
256
0
  cert_blob_free(blob);
257
0
  return FALSE;
258
0
}
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
0
{
274
0
  if (!blob)
275
0
    return;
276
0
  free(blob->data);
277
0
  blob->data = NULL;
278
0
  blob->length = 0;
279
0
}
280
281
/**
282
 * Read X.509 Certificate
283
 */
284
285
static BOOL is_rsa_key(const X509* x509)
286
0
{
287
0
  EVP_PKEY* evp = X509_get0_pubkey(x509);
288
0
  if (!evp)
289
0
    return FALSE;
290
291
0
  return (EVP_PKEY_id(evp) == EVP_PKEY_RSA);
292
0
}
293
294
static BOOL certificate_read_x509_certificate(const rdpCertBlob* cert, rdpCertInfo* info)
295
0
{
296
0
  wStream sbuffer = WINPR_C_ARRAY_INIT;
297
0
  wStream* s = NULL;
298
0
  size_t length = 0;
299
0
  BYTE padding = 0;
300
0
  UINT32 version = 0;
301
0
  size_t modulus_length = 0;
302
0
  size_t exponent_length = 0;
303
0
  int error = 0;
304
305
0
  WINPR_ASSERT(cert);
306
0
  WINPR_ASSERT(info);
307
308
0
  cert_info_free(info);
309
310
0
  s = Stream_StaticConstInit(&sbuffer, cert->data, cert->length);
311
312
0
  if (!s)
313
0
    return FALSE;
314
315
0
  if (!ber_read_sequence_tag(s, &length)) /* Certificate (SEQUENCE) */
316
0
    goto error;
317
318
0
  error++;
319
320
0
  if (!ber_read_sequence_tag(s, &length)) /* TBSCertificate (SEQUENCE) */
321
0
    goto error;
322
323
0
  error++;
324
325
0
  if (!ber_read_contextual_tag(s, 0, &length, TRUE)) /* Explicit Contextual Tag [0] */
326
0
    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
0
error:
430
0
  WLog_ERR(TAG, "error reading when reading certificate: part=%s error=%d",
431
0
           certificate_read_errors[error], error);
432
0
  cert_info_free(info);
433
0
  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
0
{
444
0
  rdpX509CertChain x509_cert_chain = WINPR_C_ARRAY_INIT;
445
446
0
  x509_cert_chain.array = (rdpCertBlob*)calloc(count, sizeof(rdpCertBlob));
447
448
0
  if (x509_cert_chain.array)
449
0
    x509_cert_chain.count = count;
450
451
0
  return x509_cert_chain;
452
0
}
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
0
{
461
0
  if (!x509_cert_chain)
462
0
    return;
463
464
0
  if (x509_cert_chain->array)
465
0
  {
466
0
    for (UINT32 i = 0; i < x509_cert_chain->count; i++)
467
0
    {
468
0
      rdpCertBlob* element = &x509_cert_chain->array[i];
469
0
      cert_blob_free(element);
470
0
    }
471
0
  }
472
473
0
  free(x509_cert_chain->array);
474
0
  x509_cert_chain->array = NULL;
475
0
  x509_cert_chain->count = 0;
476
0
}
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
0
{
536
0
  BOOL rc = FALSE;
537
538
0
  WINPR_ASSERT(cert);
539
540
0
  X509_free(cert->x509);
541
0
  cert->x509 = NULL;
542
543
0
  rdpCertInfo* info = &cert->cert_info;
544
545
0
  BIGNUM* e = BN_new();
546
0
  BIGNUM* mod = BN_new();
547
0
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
548
0
  RSA* rsa = RSA_new();
549
0
  if (!rsa)
550
0
  {
551
0
    WLog_ERR(TAG, "RSA_new() failed");
552
0
    goto fail;
553
0
  }
554
0
#endif
555
556
0
  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
0
  WINPR_ASSERT(info->ModulusLength <= INT_MAX);
564
0
  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
0
  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
0
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
577
0
  const int rec = RSA_set0_key(rsa, mod, e, NULL);
578
0
  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
0
  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
0
  if (!cert->x509)
641
0
    goto fail;
642
643
0
  rc = TRUE;
644
645
0
fail:
646
0
  if (!rc)
647
0
    WLog_ERR(TAG, "failed to update x509 from rdpCertInfo");
648
649
0
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
650
0
  if (rsa)
651
0
    RSA_free(rsa);
652
0
  else
653
0
#endif
654
0
  {
655
0
    BN_free(mod);
656
0
    BN_free(e);
657
0
  }
658
0
  return rc;
659
0
}
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
0
{
816
0
  UINT32 dwSigAlgId = 0;
817
0
  UINT32 dwKeyAlgId = 0;
818
0
  UINT16 wPublicKeyBlobType = 0;
819
0
  UINT16 wPublicKeyBlobLen = 0;
820
0
  UINT16 wSignatureBlobType = 0;
821
0
  UINT16 wSignatureBlobLen = 0;
822
0
  size_t sigdatalen = 0;
823
824
0
  WINPR_ASSERT(certificate);
825
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
826
0
    return FALSE;
827
828
  /* -4, because we need to include dwVersion */
829
0
  const BYTE* sigdata = Stream_PointerAs(s, const BYTE) - 4;
830
0
  Stream_Read_UINT32(s, dwSigAlgId);
831
0
  Stream_Read_UINT32(s, dwKeyAlgId);
832
833
0
  if (!((dwSigAlgId == SIGNATURE_ALG_RSA) && (dwKeyAlgId == KEY_EXCHANGE_ALG_RSA)))
834
0
  {
835
0
    WLog_ERR(TAG,
836
0
             "unsupported signature or key algorithm, dwSigAlgId=%" PRIu32
837
0
             " dwKeyAlgId=%" PRIu32 "",
838
0
             dwSigAlgId, dwKeyAlgId);
839
0
    return FALSE;
840
0
  }
841
842
0
  Stream_Read_UINT16(s, wPublicKeyBlobType);
843
844
0
  if (wPublicKeyBlobType != BB_RSA_KEY_BLOB)
845
0
  {
846
0
    WLog_ERR(TAG, "unsupported public key blob type %" PRIu16 "", wPublicKeyBlobType);
847
0
    return FALSE;
848
0
  }
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
0
{
1030
0
  UINT32 numCertBlobs = 0;
1031
0
  DEBUG_CERTIFICATE("Server X.509 Certificate Chain");
1032
1033
0
  WINPR_ASSERT(cert);
1034
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
1035
0
    return FALSE;
1036
1037
0
  Stream_Read_UINT32(s, numCertBlobs); /* numCertBlobs */
1038
0
  certificate_free_x509_certificate_chain(&cert->x509_cert_chain);
1039
0
  cert->x509_cert_chain = certificate_new_x509_certificate_chain(numCertBlobs);
1040
1041
0
  for (UINT32 i = 0; i < cert->x509_cert_chain.count; i++)
1042
0
  {
1043
0
    rdpCertBlob* blob = &cert->x509_cert_chain.array[i];
1044
0
    if (!cert_blob_read(blob, s))
1045
0
      return FALSE;
1046
1047
0
    if (numCertBlobs - i == 1)
1048
0
    {
1049
0
      DEBUG_CERTIFICATE("Terminal Server Certificate");
1050
1051
0
      BOOL res = certificate_read_x509_certificate(blob, &cert->cert_info);
1052
1053
0
      if (res)
1054
0
      {
1055
0
        if (!update_x509_from_info(cert))
1056
0
          res = FALSE;
1057
0
      }
1058
1059
0
      if (!res)
1060
0
      {
1061
0
        WLog_ERR(TAG, "Failed to read x509 certificate");
1062
0
        return FALSE;
1063
0
      }
1064
1065
0
      DEBUG_CERTIFICATE("modulus length:%" PRIu32 "", cert->cert_info.ModulusLength);
1066
0
    }
1067
0
  }
1068
1069
0
  return update_x509_from_info(cert);
1070
0
}
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
0
{
1082
0
  BOOL ret = FALSE;
1083
0
  wStream* s = NULL;
1084
0
  wStream sbuffer;
1085
0
  UINT32 dwVersion = 0;
1086
1087
0
  WINPR_ASSERT(certificate);
1088
0
  if (length < 4) /* NULL certificate is not an error see #1795 */
1089
0
  {
1090
0
    WLog_DBG(TAG, "Received empty certificate, ignoring...");
1091
0
    return TRUE;
1092
0
  }
1093
1094
0
  WINPR_ASSERT(server_cert);
1095
0
  s = Stream_StaticConstInit(&sbuffer, server_cert, length);
1096
1097
0
  if (!s)
1098
0
  {
1099
0
    WLog_ERR(TAG, "Stream_New failed!");
1100
0
    return FALSE;
1101
0
  }
1102
1103
0
  Stream_Read_UINT32(s, dwVersion); /* dwVersion (4 bytes) */
1104
1105
0
  switch (dwVersion & CERT_CHAIN_VERSION_MASK)
1106
0
  {
1107
0
    case CERT_CHAIN_VERSION_1:
1108
0
      ret = certificate_read_server_proprietary_certificate(certificate, s);
1109
0
      break;
1110
1111
0
    case CERT_CHAIN_VERSION_2:
1112
0
      ret = certificate_read_server_x509_certificate_chain(certificate, s);
1113
0
      break;
1114
1115
0
    default:
1116
0
      WLog_ERR(TAG, "invalid certificate chain version:%" PRIu32 "",
1117
0
               dwVersion & CERT_CHAIN_VERSION_MASK);
1118
0
      ret = FALSE;
1119
0
      break;
1120
0
  }
1121
1122
0
  return ret;
1123
0
}
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
0
{
1145
0
  WINPR_ASSERT(cert);
1146
1147
0
  certificate_free_x509_certificate_chain(cert);
1148
0
  if (!src)
1149
0
    return TRUE;
1150
1151
0
  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
0
  return TRUE;
1174
0
}
1175
1176
BOOL cert_clone_int(rdpCertificate* dst, const rdpCertificate* src)
1177
0
{
1178
0
  WINPR_ASSERT(dst);
1179
0
  WINPR_ASSERT(src);
1180
1181
0
  if (!cert_info_clone(&dst->cert_info, &src->cert_info))
1182
0
    return FALSE;
1183
1184
0
  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
0
  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
0
  return cert_x509_chain_copy(&dst->x509_cert_chain, &src->x509_cert_chain);
1209
0
}
1210
1211
rdpCertificate* freerdp_certificate_clone(const rdpCertificate* certificate)
1212
0
{
1213
0
  if (!certificate)
1214
0
    return NULL;
1215
1216
0
  rdpCertificate* _certificate = freerdp_certificate_new();
1217
1218
0
  if (!_certificate)
1219
0
    return NULL;
1220
1221
0
  if (!cert_clone_int(_certificate, certificate))
1222
0
    goto out_fail;
1223
1224
0
  return _certificate;
1225
0
out_fail:
1226
1227
0
  freerdp_certificate_free(_certificate);
1228
0
  return NULL;
1229
0
}
1230
1231
/**
1232
 * Instantiate new certificate module.
1233
 * @return new certificate module
1234
 */
1235
1236
rdpCertificate* freerdp_certificate_new(void)
1237
0
{
1238
0
  return (rdpCertificate*)calloc(1, sizeof(rdpCertificate));
1239
0
}
1240
1241
void certificate_free_int(rdpCertificate* cert)
1242
0
{
1243
0
  WINPR_ASSERT(cert);
1244
1245
0
  if (cert->x509)
1246
0
    X509_free(cert->x509);
1247
0
  if (cert->chain)
1248
0
    sk_X509_pop_free(cert->chain, X509_free);
1249
1250
0
  certificate_free_x509_certificate_chain(&cert->x509_cert_chain);
1251
0
  cert_info_free(&cert->cert_info);
1252
0
}
1253
1254
/**
1255
 * Free certificate module.
1256
 * @param cert certificate module to be freed
1257
 */
1258
1259
void freerdp_certificate_free(rdpCertificate* cert)
1260
0
{
1261
0
  if (!cert)
1262
0
    return;
1263
1264
0
  certificate_free_int(cert);
1265
0
  free(cert);
1266
0
}
1267
1268
static BOOL freerdp_rsa_from_x509(rdpCertificate* cert)
1269
0
{
1270
0
  BOOL rc = FALSE;
1271
1272
0
  WINPR_ASSERT(cert);
1273
1274
0
  if (!freerdp_certificate_is_rsa(cert))
1275
0
    return TRUE;
1276
1277
0
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1278
0
  RSA* rsa = NULL;
1279
0
  const BIGNUM* rsa_n = NULL;
1280
0
  const BIGNUM* rsa_e = NULL;
1281
#else
1282
  BIGNUM* rsa_n = NULL;
1283
  BIGNUM* rsa_e = NULL;
1284
#endif
1285
0
  EVP_PKEY* pubkey = X509_get0_pubkey(cert->x509);
1286
0
  if (!pubkey)
1287
0
    goto fail;
1288
1289
0
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1290
0
  rsa = EVP_PKEY_get1_RSA(pubkey);
1291
1292
  /* If this is not a RSA key return success */
1293
0
  rc = TRUE;
1294
0
  if (!rsa)
1295
0
    goto fail;
1296
1297
  /* Now we return failure again if something is wrong. */
1298
0
  rc = FALSE;
1299
1300
0
  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
0
  if (!rsa_n || !rsa_e)
1308
0
    goto fail;
1309
0
  if (!cert_info_create(&cert->cert_info, rsa_n, rsa_e))
1310
0
    goto fail;
1311
0
  rc = TRUE;
1312
0
fail:
1313
0
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1314
0
  RSA_free(rsa);
1315
#else
1316
  BN_free(rsa_n);
1317
  BN_free(rsa_e);
1318
#endif
1319
0
  return rc;
1320
0
}
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
0
{
1346
0
  WINPR_ASSERT(xcert);
1347
1348
0
  rdpCertificate* cert = freerdp_certificate_new();
1349
0
  if (!cert)
1350
0
    return NULL;
1351
1352
0
  X509* wcert = WINPR_CAST_CONST_PTR_AWAY(xcert, X509*);
1353
0
  cert->x509 = X509_dup(wcert);
1354
0
  if (!cert->x509)
1355
0
    goto fail;
1356
1357
0
  if (!freerdp_rsa_from_x509(cert))
1358
0
    goto fail;
1359
1360
0
  if (chain)
1361
0
    cert->chain = sk_X509_deep_copy(chain, X509_const_dup, X509_free);
1362
1363
0
  return cert;
1364
0
fail:
1365
0
  freerdp_certificate_free(cert);
1366
0
  return NULL;
1367
0
}
1368
1369
static STACK_OF(X509) * extract_chain_from_pem(const char* pem, BOOL isFile)
1370
0
{
1371
0
  if (!pem)
1372
0
  {
1373
0
    return NULL;
1374
0
  }
1375
1376
0
  BIO* bio = NULL;
1377
0
  if (isFile)
1378
0
    bio = BIO_new_file(pem, "rb");
1379
0
  else
1380
0
  {
1381
0
    const size_t len = strlen(pem);
1382
0
    bio = BIO_new_mem_buf(pem, WINPR_ASSERTING_INT_CAST(int, len));
1383
0
  }
1384
1385
0
  if (!bio)
1386
0
  {
1387
0
    return NULL;
1388
0
  }
1389
1390
0
  X509* leaf = PEM_read_bio_X509(bio, NULL, NULL, NULL);
1391
0
  if (!leaf)
1392
0
  {
1393
0
    BIO_free(bio);
1394
0
    return NULL;
1395
0
  }
1396
1397
0
  STACK_OF(X509)* chain = sk_X509_new_null();
1398
0
  if (!chain)
1399
0
  {
1400
0
    X509_free(leaf);
1401
0
    BIO_free(bio);
1402
0
    return NULL;
1403
0
  }
1404
1405
0
  X509* cert = NULL;
1406
0
  while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL)
1407
0
  {
1408
0
    sk_X509_push(chain, cert);
1409
0
  }
1410
1411
0
  X509_free(leaf);
1412
0
  BIO_free(bio);
1413
0
  return chain;
1414
0
}
1415
1416
static rdpCertificate* freerdp_certificate_new_from(const char* file, BOOL isFile)
1417
0
{
1418
0
  X509* x509 = x509_utils_from_pem(file, strlen(file), isFile);
1419
0
  if (!x509)
1420
0
    return NULL;
1421
0
  STACK_OF(X509)* chain = extract_chain_from_pem(file, isFile);
1422
0
  rdpCertificate* cert = freerdp_certificate_new_from_x509(x509, chain);
1423
0
  if (chain)
1424
0
    sk_X509_pop_free(chain, X509_free);
1425
0
  X509_free(x509);
1426
0
  return cert;
1427
0
}
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
0
{
1436
0
  return freerdp_certificate_new_from(pem, FALSE);
1437
0
}
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
0
{
1449
0
  return freerdp_certificate_get_fingerprint_by_hash(cert, "sha256");
1450
0
}
1451
1452
char* freerdp_certificate_get_fingerprint_by_hash(const rdpCertificate* cert, const char* hash)
1453
0
{
1454
0
  return freerdp_certificate_get_fingerprint_by_hash_ex(cert, hash, TRUE);
1455
0
}
1456
1457
char* freerdp_certificate_get_fingerprint_by_hash_ex(const rdpCertificate* cert, const char* hash,
1458
                                                     BOOL separator)
1459
0
{
1460
0
  size_t fp_len = 0;
1461
0
  size_t pos = 0;
1462
0
  size_t size = 0;
1463
0
  BYTE* fp = NULL;
1464
0
  char* fp_buffer = NULL;
1465
0
  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
0
  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
0
  fp = x509_utils_get_hash(cert->x509, hash, &fp_len);
1477
0
  if (!fp)
1478
0
    return NULL;
1479
1480
0
  if (fp_len < 1)
1481
0
    goto fail;
1482
1483
0
  size = fp_len * 3 + 1;
1484
0
  fp_buffer = calloc(size, sizeof(char));
1485
0
  if (!fp_buffer)
1486
0
    goto fail;
1487
1488
0
  pos = 0;
1489
1490
0
  {
1491
0
    size_t i = 0;
1492
0
    for (; i < (fp_len - 1); i++)
1493
0
    {
1494
0
      int rc = 0;
1495
0
      char* p = &fp_buffer[pos];
1496
0
      if (separator)
1497
0
        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
0
      if (rc <= 0)
1501
0
        goto fail;
1502
0
      pos += (size_t)rc;
1503
0
    }
1504
1505
0
    (void)sprintf_s(&fp_buffer[pos], size - pos, "%02" PRIx8 "", fp[i]);
1506
0
  }
1507
1508
0
  free(fp);
1509
1510
0
  return fp_buffer;
1511
0
fail:
1512
0
  free(fp);
1513
0
  free(fp_buffer);
1514
0
  return NULL;
1515
0
}
1516
1517
static BOOL bio_read_pem(BIO* bio, char** ppem, size_t* plength)
1518
0
{
1519
0
  BOOL rc = FALSE;
1520
1521
0
  WINPR_ASSERT(bio);
1522
0
  WINPR_ASSERT(ppem);
1523
1524
0
  const size_t blocksize = 2048;
1525
0
  size_t offset = 0;
1526
0
  size_t length = blocksize;
1527
0
  char* pem = NULL;
1528
1529
0
  *ppem = NULL;
1530
0
  if (plength)
1531
0
    *plength = 0;
1532
1533
0
  while (offset < length)
1534
0
  {
1535
0
    char* tmp = realloc(pem, length + 1);
1536
0
    if (!tmp)
1537
0
      goto fail;
1538
0
    pem = tmp;
1539
1540
0
    ERR_clear_error();
1541
1542
0
    const int status = BIO_read(bio, &pem[offset], (int)(length - offset));
1543
0
    if (status < 0)
1544
0
    {
1545
0
      WLog_ERR(TAG, "failed to read certificate");
1546
0
      goto fail;
1547
0
    }
1548
1549
0
    if (status == 0)
1550
0
      break;
1551
1552
0
    offset += (size_t)status;
1553
0
    if (length - offset > 0)
1554
0
      break;
1555
0
    length += blocksize;
1556
0
  }
1557
1558
0
  if (pem)
1559
0
  {
1560
0
    if (offset >= length)
1561
0
      goto fail;
1562
0
    pem[offset] = '\0';
1563
0
  }
1564
0
  *ppem = pem;
1565
0
  if (plength)
1566
0
    *plength = offset;
1567
0
  rc = TRUE;
1568
0
fail:
1569
0
  if (!rc)
1570
0
    free(pem);
1571
1572
0
  return rc;
1573
0
}
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
0
{
1583
0
  WINPR_ASSERT(cert);
1584
1585
0
  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
0
  BIO* bio = BIO_new(BIO_s_mem());
1593
1594
0
  if (!bio)
1595
0
  {
1596
0
    WLog_ERR(TAG, "BIO_new() failure");
1597
0
    return NULL;
1598
0
  }
1599
1600
0
  char* pem = NULL;
1601
1602
0
  const int status = PEM_write_bio_X509(bio, cert->x509);
1603
0
  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
0
  if (cert->chain && withCertChain)
1610
0
  {
1611
0
    const int count = sk_X509_num(cert->chain);
1612
0
    for (int x = 0; x < count; x++)
1613
0
    {
1614
0
      X509* c = sk_X509_value(cert->chain, x);
1615
0
      const int rc = PEM_write_bio_X509(bio, c);
1616
0
      if (rc < 0)
1617
0
      {
1618
0
        WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", rc);
1619
0
        goto fail;
1620
0
      }
1621
0
    }
1622
0
  }
1623
1624
0
  (void)bio_read_pem(bio, &pem, pLength);
1625
1626
0
fail:
1627
0
  BIO_free_all(bio);
1628
0
  return pem;
1629
0
}
1630
1631
char* freerdp_certificate_get_subject(const rdpCertificate* cert)
1632
0
{
1633
0
  WINPR_ASSERT(cert);
1634
0
  return x509_utils_get_subject(cert->x509);
1635
0
}
1636
1637
char* freerdp_certificate_get_issuer(const rdpCertificate* cert)
1638
0
{
1639
0
  WINPR_ASSERT(cert);
1640
0
  return x509_utils_get_issuer(cert->x509);
1641
0
}
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
0
{
1843
0
  WINPR_ASSERT(cert);
1844
0
  return is_rsa_key(cert->x509);
1845
0
}
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
}