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