Coverage Report

Created: 2026-01-17 07:10

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
123
{
287
123
  EVP_PKEY* evp = X509_get0_pubkey(x509);
288
123
  if (!evp)
289
81
    return FALSE;
290
291
42
  return (EVP_PKEY_id(evp) == EVP_PKEY_RSA);
292
123
}
293
294
static BOOL certificate_read_x509_certificate(const rdpCertBlob* cert, rdpCertInfo* info)
295
0
{
296
0
  wStream sbuffer = { 0 };
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 = { 0 };
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
125
{
461
125
  if (!x509_cert_chain)
462
0
    return;
463
464
125
  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
125
  free(x509_cert_chain->array);
474
125
  x509_cert_chain->array = NULL;
475
125
  x509_cert_chain->count = 0;
476
125
}
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)] = { 0 };
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] = { 0 };
923
0
  BYTE signature[sizeof(initial_signature)] = { 0 };
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
  crypto_rsa_private_encrypt(signature, sizeof(signature), priv_key_tssk, encryptedSignature,
930
0
                             sizeof(encryptedSignature));
931
932
0
  if (!Stream_EnsureRemainingCapacity(s, 2 * sizeof(UINT16) + sizeof(encryptedSignature) + 8))
933
0
    return FALSE;
934
0
  Stream_Write_UINT16(s, BB_RSA_SIGNATURE_BLOB);
935
0
  Stream_Write_UINT16(s, sizeof(encryptedSignature) + 8); /* wSignatureBlobLen */
936
0
  Stream_Write(s, encryptedSignature, sizeof(encryptedSignature));
937
0
  Stream_Zero(s, 8);
938
0
  return TRUE;
939
0
}
940
941
/* [MS-RDPBCGR] 2.2.1.4.3.1.1 Server Proprietary Certificate (PROPRIETARYSERVERCERTIFICATE) */
942
static BOOL cert_write_server_certificate_v1(wStream* s, const rdpCertificate* certificate)
943
0
{
944
0
  const size_t start = Stream_GetPosition(s);
945
0
  const BYTE* sigData = Stream_PointerAs(s, const BYTE) - sizeof(UINT32);
946
947
0
  WINPR_ASSERT(start >= 4);
948
0
  if (!Stream_EnsureRemainingCapacity(s, 10))
949
0
    return FALSE;
950
0
  Stream_Write_UINT32(s, SIGNATURE_ALG_RSA);
951
0
  Stream_Write_UINT32(s, KEY_EXCHANGE_ALG_RSA);
952
0
  Stream_Write_UINT16(s, BB_RSA_KEY_BLOB);
953
0
  if (!cert_write_rsa_public_key(s, certificate))
954
0
    return FALSE;
955
956
0
  const size_t end = Stream_GetPosition(s);
957
0
  return cert_write_rsa_signature(s, sigData, end - start + sizeof(UINT32));
958
0
}
959
960
static BOOL cert_write_server_certificate_v2(wStream* s, const rdpCertificate* certificate)
961
0
{
962
0
  WINPR_ASSERT(certificate);
963
964
0
  const rdpX509CertChain* chain = &certificate->x509_cert_chain;
965
0
  const size_t padding = 8ull + 4ull * chain->count;
966
967
0
  if (!Stream_EnsureRemainingCapacity(s, sizeof(UINT32)))
968
0
    return FALSE;
969
970
0
  Stream_Write_UINT32(s, chain->count);
971
0
  for (UINT32 x = 0; x < chain->count; x++)
972
0
  {
973
0
    const rdpCertBlob* cert = &chain->array[x];
974
0
    if (!cert_blob_write(cert, s))
975
0
      return FALSE;
976
0
  }
977
978
0
  if (!Stream_EnsureRemainingCapacity(s, padding))
979
0
    return FALSE;
980
0
  Stream_Zero(s, padding);
981
0
  return TRUE;
982
0
}
983
984
SSIZE_T freerdp_certificate_write_server_cert(const rdpCertificate* certificate, UINT32 dwVersion,
985
                                              wStream* s)
986
0
{
987
0
  if (!certificate)
988
0
    return -1;
989
990
0
  const size_t start = Stream_GetPosition(s);
991
0
  if (!Stream_EnsureRemainingCapacity(s, 4))
992
0
    return -1;
993
0
  Stream_Write_UINT32(s, dwVersion);
994
995
0
  switch (dwVersion & CERT_CHAIN_VERSION_MASK)
996
0
  {
997
0
    case CERT_CHAIN_VERSION_1:
998
0
      if (!cert_write_server_certificate_v1(s, certificate))
999
0
        return -1;
1000
0
      break;
1001
0
    case CERT_CHAIN_VERSION_2:
1002
0
      if (!cert_write_server_certificate_v2(s, certificate))
1003
0
        return -1;
1004
0
      break;
1005
0
    default:
1006
0
      WLog_ERR(TAG, "invalid certificate chain version:%" PRIu32 "",
1007
0
               dwVersion & CERT_CHAIN_VERSION_MASK);
1008
0
      return -1;
1009
0
  }
1010
1011
0
  const size_t end = Stream_GetPosition(s);
1012
0
  if (start > end)
1013
0
    return -1;
1014
1015
0
  const size_t diff = end - start;
1016
0
  WINPR_ASSERT(diff <= SSIZE_MAX);
1017
0
  return (SSIZE_T)diff;
1018
0
}
1019
1020
/**
1021
 * Read an X.509 Certificate Chain.
1022
 * @param cert certificate module
1023
 * @param s stream
1024
 * @return \b TRUE for success, \b FALSE otherwise.
1025
 */
