diff --git a/include/libssh/pki.h b/include/libssh/pki.h index 11e48503..6e766858 100644 --- a/include/libssh/pki.h +++ b/include/libssh/pki.h @@ -63,11 +63,9 @@ struct ssh_key_struct { mbedtls_pk_context *pk; mbedtls_ecdsa_context *ecdsa; #elif defined(HAVE_LIBCRYPTO) - /* This holds either ENGINE key for PKCS#11 support or just key in - * high-level format */ + /* This holds either ENGINE/PROVIDER key for PKCS#11 support + * or just key in high-level format */ EVP_PKEY *key; - uint8_t *ed25519_pubkey; - uint8_t *ed25519_privkey; #endif /* HAVE_LIBGCRYPT */ #ifndef HAVE_LIBCRYPTO ed25519_pubkey *ed25519_pubkey; diff --git a/include/libssh/pki_priv.h b/include/libssh/pki_priv.h index 2061ebd7..fb9ab9d1 100644 --- a/include/libssh/pki_priv.h +++ b/include/libssh/pki_priv.h @@ -148,6 +148,7 @@ int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob); int pki_privkey_build_ed25519(ssh_key key, ssh_string pubkey, ssh_string privkey); +int pki_pubkey_build_ed25519(ssh_key key, ssh_string pubkey); /* PKI Container OpenSSH */ ssh_key ssh_pki_openssh_pubkey_import(const char *text_key); diff --git a/include/libssh/wrapper.h b/include/libssh/wrapper.h index b3e28eac..c1ddc2a8 100644 --- a/include/libssh/wrapper.h +++ b/include/libssh/wrapper.h @@ -129,6 +129,7 @@ int evp_build_pkey(const char* name, OSSL_PARAM_BLD *param_bld, EVP_PKEY **pkey, int evp_dup_dsa_pkey(const ssh_key key, ssh_key new_key, int demote); int evp_dup_rsa_pkey(const ssh_key key, ssh_key new_key, int demote); int evp_dup_ecdsa_pkey(const ssh_key key, ssh_key new_key, int demote); +int evp_dup_ed25519_pkey(const ssh_key key, ssh_key new_key, int demote); #endif /* HAVE_LIBCRYPTO && OPENSSL_VERSION_NUMBER */ #ifdef __cplusplus diff --git a/src/libcrypto.c b/src/libcrypto.c index 76f6bc00..8dd48a47 100644 --- a/src/libcrypto.c +++ b/src/libcrypto.c @@ -1543,6 +1543,12 @@ int evp_dup_ecdsa_pkey(const ssh_key key, ssh_key new_key, int demote) { return evp_dup_pkey("EC", key, demote, new_key); } + +int evp_dup_ed25519_pkey(const ssh_key key, ssh_key new_key, int demote) +{ + return evp_dup_pkey("ED25519", key, demote, new_key); +} + #endif /* OPENSSL_VERSION_NUMBER */ ssh_string diff --git a/src/pki.c b/src/pki.c index d7e63371..28ee3db9 100644 --- a/src/pki.c +++ b/src/pki.c @@ -143,18 +143,13 @@ void ssh_key_clean (ssh_key key) pki_key_clean(key); - if (key->ed25519_privkey != NULL){ -#ifdef HAVE_LIBCRYPTO - /* In OpenSSL implementation the private key is only the private - * original seed. In the internal implementation the private key is the - * concatenation of the original private seed with the public key.*/ - explicit_bzero(key->ed25519_privkey, ED25519_KEY_LEN); -#else +#ifndef HAVE_LIBCRYPTO + if (key->ed25519_privkey != NULL) { explicit_bzero(key->ed25519_privkey, sizeof(ed25519_privkey)); -#endif /* HAVE_LIBCRYPTO*/ SAFE_FREE(key->ed25519_privkey); } SAFE_FREE(key->ed25519_pubkey); +#endif /* HAVE_LIBCRYPTO */ if (key->cert != NULL) { SSH_BUFFER_FREE(key->cert); } @@ -701,10 +696,12 @@ int ssh_key_cmp(const ssh_key k1, ssh_buffer_get_len(k1->cert)); } +#ifndef HAVE_LIBCRYPTO if (k1->type == SSH_KEYTYPE_ED25519 || k1->type == SSH_KEYTYPE_SK_ED25519) { return pki_ed25519_key_cmp(k1, k2, what); } +#endif return pki_key_compare(k1, k2, what); } @@ -1489,16 +1486,13 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer, goto fail; } - key->ed25519_pubkey = malloc(ED25519_KEY_LEN); - if (key->ed25519_pubkey == NULL) { - ssh_string_burn(pubkey); - SSH_STRING_FREE(pubkey); - goto fail; - } - - memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_KEY_LEN); + rc = pki_pubkey_build_ed25519(key, pubkey); ssh_string_burn(pubkey); SSH_STRING_FREE(pubkey); + if (rc < 0) { + SSH_LOG(SSH_LOG_TRACE, "Failed to build ED25519 public key"); + goto fail; + } if (type == SSH_KEYTYPE_SK_ED25519) { ssh_string application = ssh_buffer_get_ssh_string(buffer); diff --git a/src/pki_crypto.c b/src/pki_crypto.c index 36908544..7a508385 100644 --- a/src/pki_crypto.c +++ b/src/pki_crypto.c @@ -415,6 +415,59 @@ err: } #endif /* HAVE_OPENSSL_ECC */ +int pki_privkey_build_ed25519(ssh_key key, + ssh_string pubkey, + ssh_string privkey) +{ + EVP_PKEY *pkey = NULL; + + if (ssh_string_len(pubkey) != ED25519_KEY_LEN || + ssh_string_len(privkey) != (2 * ED25519_KEY_LEN)) { + SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len"); + return SSH_ERROR; + } + + pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, + NULL, + (const uint8_t *)ssh_string_data(privkey), + ED25519_KEY_LEN); + if (pkey == NULL) { + SSH_LOG(SSH_LOG_TRACE, + "Failed to create ed25519 EVP_PKEY: %s", + ERR_error_string(ERR_get_error(), NULL)); + return SSH_ERROR; + } + + key->key = pkey; + + return SSH_OK; +} + +int pki_pubkey_build_ed25519(ssh_key key, ssh_string pubkey) +{ + EVP_PKEY *pkey = NULL; + + if (ssh_string_len(pubkey) != ED25519_KEY_LEN) { + SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len"); + return SSH_ERROR; + } + + pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, + NULL, + (const uint8_t *)ssh_string_data(pubkey), + ED25519_KEY_LEN); + if (pkey == NULL) { + SSH_LOG(SSH_LOG_TRACE, + "Failed to create ed25519 EVP_PKEY: %s", + ERR_error_string(ERR_get_error(), NULL)); + return SSH_ERROR; + } + + key->key = pkey; + + return SSH_OK; +} + ssh_key pki_key_dup(const ssh_key key, int demote) { ssh_key new = NULL; @@ -651,7 +704,7 @@ ssh_key pki_key_dup(const ssh_key key, int demote) break; #endif /* HAVE_OPENSSL_ECC */ case SSH_KEYTYPE_ED25519: - rc = pki_ed25519_key_dup(new, key); + rc = evp_dup_ed25519_pkey(key, new, demote); if (rc != SSH_OK) { goto fail; } @@ -865,14 +918,13 @@ int pki_key_compare(const ssh_key k1, const ssh_key k2, enum ssh_keycmp_e what) #endif /* OPENSSL_VERSION_NUMBER */ case SSH_KEYTYPE_RSA: case SSH_KEYTYPE_RSA1: + case SSH_KEYTYPE_ED25519: + case SSH_KEYTYPE_SK_ED25519: rc = EVP_PKEY_eq(k1->key, k2->key); if (rc != 1) { return 1; } break; - case SSH_KEYTYPE_ED25519: - case SSH_KEYTYPE_SK_ED25519: - /* ed25519 keys handled globally */ case SSH_KEYTYPE_UNKNOWN: default: return 1; @@ -902,6 +954,7 @@ ssh_string pki_private_key_to_pem(const ssh_key key, case SSH_KEYTYPE_ECDSA_P256: case SSH_KEYTYPE_ECDSA_P384: case SSH_KEYTYPE_ECDSA_P521: + case SSH_KEYTYPE_ED25519: rc = EVP_PKEY_up_ref(key->key); if (rc != 1) { goto err; @@ -911,24 +964,6 @@ ssh_string pki_private_key_to_pem(const ssh_key key, /* Mark the operation as successful as for the other key types */ rc = 1; - break; - case SSH_KEYTYPE_ED25519: - /* In OpenSSL, the input is the private key seed only, which means - * the first half of the SSH private key (the second half is the - * public key) */ - pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, - NULL, - (const uint8_t *)key->ed25519_privkey, - ED25519_KEY_LEN); - if (pkey == NULL) { - SSH_LOG(SSH_LOG_TRACE, - "Failed to create ed25519 EVP_PKEY: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto err; - } - - /* Mark the operation as successful as for the other key types */ - rc = 1; break; case SSH_KEYTYPE_RSA_CERT01: case SSH_KEYTYPE_ECDSA_P256_CERT01: @@ -1008,8 +1043,6 @@ ssh_key pki_private_key_from_base64(const char *b64_key, #if OPENSSL_VERSION_NUMBER < 0x30000000L EC_KEY *ecdsa = NULL; #endif /* OPENSSL_VERSION_NUMBER */ - uint8_t *ed25519 = NULL; - uint8_t *ed25519_pubkey = NULL; ssh_key key = NULL; enum ssh_keytypes_e type = SSH_KEYTYPE_UNKNOWN; EVP_PKEY *pkey = NULL; @@ -1068,57 +1101,8 @@ ssh_key pki_private_key_from_base64(const char *b64_key, break; #endif /* HAVE_OPENSSL_ECC */ case EVP_PKEY_ED25519: - { - size_t key_len; - int evp_rc = 0; - - /* Get the key length */ - evp_rc = EVP_PKEY_get_raw_private_key(pkey, NULL, &key_len); - if (evp_rc != 1) { - SSH_LOG(SSH_LOG_TRACE, - "Failed to get ed25519 raw private key length: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto fail; - } - - if (key_len != ED25519_KEY_LEN) { - goto fail; - } - - ed25519 = malloc(key_len); - if (ed25519 == NULL) { - SSH_LOG(SSH_LOG_TRACE, "Out of memory"); - goto fail; - } - - evp_rc = EVP_PKEY_get_raw_private_key(pkey, (uint8_t *)ed25519, - &key_len); - if (evp_rc != 1) { - SSH_LOG(SSH_LOG_TRACE, - "Failed to get ed25519 raw private key: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto fail; - } - - /* length matches the private key length */ - ed25519_pubkey = malloc(ED25519_KEY_LEN); - if (ed25519_pubkey == NULL) { - SSH_LOG(SSH_LOG_TRACE, "Out of memory"); - goto fail; - } - - evp_rc = EVP_PKEY_get_raw_public_key(pkey, (uint8_t *)ed25519_pubkey, - &key_len); - if (evp_rc != 1) { - SSH_LOG(SSH_LOG_TRACE, - "Failed to get ed25519 raw public key: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto fail; - } type = SSH_KEYTYPE_ED25519; - - } - break; + break; default: SSH_LOG(SSH_LOG_TRACE, "Unknown or invalid private key type %d", EVP_PKEY_base_id(pkey)); @@ -1135,8 +1119,6 @@ ssh_key pki_private_key_from_base64(const char *b64_key, key->type_c = ssh_key_type_to_char(type); key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC; key->key = pkey; - key->ed25519_privkey = ed25519; - key->ed25519_pubkey = ed25519_pubkey; #ifdef HAVE_OPENSSL_ECC if (is_ecdsa_key_type(key->type)) { #if OPENSSL_VERSION_NUMBER < 0x30000000L @@ -1151,8 +1133,6 @@ ssh_key pki_private_key_from_base64(const char *b64_key, fail: EVP_PKEY_free(pkey); ssh_key_free(key); - SAFE_FREE(ed25519); - SAFE_FREE(ed25519_pubkey); return NULL; } @@ -1408,8 +1388,8 @@ fail: ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type) { - ssh_buffer buffer; - ssh_string type_s; + ssh_buffer buffer = NULL; + ssh_string type_s = NULL; ssh_string str = NULL; ssh_string e = NULL; ssh_string n = NULL; @@ -1425,6 +1405,9 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type) *bd = NULL, *biqmp = NULL; OSSL_PARAM *params = NULL; #endif /* OPENSSL_VERSION_NUMBER */ + uint8_t *ed25519_pubkey = NULL; + uint8_t *ed25519_privkey = NULL; + size_t key_len = 0; buffer = ssh_buffer_new(); if (buffer == NULL) { @@ -1632,11 +1615,94 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type) } case SSH_KEYTYPE_ED25519: case SSH_KEYTYPE_SK_ED25519: - if (type == SSH_KEY_PUBLIC) { - rc = pki_ed25519_public_key_to_blob(buffer, key); - if (rc == SSH_ERROR){ + rc = EVP_PKEY_get_raw_public_key(key->key, NULL, &key_len); + if (rc != 1) { + SSH_LOG(SSH_LOG_TRACE, + "Failed to get ed25519 raw public key length: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto fail; + } + + if (key_len != ED25519_KEY_LEN) { + SSH_LOG(SSH_LOG_TRACE, + "Unexpected length of private key %zu. Expected %d.", + key_len, + ED25519_KEY_LEN); + goto fail; + } + + ed25519_pubkey = malloc(key_len); + if (ed25519_pubkey == NULL) { + SSH_LOG(SSH_LOG_TRACE, "Out of memory"); + goto fail; + } + + rc = EVP_PKEY_get_raw_public_key(key->key, + (uint8_t *)ed25519_pubkey, + &key_len); + if (rc != 1) { + SSH_LOG(SSH_LOG_TRACE, + "Failed to get ed25519 raw public key: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto fail; + } + + rc = ssh_buffer_pack(buffer, + "dP", + (uint32_t)ED25519_KEY_LEN, + (size_t)ED25519_KEY_LEN, + ed25519_pubkey); + if (rc == SSH_ERROR) { + goto fail; + } + + if (type == SSH_KEY_PRIVATE) { + key_len = 0; + rc = EVP_PKEY_get_raw_private_key(key->key, NULL, &key_len); + if (rc != 1) { + SSH_LOG(SSH_LOG_TRACE, + "Failed to get ed25519 raw private key length: %s", + ERR_error_string(ERR_get_error(), NULL)); goto fail; } + + if (key_len != ED25519_KEY_LEN) { + SSH_LOG(SSH_LOG_TRACE, + "Unexpected length of private key %zu. Expected %d.", + key_len, + ED25519_KEY_LEN); + goto fail; + } + + ed25519_privkey = malloc(key_len); + if (ed25519_privkey == NULL) { + SSH_LOG(SSH_LOG_TRACE, "Out of memory"); + goto fail; + } + + rc = EVP_PKEY_get_raw_private_key(key->key, + ed25519_privkey, + &key_len); + if (rc != 1) { + SSH_LOG(SSH_LOG_TRACE, + "Failed to get ed25519 raw private key: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto fail; + } + + rc = ssh_buffer_pack(buffer, + "dPP", + (uint32_t)(2 * ED25519_KEY_LEN), + (size_t)ED25519_KEY_LEN, + ed25519_privkey, + (size_t)ED25519_KEY_LEN, + ed25519_pubkey); + if (rc == SSH_ERROR) { + goto fail; + } + explicit_bzero(ed25519_privkey, ED25519_KEY_LEN); + SAFE_FREE(ed25519_privkey); + } else { /* public key can contain certificate sk information */ if (key->type == SSH_KEYTYPE_SK_ED25519) { rc = ssh_buffer_add_ssh_string(buffer, key->sk_application); @@ -1644,12 +1710,8 @@ ssh_string pki_key_to_blob(const ssh_key key, enum ssh_key_e type) goto fail; } } - } else { - rc = pki_ed25519_private_key_to_blob(buffer, key); - if (rc == SSH_ERROR){ - goto fail; - } } + SAFE_FREE(ed25519_pubkey); break; case SSH_KEYTYPE_ECDSA_P256: case SSH_KEYTYPE_ECDSA_P384: @@ -1849,6 +1911,11 @@ fail: bignum_safe_free(biqmp); OSSL_PARAM_free(params); #endif /* OPENSSL_VERSION_NUMBER */ + free(ed25519_pubkey); + if (ed25519_privkey) { + explicit_bzero(ed25519_privkey, ED25519_KEY_LEN); + free(ed25519_privkey); + } return NULL; } @@ -2300,6 +2367,10 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key) case SSH_KEYTYPE_ECDSA_P521_CERT01: case SSH_KEYTYPE_SK_ECDSA: case SSH_KEYTYPE_SK_ECDSA_CERT01: + case SSH_KEYTYPE_ED25519: + case SSH_KEYTYPE_ED25519_CERT01: + case SSH_KEYTYPE_SK_ED25519: + case SSH_KEYTYPE_SK_ED25519_CERT01: if (key->key == NULL) { SSH_LOG(SSH_LOG_TRACE, "NULL key->key"); goto error; @@ -2311,37 +2382,6 @@ static EVP_PKEY *pki_key_to_pkey(ssh_key key) } pkey = key->key; break; - case SSH_KEYTYPE_ED25519: - case SSH_KEYTYPE_ED25519_CERT01: - case SSH_KEYTYPE_SK_ED25519: - case SSH_KEYTYPE_SK_ED25519_CERT01: - if (ssh_key_is_private(key)) { - if (key->ed25519_privkey == NULL) { - SSH_LOG(SSH_LOG_TRACE, "NULL key->ed25519_privkey"); - goto error; - } - /* In OpenSSL, the input is the private key seed only, which means - * the first half of the SSH private key (the second half is the - * public key). Both keys have the same length (32 bytes) */ - pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, - (const uint8_t *)key->ed25519_privkey, - ED25519_KEY_LEN); - } else { - if (key->ed25519_pubkey == NULL) { - SSH_LOG(SSH_LOG_TRACE, "NULL key->ed25519_pubkey"); - goto error; - } - pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, - (const uint8_t *)key->ed25519_pubkey, - ED25519_KEY_LEN); - } - if (pkey == NULL) { - SSH_LOG(SSH_LOG_TRACE, - "Failed to create ed25519 EVP_PKEY: %s", - ERR_error_string(ERR_get_error(), NULL)); - return NULL; - } - break; case SSH_KEYTYPE_UNKNOWN: default: SSH_LOG(SSH_LOG_TRACE, "Unknown private key algorithm for type: %d", @@ -2628,8 +2668,6 @@ int pki_key_generate_ed25519(ssh_key key) int evp_rc; EVP_PKEY_CTX *pctx = NULL; EVP_PKEY *pkey = NULL; - size_t privkey_len = ED25519_KEY_LEN; - size_t pubkey_len = ED25519_KEY_LEN; if (key == NULL) { return SSH_ERROR; @@ -2658,41 +2696,9 @@ int pki_key_generate_ed25519(ssh_key key) ERR_error_string(ERR_get_error(), NULL)); goto error; } - - key->ed25519_privkey = malloc(ED25519_KEY_LEN); - if (key->ed25519_privkey == NULL) { - SSH_LOG(SSH_LOG_TRACE, - "Failed to allocate memory for ed25519 private key"); - goto error; - } - - key->ed25519_pubkey = malloc(ED25519_KEY_LEN); - if (key->ed25519_pubkey == NULL) { - SSH_LOG(SSH_LOG_TRACE, - "Failed to allocate memory for ed25519 public key"); - goto error; - } - - evp_rc = EVP_PKEY_get_raw_private_key(pkey, (uint8_t *)key->ed25519_privkey, - &privkey_len); - if (evp_rc != 1) { - SSH_LOG(SSH_LOG_TRACE, - "Failed to get ed25519 raw private key: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto error; - } - - evp_rc = EVP_PKEY_get_raw_public_key(pkey, (uint8_t *)key->ed25519_pubkey, - &pubkey_len); - if (evp_rc != 1) { - SSH_LOG(SSH_LOG_TRACE, - "Failed to get ed25519 raw public key: %s", - ERR_error_string(ERR_get_error(), NULL)); - goto error; - } + key->key = pkey; EVP_PKEY_CTX_free(pctx); - EVP_PKEY_free(pkey); return SSH_OK; error: @@ -2702,8 +2708,6 @@ error: if (pkey != NULL) { EVP_PKEY_free(pkey); } - SAFE_FREE(key->ed25519_privkey); - SAFE_FREE(key->ed25519_pubkey); return SSH_ERROR; } @@ -2872,6 +2876,9 @@ int pki_uri_import(const char *uri_name, break; #endif + case EVP_PKEY_ED25519: + type = SSH_KEYTYPE_ED25519; + break; default: SSH_LOG(SSH_LOG_TRACE, "Unknown or invalid public key type %d", EVP_PKEY_base_id(pkey)); diff --git a/src/pki_ed25519.c b/src/pki_ed25519.c index 6a5a4a8a..c6ec3284 100644 --- a/src/pki_ed25519.c +++ b/src/pki_ed25519.c @@ -28,6 +28,205 @@ #include "libssh/ed25519.h" #include "libssh/buffer.h" +int pki_pubkey_build_ed25519(ssh_key key, ssh_string pubkey) +{ + if (ssh_string_len(pubkey) != ED25519_KEY_LEN) { + SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len"); + return SSH_ERROR; + } + + key->ed25519_pubkey = malloc(ED25519_KEY_LEN); + if (key->ed25519_pubkey == NULL) { + return SSH_ERROR; + } + + memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_KEY_LEN); + + return SSH_OK; +} + +int pki_privkey_build_ed25519(ssh_key key, + ssh_string pubkey, + ssh_string privkey) +{ + if (ssh_string_len(pubkey) != ED25519_KEY_LEN || + ssh_string_len(privkey) != (2 * ED25519_KEY_LEN)) { + SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len"); + return SSH_ERROR; + } + + /* In the internal implementation, the private key is the concatenation of + * the private seed with the public key. */ + key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN); + if (key->ed25519_privkey == NULL) { + goto error; + } + + key->ed25519_pubkey = malloc(ED25519_KEY_LEN); + if (key->ed25519_pubkey == NULL) { + goto error; + } + + memcpy(key->ed25519_privkey, ssh_string_data(privkey), 2 * ED25519_KEY_LEN); + memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_KEY_LEN); + + return SSH_OK; + +error: + SAFE_FREE(key->ed25519_privkey); + SAFE_FREE(key->ed25519_pubkey); + + return SSH_ERROR; +} + +/** + * @internal + * + * @brief Compare ed25519 keys if they are equal. + * + * @param[in] k1 The first key to compare. + * + * @param[in] k2 The second key to compare. + * + * @param[in] what What part or type of the key do you want to compare. + * + * @return 0 if equal, 1 if not. + */ +int +pki_ed25519_key_cmp(const ssh_key k1, const ssh_key k2, enum ssh_keycmp_e what) +{ + int cmp; + + switch (what) { + case SSH_KEY_CMP_PRIVATE: + if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) { + return 1; + } + /* In the internal implementation, the private key is the concatenation + * of the private seed with the public key. */ + cmp = memcmp(k1->ed25519_privkey, + k2->ed25519_privkey, + 2 * ED25519_KEY_LEN); + if (cmp != 0) { + return 1; + } + FALL_THROUGH; + case SSH_KEY_CMP_PUBLIC: + if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) { + return 1; + } + cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_KEY_LEN); + if (cmp != 0) { + return 1; + } + break; + case SSH_KEY_CMP_CERTIFICATE: + /* handled globally */ + return 1; + } + + return 0; +} + +/** + * @internal + * + * @brief Duplicate an Ed25519 key + * + * @param[out] new Pre-initialized ssh_key structure + * + * @param[in] key Key to copy + * + * @return SSH_ERROR on error, SSH_OK on success + */ +int pki_ed25519_key_dup(ssh_key new_key, const ssh_key key) +{ + if (key->ed25519_privkey == NULL && key->ed25519_pubkey == NULL) { + return SSH_ERROR; + } + + if (key->ed25519_privkey != NULL) { + /* In the internal implementation, the private key is the concatenation + * of the private seed with the public key. */ + new_key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN); + if (new_key->ed25519_privkey == NULL) { + return SSH_ERROR; + } + memcpy(new_key->ed25519_privkey, + key->ed25519_privkey, + 2 * ED25519_KEY_LEN); + } + + if (key->ed25519_pubkey != NULL) { + new_key->ed25519_pubkey = malloc(ED25519_KEY_LEN); + if (new_key->ed25519_pubkey == NULL) { + SAFE_FREE(new_key->ed25519_privkey); + return SSH_ERROR; + } + memcpy(new_key->ed25519_pubkey, key->ed25519_pubkey, ED25519_KEY_LEN); + } + + return SSH_OK; +} + +/** + * @internal + * + * @brief Outputs an Ed25519 public key in a blob buffer. + * + * @param[out] buffer Output buffer + * + * @param[in] key Key to output + * + * @return SSH_ERROR on error, SSH_OK on success + */ +int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key) +{ + int rc; + + if (key->ed25519_pubkey == NULL) { + return SSH_ERROR; + } + + rc = ssh_buffer_pack(buffer, + "dP", + (uint32_t)ED25519_KEY_LEN, + (size_t)ED25519_KEY_LEN, + key->ed25519_pubkey); + + 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; +} + int pki_key_generate_ed25519(ssh_key key) { int rc; diff --git a/src/pki_ed25519_common.c b/src/pki_ed25519_common.c index 03859f7c..53a683c8 100644 --- a/src/pki_ed25519_common.c +++ b/src/pki_ed25519_common.c @@ -27,213 +27,6 @@ #include "libssh/pki_priv.h" #include "libssh/buffer.h" -int pki_privkey_build_ed25519(ssh_key key, - ssh_string pubkey, - ssh_string privkey) -{ - if (ssh_string_len(pubkey) != ED25519_KEY_LEN || - ssh_string_len(privkey) != (2 * ED25519_KEY_LEN)) - { - SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len"); - return SSH_ERROR; - } - -#ifdef HAVE_LIBCRYPTO - /* In OpenSSL implementation, the private key is the original private seed, - * without the public key. */ - key->ed25519_privkey = malloc(ED25519_KEY_LEN); -#else - /* In the internal implementation, the private key is the concatenation of - * the private seed with the public key. */ - key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN); -#endif - if (key->ed25519_privkey == NULL) { - goto error; - } - - key->ed25519_pubkey = malloc(ED25519_KEY_LEN); - if (key->ed25519_pubkey == NULL) { - goto error; - } - -#ifdef HAVE_LIBCRYPTO - memcpy(key->ed25519_privkey, ssh_string_data(privkey), - ED25519_KEY_LEN); -#else - memcpy(key->ed25519_privkey, ssh_string_data(privkey), - 2 * ED25519_KEY_LEN); -#endif - memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), - ED25519_KEY_LEN); - - return SSH_OK; - -error: - SAFE_FREE(key->ed25519_privkey); - SAFE_FREE(key->ed25519_pubkey); - - return SSH_ERROR; -} - -/** - * @internal - * - * @brief Compare ed25519 keys if they are equal. - * - * @param[in] k1 The first key to compare. - * - * @param[in] k2 The second key to compare. - * - * @param[in] what What part or type of the key do you want to compare. - * - * @return 0 if equal, 1 if not. - */ -int pki_ed25519_key_cmp(const ssh_key k1, - const ssh_key k2, - enum ssh_keycmp_e what) -{ - int cmp; - - switch(what) { - case SSH_KEY_CMP_PRIVATE: - if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) { - return 1; - } -#ifdef HAVE_LIBCRYPTO - /* In OpenSSL implementation, the private key is the original private - * seed, without the public key. */ - cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey, ED25519_KEY_LEN); -#else - /* In the internal implementation, the private key is the concatenation - * of the private seed with the public key. */ - cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey, - 2 * ED25519_KEY_LEN); -#endif - if (cmp != 0) { - return 1; - } - FALL_THROUGH; - case SSH_KEY_CMP_PUBLIC: - if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) { - return 1; - } - cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_KEY_LEN); - if (cmp != 0) { - return 1; - } - break; - case SSH_KEY_CMP_CERTIFICATE: - /* handled globally */ - return 1; - } - - return 0; -} - -/** - * @internal - * - * @brief Duplicate an Ed25519 key - * - * @param[out] new Pre-initialized ssh_key structure - * - * @param[in] key Key to copy - * - * @return SSH_ERROR on error, SSH_OK on success - */ -int pki_ed25519_key_dup(ssh_key new_key, const ssh_key key) -{ - if (key->ed25519_privkey == NULL && key->ed25519_pubkey == NULL) { - return SSH_ERROR; - } - - if (key->ed25519_privkey != NULL) { -#ifdef HAVE_LIBCRYPTO - /* In OpenSSL implementation, the private key is the original private - * seed, without the public key. */ - new_key->ed25519_privkey = malloc(ED25519_KEY_LEN); -#else - /* In the internal implementation, the private key is the concatenation - * of the private seed with the public key. */ - new_key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN); -#endif - if (new_key->ed25519_privkey == NULL) { - return SSH_ERROR; - } -#ifdef HAVE_LIBCRYPTO - memcpy(new_key->ed25519_privkey, key->ed25519_privkey, ED25519_KEY_LEN); -#else - memcpy(new_key->ed25519_privkey, key->ed25519_privkey, 2 * ED25519_KEY_LEN); -#endif - } - - if (key->ed25519_pubkey != NULL) { - new_key->ed25519_pubkey = malloc(ED25519_KEY_LEN); - if (new_key->ed25519_pubkey == NULL) { - SAFE_FREE(new_key->ed25519_privkey); - return SSH_ERROR; - } - memcpy(new_key->ed25519_pubkey, key->ed25519_pubkey, ED25519_KEY_LEN); - } - - return SSH_OK; -} - -/** - * @internal - * - * @brief Outputs an Ed25519 public key in a blob buffer. - * - * @param[out] buffer Output buffer - * - * @param[in] key Key to output - * - * @return SSH_ERROR on error, SSH_OK on success - */ -int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key) -{ - int rc; - - if (key->ed25519_pubkey == NULL){ - return SSH_ERROR; - } - - rc = ssh_buffer_pack(buffer, - "dP", - (uint32_t)ED25519_KEY_LEN, - (size_t)ED25519_KEY_LEN, key->ed25519_pubkey); - - 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 *