Coverage Report

Created: 2026-04-12 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/crypto/privatekey.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Private key 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/crypto.h>
36
37
#include <openssl/pem.h>
38
#include <openssl/rsa.h>
39
#include <openssl/bn.h>
40
#include <openssl/err.h>
41
42
#include "privatekey.h"
43
#include "cert_common.h"
44
45
#include <freerdp/crypto/privatekey.h>
46
47
#include <openssl/evp.h>
48
49
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
50
#include <openssl/core_names.h>
51
#endif
52
53
#include "x509_utils.h"
54
#include "crypto.h"
55
#include "opensslcompat.h"
56
57
#define TAG FREERDP_TAG("crypto")
58
59
struct rdp_private_key
60
{
61
  EVP_PKEY* evp;
62
63
  rdpCertInfo cert;
64
  BYTE* PrivateExponent;
65
  DWORD PrivateExponentLength;
66
};
67
68
/*
69
 * Terminal Services Signing Keys.
70
 * Yes, Terminal Services Private Key is publicly available.
71
 */
72
73
static BYTE tssk_modulus[] = { 0x3d, 0x3a, 0x5e, 0xbd, 0x72, 0x43, 0x3e, 0xc9, 0x4d, 0xbb, 0xc1,
74
                             0x1e, 0x4a, 0xba, 0x5f, 0xcb, 0x3e, 0x88, 0x20, 0x87, 0xef, 0xf5,
75
                             0xc1, 0xe2, 0xd7, 0xb7, 0x6b, 0x9a, 0xf2, 0x52, 0x45, 0x95, 0xce,
76
                             0x63, 0x65, 0x6b, 0x58, 0x3a, 0xfe, 0xef, 0x7c, 0xe7, 0xbf, 0xfe,
77
                             0x3d, 0xf6, 0x5c, 0x7d, 0x6c, 0x5e, 0x06, 0x09, 0x1a, 0xf5, 0x61,
78
                             0xbb, 0x20, 0x93, 0x09, 0x5f, 0x05, 0x6d, 0xea, 0x87 };
79
80
static BYTE tssk_privateExponent[] = {
81
  0x87, 0xa7, 0x19, 0x32, 0xda, 0x11, 0x87, 0x55, 0x58, 0x00, 0x16, 0x16, 0x25, 0x65, 0x68, 0xf8,
82
  0x24, 0x3e, 0xe6, 0xfa, 0xe9, 0x67, 0x49, 0x94, 0xcf, 0x92, 0xcc, 0x33, 0x99, 0xe8, 0x08, 0x60,
83
  0x17, 0x9a, 0x12, 0x9f, 0x24, 0xdd, 0xb1, 0x24, 0x99, 0xc7, 0x3a, 0xb8, 0x0a, 0x7b, 0x0d, 0xdd,
84
  0x35, 0x07, 0x79, 0x17, 0x0b, 0x51, 0x9b, 0xb3, 0xc7, 0x10, 0x01, 0x13, 0xe7, 0x3f, 0xf3, 0x5f
85
};
86
87
static const rdpPrivateKey tssk = { .PrivateExponent = tssk_privateExponent,
88
                                  .PrivateExponentLength = sizeof(tssk_privateExponent),
89
                                  .cert = { .Modulus = tssk_modulus,
90
                                            .ModulusLength = sizeof(tssk_modulus) } };
91
const rdpPrivateKey* priv_key_tssk = &tssk;
92
93
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
94
static RSA* evp_pkey_to_rsa(const rdpPrivateKey* key)
95
0
{
96
0
  if (!freerdp_key_is_rsa(key))
97
0
  {
98
0
    WLog_WARN(TAG, "Key is no RSA key");
99
0
    return nullptr;
100
0
  }
101
102
0
  RSA* rsa = nullptr;
103
0
  BIO* bio = BIO_new(
104
#if defined(LIBRESSL_VERSION_NUMBER)
105
      BIO_s_mem()
106
#else
107
0
      BIO_s_secmem()
108
0
#endif
109
0
  );
110
0
  if (!bio)
111
0
    return nullptr;
112
0
  const int rc = PEM_write_bio_PrivateKey(bio, key->evp, nullptr, nullptr, 0, nullptr, nullptr);
113
0
  if (rc != 1)
114
0
    goto fail;
115
0
  rsa = PEM_read_bio_RSAPrivateKey(bio, nullptr, nullptr, nullptr);
116
0
fail:
117
0
  BIO_free_all(bio);
118
0
  return rsa;
119
0
}
120
#endif
121
122
static int pem_pwd_cb(char* buf, int size, WINPR_ATTR_UNUSED int rwflag, void* userdata)
123
0
{
124
0
  const char* pwd = userdata;
125
0
  if (!pwd || (size < 0))
126
0
    return -1;
127
0
  if (size == 0)
128
0
    return 0;
129
130
0
  size_t len = strlen(pwd);
131
0
  if (len >= WINPR_ASSERTING_INT_CAST(size_t, size))
132
0
    len = WINPR_ASSERTING_INT_CAST(size_t, size) - 1;
133
0
  memcpy(buf, pwd, len);
134
0
  buf[len] = '\0';
135
0
  return WINPR_ASSERTING_INT_CAST(int, len);
136
0
}
137
138
static EVP_PKEY* evp_pkey_utils_from_pem(const char* data, size_t len, BOOL fromFile,
139
                                         const char* password)
140
0
{
141
0
  EVP_PKEY* evp = nullptr;
142
0
  BIO* bio = nullptr;
143
0
  if (fromFile)
144
0
    bio = BIO_new_file(data, "rb");
145
0
  else
146
0
  {
147
0
    if (len > INT_MAX)
148
0
      return nullptr;
149
0
    bio = BIO_new_mem_buf(data, (int)len);
150
0
  }
151
152
0
  if (!bio)
153
0
  {
154
0
    WLog_ERR(TAG, "BIO_new failed for private key");
155
0
    return nullptr;
156
0
  }
157
158
0
  evp = PEM_read_bio_PrivateKey(bio, nullptr, pem_pwd_cb,
159
0
                                WINPR_CAST_CONST_PTR_AWAY(password, void*));
160
0
  BIO_free_all(bio);
161
0
  if (!evp)
162
0
    WLog_ERR(TAG, "PEM_read_bio_PrivateKey returned nullptr [input length %" PRIuz "]", len);
163
164
0
  return evp;
165
0
}
166
167
static BOOL key_read_private(rdpPrivateKey* key)
168
0
{
169
0
  BOOL rc = FALSE;
170
171
0
  WINPR_ASSERT(key);
172
0
  WINPR_ASSERT(key->evp);
173
174
  /* The key is not an RSA key, that means we just return success. */
175
0
  if (!freerdp_key_is_rsa(key))
176
0
    return TRUE;
177
178
0
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
179
0
  RSA* rsa = evp_pkey_to_rsa(key);
180
0
  if (!rsa)
181
0
  {
182
0
    char ebuffer[256] = WINPR_C_ARRAY_INIT;
183
0
    WLog_ERR(TAG, "unable to load RSA key: %s.",
184
0
             winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
185
0
    goto fail;
186
0
  }
187
188
0
  switch (RSA_check_key(rsa))
189
0
  {
190
0
    case 0:
191
0
      WLog_ERR(TAG, "invalid RSA key");
192
0
      goto fail;
193
194
0
    case 1:
195
      /* Valid key. */
196
0
      break;
197
198
0
    default:
199
0
    {
200
0
      char ebuffer[256] = WINPR_C_ARRAY_INIT;
201
0
      WLog_ERR(TAG, "unexpected error when checking RSA key: %s.",
202
0
               winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
203
0
      goto fail;
204
0
    }
205
0
  }
206
207
0
  const BIGNUM* rsa_e = nullptr;
208
0
  const BIGNUM* rsa_n = nullptr;
209
0
  const BIGNUM* rsa_d = nullptr;
210
211
0
  RSA_get0_key(rsa, &rsa_n, &rsa_e, &rsa_d);
212
#else
213
  BIGNUM* rsa_e = nullptr;
214
  BIGNUM* rsa_n = nullptr;
215
  BIGNUM* rsa_d = nullptr;
216
217
  if (!EVP_PKEY_get_bn_param(key->evp, OSSL_PKEY_PARAM_RSA_N, &rsa_n))
218
    goto fail;
219
  if (!EVP_PKEY_get_bn_param(key->evp, OSSL_PKEY_PARAM_RSA_E, &rsa_e))
220
    goto fail;
221
  if (!EVP_PKEY_get_bn_param(key->evp, OSSL_PKEY_PARAM_RSA_D, &rsa_d))
222
    goto fail;
223
#endif
224
0
  if (BN_num_bytes(rsa_e) > 4)
225
0
  {
226
0
    WLog_ERR(TAG, "RSA public exponent too large");
227
0
    goto fail;
228
0
  }
229
230
0
  if (!read_bignum(&key->PrivateExponent, &key->PrivateExponentLength, rsa_d, TRUE))
231
0
    goto fail;
232
233
0
  if (!cert_info_create(&key->cert, rsa_n, rsa_e))
234
0
    goto fail;
235
0
  rc = TRUE;
236
0
fail:
237
0
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
238
0
  RSA_free(rsa);
239
#else
240
  BN_free(rsa_d);
241
  BN_free(rsa_e);
242
  BN_free(rsa_n);
243
#endif
244
0
  return rc;
245
0
}
246
247
rdpPrivateKey* freerdp_key_new_from_pem(const char* pem)
248
0
{
249
0
  return freerdp_key_new_from_pem_enc(pem, nullptr);
250
0
}
251
252
rdpPrivateKey* freerdp_key_new_from_pem_enc(const char* pem, const char* password)
253
0
{
254
0
  rdpPrivateKey* key = freerdp_key_new();
255
0
  if (!key || !pem)
256
0
    goto fail;
257
258
0
  key->evp = evp_pkey_utils_from_pem(pem, strlen(pem), FALSE, password);
259
0
  if (!key->evp)
260
0
    goto fail;
261
0
  if (!key_read_private(key))
262
0
    goto fail;
263
0
  return key;
264
0
fail:
265
0
  freerdp_key_free(key);
266
0
  return nullptr;
267
0
}
268
269
rdpPrivateKey* freerdp_key_new_from_file(const char* keyfile)
270
0
{
271
0
  return freerdp_key_new_from_file_enc(keyfile, nullptr);
272
0
}
273
274
rdpPrivateKey* freerdp_key_new_from_file_enc(const char* keyfile, const char* password)
275
0
{
276
0
  rdpPrivateKey* key = freerdp_key_new();
277
0
  if (!key || !keyfile)
278
0
    goto fail;
279
280
0
  key->evp = evp_pkey_utils_from_pem(keyfile, strlen(keyfile), TRUE, password);
281
0
  if (!key->evp)
282
0
    goto fail;
283
0
  if (!key_read_private(key))
284
0
    goto fail;
285
0
  return key;
286
0
fail:
287
0
  freerdp_key_free(key);
288
0
  return nullptr;
289
0
}
290
291
rdpPrivateKey* freerdp_key_new(void)
292
0
{
293
0
  return calloc(1, sizeof(rdpPrivateKey));
294
0
}
295
296
rdpPrivateKey* freerdp_key_clone(const rdpPrivateKey* key)
297
0
{
298
0
  if (!key)
299
0
    return nullptr;
300
301
0
  rdpPrivateKey* _key = (rdpPrivateKey*)calloc(1, sizeof(rdpPrivateKey));
302
303
0
  if (!_key)
304
0
    return nullptr;
305
306
0
  if (key->evp)
307
0
  {
308
0
    _key->evp = key->evp;
309
0
    if (!_key->evp)
310
0
      goto out_fail;
311
0
    EVP_PKEY_up_ref(_key->evp);
312
0
  }
313
314
0
  if (key->PrivateExponent)
315
0
  {
316
0
    _key->PrivateExponent = (BYTE*)malloc(key->PrivateExponentLength);
317
318
0
    if (!_key->PrivateExponent)
319
0
      goto out_fail;
320
321
0
    CopyMemory(_key->PrivateExponent, key->PrivateExponent, key->PrivateExponentLength);
322
0
    _key->PrivateExponentLength = key->PrivateExponentLength;
323
0
  }
324
325
0
  if (!cert_info_clone(&_key->cert, &key->cert))
326
0
    goto out_fail;
327
328
0
  return _key;
329
0
out_fail:
330
0
  WINPR_PRAGMA_DIAG_PUSH
331
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
332
0
  freerdp_key_free(_key);
333
0
  WINPR_PRAGMA_DIAG_POP
334
0
  return nullptr;
335
0
}
336
337
void freerdp_key_free(rdpPrivateKey* key)
338
0
{
339
0
  if (!key)
340
0
    return;
341
342
0
  EVP_PKEY_free(key->evp);
343
0
  if (key->PrivateExponent)
344
0
    memset(key->PrivateExponent, 0, key->PrivateExponentLength);
345
0
  free(key->PrivateExponent);
346
0
  cert_info_free(&key->cert);
347
0
  free(key);
348
0
}
349
350
const rdpCertInfo* freerdp_key_get_info(const rdpPrivateKey* key)
351
0
{
352
0
  WINPR_ASSERT(key);
353
0
  if (!freerdp_key_is_rsa(key))
354
0
    return nullptr;
355
0
  return &key->cert;
356
0
}
357
358
const BYTE* freerdp_key_get_exponent(const rdpPrivateKey* key, size_t* plength)
359
0
{
360
0
  WINPR_ASSERT(key);
361
0
  if (!freerdp_key_is_rsa(key))
362
0
  {
363
0
    if (plength)
364
0
      *plength = 0;
365
0
    return nullptr;
366
0
  }
367
368
0
  if (plength)
369
0
    *plength = key->PrivateExponentLength;
370
0
  return key->PrivateExponent;
371
0
}
372
373
EVP_PKEY* freerdp_key_get_evp_pkey(const rdpPrivateKey* key)
374
0
{
375
0
  WINPR_ASSERT(key);
376
377
0
  EVP_PKEY* evp = key->evp;
378
0
  WINPR_ASSERT(evp);
379
0
  EVP_PKEY_up_ref(evp);
380
0
  return evp;
381
0
}
382
383
BOOL freerdp_key_is_rsa(const rdpPrivateKey* key)
384
0
{
385
0
  WINPR_ASSERT(key);
386
0
  if (key == priv_key_tssk)
387
0
    return TRUE;
388
389
0
  WINPR_ASSERT(key->evp);
390
0
  return (EVP_PKEY_id(key->evp) == EVP_PKEY_RSA);
391
0
}
392
393
size_t freerdp_key_get_bits(const rdpPrivateKey* key)
394
0
{
395
0
  int rc = -1;
396
0
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
397
0
  RSA* rsa = evp_pkey_to_rsa(key);
398
0
  if (rsa)
399
0
  {
400
0
    rc = RSA_bits(rsa);
401
0
    RSA_free(rsa);
402
0
  }
403
#else
404
  rc = EVP_PKEY_get_bits(key->evp);
405
#endif
406
407
0
  return WINPR_ASSERTING_INT_CAST(size_t, rc);
408
0
}
409
410
BOOL freerdp_key_generate(rdpPrivateKey* key, const char* type, size_t count, ...)
411
0
{
412
0
  BOOL rc = FALSE;
413
414
0
  if (!type)
415
0
  {
416
0
    WLog_ERR(TAG, "Invalid argument type=%s", type);
417
0
    return FALSE;
418
0
  }
419
0
  if (strncmp("RSA", type, 4) != 0)
420
0
  {
421
0
    WLog_ERR(TAG, "Argument type=%s is currently not supported, aborting", type);
422
0
    return FALSE;
423
0
  }
424
0
  if (count != 1)
425
0
  {
426
0
    WLog_ERR(TAG, "Argument type=%s requires count=1, got %" PRIuz ", aborting", type, count);
427
0
    return FALSE;
428
0
  }
429
0
  va_list ap = WINPR_C_ARRAY_INIT;
430
0
  va_start(ap, count);
431
0
  const int key_length = va_arg(ap, int);
432
0
  va_end(ap);
433
434
0
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
435
0
  RSA* rsa = nullptr;
436
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
437
  rsa = RSA_generate_key(key_length, RSA_F4, nullptr, nullptr);
438
#else
439
0
  {
440
0
    BIGNUM* bn = BN_secure_new();
441
442
0
    if (!bn)
443
0
      return FALSE;
444
445
0
    rsa = RSA_new();
446
447
0
    if (!rsa)
448
0
    {
449
0
      BN_clear_free(bn);
450
0
      return FALSE;
451
0
    }
452
453
0
    BN_set_word(bn, RSA_F4);
454
0
    const int res = RSA_generate_key_ex(rsa, key_length, bn, nullptr);
455
0
    BN_clear_free(bn);
456
457
0
    if (res != 1)
458
0
      return FALSE;
459
0
  }
460
0
#endif
461
462
0
  EVP_PKEY_free(key->evp);
463
0
  key->evp = EVP_PKEY_new();
464
465
0
  if (!EVP_PKEY_assign_RSA(key->evp, rsa))
466
0
  {
467
0
    EVP_PKEY_free(key->evp);
468
0
    key->evp = nullptr;
469
0
    RSA_free(rsa);
470
0
    return FALSE;
471
0
  }
472
473
0
  rc = TRUE;
474
#else
475
  EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_from_name(nullptr, type, nullptr);
476
  if (!pctx)
477
    return FALSE;
478
479
  if (EVP_PKEY_keygen_init(pctx) != 1)
480
    goto fail;
481
482
  if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, key_length) != 1)
483
    goto fail;
484
485
  EVP_PKEY_free(key->evp);
486
  key->evp = nullptr;
487
488
  if (EVP_PKEY_generate(pctx, &key->evp) != 1)
489
    goto fail;
490
491
  rc = TRUE;
492
fail:
493
  EVP_PKEY_CTX_free(pctx);
494
#endif
495
0
  return rc;
496
0
}
497
498
BYTE* freerdp_key_get_param(const rdpPrivateKey* key, enum FREERDP_KEY_PARAM param, size_t* plength)
499
0
{
500
0
  BYTE* buf = nullptr;
501
502
0
  WINPR_ASSERT(key);
503
0
  WINPR_ASSERT(plength);
504
505
0
  *plength = 0;
506
507
0
  BIGNUM* bn = nullptr;
508
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
509
510
  const char* pk = nullptr;
511
  switch (param)
512
  {
513
    case FREERDP_KEY_PARAM_RSA_D:
514
      pk = OSSL_PKEY_PARAM_RSA_D;
515
      break;
516
    case FREERDP_KEY_PARAM_RSA_E:
517
      pk = OSSL_PKEY_PARAM_RSA_E;
518
      break;
519
    case FREERDP_KEY_PARAM_RSA_N:
520
      pk = OSSL_PKEY_PARAM_RSA_N;
521
      break;
522
    default:
523
      return nullptr;
524
  }
525
526
  if (!EVP_PKEY_get_bn_param(key->evp, pk, &bn))
527
    return nullptr;
528
#else
529
0
  {
530
0
    const RSA* rsa = EVP_PKEY_get0_RSA(key->evp);
531
0
    if (!rsa)
532
0
      return nullptr;
533
534
0
    const BIGNUM* cbn = nullptr;
535
0
    switch (param)
536
0
    {
537
0
      case FREERDP_KEY_PARAM_RSA_D:
538
0
#if OPENSSL_VERSION_NUMBER >= 0x10101007L
539
0
        cbn = RSA_get0_d(rsa);
540
0
#endif
541
0
        break;
542
0
      case FREERDP_KEY_PARAM_RSA_E:
543
0
#if OPENSSL_VERSION_NUMBER >= 0x10101007L
544
0
        cbn = RSA_get0_e(rsa);
545
0
#endif
546
0
        break;
547
0
      case FREERDP_KEY_PARAM_RSA_N:
548
0
#if OPENSSL_VERSION_NUMBER >= 0x10101007L
549
0
        cbn = RSA_get0_n(rsa);
550
0
#endif
551
0
        break;
552
0
      default:
553
0
        return nullptr;
554
0
    }
555
0
    if (!cbn)
556
0
      return nullptr;
557
0
    bn = BN_dup(cbn);
558
0
    if (!bn)
559
0
      return nullptr;
560
0
  }
561
0
#endif
562
563
0
  const int length = BN_num_bytes(bn);
564
0
  if (length < 0)
565
0
    goto fail;
566
567
0
  {
568
0
    const size_t alloc_size = (size_t)length + 1ull;
569
0
    buf = calloc(alloc_size, sizeof(BYTE));
570
0
  }
571
572
0
  if (!buf)
573
0
    goto fail;
574
575
0
  {
576
0
    const int bnlen = BN_bn2bin(bn, buf);
577
0
    if (bnlen != length)
578
0
    {
579
0
      free(buf);
580
0
      buf = nullptr;
581
0
    }
582
0
    else
583
0
      *plength = WINPR_ASSERTING_INT_CAST(size_t, length);
584
0
  }
585
586
0
fail:
587
0
  BN_free(bn);
588
0
  return buf;
589
0
}
590
591
WINPR_DIGEST_CTX* freerdp_key_digest_sign(rdpPrivateKey* key, WINPR_MD_TYPE digest)
592
0
{
593
0
  WINPR_DIGEST_CTX* md_ctx = winpr_Digest_New();
594
0
  if (!md_ctx)
595
0
    return nullptr;
596
597
0
  if (!winpr_DigestSign_Init(md_ctx, digest, key->evp))
598
0
  {
599
0
    winpr_Digest_Free(md_ctx);
600
0
    return nullptr;
601
0
  }
602
0
  return md_ctx;
603
0
}
604
605
static BOOL bio_read_pem(BIO* bio, char** ppem, size_t* plength)
606
0
{
607
0
  BOOL rc = FALSE;
608
609
0
  WINPR_ASSERT(bio);
610
0
  WINPR_ASSERT(ppem);
611
612
0
  const size_t blocksize = 2048;
613
0
  size_t offset = 0;
614
0
  size_t length = blocksize;
615
0
  char* pem = nullptr;
616
617
0
  *ppem = nullptr;
618
0
  if (plength)
619
0
    *plength = 0;
620
621
0
  while (offset < length)
622
0
  {
623
0
    char* tmp = realloc(pem, length + 1);
624
0
    if (!tmp)
625
0
      goto fail;
626
0
    pem = tmp;
627
628
0
    ERR_clear_error();
629
630
0
    const int status = BIO_read(bio, &pem[offset], (int)(length - offset));
631
0
    if (status < 0)
632
0
    {
633
0
      WLog_ERR(TAG, "failed to read certificate");
634
0
      goto fail;
635
0
    }
636
637
0
    if (status == 0)
638
0
      break;
639
640
0
    offset += (size_t)status;
641
0
    if (length - offset > 0)
642
0
      break;
643
0
    length += blocksize;
644
0
  }
645
646
0
  if (pem)
647
0
  {
648
0
    if (offset >= length)
649
0
      goto fail;
650
0
    pem[offset] = '\0';
651
0
  }
652
0
  *ppem = pem;
653
0
  if (plength)
654
0
    *plength = offset;
655
0
  rc = TRUE;
656
0
fail:
657
0
  if (!rc)
658
0
    free(pem);
659
660
0
  return rc;
661
0
}
662
663
char* freerdp_key_get_pem(const rdpPrivateKey* key, size_t* plen, const char* password)
664
0
{
665
0
  WINPR_ASSERT(key);
666
667
0
  if (!key->evp)
668
0
    return nullptr;
669
670
  /**
671
   * Don't manage certificates internally, leave it up entirely to the external client
672
   * implementation
673
   */
674
0
  BIO* bio = BIO_new(BIO_s_mem());
675
676
0
  if (!bio)
677
0
  {
678
0
    WLog_ERR(TAG, "BIO_new() failure");
679
0
    return nullptr;
680
0
  }
681
682
0
  char* pem = nullptr;
683
684
0
  const EVP_CIPHER* enc = nullptr;
685
0
  if (password)
686
0
    enc = EVP_aes_256_xts();
687
688
0
  const int status = PEM_write_bio_PrivateKey(bio, key->evp, enc, nullptr, 0, nullptr,
689
0
                                              WINPR_CAST_CONST_PTR_AWAY(password, void*));
690
0
  if (status < 0)
691
0
  {
692
0
    WLog_ERR(TAG, "PEM_write_bio_PrivateKey failure: %d", status);
693
0
    goto fail;
694
0
  }
695
696
0
  (void)bio_read_pem(bio, &pem, plen);
697
698
0
fail:
699
0
  BIO_free_all(bio);
700
0
  return pem;
701
0
}