1026
1027
static BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* cert, wStream* s)
1028
0
{
1029
0
  UINT32 numCertBlobs = 0;
1030
0
  DEBUG_CERTIFICATE("Server X.509 Certificate Chain");
1031
1032
0
  WINPR_ASSERT(cert);
1033
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
1034
0
    return FALSE;
1035
1036
0
  Stream_Read_UINT32(s, numCertBlobs); /* numCertBlobs */
1037
0
  certificate_free_x509_certificate_chain(&cert->x509_cert_chain);
1038
0
  cert->x509_cert_chain = certificate_new_x509_certificate_chain(numCertBlobs);
1039
1040
0
  for (UINT32 i = 0; i < cert->x509_cert_chain.count; i++)
1041
0
  {
1042
0
    rdpCertBlob* blob = &cert->x509_cert_chain.array[i];
1043
0
    if (!cert_blob_read(blob, s))
1044
0
      return FALSE;
1045
1046
0
    if (numCertBlobs - i == 1)
1047
0
    {
1048
0
      DEBUG_CERTIFICATE("Terminal Server Certificate");
1049
1050
0
      BOOL res = certificate_read_x509_certificate(blob, &cert->cert_info);
1051
1052
0
      if (res)
1053
0
      {
1054
0
        if (!update_x509_from_info(cert))
1055
0
          res = FALSE;
1056
0
      }
1057
1058
0
      if (!res)
1059
0
      {
1060
0
        WLog_ERR(TAG, "Failed to read x509 certificate");
1061
0
        return FALSE;
1062
0
      }
1063
1064
0
      DEBUG_CERTIFICATE("modulus length:%" PRIu32 "", cert->cert_info.ModulusLength);
1065
0
    }
1066
0
  }
1067
1068
0
  return update_x509_from_info(cert);
1069
0
}
1070
1071
/**
1072
 * Read a Server Certificate.
1073
 * @param certificate certificate module
1074
 * @param server_cert server certificate
1075
 * @param length certificate length
1076
 */
1077
1078
BOOL freerdp_certificate_read_server_cert(rdpCertificate* certificate, const BYTE* server_cert,
1079
                                          size_t length)
