1
0
mirror of https://git.libssh.org/projects/libssh.git synced 2025-11-29 01:03:57 +03:00

pki: New API functions exporting (also ed25519 keys in different formats)

This also adds an fallback to OpenSSH file format in non-OpenSSL backends and
OpenSSH-compatible private key export for writing OpenSSH private keys.

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
Jakub Jelen
2023-08-11 16:22:01 +02:00
parent 30d5ab4313
commit 3fa28aaf49
10 changed files with 746 additions and 182 deletions

View File

@@ -686,6 +686,12 @@ typedef int (*ssh_auth_callback) (const char *prompt, char *buf, size_t len,
/** @} */
enum ssh_file_format_e {
SSH_FILE_FORMAT_DEFAULT = 0,
SSH_FILE_FORMAT_OPENSSH,
SSH_FILE_FORMAT_PEM,
};
LIBSSH_API ssh_key ssh_key_new(void);
#define SSH_KEY_FREE(x) \
do { if ((x) != NULL) { ssh_key_free(x); x = NULL; } } while(0)
@@ -712,6 +718,13 @@ LIBSSH_API int ssh_pki_export_privkey_base64(const ssh_key privkey,
ssh_auth_callback auth_fn,
void *auth_data,
char **b64_key);
LIBSSH_API int
ssh_pki_export_privkey_base64_format(const ssh_key privkey,
const char *passphrase,
ssh_auth_callback auth_fn,
void *auth_data,
char **b64_key,
enum ssh_file_format_e format);
LIBSSH_API int ssh_pki_import_privkey_file(const char *filename,
const char *passphrase,
ssh_auth_callback auth_fn,
@@ -722,6 +735,13 @@ LIBSSH_API int ssh_pki_export_privkey_file(const ssh_key privkey,
ssh_auth_callback auth_fn,
void *auth_data,
const char *filename);
LIBSSH_API int
ssh_pki_export_privkey_file_format(const ssh_key privkey,
const char *passphrase,
ssh_auth_callback auth_fn,
void *auth_data,
const char *filename,
enum ssh_file_format_e format);
LIBSSH_API int ssh_pki_copy_cert_to_privkey(const ssh_key cert_key,
ssh_key privkey);

View File

@@ -153,6 +153,10 @@ int ssh_pki_import_pubkey_blob(const ssh_string key_blob,
int ssh_pki_import_cert_blob(const ssh_string cert_blob,
ssh_key *pkey);
/* SSH Private Key Functions */
int ssh_pki_export_privkey_blob(const ssh_key key,
ssh_string *pblob);
/* SSH Signing Functions */
ssh_string ssh_pki_do_sign(ssh_session session, ssh_buffer sigbuf,

View File

@@ -92,7 +92,7 @@ int pki_pubkey_build_rsa(ssh_key key,
ssh_string e,
ssh_string n);
int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e);
ssh_string pki_publickey_to_blob(const ssh_key key);
ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type);
/* SSH Private Key Functions */
int pki_privkey_build_rsa(ssh_key key,
@@ -106,7 +106,6 @@ int pki_privkey_build_ecdsa(ssh_key key,
int nid,
ssh_string e,
ssh_string exp);
ssh_string pki_publickey_to_blob(const ssh_key key);
/* SSH Signature Functions */
ssh_signature pki_sign_data(const ssh_key privkey,
@@ -143,6 +142,7 @@ int pki_ed25519_key_cmp(const ssh_key k1,
enum ssh_keycmp_e what);
int pki_ed25519_key_dup(ssh_key new_key, const ssh_key key);
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key);
int pki_ed25519_private_key_to_blob(ssh_buffer buffer, const ssh_key privkey);
ssh_string pki_ed25519_signature_to_blob(ssh_signature sig);
int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob);
int pki_privkey_build_ed25519(ssh_key key,

View File

@@ -469,5 +469,7 @@ LIBSSH_AFTER_4_9_0
sftp_aio_free;
sftp_aio_wait_read;
sftp_aio_wait_write;
ssh_pki_export_privkey_base64_format;
ssh_pki_export_privkey_file_format;
} LIBSSH_4_9_0;

244
src/pki.c
View File

@@ -836,6 +836,88 @@ int ssh_pki_import_privkey_base64(const char *b64_key,
return SSH_OK;
}
/**
* @brief Convert a private key to a base64 encoded key in given format
*
* @param[in] privkey The private key to export.
*
* @param[in] passphrase The passphrase to use to encrypt the key with or
* NULL. An empty string means no passphrase.
*
* @param[in] auth_fn An auth function you may want to use or NULL.
*
* @param[in] auth_data Private data passed to the auth function.
*
* @param[out] b64_key A pointer to store the allocated base64 encoded key. You
* need to free the buffer using ssh_string_from_char().
*
* @param[in] format The file format (OpenSSH, PEM, or default)
*
* @return SSH_OK on success, SSH_ERROR on error.
*
* @see ssh_string_free_char()
*/
int
ssh_pki_export_privkey_base64_format(const ssh_key privkey,
const char *passphrase,
ssh_auth_callback auth_fn,
void *auth_data,
char **b64_key,
enum ssh_file_format_e format)
{
ssh_string blob = NULL;
char *b64 = NULL;
if (privkey == NULL || !ssh_key_is_private(privkey)) {
return SSH_ERROR;
}
/* The PEM export is supported only with OpenSSL. We fall back to
* OpenSSH key format elsewhere */
if (format == SSH_FILE_FORMAT_DEFAULT) {
#ifdef HAVE_LIBCRYPTO
if (privkey->type != SSH_KEYTYPE_ED25519) {
format = SSH_FILE_FORMAT_PEM;
} else {
#else
if (1) {
#endif /* HAVE_LIBCRYPTO */
format = SSH_FILE_FORMAT_OPENSSH;
}
}
switch (format) {
case SSH_FILE_FORMAT_DEFAULT:
case SSH_FILE_FORMAT_PEM:
blob = pki_private_key_to_pem(privkey,
passphrase,
auth_fn,
auth_data);
break;
case SSH_FILE_FORMAT_OPENSSH:
blob = ssh_pki_openssh_privkey_export(privkey,
passphrase,
auth_fn,
auth_data);
break;
}
if (blob == NULL) {
return SSH_ERROR;
}
b64 = strndup(ssh_string_data(blob), ssh_string_len(blob));
SSH_STRING_FREE(blob);
if (b64 == NULL) {
return SSH_ERROR;
}
*b64_key = b64;
return SSH_OK;
}
/**
* @brief Convert a private key to a pem base64 encoded key, or OpenSSH format for
* keytype ssh-ed25519
@@ -862,39 +944,16 @@ int ssh_pki_export_privkey_base64(const ssh_key privkey,
void *auth_data,
char **b64_key)
{
ssh_string blob = NULL;
char *b64 = NULL;
if (privkey == NULL || !ssh_key_is_private(privkey)) {
return SSH_ERROR;
}
if (privkey->type == SSH_KEYTYPE_ED25519){
blob = ssh_pki_openssh_privkey_export(privkey,
passphrase,
auth_fn,
auth_data);
} else {
blob = pki_private_key_to_pem(privkey,
passphrase,
auth_fn,
auth_data);
}
if (blob == NULL) {
return SSH_ERROR;
}
b64 = strndup(ssh_string_data(blob), ssh_string_len(blob));
SSH_STRING_FREE(blob);
if (b64 == NULL) {
return SSH_ERROR;
}
*b64_key = b64;
return SSH_OK;
return ssh_pki_export_privkey_base64_format(privkey,
passphrase,
auth_fn,
auth_data,
b64_key,
SSH_FILE_FORMAT_DEFAULT);
}
/**
* @brief Import a private key from a file or a PKCS #11 device.
*
@@ -1002,8 +1061,7 @@ int ssh_pki_import_privkey_file(const char *filename,
}
/**
* @brief Export a private key to a pem file on disk, or OpenSSH format for
* keytype ssh-ed25519
* @brief Export a private key to a file in format specified in the argument
*
* @param[in] privkey The private key to export.
*
@@ -1016,16 +1074,21 @@ int ssh_pki_import_privkey_file(const char *filename,
*
* @param[in] filename The path where to store the pem file.
*
* @param[in] format The file format (OpenSSH, PEM, or default)
*
* @return SSH_OK on success, SSH_ERROR on error.
*/
int ssh_pki_export_privkey_file(const ssh_key privkey,
const char *passphrase,
ssh_auth_callback auth_fn,
void *auth_data,
const char *filename)
int
ssh_pki_export_privkey_file_format(const ssh_key privkey,
const char *passphrase,
ssh_auth_callback auth_fn,
void *auth_data,
const char *filename,
enum ssh_file_format_e format)
{
ssh_string blob;
FILE *fp;
ssh_string blob = NULL;
FILE *fp = NULL;
int rc;
if (privkey == NULL || !ssh_key_is_private(privkey)) {
@@ -1040,16 +1103,34 @@ int ssh_pki_export_privkey_file(const ssh_key privkey,
return SSH_EOF;
}
if (privkey->type == SSH_KEYTYPE_ED25519){
blob = ssh_pki_openssh_privkey_export(privkey,
passphrase,
auth_fn,
auth_data);
} else {
/* The PEM export is supported only with OpenSSL. We fall back to
* OpenSSH key format elsewhere */
if (format == SSH_FILE_FORMAT_DEFAULT) {
#ifdef HAVE_LIBCRYPTO
if (privkey->type != SSH_KEYTYPE_ED25519) {
format = SSH_FILE_FORMAT_PEM;
} else {
#else
if (1) {
#endif /* HAVE_LIBCRYPTO */
format = SSH_FILE_FORMAT_OPENSSH;
}
}
switch (format) {
case SSH_FILE_FORMAT_DEFAULT:
case SSH_FILE_FORMAT_PEM:
blob = pki_private_key_to_pem(privkey,
passphrase,
auth_fn,
auth_data);
break;
case SSH_FILE_FORMAT_OPENSSH:
blob = ssh_pki_openssh_privkey_export(privkey,
passphrase,
auth_fn,
auth_data);
break;
}
if (blob == NULL) {
fclose(fp);
@@ -1068,6 +1149,38 @@ int ssh_pki_export_privkey_file(const ssh_key privkey,
return SSH_OK;
}
/**
* @brief Export a private key to a pem file on disk, or OpenSSH format for
* keytype ssh-ed25519
*
* @param[in] privkey The private key to export.
*
* @param[in] passphrase The passphrase to use to encrypt the key with or
* NULL. An empty string means no passphrase.
*
* @param[in] auth_fn An auth function you may want to use or NULL.
*
* @param[in] auth_data Private data passed to the auth function.
*
* @param[in] filename The path where to store the pem file.
*
* @return SSH_OK on success, SSH_ERROR on error.
*/
int
ssh_pki_export_privkey_file(const ssh_key privkey,
const char *passphrase,
ssh_auth_callback auth_fn,
void *auth_data,
const char *filename)
{
return ssh_pki_export_privkey_file_format(privkey,
passphrase,
auth_fn,
auth_data,
filename,
SSH_FILE_FORMAT_DEFAULT);
}
/* temporary function to migrate seamlessly to ssh_key */
ssh_public_key ssh_pki_convert_key_to_publickey(const ssh_key key)
{
@@ -2035,7 +2148,42 @@ int ssh_pki_export_pubkey_blob(const ssh_key key,
return SSH_OK;
}
blob = pki_publickey_to_blob(key);
blob = pki_key_to_blob(key, SSH_KEY_PUBLIC);
if (blob == NULL) {
return SSH_ERROR;
}
*pblob = blob;
return SSH_OK;
}
/**
* @internal
*
* @brief Create a key_blob from a private key.
*
* The "key_blob" is encoded as per draft-miller-ssh-agent-08 section 4.2
* "Adding keys to the agent" for any of the supported key types.
*
* @param[in] key A private key to create the private ssh_string from.
*
* @param[out] pblob A pointer to store the newly allocated key blob. You
* need to free it using ssh_string_free().
*
* @return SSH_OK on success, SSH_ERROR otherwise.
*
* @see ssh_string_free()
*/
int ssh_pki_export_privkey_blob(const ssh_key key,
ssh_string *pblob)
{
ssh_string blob;
if (key == NULL) {
return SSH_OK;
}
blob = pki_key_to_blob(key, SSH_KEY_PRIVATE);
if (blob == NULL) {
return SSH_ERROR;
}
@@ -2066,7 +2214,7 @@ int ssh_pki_export_pubkey_base64(const ssh_key key,
return SSH_ERROR;
}
key_blob = pki_publickey_to_blob(key);
key_blob = pki_key_to_blob(key, SSH_KEY_PUBLIC);
if (key_blob == NULL) {
return SSH_ERROR;
}

View File

@@ -394,37 +394,6 @@ ssh_key ssh_pki_openssh_pubkey_import(const char *text_key)
}
/** @internal
* @brief exports a private key to a string blob.
* @param[in] privkey private key to convert
* @param[out] buffer buffer to write the blob in.
* @returns SSH_OK on success
* @warning only supports ed25519 key type at the moment.
*/
static int pki_openssh_export_privkey_blob(const ssh_key privkey,
ssh_buffer buffer)
{
int rc;
if (privkey->type != SSH_KEYTYPE_ED25519) {
SSH_LOG(SSH_LOG_TRACE, "Type %s not supported", privkey->type_c);
return SSH_ERROR;
}
if (privkey->ed25519_privkey == NULL ||
privkey->ed25519_pubkey == NULL) {
return SSH_ERROR;
}
rc = ssh_buffer_pack(buffer,
"sdPdPP",
privkey->type_c,
(uint32_t)ED25519_KEY_LEN,
(size_t)ED25519_KEY_LEN, privkey->ed25519_pubkey,
(uint32_t)(2 * ED25519_KEY_LEN),
(size_t)ED25519_KEY_LEN, privkey->ed25519_privkey,
(size_t)ED25519_KEY_LEN, privkey->ed25519_pubkey);
return rc;
}
/** @internal
* @brief encrypts an ed25519 private key blob
*
@@ -536,8 +505,8 @@ ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey,
ssh_auth_callback auth_fn,
void *auth_data)
{
ssh_buffer buffer;
ssh_string str = NULL;
ssh_buffer buffer = NULL;
ssh_string str = NULL, blob = NULL;
ssh_string pubkey_s=NULL;
ssh_buffer privkey_buffer = NULL;
uint32_t rnd;
@@ -554,17 +523,13 @@ ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey,
if (privkey == NULL) {
return NULL;
}
if (privkey->type != SSH_KEYTYPE_ED25519){
SSH_LOG(SSH_LOG_TRACE, "Unsupported key type %s", privkey->type_c);
return NULL;
}
if (passphrase != NULL || auth_fn != NULL){
SSH_LOG(SSH_LOG_DEBUG, "Enabling encryption for private key export");
to_encrypt = 1;
}
buffer = ssh_buffer_new();
pubkey_s = pki_publickey_to_blob(privkey);
if(buffer == NULL || pubkey_s == NULL){
rc = ssh_pki_export_pubkey_blob(privkey, &pubkey_s);
if (buffer == NULL || rc != SSH_OK) {
goto error;
}
@@ -578,22 +543,17 @@ ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey,
goto error;
}
/* checkint1 & 2 */
rc = ssh_pki_export_privkey_blob(privkey, &blob);
if (rc != SSH_OK) {
goto error;
}
rc = ssh_buffer_pack(privkey_buffer,
"dd",
"ddPs",
rnd, /* checkint 1 & 2 */
rnd,
rnd);
if (rc == SSH_ERROR){
goto error;
}
rc = pki_openssh_export_privkey_blob(privkey, privkey_buffer);
if (rc == SSH_ERROR){
goto error;
}
/* comment */
rc = ssh_buffer_pack(privkey_buffer, "s", "" /* comment */);
ssh_string_len(blob), ssh_string_data(blob),
"" /* comment */);
if (rc == SSH_ERROR){
goto error;
}
@@ -710,6 +670,8 @@ ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey,
}
error:
ssh_string_burn(blob);
ssh_string_free(blob);
if (privkey_buffer != NULL) {
void *bufptr = ssh_buffer_get(privkey_buffer);
explicit_bzero(bufptr, ssh_buffer_get_len(privkey_buffer));

View File

@@ -1309,18 +1309,9 @@ fail:
rc = evp_build_pkey("RSA", param_bld, &(key->key), EVP_PKEY_KEYPAIR);
if (rc != SSH_OK) {
rc = SSH_ERROR;
goto fail;
}
rc = EVP_PKEY_set_bn_param(key->key, OSSL_PKEY_PARAM_RSA_FACTOR1, bp);
if (rc != 1) {
rc = SSH_ERROR;
goto fail;
}
rc = EVP_PKEY_set_bn_param(key->key, OSSL_PKEY_PARAM_RSA_FACTOR2, bq);
if (rc != 1) {
SSH_LOG(SSH_LOG_WARNING,
"Failed to import private key: %s\n",
ERR_error_string(ERR_get_error(), NULL));
rc = SSH_ERROR;
goto fail;
}
@@ -1412,7 +1403,7 @@ fail:
#endif /* OPENSSL_VERSION_NUMBER */
}
ssh_string pki_publickey_to_blob(const ssh_key key)
ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
{
ssh_buffer buffer;
ssh_string type_s;
@@ -1422,10 +1413,13 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
ssh_string p = NULL;
ssh_string g = NULL;
ssh_string q = NULL;
ssh_string d = NULL;
ssh_string iqmp = NULL;
int rc;
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
BIGNUM *bp = NULL, *bq = NULL, *bg = NULL, *bpub_key = NULL,
*bn = NULL, *be = NULL;
*bn = NULL, *be = NULL,
*bd = NULL, *biqmp = NULL;
OSSL_PARAM *params = NULL;
#endif /* OPENSSL_VERSION_NUMBER */
@@ -1460,7 +1454,7 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
case SSH_KEYTYPE_RSA:
case SSH_KEYTYPE_RSA1: {
#if OPENSSL_VERSION_NUMBER < 0x30000000L
const BIGNUM *be, *bn;
const BIGNUM *be = NULL, *bn = NULL;
const RSA *key_rsa = EVP_PKEY_get0_RSA(key->key);
RSA_get0_key(key_rsa, &bn, &be, NULL);
#else
@@ -1498,13 +1492,133 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
goto fail;
}
if (ssh_buffer_add_ssh_string(buffer, e) < 0) {
goto fail;
}
if (ssh_buffer_add_ssh_string(buffer, n) < 0) {
goto fail;
}
if (type == SSH_KEY_PUBLIC) {
/* The N and E parts are swapped in the public key export ! */
rc = ssh_buffer_add_ssh_string(buffer, e);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, n);
if (rc < 0) {
goto fail;
}
} else if (type == SSH_KEY_PRIVATE) {
#if OPENSSL_VERSION_NUMBER < 0x30000000L
const BIGNUM *bd, *biqmp, *bp, *bq;
RSA_get0_key(key_rsa, NULL, NULL, &bd);
RSA_get0_factors(key_rsa, &bp, &bq);
RSA_get0_crt_params(key_rsa, NULL, NULL, &biqmp);
#else
rc = EVP_PKEY_todata(key->key, EVP_PKEY_KEYPAIR, &params);
if (rc != 1) {
goto fail;
}
out_param = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_D);
if (out_param == NULL) {
SSH_LOG(SSH_LOG_TRACE, "RSA: No param D has been found");
goto fail;
}
rc = OSSL_PARAM_get_BN(out_param, &bd);
if (rc != 1) {
goto fail;
}
out_param = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR1);
if (out_param == NULL) {
SSH_LOG(SSH_LOG_TRACE, "RSA: No param P has been found");
goto fail;
}
rc = OSSL_PARAM_get_BN(out_param, &bp);
if (rc != 1) {
goto fail;
}
out_param = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_FACTOR2);
if (out_param == NULL) {
SSH_LOG(SSH_LOG_TRACE, "RSA: No param Q has been found");
goto fail;
}
rc = OSSL_PARAM_get_BN(out_param, &bq);
if (rc != 1) {
goto fail;
}
out_param = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_COEFFICIENT1);
if (out_param == NULL) {
SSH_LOG(SSH_LOG_TRACE, "RSA: No param IQMP has been found");
goto fail;
}
rc = OSSL_PARAM_get_BN(out_param, &biqmp);
if (rc != 1) {
goto fail;
}
#endif /* OPENSSL_VERSION_NUMBER */
rc = ssh_buffer_add_ssh_string(buffer, n);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, e);
if (rc < 0) {
goto fail;
}
d = ssh_make_bignum_string((BIGNUM *)bd);
if (d == NULL) {
goto fail;
}
iqmp = ssh_make_bignum_string((BIGNUM *)biqmp);
if (iqmp == NULL) {
goto fail;
}
p = ssh_make_bignum_string((BIGNUM *)bp);
if (p == NULL) {
goto fail;
}
q = ssh_make_bignum_string((BIGNUM *)bq);
if (q == NULL) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, d);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, iqmp);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, p);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, q);
if (rc < 0) {
goto fail;
}
ssh_string_burn(d);
SSH_STRING_FREE(d);
d = NULL;
ssh_string_burn(iqmp);
SSH_STRING_FREE(iqmp);
iqmp = NULL;
ssh_string_burn(p);
SSH_STRING_FREE(p);
p = NULL;
ssh_string_burn(q);
SSH_STRING_FREE(q);
q = NULL;
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
bignum_safe_free(bd);
bignum_safe_free(biqmp);
bignum_safe_free(bp);
bignum_safe_free(bq);
#endif /* OPENSSL_VERSION_NUMBER */
}
ssh_string_burn(e);
SSH_STRING_FREE(e);
e = NULL;
@@ -1520,13 +1634,23 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
}
case SSH_KEYTYPE_ED25519:
case SSH_KEYTYPE_SK_ED25519:
rc = pki_ed25519_public_key_to_blob(buffer, key);
if (rc == SSH_ERROR){
goto fail;
}
if (key->type == SSH_KEYTYPE_SK_ED25519 &&
ssh_buffer_add_ssh_string(buffer, key->sk_application) < 0) {
goto fail;
if (type == SSH_KEY_PUBLIC) {
rc = pki_ed25519_public_key_to_blob(buffer, key);
if (rc == SSH_ERROR){
goto fail;
}
/* public key can contain certificate sk information */
if (key->type == SSH_KEYTYPE_SK_ED25519) {
rc = ssh_buffer_add_ssh_string(buffer, key->sk_application);
if (rc < 0) {
goto fail;
}
}
} else {
rc = pki_ed25519_private_key_to_blob(buffer, key);
if (rc == SSH_ERROR){
goto fail;
}
}
break;
case SSH_KEYTYPE_ECDSA_P256:
@@ -1544,6 +1668,7 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
#else
const EC_GROUP *group = NULL;
const EC_POINT *point = NULL;
const BIGNUM *exp = NULL;
EC_KEY *ec = NULL;
#endif /* OPENSSL_VERSION_NUMBER */
@@ -1628,15 +1753,52 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
ssh_string_burn(e);
SSH_STRING_FREE(e);
e = NULL;
if (type == SSH_KEY_PRIVATE) {
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
rc = EVP_PKEY_todata(key->key, EVP_PKEY_KEYPAIR, &params);
if (rc < 0) {
goto fail;
}
locate_param = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PRIV_KEY);
rc = OSSL_PARAM_get_BN(locate_param, &bd);
if (rc != 1) {
goto fail;
}
d = ssh_make_bignum_string((BIGNUM *)bd);
if (d == NULL) {
goto fail;
}
if (ssh_buffer_add_ssh_string(buffer, d) < 0) {
goto fail;
}
#else
exp = EC_KEY_get0_private_key(ec);
if (exp == NULL) {
goto fail;
}
d = ssh_make_bignum_string((BIGNUM *)exp);
if (d == NULL) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, d);
if (rc < 0) {
goto fail;
}
#endif /* OPENSSL_VERSION_NUMBER */
ssh_string_burn(d);
SSH_STRING_FREE(d);
d = NULL;
} else if (key->type == SSH_KEYTYPE_SK_ECDSA) {
/* public key can contain certificate sk information */
rc = ssh_buffer_add_ssh_string(buffer, key->sk_application);
if (rc < 0) {
goto fail;
}
}
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
OSSL_PARAM_free(params);
#endif /* OPENSSL_VERSION_NUMBER */
if (key->type == SSH_KEYTYPE_SK_ECDSA &&
ssh_buffer_add_ssh_string(buffer, key->sk_application) < 0) {
goto fail;
}
break;
}
#endif /* HAVE_OPENSSL_ECC */
@@ -1672,6 +1834,10 @@ fail:
SSH_STRING_FREE(q);
ssh_string_burn(n);
SSH_STRING_FREE(n);
ssh_string_burn(d);
SSH_STRING_FREE(d);
ssh_string_burn(iqmp);
SSH_STRING_FREE(iqmp);
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
bignum_safe_free(bp);
bignum_safe_free(bq);
@@ -1679,6 +1845,8 @@ fail:
bignum_safe_free(bpub_key);
bignum_safe_free(bn);
bignum_safe_free(be);
bignum_safe_free(bd);
bignum_safe_free(biqmp);
OSSL_PARAM_free(params);
#endif /* OPENSSL_VERSION_NUMBER */

