mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-14 00:14:11 +09:00
[crypto,key] add function to export PEM and create a key
* freerdp_key_generate creates a new key * freerdp_key_get_pem exports the key as PEM
This commit is contained in:
@@ -35,16 +35,62 @@ extern "C"
|
||||
WINPR_ATTR_MALLOC(freerdp_key_free, 1)
|
||||
FREERDP_API rdpPrivateKey* freerdp_key_new(void);
|
||||
|
||||
WINPR_ATTR_MALLOC(freerdp_key_free, 1)
|
||||
FREERDP_API rdpPrivateKey* freerdp_key_new_from_file(const char* keyfile);
|
||||
WINPR_DEPRECATED_VAR(
|
||||
"[since 3.16.0] use freerdp_key_new_from_file_enc",
|
||||
WINPR_ATTR_MALLOC(freerdp_key_free, 1)
|
||||
FREERDP_API rdpPrivateKey* freerdp_key_new_from_file(const char* keyfile));
|
||||
|
||||
WINPR_DEPRECATED_VAR("[since 3.16.0] use freerdp_key_new_from_pem_enc",
|
||||
WINPR_ATTR_MALLOC(freerdp_key_free, 1)
|
||||
FREERDP_API rdpPrivateKey* freerdp_key_new_from_pem(const char* pem));
|
||||
|
||||
/** @brief Create a private key from file \b keyfile with optional password \b password
|
||||
*
|
||||
* @param keyfile The file to read the key from
|
||||
* @param password The optional password the key is enecrypted with, \b NULL for unencrypted
|
||||
* @return An allocated private key, \b NULL in case of failure.
|
||||
* @since version 3.16.0
|
||||
*/
|
||||
FREERDP_API rdpPrivateKey* freerdp_key_new_from_file_enc(const char* keyfile,
|
||||
const char* password);
|
||||
|
||||
/** @brief Create a private key from a PEM file with optional \b password
|
||||
*
|
||||
* @param pem The PEM string to use
|
||||
* @param password The optional password, use \b NULL if no encryption is used.
|
||||
* @return An allocated private key, \b NULL in case of failure.
|
||||
* @since version 3.16.0
|
||||
*/
|
||||
WINPR_ATTR_MALLOC(freerdp_key_free, 1)
|
||||
FREERDP_API rdpPrivateKey* freerdp_key_new_from_pem(const char* pem);
|
||||
FREERDP_API rdpPrivateKey* freerdp_key_new_from_pem_enc(const char* pem, const char* password);
|
||||
|
||||
FREERDP_API BOOL freerdp_key_is_rsa(const rdpPrivateKey* key);
|
||||
|
||||
FREERDP_API size_t freerdp_key_get_bits(const rdpPrivateKey* key);
|
||||
|
||||
/** @brief Create a PEM from a private key
|
||||
*
|
||||
* @param key The key to convert
|
||||
* @param plen Optional pointer, value set to strlen of the PEM
|
||||
* @param password Optional password string. If \b NULL an unencrypted PEM is written.
|
||||
* @return A PEM string or \b NULL in case of errors
|
||||
*
|
||||
* @since version 3.16.0
|
||||
*/
|
||||
WINPR_ATTR_MALLOC(free, 1)
|
||||
FREERDP_API char* freerdp_key_get_pem(const rdpPrivateKey* key, size_t* plen,
|
||||
const char* password);
|
||||
|
||||
/** @brief Create a new private key
|
||||
*
|
||||
* @param key The key to initialize
|
||||
* @param type The key type (RSA, ...)
|
||||
* @param count The number of arguments following, depends on type
|
||||
* @return \b TRUE for success, \b FALSE otherwise
|
||||
* @since version 3.16.0
|
||||
*/
|
||||
FREERDP_API BOOL freerdp_key_generate(rdpPrivateKey* key, const char* type, size_t count, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -586,7 +586,7 @@ int aad_recv(rdpAad* aad, wStream* s)
|
||||
static BOOL generate_rsa_2048(rdpAad* aad)
|
||||
{
|
||||
WINPR_ASSERT(aad);
|
||||
return freerdp_key_generate(aad->key, 2048);
|
||||
return freerdp_key_generate(aad->key, "RSA", 1, 2048);
|
||||
}
|
||||
|
||||
static char* generate_rsa_digest_base64_str(rdpAad* aad, const char* input, size_t ilen)
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "privatekey.h"
|
||||
#include "cert_common.h"
|
||||
@@ -118,7 +119,8 @@ fail:
|
||||
}
|
||||
#endif
|
||||
|
||||
static EVP_PKEY* evp_pkey_utils_from_pem(const char* data, size_t len, BOOL fromFile)
|
||||
static EVP_PKEY* evp_pkey_utils_from_pem(const char* data, size_t len, BOOL fromFile,
|
||||
const char* password)
|
||||
{
|
||||
EVP_PKEY* evp = NULL;
|
||||
BIO* bio = NULL;
|
||||
@@ -137,7 +139,7 @@ static EVP_PKEY* evp_pkey_utils_from_pem(const char* data, size_t len, BOOL from
|
||||
return NULL;
|
||||
}
|
||||
|
||||
evp = PEM_read_bio_PrivateKey(bio, NULL, NULL, 0);
|
||||
evp = PEM_read_bio_PrivateKey(bio, NULL, NULL, WINPR_CAST_CONST_PTR_AWAY(password, void*));
|
||||
BIO_free_all(bio);
|
||||
if (!evp)
|
||||
WLog_ERR(TAG, "PEM_read_bio_PrivateKey returned NULL [input length %" PRIuz "]", len);
|
||||
@@ -226,11 +228,16 @@ fail:
|
||||
}
|
||||
|
||||
rdpPrivateKey* freerdp_key_new_from_pem(const char* pem)
|
||||
{
|
||||
return freerdp_key_new_from_pem_enc(pem, NULL);
|
||||
}
|
||||
|
||||
rdpPrivateKey* freerdp_key_new_from_pem_enc(const char* pem, const char* password)
|
||||
{
|
||||
rdpPrivateKey* key = freerdp_key_new();
|
||||
if (!key || !pem)
|
||||
goto fail;
|
||||
key->evp = evp_pkey_utils_from_pem(pem, strlen(pem), FALSE);
|
||||
key->evp = evp_pkey_utils_from_pem(pem, strlen(pem), FALSE, password);
|
||||
if (!key->evp)
|
||||
goto fail;
|
||||
if (!key_read_private(key))
|
||||
@@ -243,12 +250,16 @@ fail:
|
||||
|
||||
rdpPrivateKey* freerdp_key_new_from_file(const char* keyfile)
|
||||
{
|
||||
return freerdp_key_new_from_file_enc(keyfile, NULL);
|
||||
}
|
||||
|
||||
rdpPrivateKey* freerdp_key_new_from_file_enc(const char* keyfile, const char* password)
|
||||
{
|
||||
rdpPrivateKey* key = freerdp_key_new();
|
||||
if (!key || !keyfile)
|
||||
goto fail;
|
||||
|
||||
key->evp = evp_pkey_utils_from_pem(keyfile, strlen(keyfile), TRUE);
|
||||
key->evp = evp_pkey_utils_from_pem(keyfile, strlen(keyfile), TRUE, password);
|
||||
if (!key->evp)
|
||||
goto fail;
|
||||
if (!key_read_private(key))
|
||||
@@ -378,10 +389,30 @@ size_t freerdp_key_get_bits(const rdpPrivateKey* key)
|
||||
return WINPR_ASSERTING_INT_CAST(size_t, rc);
|
||||
}
|
||||
|
||||
BOOL freerdp_key_generate(rdpPrivateKey* key, size_t key_length)
|
||||
BOOL freerdp_key_generate(rdpPrivateKey* key, const char* type, size_t count, ...)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
|
||||
if (!type)
|
||||
{
|
||||
WLog_ERR(TAG, "Invalid argument type=%s", type);
|
||||
return FALSE;
|
||||
}
|
||||
if (strncmp("RSA", type, 4) != 0)
|
||||
{
|
||||
WLog_ERR(TAG, "Argument type=%s is currently not supported, aborting", type);
|
||||
return FALSE;
|
||||
}
|
||||
if (count != 1)
|
||||
{
|
||||
WLog_ERR(TAG, "Argument type=%s requires count=1, got %" PRIuz ", aborting", type, count);
|
||||
return FALSE;
|
||||
}
|
||||
va_list ap;
|
||||
va_start(ap, count);
|
||||
const int key_length = va_arg(ap, int);
|
||||
va_end(ap);
|
||||
|
||||
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
|
||||
RSA* rsa = NULL;
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
|
||||
@@ -423,7 +454,7 @@ BOOL freerdp_key_generate(rdpPrivateKey* key, size_t key_length)
|
||||
|
||||
rc = TRUE;
|
||||
#else
|
||||
EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
|
||||
EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_from_name(NULL, type, NULL);
|
||||
if (!pctx)
|
||||
return FALSE;
|
||||
|
||||
@@ -433,7 +464,7 @@ BOOL freerdp_key_generate(rdpPrivateKey* key, size_t key_length)
|
||||
if (key_length > INT_MAX)
|
||||
goto fail;
|
||||
|
||||
if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, (int)key_length) != 1)
|
||||
if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, key_length) != 1)
|
||||
goto fail;
|
||||
|
||||
EVP_PKEY_free(key->evp);
|
||||
@@ -550,3 +581,101 @@ WINPR_DIGEST_CTX* freerdp_key_digest_sign(rdpPrivateKey* key, WINPR_MD_TYPE dige
|
||||
}
|
||||
return md_ctx;
|
||||
}
|
||||
|
||||
static BOOL bio_read_pem(BIO* bio, char** ppem, size_t* plength)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
|
||||
WINPR_ASSERT(bio);
|
||||
WINPR_ASSERT(ppem);
|
||||
|
||||
const size_t blocksize = 2048;
|
||||
size_t offset = 0;
|
||||
size_t length = blocksize;
|
||||
char* pem = NULL;
|
||||
|
||||
*ppem = NULL;
|
||||
if (plength)
|
||||
*plength = 0;
|
||||
|
||||
while (offset < length)
|
||||
{
|
||||
char* tmp = realloc(pem, length + 1);
|
||||
if (!tmp)
|
||||
goto fail;
|
||||
pem = tmp;
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
const int status = BIO_read(bio, &pem[offset], (int)(length - offset));
|
||||
if (status < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "failed to read certificate");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (status == 0)
|
||||
break;
|
||||
|
||||
offset += (size_t)status;
|
||||
if (length - offset > 0)
|
||||
break;
|
||||
length += blocksize;
|
||||
}
|
||||
|
||||
if (pem)
|
||||
{
|
||||
if (offset >= length)
|
||||
goto fail;
|
||||
pem[offset] = '\0';
|
||||
}
|
||||
*ppem = pem;
|
||||
if (plength)
|
||||
*plength = offset;
|
||||
rc = TRUE;
|
||||
fail:
|
||||
if (!rc)
|
||||
free(pem);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
char* freerdp_key_get_pem(const rdpPrivateKey* key, size_t* plen, const char* password)
|
||||
{
|
||||
WINPR_ASSERT(key);
|
||||
|
||||
if (!key->evp)
|
||||
return NULL;
|
||||
|
||||
/**
|
||||
* Don't manage certificates internally, leave it up entirely to the external client
|
||||
* implementation
|
||||
*/
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
|
||||
if (!bio)
|
||||
{
|
||||
WLog_ERR(TAG, "BIO_new() failure");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* pem = NULL;
|
||||
|
||||
const EVP_CIPHER* enc = NULL;
|
||||
if (password)
|
||||
enc = EVP_aes_256_cbc_hmac_sha256();
|
||||
|
||||
const int status = PEM_write_bio_PrivateKey(bio, key->evp, enc, NULL, 0, 0,
|
||||
WINPR_CAST_CONST_PTR_AWAY(password, void*));
|
||||
if (status < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "PEM_write_bio_PrivateKey failure: %d", status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
(void)bio_read_pem(bio, &pem, plen);
|
||||
|
||||
fail:
|
||||
BIO_free_all(bio);
|
||||
return pem;
|
||||
}
|
||||
|
||||
@@ -45,8 +45,6 @@ extern "C"
|
||||
FREERDP_LOCAL const rdpCertInfo* freerdp_key_get_info(const rdpPrivateKey* key);
|
||||
FREERDP_LOCAL const BYTE* freerdp_key_get_exponent(const rdpPrivateKey* key, size_t* plength);
|
||||
|
||||
FREERDP_LOCAL BOOL freerdp_key_generate(rdpPrivateKey* key, size_t bits);
|
||||
|
||||
/** \brief returns a pointer to a EVP_PKEY structure.
|
||||
* Call EVP_PKEY_free when done.
|
||||
*/
|
||||
|
||||
@@ -1499,7 +1499,7 @@ BOOL vgids_init(vgidsContext* ctx, const char* cert, const char* privateKey, con
|
||||
if (!ctx->certificate)
|
||||
goto init_failed;
|
||||
|
||||
ctx->privateKey = freerdp_key_new_from_pem(privateKey);
|
||||
ctx->privateKey = freerdp_key_new_from_pem_enc(privateKey, NULL);
|
||||
if (!ctx->privateKey)
|
||||
goto init_failed;
|
||||
|
||||
|
||||
@@ -376,7 +376,7 @@ static void* mf_peer_main_loop(void* arg)
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
/* Initialize the real server settings here */
|
||||
rdpPrivateKey* key = freerdp_key_new_from_file(info->key);
|
||||
rdpPrivateKey* key = freerdp_key_new_from_file_enc(info->key, NULL);
|
||||
if (!key)
|
||||
goto fail;
|
||||
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1))
|
||||
|
||||
@@ -1115,7 +1115,7 @@ static DWORD WINAPI test_peer_mainloop(LPVOID arg)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rdpPrivateKey* key = freerdp_key_new_from_file(info->key);
|
||||
rdpPrivateKey* key = freerdp_key_new_from_file_enc(info->key, NULL);
|
||||
if (!key)
|
||||
goto fail;
|
||||
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1))
|
||||
|
||||
@@ -255,7 +255,7 @@ static BOOL wf_peer_read_settings(freerdp_peer* client)
|
||||
&(PrivateKeyFile)))
|
||||
PrivateKeyFile = _strdup("server.key");
|
||||
|
||||
rdpPrivateKey* key = freerdp_key_new_from_file(PrivateKeyFile);
|
||||
rdpPrivateKey* key = freerdp_key_new_from_file_enc(PrivateKeyFile, NULL);
|
||||
free(PrivateKeyFile);
|
||||
|
||||
if (!key)
|
||||
|
||||
@@ -480,7 +480,7 @@ static BOOL pf_server_initialize_peer_connection(freerdp_peer* peer)
|
||||
pdata->module = server->module;
|
||||
const proxyConfig* config = pdata->config = server->config;
|
||||
|
||||
rdpPrivateKey* key = freerdp_key_new_from_pem(config->PrivateKeyPEM);
|
||||
rdpPrivateKey* key = freerdp_key_new_from_pem_enc(config->PrivateKeyPEM, NULL);
|
||||
if (!key)
|
||||
return FALSE;
|
||||
|
||||
|
||||
@@ -925,7 +925,7 @@ static BOOL shadow_server_init_certificate(rdpShadowServer* server)
|
||||
rdpSettings* settings = server->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
rdpPrivateKey* key = freerdp_key_new_from_file(server->PrivateKeyFile);
|
||||
rdpPrivateKey* key = freerdp_key_new_from_file_enc(server->PrivateKeyFile, NULL);
|
||||
if (!key)
|
||||
goto out_fail;
|
||||
if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1))
|
||||
|
||||
Reference in New Issue
Block a user