1080
0
{
1081
0
  BOOL ret = FALSE;
1082
0
  wStream* s = NULL;
1083
0
  wStream sbuffer;
1084
0
  UINT32 dwVersion = 0;
1085
1086
0
  WINPR_ASSERT(certificate);
1087
0
  if (length < 4) /* NULL certificate is not an error see #1795 */
1088
0
  {
1089
0
    WLog_DBG(TAG, "Received empty certificate, ignoring...");
1090
0
    return TRUE;
1091
0
  }
1092
1093
0
  WINPR_ASSERT(server_cert);
1094
0
  s = Stream_StaticConstInit(&sbuffer, server_cert, length);
1095
1096
0
  if (!s)
1097
0
  {
1098
0
    WLog_ERR(TAG, "Stream_New failed!");
1099
0
    return FALSE;
1100
0
  }
1101
1102
0
  Stream_Read_UINT32(s, dwVersion); /* dwVersion (4 bytes) */
1103
1104
0
  switch (dwVersion & CERT_CHAIN_VERSION_MASK)
1105
0
  {
1106
0
    case CERT_CHAIN_VERSION_1:
1107
0
      ret = certificate_read_server_proprietary_certificate(certificate, s);
1108
0
      break;
1109
1110
0
    case CERT_CHAIN_VERSION_2:
1111
0
      ret = certificate_read_server_x509_certificate_chain(certificate, s);
1112
0
      break;
1113
1114
0
    default:
1115
0
      WLog_ERR(TAG, "invalid certificate chain version:%" PRIu32 "",
1116
0
               dwVersion & CERT_CHAIN_VERSION_MASK);
1117
0
      ret = FALSE;
1118
0
      break;
1119
0
  }
1120
1121
0
  return ret;
1122
0
}
1123
1124
static BOOL cert_blob_copy(rdpCertBlob* dst, const rdpCertBlob* src)
1125
0
{
1126
0
  WINPR_ASSERT(dst);
1127
0
  WINPR_ASSERT(src);
1128
1129
0
  cert_blob_free(dst);
1130
0
  if (src->length > 0)
1131
0
  {
1132
0
    dst->data = malloc(src->length);
1133
0
    if (!dst->data)
1134
0
      return FALSE;
1135
0
    dst->length = src->length;
1136
0
    memcpy(dst->data, src->data, src->length);
1137
0
  }
1138
1139
0
  return TRUE;
1140
0
}
1141
1142
static BOOL cert_x509_chain_copy(rdpX509CertChain* cert, const rdpX509CertChain* src)
1143
0
{
1144
0
  WINPR_ASSERT(cert);
1145
1146
0
  certificate_free_x509_certificate_chain(cert);
1147
0
  if (!src)
1148
0
    return TRUE;
1149
1150
0
  if (src->count > 0)
1151
0
  {
1152
0
    cert->array = calloc(src->count, sizeof(rdpCertBlob));
1153
0
    if (!cert->array)
1154
0
    {
1155
0
      return FALSE;
1156
0
    }
1157
0
    cert->count = src->count;
1158
1159
0
    for (UINT32 x = 0; x < cert->count; x++)
1160
0
    {
1161
0
      const rdpCertBlob* srcblob = &src->array[x];
1162
0
      rdpCertBlob* dstblob = &cert->array[x];
1163
1164
0
      if (!cert_blob_copy(dstblob, srcblob))
1165
0
      {
1166
0
        certificate_free_x509_certificate_chain(cert);
1167
0
        return FALSE;
1168
0
      }
1169
0
    }
1170
0
  }
1171
1172
0
  return TRUE;
1173
0
}
1174
1175
BOOL cert_clone_int(rdpCertificate* dst, const rdpCertificate* src)
1176
0
{
1177
0
  WINPR_ASSERT(dst);
1178
0
  WINPR_ASSERT(src);
1179
1180
0
  if (!cert_info_clone(&dst->cert_info, &src->cert_info))
1181
0
    return FALSE;
1182
1183
0
  if (src->x509)
1184
0
  {
1185
0
    dst->x509 = X509_dup(src->x509);
1186
0
    if (!dst->x509)
1187
0
    {
1188
      /* Workaround for SSL deprecation issues:
1189
       * some security modes use weak RSA ciphers where X509_dup fails.
1190
       * In that case recreate the X509 from the raw RSA data
1191
       */
1192
0
      if (!update_x509_from_info(dst))
1193
0
      {
1194
0
        WLog_ERR(TAG, "X509_dup failed, SSL configuration bug?");
1195
0
        return FALSE;
1196
0
      }
1197
0
    }
1198
0
  }
1199
1200
0
  if (src->chain)
1201
0
  {
1202
0
    if (dst->chain)
1203
0
      sk_X509_pop_free(dst->chain, X509_free);
1204
1205
0
    dst->chain = sk_X509_deep_copy(src->chain, X509_const_dup, X509_free);
1206
0
  }
1207
0
  return cert_x509_chain_copy(&dst->x509_cert_chain, &src->x509_cert_chain);
1208
0
}
1209
1210
rdpCertificate* freerdp_certificate_clone(const rdpCertificate* certificate)
1211
0
{
1212
0
  if (!certificate)
1213
0
    return NULL;
1214
1215
0
  rdpCertificate* _certificate = freerdp_certificate_new();
1216
1217
0
  if (!_certificate)
1218
0
    return NULL;
1219
1220
0
  if (!cert_clone_int(_certificate, certificate))
1221
0
    goto out_fail;
1222
1223
0
  return _certificate;
1224
0
out_fail:
1225
1226
0
  freerdp_certificate_free(_certificate);
1227
0
  return NULL;
1228
0
}
1229
1230
/**
1231
 * Instantiate new certificate module.
1232
 * @return new certificate module
1233
 */
1234
1235
rdpCertificate* freerdp_certificate_new(void)
1236
125
{
1237
125
  return (rdpCertificate*)calloc(1, sizeof(rdpCertificate));
1238
125
}
1239
1240
void certificate_free_int(rdpCertificate* cert)
1241
125
{
1242
125
  WINPR_ASSERT(cert);
1243
1244
125
  if (cert->x509)
1245
123
    X509_free(cert->x509);
1246
125
  if (cert->chain)
1247
106
    sk_X509_pop_free(cert->chain, X509_free);
1248
1249
125
  certificate_free_x509_certificate_chain(&cert->x509_cert_chain);
1250
125
  cert_info_free(&cert->cert_info);
1251
125
}
1252
1253
/**
1254
 * Free certificate module.
1255
 * @param cert certificate module to be freed
1256
 */
1257
1258
void freerdp_certificate_free(rdpCertificate* cert)
1259
1.04k
{
1260
1.04k
  if (!cert)
1261
916
    return;
1262
1263
125
  certificate_free_int(cert);
1264
125
  free(cert);
1265
125
}
1266
1267
static BOOL freerdp_rsa_from_x509(rdpCertificate* cert)
1268
123
{
1269
123
  BOOL rc = FALSE;
1270
1271
123
  WINPR_ASSERT(cert);
1272
1273
123
  if (!freerdp_certificate_is_rsa(cert))
1274
91
    return TRUE;
1275
1276
32
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1277
32
  RSA* rsa = NULL;
1278
32
  const BIGNUM* rsa_n = NULL;
1279
32
  const BIGNUM* rsa_e = NULL;
1280
#else
1281
  BIGNUM* rsa_n = NULL;
1282
  BIGNUM* rsa_e = NULL;
1283
#endif
1284
32
  EVP_PKEY* pubkey = X509_get0_pubkey(cert->x509);
1285
32
  if (!pubkey)
1286
0
    goto fail;
1287
1288
32
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1289
32
  rsa = EVP_PKEY_get1_RSA(pubkey);
1290
1291
  /* If this is not a RSA key return success */
1292
32
  rc = TRUE;
1293
32
  if (!rsa)
1294
0
    goto fail;
1295
1296
  /* Now we return failure again if something is wrong. */
1297
32
  rc = FALSE;
1298
1299
32
  RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
1300
#else
1301
  if (!EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_E, &rsa_e))