View File

@@ -206,6 +206,34 @@ int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key)
return rc;
}
/** @internal
* @brief exports a ed25519 private key to a string blob.
* @param[in] privkey private key to convert
* @param[out] buffer buffer to write the blob in.
* @returns SSH_OK on success
*/
int pki_ed25519_private_key_to_blob(ssh_buffer buffer, const ssh_key privkey)
{
int rc;
if (privkey->type != SSH_KEYTYPE_ED25519) {
SSH_LOG(SSH_LOG_TRACE, "Type %s not supported", privkey->type_c);
return SSH_ERROR;
}
if (privkey->ed25519_privkey == NULL ||
privkey->ed25519_pubkey == NULL) {
return SSH_ERROR;
}
rc = ssh_buffer_pack(buffer,
"dPdPP",
(uint32_t)ED25519_KEY_LEN,
(size_t)ED25519_KEY_LEN, privkey->ed25519_pubkey,
(uint32_t)(2 * ED25519_KEY_LEN),
(size_t)ED25519_KEY_LEN, privkey->ed25519_privkey,
(size_t)ED25519_KEY_LEN, privkey->ed25519_pubkey);
return rc;
}
/**
* @internal
*

View File

@@ -1366,16 +1366,18 @@ int pki_key_compare(const ssh_key k1,
return 0;
}
ssh_string pki_publickey_to_blob(const ssh_key key)
ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
{
ssh_buffer buffer;
ssh_string type_s;
ssh_string str = NULL;
ssh_string e = NULL;
ssh_string n = NULL;
ssh_string d = NULL;
ssh_string p = NULL;
ssh_string g = NULL;
ssh_string q = NULL;
ssh_string u = NULL;
int rc;
buffer = ssh_buffer_new();
@@ -1423,30 +1425,108 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, e);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, n);
if (rc < 0) {
goto fail;
}
if (type == SSH_KEY_PUBLIC) {
/* The N and E parts are swapped in the public key export ! */
rc = ssh_buffer_add_ssh_string(buffer, e);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, n);
if (rc < 0) {
goto fail;
}
} else if (type == SSH_KEY_PRIVATE) {
rc = ssh_buffer_add_ssh_string(buffer, n);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, e);
if (rc < 0) {
goto fail;
}
d = ssh_sexp_extract_mpi(key->rsa,
"d",
GCRYMPI_FMT_USG,
GCRYMPI_FMT_STD);
if (d == NULL) {
goto fail;
}
p = ssh_sexp_extract_mpi(key->rsa,
"p",
GCRYMPI_FMT_USG,
GCRYMPI_FMT_STD);
if (p == NULL) {
goto fail;
}
q = ssh_sexp_extract_mpi(key->rsa,
"q",
GCRYMPI_FMT_USG,
GCRYMPI_FMT_STD);
if (q == NULL) {
goto fail;
}
u = ssh_sexp_extract_mpi(key->rsa,
"u",
GCRYMPI_FMT_USG,
GCRYMPI_FMT_STD);
if (u == NULL) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, d);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, u);
if (rc < 0) {
goto fail;
}
/* Swap the P and Q as the iqmp in gcrypt is ipmq ... */
rc = ssh_buffer_add_ssh_string(buffer, q);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, p);
if (rc < 0) {
goto fail;
}
ssh_string_burn(d);
SSH_STRING_FREE(d);
ssh_string_burn(p);
SSH_STRING_FREE(p);
ssh_string_burn(q);
SSH_STRING_FREE(q);
ssh_string_burn(u);
SSH_STRING_FREE(u);
}
ssh_string_burn(e);
SSH_STRING_FREE(e);
ssh_string_burn(n);
SSH_STRING_FREE(n);
break;
case SSH_KEYTYPE_ED25519:
case SSH_KEYTYPE_SK_ED25519:
rc = pki_ed25519_public_key_to_blob(buffer, key);
if (rc != SSH_OK){
goto fail;
}
if (key->type == SSH_KEYTYPE_SK_ED25519 &&
ssh_buffer_add_ssh_string(buffer, key->sk_application) < 0) {
goto fail;
if (type == SSH_KEY_PUBLIC) {
rc = pki_ed25519_public_key_to_blob(buffer, key);
if (rc == SSH_ERROR) {
goto fail;
}
/* public key can contain certificate sk information */
if (key->type == SSH_KEYTYPE_SK_ED25519) {
rc = ssh_buffer_add_ssh_string(buffer, key->sk_application);
if (rc < 0) {
goto fail;
}
}
} else {
rc = pki_ed25519_private_key_to_blob(buffer, key);
if (rc == SSH_ERROR) {
goto fail;
}
}
break;
case SSH_KEYTYPE_ECDSA_P256:
@@ -1457,22 +1537,19 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
type_s = ssh_string_from_char(
pki_key_ecdsa_nid_to_char(key->ecdsa_nid));
if (type_s == NULL) {
SSH_BUFFER_FREE(buffer);
return NULL;
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, type_s);
SSH_STRING_FREE(type_s);
if (rc < 0) {
SSH_BUFFER_FREE(buffer);
return NULL;
goto fail;
}
e = ssh_sexp_extract_mpi(key->ecdsa, "q", GCRYMPI_FMT_STD,
GCRYMPI_FMT_STD);
if (e == NULL) {
SSH_BUFFER_FREE(buffer);
return NULL;
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, e);
@@ -1484,9 +1561,27 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
SSH_STRING_FREE(e);
e = NULL;
if (key->type == SSH_KEYTYPE_SK_ECDSA &&
ssh_buffer_add_ssh_string(buffer, key->sk_application) < 0) {
goto fail;
if (type == SSH_KEY_PRIVATE) {
d = ssh_sexp_extract_mpi(key->ecdsa, "d", GCRYMPI_FMT_STD,
GCRYMPI_FMT_STD);
if (d == NULL) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, d);
if (rc < 0) {
goto fail;
}
ssh_string_burn(d);
SSH_STRING_FREE(d);
d = NULL;
} else if (key->type == SSH_KEYTYPE_SK_ECDSA) {
/* public key can contain certificate sk information */
rc = ssh_buffer_add_ssh_string(buffer, key->sk_application);
if (rc < 0) {
goto fail;
}
}
break;

View File

@@ -878,7 +878,7 @@ static const char* pki_key_ecdsa_nid_to_char(int nid)
return "unknown";
}
ssh_string pki_publickey_to_blob(const ssh_key key)
ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type)
{
ssh_buffer buffer = NULL;
ssh_string type_s = NULL;
@@ -888,6 +888,10 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
#if MBEDTLS_VERSION_MAJOR > 2
mbedtls_mpi E;
mbedtls_mpi N;
mbedtls_mpi D;
mbedtls_mpi IQMP;
mbedtls_mpi P;
mbedtls_mpi Q;
#endif
int rc;
@@ -961,21 +965,124 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
}
#endif
if (ssh_buffer_add_ssh_string(buffer, e) < 0) {
goto fail;
}
if (type == SSH_KEY_PUBLIC) {
/* The N and E parts are swapped in the public key export ! */
rc = ssh_buffer_add_ssh_string(buffer, e);
if (rc < 0) {
goto fail;
}
if (ssh_buffer_add_ssh_string(buffer, n) < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, n);
if (rc < 0) {
goto fail;
}
} else if (type == SSH_KEY_PRIVATE) {
ssh_string p = NULL;
ssh_string q = NULL;
ssh_string d = NULL;
ssh_string iqmp = NULL;
rc = ssh_buffer_add_ssh_string(buffer, n);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, e);
if (rc < 0) {
goto fail;
}
#if MBEDTLS_VERSION_MAJOR > 2
rc = mbedtls_rsa_export(rsa, NULL, &P, &Q, &D, NULL);
if (rc != 0) {
goto fail;
}
p = ssh_make_bignum_string(&P);
if (p == NULL) {
goto fail;
}
q = ssh_make_bignum_string(&Q);
if (q == NULL) {
goto fail;
}
d = ssh_make_bignum_string(&D);
if (d == NULL) {
goto fail;
}
rc = mbedtls_rsa_export_crt(rsa, NULL, NULL, &IQMP)
if (rc != 0) {
goto fail;
}
iqmp = ssh_make_bignum_string(&IQMP);
if (iqmp == NULL) {
goto fail;
}
#else
p = ssh_make_bignum_string(&rsa->P);
if (p == NULL) {
goto fail;
}
q = ssh_make_bignum_string(&rsa->Q);
if (q == NULL) {
goto fail;
}
d = ssh_make_bignum_string(&rsa->D);
if (d == NULL) {
goto fail;
}
iqmp = ssh_make_bignum_string(&rsa->QP);
if (iqmp == NULL) {
goto fail;
}
#endif
rc = ssh_buffer_add_ssh_string(buffer, d);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, iqmp);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, p);
if (rc < 0) {
goto fail;
}
rc = ssh_buffer_add_ssh_string(buffer, q);
if (rc < 0) {
goto fail;
}
ssh_string_burn(d);
SSH_STRING_FREE(d);
d = NULL;
ssh_string_burn(iqmp);
SSH_STRING_FREE(iqmp);
iqmp = NULL;
ssh_string_burn(p);
SSH_STRING_FREE(p);
p = NULL;
ssh_string_burn(q);
SSH_STRING_FREE(q);
q = NULL;
}
ssh_string_burn(e);
SSH_STRING_FREE(e);
e = NULL;
ssh_string_burn(n);
SSH_STRING_FREE(n);
n = NULL;
break;
}
case SSH_KEYTYPE_ECDSA_P256:
@@ -1013,21 +1120,51 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
SSH_STRING_FREE(e);
e = NULL;
if (key->type == SSH_KEYTYPE_SK_ECDSA &&
ssh_buffer_add_ssh_string(buffer, key->sk_application) < 0) {
goto fail;
}
if (type == SSH_KEY_PRIVATE) {
ssh_string d = NULL;
d = ssh_make_bignum_string(&key->ecdsa->MBEDTLS_PRIVATE(d));
if (d == NULL) {
SSH_BUFFER_FREE(buffer);
return NULL;
}
rc = ssh_buffer_add_ssh_string(buffer, d);
if (rc < 0) {
goto fail;
}
ssh_string_burn(d);
SSH_STRING_FREE(d);
d = NULL;
} else if (key->type == SSH_KEYTYPE_SK_ECDSA) {
/* public key can contain certificate sk information */
rc = ssh_buffer_add_ssh_string(buffer, key->sk_application);
if (rc < 0) {
goto fail;
}
}
break;
case SSH_KEYTYPE_ED25519:
case SSH_KEYTYPE_SK_ED25519:
rc = pki_ed25519_public_key_to_blob(buffer, key);
if (rc != SSH_OK) {
goto fail;
}
if (key->type == SSH_KEYTYPE_SK_ED25519 &&
ssh_buffer_add_ssh_string(buffer, key->sk_application) < 0) {
goto fail;
if (type == SSH_KEY_PUBLIC) {
rc = pki_ed25519_public_key_to_blob(buffer, key);
if (rc == SSH_ERROR) {
goto fail;
}
/* public key can contain certificate sk information */
if (key->type == SSH_KEYTYPE_SK_ED25519) {
rc = ssh_buffer_add_ssh_string(buffer, key->sk_application);
if (rc < 0) {
goto fail;
}
}
} else {
rc = pki_ed25519_private_key_to_blob(buffer, key);
if (rc == SSH_ERROR) {
goto fail;
}
}
break;
default: