aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelen <jjelen@redhat.com>2018-09-06 17:53:19 +0200
committerAndreas Schneider <asn@cryptomilk.org>2018-09-18 09:53:49 +0200
commit39102224b25c937bd07cb61eccf12f0aec62e159 (patch)
treec92a5a72626ffa63c4ed46306d5c6ce7f178294d
parente365aed6d2cf829d55e6f0c26203a8e66976cf28 (diff)
downloadlibssh-39102224b25c937bd07cb61eccf12f0aec62e159.tar.gz
libssh-39102224b25c937bd07cb61eccf12f0aec62e159.tar.xz
libssh-39102224b25c937bd07cb61eccf12f0aec62e159.zip
pki: Allow reading keys in new OpenSSH format
This implements reading the OpenSSH key format accross the cryptographic backends. Most of the code is shared and moved to pki.c, just the building of the keys is implemented in pki_privkey_build_*() functions. Signed-off-by: Jakub Jelen <jjelen@redhat.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
-rw-r--r--include/libssh/pki_priv.h26
-rw-r--r--src/pki.c173
-rw-r--r--src/pki_container_openssh.c56
-rw-r--r--src/pki_crypto.c150
-rw-r--r--src/pki_ed25519.c22
-rw-r--r--src/pki_gcrypt.c66
-rw-r--r--src/pki_mbedcrypto.c137
7 files changed, 578 insertions, 52 deletions
diff --git a/include/libssh/pki_priv.h b/include/libssh/pki_priv.h
index fe7e92a8..f8d94616 100644
--- a/include/libssh/pki_priv.h
+++ b/include/libssh/pki_priv.h
@@ -72,6 +72,9 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
const char *passphrase,
ssh_auth_callback auth_fn,
void *auth_data);
+int pki_import_privkey_buffer(enum ssh_keytypes_e type,
+ ssh_buffer buffer,
+ ssh_key *pkey);
/* SSH Public Key Functions */
int pki_pubkey_build_dss(ssh_key key,
@@ -85,6 +88,26 @@ int pki_pubkey_build_rsa(ssh_key key,
int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e);
ssh_string pki_publickey_to_blob(const ssh_key key);
+/* SSH Private Key Functions */
+int pki_privkey_build_dss(ssh_key key,
+ ssh_string p,
+ ssh_string q,
+ ssh_string g,
+ ssh_string pubkey,
+ ssh_string privkey);
+int pki_privkey_build_rsa(ssh_key key,
+ ssh_string n,
+ ssh_string e,
+ ssh_string d,
+ ssh_string iqmp,
+ ssh_string p,
+ ssh_string q);
+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_string pki_signature_to_blob(const ssh_signature sign);
ssh_signature pki_signature_from_blob(const ssh_key pubkey,
@@ -121,6 +144,9 @@ int pki_ed25519_key_dup(ssh_key new, const ssh_key key);
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key);
ssh_string pki_ed25519_sig_to_blob(ssh_signature sig);
int pki_ed25519_sig_from_blob(ssh_signature sig, ssh_string sig_blob);
+int pki_privkey_build_ed25519(ssh_key key,
+ ssh_string pubkey,
+ ssh_string privkey);
/* PKI Container OpenSSH */
ssh_key ssh_pki_openssh_privkey_import(const char *text_key,
diff --git a/src/pki.c b/src/pki.c
index aa188767..f819b94d 100644
--- a/src/pki.c
+++ b/src/pki.c
@@ -810,6 +810,179 @@ ssh_private_key ssh_pki_convert_key_to_privatekey(const ssh_key key) {
return privkey;
}
+int pki_import_privkey_buffer(enum ssh_keytypes_e type,
+ ssh_buffer buffer,
+ ssh_key *pkey)
+{
+ ssh_key key = NULL;
+ int rc;
+
+ key = ssh_key_new();
+ if (key == NULL) {
+ return SSH_ERROR;
+ }
+
+ key->type = type;
+ key->type_c = ssh_key_type_to_char(type);
+ key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
+
+ switch (type) {
+ case SSH_KEYTYPE_DSS:
+ {
+ ssh_string p = NULL;
+ ssh_string q = NULL;
+ ssh_string g = NULL;
+ ssh_string pubkey = NULL;
+ ssh_string privkey = NULL;
+
+ rc = ssh_buffer_unpack(buffer, "SSSSS", &p, &q, &g,
+ &pubkey, &privkey);
+ if (rc != SSH_OK) {
+ SSH_LOG(SSH_LOG_WARN, "Unpack error");
+ goto fail;
+ }
+
+ rc = pki_privkey_build_dss(key, p, q, g, pubkey, privkey);
+#ifdef DEBUG_CRYPTO
+ ssh_print_hexa("p", ssh_string_data(p), ssh_string_len(p));
+ ssh_print_hexa("q", ssh_string_data(q), ssh_string_len(q));
+ ssh_print_hexa("g", ssh_string_data(g), ssh_string_len(g));
+ ssh_print_hexa("pubkey", ssh_string_data(pubkey),
+ ssh_string_len(pubkey));
+ ssh_print_hexa("privkey", ssh_string_data(privkey),
+ ssh_string_len(privkey));
+#endif
+ ssh_string_burn(p);
+ ssh_string_free(p);
+ ssh_string_burn(q);
+ ssh_string_free(q);
+ ssh_string_burn(g);
+ ssh_string_free(g);
+ ssh_string_burn(pubkey);
+ ssh_string_free(pubkey);
+ ssh_string_burn(privkey);
+ ssh_string_free(privkey);
+ if (rc == SSH_ERROR) {
+ goto fail;
+ }
+ }
+ break;
+ case SSH_KEYTYPE_RSA:
+ {
+ ssh_string n = NULL;
+ ssh_string e = NULL;
+ ssh_string d = NULL;
+ ssh_string iqmp = NULL;
+ ssh_string p = NULL;
+ ssh_string q = NULL;
+
+ rc = ssh_buffer_unpack(buffer, "SSSSSS", &n, &e, &d,
+ &iqmp, &p, &q);
+ if (rc != SSH_OK) {
+ SSH_LOG(SSH_LOG_WARN, "Unpack error");
+ goto fail;
+ }
+
+ rc = pki_privkey_build_rsa(key, n, e, d, iqmp, p, q);
+#ifdef DEBUG_CRYPTO
+ ssh_print_hexa("n", ssh_string_data(n), ssh_string_len(n));
+ ssh_print_hexa("e", ssh_string_data(e), ssh_string_len(e));
+ ssh_print_hexa("d", ssh_string_data(d), ssh_string_len(d));
+ ssh_print_hexa("iqmp", ssh_string_data(iqmp),
+ ssh_string_len(iqmp));
+ ssh_print_hexa("p", ssh_string_data(p), ssh_string_len(p));
+ ssh_print_hexa("q", ssh_string_data(q), ssh_string_len(q));
+#endif
+ ssh_string_burn(n);
+ ssh_string_free(n);
+ ssh_string_burn(e);
+ ssh_string_free(e);
+ ssh_string_burn(d);
+ ssh_string_free(d);
+ ssh_string_burn(iqmp);
+ ssh_string_free(iqmp);
+ ssh_string_burn(p);
+ ssh_string_free(p);
+ ssh_string_burn(q);
+ ssh_string_free(q);
+ if (rc == SSH_ERROR) {
+ SSH_LOG(SSH_LOG_WARN, "Failed to build RSA private key");
+ goto fail;
+ }
+ }
+ break;
+#ifdef HAVE_ECC
+ case SSH_KEYTYPE_ECDSA:
+ {
+ ssh_string e = NULL;
+ ssh_string exp = NULL;
+ ssh_string i = NULL;
+ int nid;
+
+ rc = ssh_buffer_unpack(buffer, "SSS", &i, &e, &exp);
+ if (rc != SSH_OK) {
+ SSH_LOG(SSH_LOG_WARN, "Unpack error");
+ goto fail;
+ }
+
+ nid = pki_key_ecdsa_nid_from_name(ssh_string_get_char(i));
+ ssh_string_free(i);
+ if (nid == -1) {
+ goto fail;
+ }
+
+ rc = pki_privkey_build_ecdsa(key, nid, e, exp);
+ ssh_string_burn(e);
+ ssh_string_free(e);
+ ssh_string_burn(exp);
+ ssh_string_free(exp);
+ if (rc < 0) {
+ SSH_LOG(SSH_LOG_WARN, "Failed to build ECDSA private key");
+ goto fail;
+ }
+
+ /* Update key type */
+ key->type_c = ssh_pki_key_ecdsa_name(key);
+ }
+ break;
+#endif
+ case SSH_KEYTYPE_ED25519:
+ {
+ ssh_string pubkey = NULL, privkey = NULL;
+
+ rc = ssh_buffer_unpack(buffer, "SS", &pubkey, &privkey);
+ if (rc != SSH_OK){
+ SSH_LOG(SSH_LOG_WARN, "Unpack error");
+ goto fail;
+ }
+
+ rc = pki_privkey_build_ed25519(key, pubkey, privkey);
+ ssh_string_burn(privkey);
+ ssh_string_free(privkey);
+ ssh_string_free(pubkey);
+ if (rc != SSH_OK) {
+ SSH_LOG(SSH_LOG_WARN, "Failed to build ed25519 key");
+ goto fail;
+ }
+ }
+ break;
+ case SSH_KEYTYPE_DSS_CERT01:
+ case SSH_KEYTYPE_RSA_CERT01:
+ case SSH_KEYTYPE_RSA1:
+ case SSH_KEYTYPE_UNKNOWN:
+ default:
+ SSH_LOG(SSH_LOG_WARN, "Unknown private key type (%d)", type);
+ goto fail;
+ }
+
+ *pkey = key;
+ return SSH_OK;
+fail:
+ ssh_key_free(key);
+
+ return SSH_ERROR;
+}
+
static int pki_import_pubkey_buffer(ssh_buffer buffer,
enum ssh_keytypes_e type,
ssh_key *pkey) {
diff --git a/src/pki_container_openssh.c b/src/pki_container_openssh.c
index 2c4b6c46..4154b424 100644
--- a/src/pki_container_openssh.c
+++ b/src/pki_container_openssh.c
@@ -60,7 +60,6 @@ static int pki_openssh_import_privkey_blob(ssh_buffer key_blob_buffer,
enum ssh_keytypes_e type;
char *type_s = NULL;
ssh_key key = NULL;
- ssh_string pubkey = NULL, privkey = NULL;
int rc;
if (pkey == NULL) {
@@ -75,57 +74,14 @@ static int pki_openssh_import_privkey_blob(ssh_buffer key_blob_buffer,
type = ssh_key_type_from_name(type_s);
if (type == SSH_KEYTYPE_UNKNOWN) {
- SSH_LOG(SSH_LOG_WARN, "Unknown key type found!");
+ SSH_LOG(SSH_LOG_WARN, "Unknown key type '%s' found!", type_s);
return SSH_ERROR;
}
SAFE_FREE(type_s);
- key = ssh_key_new();
- if (key == NULL) {
- SSH_LOG(SSH_LOG_WARN, "Out of memory");
- return SSH_ERROR;
- }
-
- key->type = type;
- key->type_c = ssh_key_type_to_char(type);
- key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
-
- switch (type) {
- case SSH_KEYTYPE_ED25519:
- rc = ssh_buffer_unpack(key_blob_buffer, "SS", &pubkey, &privkey);
- if (rc != SSH_OK){
- SSH_LOG(SSH_LOG_WARN, "Unpack error");
- goto fail;
- }
- if(ssh_string_len(pubkey) != ED25519_PK_LEN ||
- ssh_string_len(privkey) != ED25519_SK_LEN){
- SSH_LOG(SSH_LOG_WARN, "Invalid ed25519 key len");
- goto fail;
- }
- key->ed25519_privkey = malloc(ED25519_SK_LEN);
- key->ed25519_pubkey = malloc(ED25519_PK_LEN);
- if(key->ed25519_privkey == NULL || key->ed25519_pubkey == NULL){
- goto fail;
- }
- memcpy(key->ed25519_privkey, ssh_string_data(privkey), ED25519_SK_LEN);
- memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_PK_LEN);
- explicit_bzero(ssh_string_data(privkey), ED25519_SK_LEN);
- SAFE_FREE(privkey);
- SAFE_FREE(pubkey);
- break;
- case SSH_KEYTYPE_DSS_CERT01:
- case SSH_KEYTYPE_DSS:
- /* p,q,g,pub_key,priv_key */
- case SSH_KEYTYPE_RSA_CERT01:
- case SSH_KEYTYPE_RSA:
- /* n,e,d,iqmp,p,q */
- case SSH_KEYTYPE_ECDSA:
- /* curve_name, group, privkey */
- SSH_LOG(SSH_LOG_WARN, "Unsupported private key method %s", key->type_c);
- goto fail;
- case SSH_KEYTYPE_RSA1:
- case SSH_KEYTYPE_UNKNOWN:
- SSH_LOG(SSH_LOG_WARN, "Unknown private key protocol %s", key->type_c);
+ rc = pki_import_privkey_buffer(type, key_blob_buffer, &key);
+ if (rc != SSH_OK) {
+ SSH_LOG(SSH_LOG_WARN, "Failed to read key in OpenSSH format");
goto fail;
}
@@ -134,10 +90,6 @@ static int pki_openssh_import_privkey_blob(ssh_buffer key_blob_buffer,
fail:
ssh_key_free(key);
- ssh_string_burn(privkey);
- ssh_string_free(privkey);
- ssh_string_free(pubkey);
-
return SSH_ERROR;
}
diff --git a/src/pki_crypto.c b/src/pki_crypto.c
index 8cf029a6..a90b6d00 100644
--- a/src/pki_crypto.c
+++ b/src/pki_crypto.c
@@ -172,6 +172,61 @@ static ssh_string make_ecpoint_string(const EC_GROUP *g,
return s;
}
+int pki_privkey_build_ecdsa(ssh_key key, int nid, ssh_string e, ssh_string exp)
+{
+ EC_POINT *p = NULL;
+ const EC_GROUP *g = NULL;
+ int ok;
+ BIGNUM *bexp = NULL;
+
+ key->ecdsa_nid = nid;
+ key->type_c = pki_key_ecdsa_nid_to_name(nid);
+
+ key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid);
+ if (key->ecdsa == NULL) {
+ return -1;
+ }
+
+ g = EC_KEY_get0_group(key->ecdsa);
+
+ p = EC_POINT_new(g);
+ if (p == NULL) {
+ return -1;
+ }
+
+ ok = EC_POINT_oct2point(g,
+ p,
+ ssh_string_data(e),
+ ssh_string_len(e),
+ NULL);
+ if (!ok) {
+ EC_POINT_free(p);
+ return -1;
+ }
+
+ /* EC_KEY_set_public_key duplicates p */
+ ok = EC_KEY_set_public_key(key->ecdsa, p);
+ EC_POINT_free(p);
+ if (!ok) {
+ return -1;
+ }
+
+ bexp = ssh_make_string_bn(exp);
+ if (bexp == NULL) {
+ EC_KEY_free(key->ecdsa);
+ return -1;
+ }
+ /* EC_KEY_set_private_key duplicates exp */
+ ok = EC_KEY_set_private_key(key->ecdsa, bexp);
+ BN_free(bexp);
+ if (!ok) {
+ EC_KEY_free(key->ecdsa);
+ return -1;
+ }
+
+ return 0;
+}
+
int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
{
EC_POINT *p = NULL;
@@ -896,6 +951,49 @@ fail:
return NULL;
}
+int pki_privkey_build_dss(ssh_key key,
+ ssh_string p,
+ ssh_string q,
+ ssh_string g,
+ ssh_string pubkey,
+ ssh_string privkey)
+{
+ int rc;
+ BIGNUM *bp, *bq, *bg, *bpub_key, *bpriv_key;
+
+ key->dsa = DSA_new();
+ if (key->dsa == NULL) {
+ return SSH_ERROR;
+ }
+
+ bp = ssh_make_string_bn(p);
+ bq = ssh_make_string_bn(q);
+ bg = ssh_make_string_bn(g);
+ bpub_key = ssh_make_string_bn(pubkey);
+ bpriv_key = ssh_make_string_bn(privkey);
+ if (bp == NULL || bq == NULL ||
+ bg == NULL || bpub_key == NULL) {
+ goto fail;
+ }
+
+ /* Memory management of bp, qq and bg is transfered to DSA object */
+ rc = DSA_set0_pqg(key->dsa, bp, bq, bg);
+ if (rc == 0) {
+ goto fail;
+ }
+
+ /* Memory management of bpub_key and bpriv_key is transfered to DSA object */
+ rc = DSA_set0_key(key->dsa, bpub_key, bpriv_key);
+ if (rc == 0) {
+ goto fail;
+ }
+
+ return SSH_OK;
+fail:
+ DSA_free(key->dsa);
+ return SSH_ERROR;
+}
+
int pki_pubkey_build_dss(ssh_key key,
ssh_string p,
ssh_string q,
@@ -936,6 +1034,58 @@ fail:
return SSH_ERROR;
}
+int pki_privkey_build_rsa(ssh_key key,
+ ssh_string n,
+ ssh_string e,
+ ssh_string d,
+ ssh_string iqmp,
+ ssh_string p,
+ ssh_string q)
+{
+ int rc;
+ BIGNUM *be, *bn, *bd/*, *biqmp*/, *bp, *bq;
+
+ key->rsa = RSA_new();
+ if (key->rsa == NULL) {
+ return SSH_ERROR;
+ }
+
+ bn = ssh_make_string_bn(n);
+ be = ssh_make_string_bn(e);
+ bd = ssh_make_string_bn(d);
+ /*biqmp = ssh_make_string_bn(iqmp);*/
+ bp = ssh_make_string_bn(p);
+ bq = ssh_make_string_bn(q);
+ if (be == NULL || bn == NULL || bd == NULL ||
+ /*biqmp == NULL ||*/ bp == NULL || bq == NULL) {
+ goto fail;
+ }
+
+ /* Memory management of be, bn and bd is transfered to RSA object */
+ rc = RSA_set0_key(key->rsa, bn, be, bd);
+ if (rc == 0) {
+ goto fail;
+ }
+
+ /* Memory management of bp and bq is transfered to RSA object */
+ rc = RSA_set0_factors(key->rsa, bp, bq);
+ if (rc == 0) {
+ goto fail;
+ }
+
+ /* p, q, dmp1, dmq1 and iqmp may be NULL in private keys, but the RSA
+ * operations are much faster when these values are available.
+ * https://www.openssl.org/docs/man1.0.2/crypto/rsa.html
+ */
+ /* RSA_set0_crt_params(key->rsa, biqmp, NULL, NULL);
+ TODO calculate missing crt_params */
+
+ return SSH_OK;
+fail:
+ RSA_free(key->rsa);
+ return SSH_ERROR;
+}
+
int pki_pubkey_build_rsa(ssh_key key,
ssh_string e,
ssh_string n) {
diff --git a/src/pki_ed25519.c b/src/pki_ed25519.c
index 45362c4f..981a74b6 100644
--- a/src/pki_ed25519.c
+++ b/src/pki_ed25519.c
@@ -56,6 +56,28 @@ error:
return SSH_ERROR;
}
+int pki_privkey_build_ed25519(ssh_key key,
+ ssh_string pubkey,
+ ssh_string privkey)
+{
+ if (ssh_string_len(pubkey) != ED25519_PK_LEN ||
+ ssh_string_len(privkey) != ED25519_SK_LEN) {
+ SSH_LOG(SSH_LOG_WARN, "Invalid ed25519 key len");
+ return SSH_ERROR;
+ }
+ key->ed25519_privkey = malloc(ED25519_SK_LEN);
+ key->ed25519_pubkey = malloc(ED25519_PK_LEN);
+ if (key->ed25519_privkey == NULL || key->ed25519_pubkey == NULL) {
+ return SSH_ERROR;
+ }
+ memcpy(key->ed25519_privkey, ssh_string_data(privkey),
+ ED25519_SK_LEN);
+ memcpy(key->ed25519_pubkey, ssh_string_data(pubkey),
+ ED25519_PK_LEN);
+
+ return SSH_OK;
+}
+
int pki_ed25519_sign(const ssh_key privkey,
ssh_signature sig,
const unsigned char *hash,
diff --git a/src/pki_gcrypt.c b/src/pki_gcrypt.c
index a988d805..95499f00 100644
--- a/src/pki_gcrypt.c
+++ b/src/pki_gcrypt.c
@@ -1030,6 +1030,27 @@ fail:
return NULL;
}
+int pki_privkey_build_dss(ssh_key key,
+ ssh_string p,
+ ssh_string q,
+ ssh_string g,
+ ssh_string pubkey,
+ ssh_string privkey)
+{
+ gcry_sexp_build(&key->dsa, NULL,
+ "(private-key(dsa(p %b)(q %b)(g %b)(y %b)(x %b)))",
+ ssh_string_len(p), ssh_string_data(p),
+ ssh_string_len(q), ssh_string_data(q),
+ ssh_string_len(g), ssh_string_data(g),
+ ssh_string_len(pubkey), ssh_string_data(pubkey),
+ ssh_string_len(privkey), ssh_string_data(privkey));
+ if (key->dsa == NULL) {
+ return SSH_ERROR;
+ }
+
+ return SSH_OK;
+}
+
int pki_pubkey_build_dss(ssh_key key,
ssh_string p,
ssh_string q,
@@ -1048,6 +1069,32 @@ int pki_pubkey_build_dss(ssh_key key,
return SSH_OK;
}
+int pki_privkey_build_rsa(ssh_key key,
+ ssh_string n,
+ ssh_string e,
+ ssh_string d,
+ ssh_string iqmp,
+ ssh_string p,
+ ssh_string q)
+{
+ /* in gcrypt, there is no iqmp (inverse of q mod p) argument,
+ * but it is ipmq (inverse of p mod q) so we need to swap
+ * the p and q arguments */
+ gcry_sexp_build(&key->rsa, NULL,
+ "(private-key(rsa(n %b)(e %b)(d %b)(p %b)(q %b)(u %b)))",
+ ssh_string_len(n), ssh_string_data(n),
+ ssh_string_len(e), ssh_string_data(e),
+ ssh_string_len(d), ssh_string_data(d),
+ ssh_string_len(q), ssh_string_data(q),
+ ssh_string_len(p), ssh_string_data(p),
+ ssh_string_len(iqmp), ssh_string_data(iqmp));
+ if (key->rsa == NULL) {
+ return SSH_ERROR;
+ }
+
+ return SSH_OK;
+}
+
int pki_pubkey_build_rsa(ssh_key key,
ssh_string e,
ssh_string n) {
@@ -1063,6 +1110,25 @@ int pki_pubkey_build_rsa(ssh_key key,
}
#ifdef HAVE_GCRYPT_ECC
+int pki_privkey_build_ecdsa(ssh_key key, int nid, ssh_string e, ssh_string exp)
+{
+ gpg_error_t err;
+
+ key->ecdsa_nid = nid;
+ key->type_c = pki_key_ecdsa_nid_to_name(nid);
+
+ err = gcry_sexp_build(&key->ecdsa, NULL,
+ "(private-key(ecdsa(curve %s)(d %b)(q %b)))",
+ pki_key_ecdsa_nid_to_gcrypt_name(nid),
+ ssh_string_len(exp), ssh_string_data(exp),
+ ssh_string_len(e), ssh_string_data(e));
+ if (err) {
+ return SSH_ERROR;
+ }
+
+ return SSH_OK;
+}
+
int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
{
gpg_error_t err;
diff --git a/src/pki_mbedcrypto.c b/src/pki_mbedcrypto.c
index a5954980..26a80be0 100644
--- a/src/pki_mbedcrypto.c
+++ b/src/pki_mbedcrypto.c
@@ -214,6 +214,64 @@ fail:
return NULL;
}
+int pki_privkey_build_rsa(ssh_key key,
+ ssh_string n,
+ ssh_string e,
+ ssh_string d,
+ ssh_string iqmp,
+ ssh_string p,
+ ssh_string q)
+{
+ mbedtls_rsa_context *rsa = NULL;
+ const mbedtls_pk_info_t *pk_info = NULL;
+ int rc;
+
+ key->rsa = malloc(sizeof(mbedtls_pk_context));
+ if (key->rsa == NULL) {
+ return SSH_ERROR;
+ }
+
+ mbedtls_pk_init(key->rsa);
+ pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA);
+ mbedtls_pk_setup(key->rsa, pk_info);
+
+ rc = mbedtls_pk_can_do(key->rsa, MBEDTLS_PK_RSA);
+ if (rc == 0) {
+ goto fail;
+ }
+
+ rsa = mbedtls_pk_rsa(*key->rsa);
+ rc = mbedtls_rsa_import_raw(rsa,
+ ssh_string_data(n), ssh_string_len(n),
+ ssh_string_data(p), ssh_string_len(p),
+ ssh_string_data(q), ssh_string_len(q),
+ ssh_string_data(d), ssh_string_len(d),
+ ssh_string_data(e), ssh_string_len(e));
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARN, "Failed to import private RSA key");
+ goto fail;
+ }
+
+ rc = mbedtls_rsa_complete(rsa);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARN, "Failed to complete private RSA key");
+ goto fail;
+ }
+
+ rc = mbedtls_rsa_check_privkey(rsa);
+ if (rc != 0) {
+ SSH_LOG(SSH_LOG_WARN, "Inconsistent private RSA key");
+ goto fail;
+ }
+
+ return SSH_OK;
+
+fail:
+ mbedtls_pk_free(key->rsa);
+ SAFE_FREE(key->rsa);
+ return SSH_ERROR;
+}
+
int pki_pubkey_build_rsa(ssh_key key, ssh_string e, ssh_string n)
{
mbedtls_rsa_context *rsa = NULL;
@@ -1243,6 +1301,73 @@ static mbedtls_ecp_group_id pki_key_ecdsa_nid_to_mbed_gid(int nid)
return MBEDTLS_ECP_DP_NONE;
}
+int pki_privkey_build_ecdsa(ssh_key key, int nid, ssh_string e, ssh_string exp)
+{
+ int rc;
+ mbedtls_ecp_keypair keypair;
+ mbedtls_ecp_group group;
+ mbedtls_ecp_point Q;
+
+ key->ecdsa_nid = nid;
+ key->type_c = pki_key_ecdsa_nid_to_name(nid);
+
+ key->ecdsa = malloc(sizeof(mbedtls_ecdsa_context));
+ if (key->ecdsa == NULL) {
+ return SSH_ERROR;
+ }
+
+ mbedtls_ecdsa_init(key->ecdsa);
+ mbedtls_ecp_keypair_init(&keypair);
+ mbedtls_ecp_group_init(&group);
+ mbedtls_ecp_point_init(&Q);
+
+ rc = mbedtls_ecp_group_load(&group,
+ pki_key_ecdsa_nid_to_mbed_gid(nid));
+ if (rc != 0) {
+ goto fail;
+ }
+
+ rc = mbedtls_ecp_point_read_binary(&group, &Q, ssh_string_data(e),
+ ssh_string_len(e));
+ if (rc != 0) {
+ goto fail;
+ }
+
+ rc = mbedtls_ecp_copy(&keypair.Q, &Q);
+ if (rc != 0) {
+ goto fail;
+ }
+
+ rc = mbedtls_ecp_group_copy(&keypair.grp, &group);
+ if (rc != 0) {
+ goto fail;
+ }
+
+ rc = mbedtls_mpi_read_binary(&keypair.d, ssh_string_data(exp),
+ ssh_string_len(exp));
+ if (rc != 0) {
+ goto fail;
+ }
+
+ rc = mbedtls_ecdsa_from_keypair(key->ecdsa, &keypair);
+ if (rc != 0) {
+ goto fail;
+ }
+
+ mbedtls_ecp_point_free(&Q);
+ mbedtls_ecp_group_free(&group);
+ mbedtls_ecp_keypair_free(&keypair);
+ return SSH_OK;
+
+fail:
+ mbedtls_ecdsa_free(key->ecdsa);
+ mbedtls_ecp_point_free(&Q);
+ mbedtls_ecp_group_free(&group);
+ mbedtls_ecp_keypair_free(&keypair);
+ SAFE_FREE(key->ecdsa);
+ return SSH_ERROR;
+}
+
int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
{
int rc;
@@ -1347,6 +1472,18 @@ int pki_key_generate_ecdsa(ssh_key key, int parameter)
return SSH_OK;
}
+int pki_privkey_build_dss(ssh_key key, ssh_string p, ssh_string q, ssh_string g,
+ ssh_string pubkey, ssh_string privkey)
+{
+ (void) key;
+ (void) p;
+ (void) q;
+ (void) g;
+ (void) pubkey;
+ (void) privkey;
+ return SSH_ERROR;
+}
+
int pki_pubkey_build_dss(ssh_key key, ssh_string p, ssh_string q, ssh_string g,
ssh_string pubkey)
{