1302
    goto fail;
1303
  if (!EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_N, &rsa_n))
1304
    goto fail;
1305
#endif
1306
32
  if (!rsa_n || !rsa_e)
1307
0
    goto fail;
1308
32
  if (!cert_info_create(&cert->cert_info, rsa_n, rsa_e))
1309
14
    goto fail;
1310
18
  rc = TRUE;
1311
32
fail:
1312
32
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1313
32
  RSA_free(rsa);
1314
#else
1315
  BN_free(rsa_n);
1316
  BN_free(rsa_e);
1317
#endif
1318
32
  return rc;
1319
18
}
1320
1321
rdpCertificate* freerdp_certificate_new_from_der(const BYTE* data, size_t length)
1322
0
{
1323
0
  rdpCertificate* cert = freerdp_certificate_new();
1324
1325
0
  if (!cert || !data || (length == 0) || (length > INT_MAX))
1326
0
    goto fail;
1327
1328
0
  {
1329
0
    const BYTE* ptr = data;
1330
0
    cert->x509 = d2i_X509(NULL, &ptr, (int)length);
1331
0
  }
1332
1333
0
  if (!cert->x509)
1334
0
    goto fail;
1335
0
  if (!freerdp_rsa_from_x509(cert))
1336
0
    goto fail;
1337
0
  return cert;
1338
0
fail:
1339
0
  freerdp_certificate_free(cert);
1340
0
  return NULL;
1341
0
}
1342
1343
rdpCertificate* freerdp_certificate_new_from_x509(const X509* xcert, const STACK_OF(X509) * chain)
1344
125
{
1345
125
  WINPR_ASSERT(xcert);
1346
1347
125
  rdpCertificate* cert = freerdp_certificate_new();
1348
125
  if (!cert)
1349
0
    return NULL;
1350
1351
125
  X509* wcert = WINPR_CAST_CONST_PTR_AWAY(xcert, X509*);
1352
125
  cert->x509 = X509_dup(wcert);
1353
125
  if (!cert->x509)
1354
2
    goto fail;
1355
1356
123
  if (!freerdp_rsa_from_x509(cert))
1357
14
    goto fail;
1358
1359
109
  if (chain)
1360
109
    cert->chain = sk_X509_deep_copy(chain, X509_const_dup, X509_free);
1361
1362
109
  return cert;
1363
16
fail:
1364
16
  freerdp_certificate_free(cert);
1365
16
  return NULL;
1366
123
}
1367
1368
static STACK_OF(X509) * extract_chain_from_pem(const char* pem, BOOL isFile)
1369
125
{
1370
125
  if (!pem)
1371
0
  {
1372
0
    return NULL;
1373
0
  }
1374
1375
125
  BIO* bio = NULL;
1376
125
  if (isFile)
1377
0
    bio = BIO_new_file(pem, "rb");
1378
125
  else
1379
125
  {
1380
125
    const size_t len = strlen(pem);
1381
250
    bio = BIO_new_mem_buf(pem, WINPR_ASSERTING_INT_CAST(int, len));
1382
250
  }
1383
1384
125
  if (!bio)
1385
0
  {
1386
0
    return NULL;
1387
0
  }
1388
1389
125
  X509* leaf = PEM_read_bio_X509(bio, NULL, NULL, NULL);
1390
125
  if (!leaf)
1391
0
  {
1392
0
    BIO_free(bio);
1393
0
    return NULL;
1394
0
  }
1395
1396
125
  STACK_OF(X509)* chain = sk_X509_new_null();
1397
125
  if (!chain)
1398
0
  {
1399
0
    X509_free(leaf);
1400
0
    BIO_free(bio);
1401
0
    return NULL;
1402
0
  }
1403
1404
125
  X509* cert = NULL;
1405
6.04k
  while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL)
1406
5.91k
  {
1407
5.91k
    sk_X509_push(chain, cert);
1408
5.91k
  }
1409
1410
125
  X509_free(leaf);
1411
125
  BIO_free(bio);
1412
125
  return chain;
