Coverage Report

Created: 2026-03-04 06:13

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 EVP_PKEY* evp_pkey_utils_from_pem(const char* data, size_t len, BOOL fromFile,
123
                                         const char* password)
124
0
{
125
0
  EVP_PKEY* evp = nullptr;
126
0
  BIO* bio = nullptr;
127
0
  if (fromFile)
128
0
    bio = BIO_new_file(data, "rb");
129
0
  else
130
0
  {
131
0
    if (len > INT_MAX)
132
0
      return nullptr;
133
0
    bio = BIO_new_mem_buf(data, (int)len);
134
0
  }
135
136
0
  if (!bio)
137
0
  {
138
0
    WLog_ERR(TAG, "BIO_new failed for private key");
139
0
    return nullptr;
140
0
  }
141
142
0
  evp =
143
0
      PEM_read_bio_PrivateKey(bio, nullptr, nullptr, WINPR_CAST_CONST_PTR_AWAY(password, void*));
144
0
  BIO_free_all(bio);
145
0
  if (!evp)
146
0
    WLog_ERR(TAG, "PEM_read_bio_PrivateKey returned nullptr [input length %" PRIuz "]", len);
147
148
0
  return evp;
149
0
}
150
151
static BOOL key_read_private(rdpPrivateKey* key)
152
0
{
153
0
  BOOL rc = FALSE;
154
155
0
  WINPR_ASSERT(key);
156
0
  WINPR_ASSERT(key->evp);
157
158
  /* The key is not an RSA key, that means we just return success. */
159
0
  if (!freerdp_key_is_rsa(key))
160
0
    return TRUE;
161
162
0
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
163
0
  RSA* rsa = evp_pkey_to_rsa(key);
164
0
  if (!rsa)
165
0
  {
166
0
    char ebuffer[256] = WINPR_C_ARRAY_INIT;
167
0
    WLog_ERR(TAG, "unable to load RSA key: %s.",
168
0
             winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
169
0
    goto fail;
170
0
  }
171
172
0
  switch (RSA_check_key(rsa))
173
0
  {
174
0
    case 0:
175
0
      WLog_ERR(TAG, "invalid RSA key");
176
0
      goto fail;
177
178
0
    case 1:
179
      /* Valid key. */
180
0
      break;
181
182
0
    default:
183
0
    {
184
0
      char ebuffer[256] = WINPR_C_ARRAY_INIT;
185
0
      WLog_ERR(TAG, "unexpected error when checking RSA key: %s.",
186
0
               winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
187
0
      goto fail;
188
0
    }
189
0
  }
190
191
0
  const BIGNUM* rsa_e = nullptr;
192
0
  const BIGNUM* rsa_n = nullptr;
193
0
  const BIGNUM* rsa_d = nullptr;
194
195
0
  RSA_get0_key(rsa, &rsa_n, &rsa_e, &rsa_d);
196
#else
197
  BIGNUM* rsa_e = nullptr;
198
  BIGNUM* rsa_n = nullptr;
199
  BIGNUM* rsa_d = nullptr;
200
201
  if (!EVP_PKEY_get_bn_param(key->evp, OSSL_PKEY_PARAM_RSA_N, &rsa_n))
202
    goto fail;
203
  if (!EVP_PKEY_get_bn_param(key->evp, OSSL_PKEY_PARAM_RSA_E, &rsa_e))
204
    goto fail;
205
  if (!EVP_PKEY_get_bn_param(key->evp, OSSL_PKEY_PARAM_RSA_D, &rsa_d))
206
    goto fail;
207
#endif
208
0
  if (BN_num_bytes(rsa_e) > 4)
209
0
  {
210
0
    WLog_ERR(TAG, "RSA public exponent too large");
211
0
    goto fail;
212
0
  }
213
214
0
  if (!read_bignum(&key->PrivateExponent, &key->PrivateExponentLength, rsa_d, TRUE))
215
0
    goto fail;
216
217
0
  if (!cert_info_create(&key->cert, rsa_n, rsa_e))
218
0
    goto fail;
219
0
  rc = TRUE;
220
0
fail:
221
0
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
222
0
  RSA_free(rsa);
223
#else
224
  BN_free(rsa_d);
225
  BN_free(rsa_e);
226
  BN_free(rsa_n);
227
#endif
228
0
  return rc;
229
0
}
230
231
rdpPrivateKey* freerdp_key_new_from_pem(const char* pem)
232
0
{
233
0
  return freerdp_key_new_from_pem_enc(pem, nullptr);
234
0
}
235
236
rdpPrivateKey* freerdp_key_new_from_pem_enc(const char* pem, const char* password)
237
0
{
238
0
  rdpPrivateKey* key = freerdp_key_new();
239
0
  if (!key || !pem)
240
0
    goto fail;
241
0
  key->evp = evp_pkey_utils_from_pem(pem, strlen(pem), FALSE, password);
242
0
  if (!key->evp)
243
0
    goto fail;
244
0
  if (!key_read_private(key))
245
0
    goto fail;
246
0
  return key;
247
0
fail:
248
0
  freerdp_key_free(key);
249
0
  return nullptr;
250
0
}
251
252
rdpPrivateKey* freerdp_key_new_from_file(const char* keyfile)
253
0
{
254
0
  return freerdp_key_new_from_file_enc(keyfile, nullptr);
255
0
}
256
257
rdpPrivateKey* freerdp_key_new_from_file_enc(const char* keyfile, const char* password)
258
0
{
259
0
  rdpPrivateKey* key = freerdp_key_new();
260
0
  if (!key || !keyfile)
261
0
    goto fail;
262
263
0
  key->evp = evp_pkey_utils_from_pem(keyfile, strlen(keyfile), TRUE, password);
264
0
  if (!key->evp)
265
0
    goto fail;
266
0
  if (!key_read_private(key))
267
0
    goto fail;
268
0
  return key;
269
0
fail:
270
0
  freerdp_key_free(key);
271
0
  return nullptr;
272
0
}
273
274
rdpPrivateKey* freerdp_key_new(void)
275
0
{
276
0
  return calloc(1, sizeof(rdpPrivateKey));
277
0
}
278
279
rdpPrivateKey* freerdp_key_clone(const rdpPrivateKey* key)
280
0
{
281
0
  if (!key)
282
0
    return nullptr;
283
284
0
  rdpPrivateKey* _key = (rdpPrivateKey*)calloc(1, sizeof(rdpPrivateKey));
285
286
0
  if (!_key)
287
0
    return nullptr;
288
289
0
  if (key->evp)
290
0
  {
291
0
    _key->evp = key->evp;
292
0
    if (!_key->evp)
293
0
      goto out_fail;
294
0
    EVP_PKEY_up_ref(_key->evp);
295
0
  }
296
297
0
  if (key->PrivateExponent)
298
0
  {
299
0
    _key->PrivateExponent = (BYTE*)malloc(key->PrivateExponentLength);
300
301
0
    if (!_key->PrivateExponent)
302
0
      goto out_fail;
303
304
0
    CopyMemory(_key->PrivateExponent, key->PrivateExponent, key->PrivateExponentLength);
305
0
    _key->PrivateExponentLength = key->PrivateExponentLength;
306
0
  }
307
308
0
  if (!cert_info_clone(&_key->cert, &key->cert))
309
0
    goto out_fail;
310
311
0
  return _key;
312
0
out_fail:
313
0
  WINPR_PRAGMA_DIAG_PUSH
314
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
315
0
  freerdp_key_free(_key);
316
0
  WINPR_PRAGMA_DIAG_POP
317
0
  return nullptr;
318
0
}
319
320
void freerdp_key_free(rdpPrivateKey* key)
321
0
{
322
0
  if (!key)
323
0
    return;
324
325
0
  EVP_PKEY_free(key->evp);
326
0
  if (key->PrivateExponent)
327
0
    memset(key->PrivateExponent, 0, key->PrivateExponentLength);
328
0
  free(key->PrivateExponent);
329
0
  cert_info_free(&key->cert);
330
0
  free(key);
331
0
}
332
333
const rdpCertInfo* freerdp_key_get_info(const rdpPrivateKey* key)
334
0
{
335
0
  WINPR_ASSERT(key);
336
0
  if (!freerdp_key_is_rsa(key))
337
0
    return nullptr;
338
0
  return &key->cert;
339
0
}
340
341
const BYTE* freerdp_key_get_exponent(const rdpPrivateKey* key, size_t* plength)
342
0
{
343
0
  WINPR_ASSERT(key);
344
0
  if (!freerdp_key_is_rsa(key))
345
0
  {
346
0
    if (plength)
347
0
      *plength = 0;
348
0
    return nullptr;
349
0
  }
350
351
0
  if (plength)
352
0
    *plength = key->PrivateExponentLength;
353
0
  return key->PrivateExponent;
354
0
}
355
356
EVP_PKEY* freerdp_key_get_evp_pkey(const rdpPrivateKey* key)
357
0
{
358
0
  WINPR_ASSERT(key);
359
360
0
  EVP_PKEY* evp = key->evp;
361
0
  WINPR_ASSERT(evp);
362
0
  EVP_PKEY_up_ref(evp);
363
0
  return evp;
364
0
}
365
366
BOOL freerdp_key_is_rsa(const rdpPrivateKey* key)
367
0
{
368
0
  WINPR_ASSERT(key);
369
0
  if (key == priv_key_tssk)
370
0
    return TRUE;
371
372
0
  WINPR_ASSERT(key->evp);
373
0
  return (EVP_PKEY_id(key->evp) == EVP_PKEY_RSA);
374
0
}
375
376
size_t freerdp_key_get_bits(const rdpPrivateKey* key)
377
0
{
378
0
  int rc = -1;
379
0
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
380
0
  RSA* rsa = evp_pkey_to_rsa(key);
381
0
  if (rsa)
382
0
  {
383
0
    rc = RSA_bits(rsa);
384
0
    RSA_free(rsa);
385
0
  }
386
#else
387
  rc = EVP_PKEY_get_bits(key->evp);
388
#endif
389
390
0
  return WINPR_ASSERTING_INT_CAST(size_t, rc);
391
0
}
392
393
BOOL freerdp_key_generate(rdpPrivateKey* key, const char* type, size_t count, ...)
394
0
{
395
0
  BOOL rc = FALSE;
396
397
0
  if (!type)
398
0
  {
399
0
    WLog_ERR(TAG, "Invalid argument type=%s", type);
400
0
    return FALSE;
401
0
  }
402
0
  if (strncmp("RSA", type, 4) != 0)
403
0
  {
404
0
    WLog_ERR(TAG, "Argument type=%s is currently not supported, aborting", type);
405
0
    return FALSE;
406
0
  }
407
0
  if (count != 1)
408
0
  {
409
0
    WLog_ERR(TAG, "Argument type=%s requires count=1, got %" PRIuz ", aborting", type, count);
410
0
    return FALSE;
411
0
  }
412
0
  va_list ap = WINPR_C_ARRAY_INIT;
413
0
  va_start(ap, count);
414
0
  const int key_length = va_arg(ap, int);
415
0
  va_end(ap);
416
417
0
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
418
0
  RSA* rsa = nullptr;
419
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
420
  rsa = RSA_generate_key(key_length, RSA_F4, nullptr, nullptr);
421
#else
422
0
  {
423
0
    BIGNUM* bn = BN_secure_new();
424
425
0
    if (!bn)
426
0
      return FALSE;
427
428
0
    rsa = RSA_new();
429
430
0
    if (!rsa)
431
0
    {
432
0
      BN_clear_free(bn);
433
0
      return FALSE;
434
0
    }
435
436
0
    BN_set_word(bn, RSA_F4);
437
0
    const int res = RSA_generate_key_ex(rsa, key_length, bn, nullptr);
438
0
    BN_clear_free(bn);
439
440
0
    if (res != 1)
441
0
      return FALSE;
442
0
  }
443
0
#endif
444
445
0
  EVP_PKEY_free(key->evp);
446
0
  key->evp = EVP_PKEY_new();
447
448
0
  if (!EVP_PKEY_assign_RSA(key->evp, rsa))
449
0
  {
450
0
    EVP_PKEY_free(key->evp);
451
0
    key->evp = nullptr;
452
0
    RSA_free(rsa);
453
0
    return FALSE;
454
0
  }
455
456
0
  rc = TRUE;
457
#else
458
  EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_from_name(nullptr, type, nullptr);
459
  if (!pctx)
460
    return FALSE;
461
462
  if (EVP_PKEY_keygen_init(pctx) != 1)
463
    goto fail;
464
465
  if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, key_length) != 1)
466
    goto fail;
467
468
  EVP_PKEY_free(key->evp);
469
  key->evp = nullptr;
470
471
  if (EVP_PKEY_generate(pctx, &key->evp) != 1)
472
    goto fail;
473
474
  rc = TRUE;
475
fail:
476
  EVP_PKEY_CTX_free(pctx);
477
#endif
478
0
  return rc;
479
0
}
480
481
BYTE* freerdp_key_get_param(const rdpPrivateKey* key, enum FREERDP_KEY_PARAM param, size_t* plength)
482
0
{
483
0
  BYTE* buf = nullptr;
484
485
0
  WINPR_ASSERT(key);
486
0
  WINPR_ASSERT(plength);
487
488
0
  *plength = 0;
489
490
0
  BIGNUM* bn = nullptr;
491
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
492
493
  const char* pk = nullptr;
494
  switch (param)
495
  {
496
    case FREERDP_KEY_PARAM_RSA_D:
497
      pk = OSSL_PKEY_PARAM_RSA_D;
498
      break;
499
    case FREERDP_KEY_PARAM_RSA_E:
500
      pk = OSSL_PKEY_PARAM_RSA_E;
501
      break;
502
    case FREERDP_KEY_PARAM_RSA_N:
503
      pk = OSSL_PKEY_PARAM_RSA_N;
504
      break;
505
    default:
506
      return nullptr;
507
  }
508
509
  if (!EVP_PKEY_get_bn_param(key->evp, pk, &bn))
510
    return nullptr;
511
#else
512
0
  {
513
0
    const RSA* rsa = EVP_PKEY_get0_RSA(key->evp);
514
0
    if (!rsa)
515
0
      return nullptr;
516
517
0
    const BIGNUM* cbn = nullptr;
518
0
    switch (param)
519
0
    {
520
0
      case FREERDP_KEY_PARAM_RSA_D:
521
0
#if OPENSSL_VERSION_NUMBER >= 0x10101007L
522
0
        cbn = RSA_get0_d(rsa);
523
0
#endif
524
0
        break;
525
0
      case FREERDP_KEY_PARAM_RSA_E:
526
0
#if OPENSSL_VERSION_NUMBER >= 0x10101007L
527
0
        cbn = RSA_get0_e(rsa);
528
0
#endif
529
0
        break;
530
0
      case FREERDP_KEY_PARAM_RSA_N:
531
0
#if OPENSSL_VERSION_NUMBER >= 0x10101007L
532
0
        cbn = RSA_get0_n(rsa);
533
0
#endif
534
0
        break;
535
0
      default:
536
0
        return nullptr;
537
0
    }
538
0
    if (!cbn)
539
0
      return nullptr;
540
0
    bn = BN_dup(cbn);
541
0
    if (!bn)
542
0
      return nullptr;
543
0
  }
544
0
#endif
545
546
0
  const int length = BN_num_bytes(bn);
547
0
  if (length < 0)
548
0
    goto fail;
549
550
0
  {
551
0
    const size_t alloc_size = (size_t)length + 1ull;
552
0
    buf = calloc(alloc_size, sizeof(BYTE));
553
0
  }
554
555
0
  if (!buf)
556
0
    goto fail;
557
558
0
  {
559
0
    const int bnlen = BN_bn2bin(bn, buf);
560
0
    if (bnlen != length)
561
0
    {
562
0
      free(buf);
563
0
      buf = nullptr;
564
0
    }
565
0
    else
566
0
      *plength = WINPR_ASSERTING_INT_CAST(size_t, length);
567
0
  }
568
569
0
fail:
570
0
  BN_free(bn);
571
0
  return buf;
572
0
}
573
574
WINPR_DIGEST_CTX* freerdp_key_digest_sign(rdpPrivateKey* key, WINPR_MD_TYPE digest)
575
0
{
576
0
  WINPR_DIGEST_CTX* md_ctx = winpr_Digest_New();
577
0
  if (!md_ctx)
578
0
    return nullptr;
579
580
0
  if (!winpr_DigestSign_Init(md_ctx, digest, key->evp))
581
0
  {
582
0
    winpr_Digest_Free(md_ctx);
583
0
    return nullptr;
584
0
  }
585
0
  return md_ctx;
586
0
}
587
588
static BOOL bio_read_pem(BIO* bio, char** ppem, size_t* plength)
589
0
{
590
0
  BOOL rc = FALSE;
591
592
0
  WINPR_ASSERT(bio);
593
0
  WINPR_ASSERT(ppem);
594
595
0
  const size_t blocksize = 2048;
596
0
  size_t offset = 0;
597
0
  size_t length = blocksize;
598
0
  char* pem = nullptr;
599
600
0
  *ppem = nullptr;
601
0
  if (plength)
602
0
    *plength = 0;
603
604
0
  while (offset < length)
605
0
  {
606
0
    char* tmp = realloc(pem, length + 1);
607
0
    if (!tmp)
608
0
      goto fail;
609
0
    pem = tmp;
610
611
0
    ERR_clear_error();
612
613
0
    const int status = BIO_read(bio, &pem[offset], (int)(length - offset));
614
0
    if (status < 0)
615
0
    {
616
0
      WLog_ERR(TAG, "failed to read certificate");
617
0
      goto fail;
618
0
    }
619
620
0
    if (status == 0)
621
0
      break;
622
623
0
    offset += (size_t)status;
624
0
    if (length - offset > 0)
625
0
      break;
626
0
    length += blocksize;
627
0
  }
628
629
0
  if (pem)
630
0
  {
631
0
    if (offset >= length)
632
0
      goto fail;
633
0
    pem[offset] = '\0';
634
0
  }
635
0
  *ppem = pem;
636
0
  if (plength)
637
0
    *plength = offset;
638
0
  rc = TRUE;
639
0
fail:
640
0
  if (!rc)
641
0
    free(pem);
642
643
0
  return rc;
644
0
}
645
646
char* freerdp_key_get_pem(const rdpPrivateKey* key, size_t* plen, const char* password)
647
0
{
648
0
  WINPR_ASSERT(key);
649
650
0
  if (!key->evp)
651
0
    return nullptr;
652
653
  /**
654
   * Don't manage certificates internally, leave it up entirely to the external client
655
   * implementation
656
   */
657
0
  BIO* bio = BIO_new(BIO_s_mem());
658
659
0
  if (!bio)
660
0
  {
661
0
    WLog_ERR(TAG, "BIO_new() failure");
662
0
    return nullptr;
663
0
  }
664
665
0
  char* pem = nullptr;
666
667
0
  const EVP_CIPHER* enc = nullptr;
668
0
  if (password)
669
0
    enc = EVP_aes_256_xts();
670
671
0
  const int status = PEM_write_bio_PrivateKey(bio, key->evp, enc, nullptr, 0, nullptr,
672
0
                                              WINPR_CAST_CONST_PTR_AWAY(password, void*));
673
0
  if (status < 0)
674
0
  {
675
0
    WLog_ERR(TAG, "PEM_write_bio_PrivateKey failure: %d", status);
676
0
    goto fail;
677
0
  }
678
679
0
  (void)bio_read_pem(bio, &pem, plen);
680
681
0
fail:
682
0
  BIO_free_all(bio);
683
0
  return pem;
684
0
}