1413
125
}
1414
1415
static rdpCertificate* freerdp_certificate_new_from(const char* file, BOOL isFile)
1416
1.01k
{
1417
1.01k
  X509* x509 = x509_utils_from_pem(file, strlen(file), isFile);
1418
1.01k
  if (!x509)
1419
894
    return NULL;
1420
1.01k
  STACK_OF(X509)* chain = extract_chain_from_pem(file, isFile);
1421
125
  rdpCertificate* cert = freerdp_certificate_new_from_x509(x509, chain);
1422
125
  if (chain)
1423
125
    sk_X509_pop_free(chain, X509_free);
1424
125
  X509_free(x509);
1425
125
  return cert;
1426
1.01k
}
1427
1428
rdpCertificate* freerdp_certificate_new_from_file(const char* file)
1429
0
{
1430
0
  return freerdp_certificate_new_from(file, TRUE);
1431
0
}
1432
1433
rdpCertificate* freerdp_certificate_new_from_pem(const char* pem)
1434
1.01k
{
1435
1.01k
  return freerdp_certificate_new_from(pem, FALSE);
1436
1.01k
}
1437
1438
const rdpCertInfo* freerdp_certificate_get_info(const rdpCertificate* cert)
1439
0
{
1440
0
  WINPR_ASSERT(cert);
1441
0
  if (!freerdp_certificate_is_rsa(cert))
1442
0
    return NULL;
1443
0
  return &cert->cert_info;
1444
0
}
1445
1446
char* freerdp_certificate_get_fingerprint(const rdpCertificate* cert)
1447
103
{
1448
103
  return freerdp_certificate_get_fingerprint_by_hash(cert, "sha256");
1449
103
}
1450
1451
char* freerdp_certificate_get_fingerprint_by_hash(const rdpCertificate* cert, const char* hash)
1452
103
{
1453
103
  return freerdp_certificate_get_fingerprint_by_hash_ex(cert, hash, TRUE);
1454
103
}
1455
1456
char* freerdp_certificate_get_fingerprint_by_hash_ex(const rdpCertificate* cert, const char* hash,
1457
                                                     BOOL separator)
1458
103
{
1459
103
  size_t fp_len = 0;
1460
103
  size_t pos = 0;
1461
103
  size_t size = 0;
1462
103
  BYTE* fp = NULL;
1463
103
  char* fp_buffer = NULL;
1464
103
  if (!cert || !cert->x509)
1465
0
  {
1466
0
    WLog_ERR(TAG, "Invalid certificate [%p, %p]", WINPR_CXX_COMPAT_CAST(const void*, cert),
1467
0
             WINPR_CXX_COMPAT_CAST(const void*, cert ? cert->x509 : NULL));
1468
0
    return NULL;
1469
0
  }
1470
103
  if (!hash)
1471
0
  {
1472
0
    WLog_ERR(TAG, "Invalid certificate hash %p", WINPR_CXX_COMPAT_CAST(const void*, hash));
1473
0
    return NULL;
1474
0
  }
1475
103
  fp = x509_utils_get_hash(cert->x509, hash, &fp_len);
1476
103
  if (!fp)
1477
0
    return NULL;
1478
1479
103
  if (fp_len < 1)
1480
0
    goto fail;
1481
1482
103
  size = fp_len * 3 + 1;
1483
103
  fp_buffer = calloc(size, sizeof(char));
1484
103
  if (!fp_buffer)
1485
0
    goto fail;
1486
1487
103
  pos = 0;
1488
1489
103
  {
1490
103
    size_t i = 0;
1491
3.29k
    for (; i < (fp_len - 1); i++)
1492
3.19k
    {
1493
3.19k
      int rc = 0;
1494
3.19k
      char* p = &fp_buffer[pos];
1495
3.19k
      if (separator)
1496
3.19k
        rc = sprintf_s(p, size - pos, "%02" PRIx8 ":", fp[i]);
1497
0
      else
1498
0
        rc = sprintf_s(p, size - pos, "%02" PRIx8, fp[i]);
1499
3.19k
      if (rc <= 0)
1500
0
        goto fail;
1501
3.19k
      pos += (size_t)rc;
1502
3.19k
    }
1503
1504
103
    (void)sprintf_s(&fp_buffer[pos], size - pos, "%02" PRIx8 "", fp[i]);
1505
103
  }
1506
1507
0
  free(fp);
1508
1509
103
  return fp_buffer;
1510
0
fail:
1511
0
  free(fp);
1512
0
  free(fp_buffer);
1513
0
  return NULL;
1514
103
}
1515
1516
static BOOL bio_read_pem(BIO* bio, char** ppem, size_t* plength)
1517
215
{
1518
215
  BOOL rc = FALSE;
1519
1520
215
  WINPR_ASSERT(bio);
1521
215
  WINPR_ASSERT(ppem);
1522
1523
215
  const size_t blocksize = 2048;
1524
215
  size_t offset = 0;
1525
215
  size_t length = blocksize;
1526
215
  char* pem = NULL;
1527
1528
215
  *ppem = NULL;
1529
215
  if (plength)
1530
215
    *plength = 0;
1531
1532
4.79k
  while (offset < length)
1533
4.79k
  {
1534
4.79k
    char* tmp = realloc(pem, length + 1);
1535
4.79k
    if (!tmp)
1536
0
      goto fail;
1537
4.79k
    pem = tmp;
1538
1539
4.79k
    ERR_clear_error();
1540
1541
4.79k
    const int status = BIO_read(bio, &pem[offset], (int)(length - offset));
1542
4.79k
    if (status < 0)
1543
6
    {
1544
6
      WLog_ERR(TAG, "failed to read certificate");
1545
6
      goto fail;
1546
6
    }
1547
1548
4.78k
    if (status == 0)
1549
0
      break;
1550
1551
4.78k
    offset += (size_t)status;
1552
4.78k
    if (length - offset > 0)
1553
209
      break;
1554
4.58k
    length += blocksize;
1555
4.58k
  }
1556
1557
209
  if (pem)
1558
209
  {
1559
209
    if (offset >= length)
1560
0
      goto fail;
1561
209
    pem[offset] = '\0';
1562
209
  }
1563
209
  *ppem = pem;
1564
209
  if (plength)
1565
209
    *plength = offset;
1566
209
  rc = TRUE;
1567
215
fail:
1568
215
  if (!rc)
1569
6
    free(pem);
1570
1571
215
  return rc;
1572
209
}
1573
1574
char* freerdp_certificate_get_pem(const rdpCertificate* cert, size_t* pLength)
1575
0
{
1576
0
  return freerdp_certificate_get_pem_ex(cert, pLength, TRUE);
1577
0
}
1578
1579
char* freerdp_certificate_get_pem_ex(const rdpCertificate* cert, size_t* pLength,
1580
                                     BOOL withCertChain)
1581
215
{
1582
215
  WINPR_ASSERT(cert);
1583
1584
215
  if (!cert->x509)
1585
0
    return NULL;
1586
1587
  /**
1588
   * Don't manage certificates internally, leave it up entirely to the external client
1589
   * implementation
1590
   */
1591
215
  BIO* bio = BIO_new(BIO_s_mem());
1592
1593
215
  if (!bio)
1594
0
  {
1595
0
    WLog_ERR(TAG, "BIO_new() failure");
1596
0
    return NULL;
1597
0
  }
1598
1599
215
  char* pem = NULL;
1600
1601
215
  const int status = PEM_write_bio_X509(bio, cert->x509);
1602
215
  if (status < 0)
1603
0
  {
1604
0
    WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", status);
1605
0
    goto fail;
1606
0
  }
1607
1608
215
  if (cert->chain && withCertChain)
1609
104
  {
1610
104
    const int count = sk_X509_num(cert->chain);
1611
6.01k
    for (int x = 0; x < count; x++)
1612
5.91k
    {
1613
5.91k
      X509* c = sk_X509_value(cert->chain, x);
1614
5.91k
      const int rc = PEM_write_bio_X509(bio, c);
1615
5.91k
      if (rc < 0)
1616
0
      {
1617
0
        WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", rc);
1618
0
        goto fail;
1619
0
      }
1620
5.91k
    }
1621
104
  }
1622
1623
215
  (void)bio_read_pem(bio, &pem, pLength);
1624
1625
215
fail:
1626
215
  BIO_free_all(bio);
1627
215
  return pem;
1628
215
}
1629
1630
char* freerdp_certificate_get_subject(const rdpCertificate* cert)
1631
109
{
1632
109
  WINPR_ASSERT(cert);
1633
109
  return x509_utils_get_subject(cert->x509);
1634
109
}
1635
1636
char* freerdp_certificate_get_issuer(const rdpCertificate* cert)
1637
103
{
1638
103
  WINPR_ASSERT(cert);
1639
103
  return x509_utils_get_issuer(cert->x509);
1640
103
}
1641
1642
char* freerdp_certificate_get_upn(const rdpCertificate* cert)
1643
0
{
1644
0
  WINPR_ASSERT(cert);
1645
0
  return x509_utils_get_upn(cert->x509);
1646
0
}
1647
1648
char* freerdp_certificate_get_email(const rdpCertificate* cert)
1649
0
{
1650
0
  WINPR_ASSERT(cert);
1651
0
  return x509_utils_get_email(cert->x509);
1652
0
}
1653
1654
char* freerdp_certificate_get_validity(const rdpCertificate* cert, BOOL startDate)
1655
0
{
1656
0
  WINPR_ASSERT(cert);
1657
0
  return x509_utils_get_date(cert->x509, startDate);
1658
0
}
1659
1660
BOOL freerdp_certificate_check_eku(const rdpCertificate* cert, int nid)
1661
0
{
1662
0
  WINPR_ASSERT(cert);
1663
0
  return x509_utils_check_eku(cert->x509, nid);
1664
0
}
1665
1666
BOOL freerdp_certificate_get_public_key(const rdpCertificate* cert, BYTE** PublicKey,
1667
                                        DWORD* PublicKeyLength)
1668
0
{
1669
0
  BYTE* ptr = NULL;
1670
0
  BYTE* optr = NULL;
1671
0
  int length = 0;
1672
0
  BOOL status = FALSE;
1673
0
  EVP_PKEY* pkey = NULL;
1674
1675
0
  WINPR_ASSERT(cert);
1676
1677
0
  pkey = X509_get0_pubkey(cert->x509);
1678
1679
0
  if (!pkey)
1680
0
  {
1681
0
    WLog_ERR(TAG, "X509_get_pubkey() failed");
1682
0
    goto exit;
1683
0
  }
1684
1685
0
  length = i2d_PublicKey(pkey, NULL);
1686
1687
0
  if (length < 1)
1688
0
  {
1689
0
    WLog_ERR(TAG, "i2d_PublicKey() failed");
1690
0
    goto exit;
1691
0
  }
1692
1693
0
  *PublicKey = optr = ptr = (BYTE*)calloc(WINPR_ASSERTING_INT_CAST(size_t, length), sizeof(BYTE));
1694
1695
0
  if (!ptr)
1696
0
    goto exit;
1697
1698
0
  {
1699
0
    const int length2 = i2d_PublicKey(pkey, &ptr);
1700
0
    if (length != length2)
1701
0
      goto exit;
1702
0
    *PublicKeyLength = (DWORD)length2;
1703
0
  }
1704
0
  status = TRUE;
1705
0
exit:
1706
1707
0
  if (!status)
1708
0
    free(optr);
1709
1710
0
  return status;
1711
0
}
1712
1713
BOOL freerdp_certificate_verify(const rdpCertificate* cert, const char* certificate_store_path)
1714
0
{
1715
0
  WINPR_ASSERT(cert);
1716
0
  return x509_utils_verify(cert->x509, cert->chain, certificate_store_path);
1717
0
}
1718
1719
char** freerdp_certificate_get_dns_names(const rdpCertificate* cert, size_t* pcount,
1720
                                         size_t** pplengths)
1721
0
{
1722
0
  WINPR_ASSERT(cert);
1723
0
  return x509_utils_get_dns_names(cert->x509, pcount, pplengths);
1724
0
}
1725
1726
char* freerdp_certificate_get_common_name(const rdpCertificate* cert, size_t* plength)
1727
0
{
1728
0
  WINPR_ASSERT(cert);
1729
0
  return x509_utils_get_common_name(cert->x509, plength);
1730
0
}
1731
1732
WINPR_MD_TYPE freerdp_certificate_get_signature_alg(const rdpCertificate* cert)
1733
0
{
1734
0
  WINPR_ASSERT(cert);
1735
0
  return x509_utils_get_signature_alg(cert->x509);
1736
0
}
1737
1738
void freerdp_certificate_free_dns_names(size_t count, size_t* lengths, char** names)
1739
0
{
1740
0
  x509_utils_dns_names_free(count, lengths, names);
1741
0
}
1742
1743
char* freerdp_certificate_get_hash(const rdpCertificate* cert, const char* hash, size_t* plength)
1744
0
{
1745
0
  WINPR_ASSERT(cert);
1746
0
  return (char*)x509_utils_get_hash(cert->x509, hash, plength);
1747
0
}
1748
1749
X509* freerdp_certificate_get_x509(rdpCertificate* cert)
1750
0
{
1751
0
  WINPR_ASSERT(cert);
1752
0
  return cert->x509;
1753
0
}
1754
1755
BOOL freerdp_certificate_publickey_encrypt(const rdpCertificate* cert, const BYTE* input,
1756
                                           size_t cbInput, BYTE** poutput, size_t* pcbOutput)
1757
0
{
1758
0
  WINPR_ASSERT(cert);
1759
0
  WINPR_ASSERT(input);
1760
0
  WINPR_ASSERT(poutput);
1761
0
  WINPR_ASSERT(pcbOutput);
1762
1763
0
  BOOL ret = FALSE;
1764
0
  BYTE* output = NULL;
1765
0
  EVP_PKEY* pkey = X509_get0_pubkey(cert->x509);
1766
0
  if (!pkey)
1767
0
    return FALSE;
1768
1769
0
  EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, NULL);
1770
0
  if (!ctx)
1771
0
    return FALSE;
1772
1773
0
  size_t outputSize = WINPR_ASSERTING_INT_CAST(size_t, EVP_PKEY_size(pkey));
1774
0
  output = malloc(outputSize);
1775
0
  if (output == NULL)
1776
0
    goto out;
1777
0
  *pcbOutput = outputSize;
1778
1779
0
  if (EVP_PKEY_encrypt_init(ctx) != 1 ||
1780
0
      EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) != 1 ||
1781
0
      EVP_PKEY_encrypt(ctx, output, pcbOutput, input, cbInput) != 1)
1782
0
  {
1783
0
    WLog_ERR(TAG, "error when setting up public key");
1784
0
    goto out;
1785
0
  }
1786
1787
0
  *poutput = output;
1788
0
  output = NULL;
1789
0
  ret = TRUE;
1790
0
out:
1791
0
  EVP_PKEY_CTX_free(ctx);
1792
0
  free(output);
1793
0
  return ret;
1794
0
}
1795
1796
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1797
static RSA* freerdp_certificate_get_RSA(const rdpCertificate* cert)
1798
0
{
1799
0
  WINPR_ASSERT(cert);
1800
1801
0
  if (!freerdp_certificate_is_rsa(cert))
1802
0
    return NULL;
1803
1804
0
  EVP_PKEY* pubkey = X509_get0_pubkey(cert->x509);
1805
0
  if (!pubkey)
1806
0
    return NULL;
1807
1808
0
  return EVP_PKEY_get1_RSA(pubkey);
1809
0
}
1810
#endif
1811
1812
BYTE* freerdp_certificate_get_der(const rdpCertificate* cert, size_t* pLength)
1813
0
{
1814
0
  WINPR_ASSERT(cert);
1815
1816
0
  if (pLength)
1817
0
    *pLength = 0;
1818
1819
0
  const int rc = i2d_X509(cert->x509, NULL);
1820
0
  if (rc <= 0)
1821
0
    return NULL;
1822
1823
0
  BYTE* ptr = calloc(WINPR_ASSERTING_INT_CAST(size_t, rc) + 1, sizeof(BYTE));
1824
0
  if (!ptr)
1825
0
    return NULL;
1826
0
  BYTE* i2d_ptr = ptr;
1827
1828
0
  const int rc2 = i2d_X509(cert->x509, &i2d_ptr);
1829
0
  if (rc2 <= 0)
1830
0
  {
1831
0
    free(ptr);
1832
0
    return NULL;
1833
0
  }
1834
1835
0
  if (pLength)
1836
0
    *pLength = (size_t)rc2;
1837
0
  return ptr;
1838
0
}
1839
1840
BOOL freerdp_certificate_is_rsa(const rdpCertificate* cert)
1841
123
{
1842
123
  WINPR_ASSERT(cert);
1843
123
  return is_rsa_key(cert->x509);
1844
123
}
1845
1846
BOOL freerdp_certificate_is_rdp_security_compatible(const rdpCertificate* cert)
1847
0
{
1848
0
  const rdpCertInfo* info = freerdp_certificate_get_info(cert);
1849
0
  if (!freerdp_certificate_is_rsa(cert) || !info || (info->ModulusLength != 2048 / 8))
1850
0
  {
1851
0
    WLog_INFO(TAG, "certificate is not RSA 2048, RDP security not supported.");
1852
0
    return FALSE;
1853
0
  }
1854
0
  return TRUE;
1855
0
}
1856
1857
char* freerdp_certificate_get_param(const rdpCertificate* cert, enum FREERDP_CERT_PARAM what,
1858
                                    size_t* psize)
1859
0
{
1860
0
  WINPR_ASSERT(cert);
1861
0
  WINPR_ASSERT(psize);
1862
1863
0
  *psize = 0;
1864
1865
0
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
1866
0
  const BIGNUM* bn = NULL;
1867
0
  RSA* rsa = freerdp_certificate_get_RSA(cert);
1868
0
  switch (what)
1869
0
  {
1870
0
    case FREERDP_CERT_RSA_E:
1871
0
      RSA_get0_key(rsa, NULL, &bn, NULL);
1872
0
      break;
1873
0
    case FREERDP_CERT_RSA_N:
1874
0
      RSA_get0_key(rsa, &bn, NULL, NULL);
1875
0
      break;
1876
0
    default:
1877
0
      RSA_free(rsa);
1878
0
      return NULL;
1879
0
  }
1880
0
  RSA_free(rsa);
1881
#else
1882
  EVP_PKEY* pkey = X509_get0_pubkey(cert->x509);
1883
  if (!pkey)
1884
    return NULL;
1885
1886
  BIGNUM* bn = NULL;
1887
  switch (what)
1888
  {
1889
    case FREERDP_CERT_RSA_E:
1890
      if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &bn))
1891
        return NULL;
1892
      break;
1893
    case FREERDP_CERT_RSA_N:
1894
      if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &bn))
1895
        return NULL;
1896
      break;
1897
    default:
1898
      return NULL;
1899
  }
1900
#endif
1901
1902
0
  const size_t bnsize = WINPR_ASSERTING_INT_CAST(size_t, BN_num_bytes(bn));
1903
0
  char* rc = calloc(bnsize + 1, sizeof(char));
1904
0
  if (!rc)
1905
0
    goto fail;
1906
0
  BN_bn2bin(bn, (BYTE*)rc);
1907
0
  *psize = bnsize;
1908
1909
0
fail:
1910
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR < 3)
1911
  BN_free(bn);
1912
#endif
1913
0
  return rc;
1914
0
}
1915
1916
size_t freerdp_certificate_get_chain_len(rdpCertificate* certificate)
1917
0
{
1918
0
  WINPR_ASSERT(certificate);
1919
0
  if (!certificate->chain)
1920
0
    return 0;
1921
1922
0
  return WINPR_ASSERTING_INT_CAST(size_t, sk_X509_num(certificate->chain));
1923
0
}
1924
1925
X509* freerdp_certificate_get_chain_at(rdpCertificate* certificate, size_t offset)
1926
0
{
1927
0
  WINPR_ASSERT(certificate);
1928
0
  WINPR_ASSERT(freerdp_certificate_get_chain_len(certificate) > offset);
1929
0
  const int ioff = WINPR_ASSERTING_INT_CAST(int, offset);
1930
0
  return sk_X509_value(certificate->chain, ioff);
1931
0
}