From 2ff20d7966f44444357dc598cae341c225a9ef8d Mon Sep 17 00:00:00 2001 From: Steffen Jaeckel Date: Wed, 2 Oct 2019 12:42:49 +0200 Subject: [PATCH] add ecdsa key support Signed-off-by: Steffen Jaeckel --- demos/openssh-privkey.c | 173 +++++++++++++++++++++++++++++----------- 1 file changed, 128 insertions(+), 45 deletions(-) diff --git a/demos/openssh-privkey.c b/demos/openssh-privkey.c index 7a0923a3..dec65cf4 100644 --- a/demos/openssh-privkey.c +++ b/demos/openssh-privkey.c @@ -18,7 +18,7 @@ #include #include -static int verbose = 1; +static int verbose = 0; static void print_hex(const char* what, const void* v, const unsigned long l) { @@ -68,12 +68,13 @@ static void print_err(const char *fmt, ...) static void die_(int err, int line) { + verbose = 1; print_err("%3d: LTC sez %s\n", line, error_to_string(err)); exit(EXIT_FAILURE); } #define die(i) do { die_(i, __LINE__); } while(0) -#define DIE(s, ...) do { print_err("%3d: " s "\n", __LINE__, ##__VA_ARGS__); exit(EXIT_FAILURE); } while(0) +#define DIE(s, ...) do { verbose = 1; print_err("%3d: " s "\n", __LINE__, ##__VA_ARGS__); exit(EXIT_FAILURE); } while(0) static void check_padding(unsigned char *p, unsigned long len) @@ -91,6 +92,7 @@ typedef struct pka_key_ { enum ltc_oid_id id; union { curve25519_key ed25519; + ecc_key ecdsa; rsa_key rsa; } u; } pka_key; @@ -135,6 +137,115 @@ const struct ssh_kdf ssh_kdfs[] = { 0 }, }; +int ssh_find_init_ecc(const char *pka, pka_key *key) +{ + int err; + const char* prefix = "ecdsa-sha2-"; + size_t prefixlen = strlen(prefix); + const ltc_ecc_curve *cu; + if (strstr(pka, prefix) == NULL) return CRYPT_PK_INVALID_TYPE; + if ((err = ecc_find_curve(pka + prefixlen, &cu)) != CRYPT_OK) return err; + return ecc_set_curve(cu, &key->u.ecdsa); +} + +int ssh_decode_ecdsa(const unsigned char *in, unsigned long *inlen, pka_key *key) +{ + int err; + unsigned char groupname[64], group[512], privkey[512]; + ulong32 groupnamelen = sizeof(groupname), grouplen = sizeof(group), privkeylen = sizeof(privkey); + + if ((err = ssh_decode_sequence_multi(in, inlen, + LTC_SSHDATA_STRING, group, &groupnamelen, + LTC_SSHDATA_STRING, group, &grouplen, + LTC_SSHDATA_STRING, privkey, &privkeylen, + LTC_SSHDATA_EOL)) != CRYPT_OK) { + die(err); + } + + if ((err = ecc_set_key(privkey, privkeylen, PK_PRIVATE, &key->u.ecdsa)) != CRYPT_OK) { + die(err); + } + + key->id = PKA_EC; + + zeromem(groupname, sizeof(groupname)); + zeromem(group, sizeof(group)); + zeromem(privkey, sizeof(privkey)); + + return err; +} + +int ssh_decode_ed25519(const unsigned char *in, unsigned long *inlen, pka_key *key) +{ + int err; + unsigned char pubkey[2048], privkey[2048]; + ulong32 pubkeylen = sizeof(pubkey), privkeylen = sizeof(privkey); + + if ((err = ssh_decode_sequence_multi(in, inlen, + LTC_SSHDATA_STRING, pubkey, &pubkeylen, + LTC_SSHDATA_STRING, privkey, &privkeylen, + LTC_SSHDATA_EOL)) != CRYPT_OK) { + die(err); + } + + if ((err = ed25519_set_key(privkey, 32, &privkey[32], 32, &key->u.ed25519)) != CRYPT_OK) { + die(err); + } + + key->id = PKA_ED25519; + + zeromem(pubkey, sizeof(pubkey)); + zeromem(privkey, sizeof(privkey)); + + return err; +} + +int ssh_decode_rsa(const unsigned char *in, unsigned long *inlen, pka_key *key) +{ + int err; + void *tmp1, *tmp2; + if ((err = mp_init_multi(&tmp1, &tmp2, NULL)) != CRYPT_OK) { + die(err); + } + if ((err = rsa_init(&key->u.rsa)) != CRYPT_OK) { + die(err); + } + + if ((err = ssh_decode_sequence_multi(in, inlen, + LTC_SSHDATA_MPINT, key->u.rsa.N, + LTC_SSHDATA_MPINT, key->u.rsa.e, + LTC_SSHDATA_MPINT, key->u.rsa.d, + LTC_SSHDATA_MPINT, key->u.rsa.qP, + LTC_SSHDATA_MPINT, key->u.rsa.q, + LTC_SSHDATA_MPINT, key->u.rsa.p, + LTC_SSHDATA_EOL)) != CRYPT_OK) { + die(err); + } + + if ((err = mp_sub_d(key->u.rsa.p, 1, tmp1)) != CRYPT_OK) { die(err); } /* tmp1 = q-1 */ + if ((err = mp_sub_d(key->u.rsa.q, 1, tmp2)) != CRYPT_OK) { die(err); } /* tmp2 = p-1 */ + if ((err = mp_mod( key->u.rsa.d, tmp1, key->u.rsa.dP)) != CRYPT_OK) { die(err); } /* dP = d mod p-1 */ + if ((err = mp_mod( key->u.rsa.d, tmp2, key->u.rsa.dQ)) != CRYPT_OK) { die(err); } /* dQ = d mod q-1 */ + + key->id = PKA_RSA; + + mp_clear_multi(tmp2, tmp1, NULL); + + return err; +} + +struct ssh_pka { + const char *name; + int (*init)(const char*, pka_key*); + int (*decode)(const unsigned char*, unsigned long*, pka_key*); +}; + +struct ssh_pka ssh_pkas[] = { + { "ssh-ed25519", NULL, ssh_decode_ed25519 }, + { "ssh-rsa", NULL, ssh_decode_rsa }, + { NULL, ssh_find_init_ecc, ssh_decode_ecdsa }, +}; + int ssh_decode_private_key(const unsigned char *in, unsigned long *inlen, pka_key *key) { int err; @@ -143,7 +254,8 @@ int ssh_decode_private_key(const unsigned char *in, unsigned long *inlen, pka_ke ulong32 pkalen = sizeof(pka), pubkeylen = sizeof(pubkey); ulong32 privkeylen = sizeof(privkey), commentlen = sizeof(comment); unsigned long remaining, cur_len; - unsigned char *p; + const unsigned char *p; + size_t n; LTC_ARGCHK(in != NULL); LTC_ARGCHK(inlen != NULL); @@ -163,55 +275,26 @@ int ssh_decode_private_key(const unsigned char *in, unsigned long *inlen, pka_ke p += cur_len; remaining = *inlen - cur_len; + cur_len = remaining; - if (XSTRCMP(pka, "ssh-ed25519") == 0) { - cur_len = remaining; - if ((err = ssh_decode_sequence_multi(p, &cur_len, - LTC_SSHDATA_STRING, pubkey, &pubkeylen, - LTC_SSHDATA_STRING, privkey, &privkeylen, - LTC_SSHDATA_EOL)) != CRYPT_OK) { + for (n = 0; n < sizeof(ssh_pkas)/sizeof(ssh_pkas[0]); ++n) { + if (ssh_pkas[n].name != NULL) { + if (XSTRCMP(pka, ssh_pkas[n].name) != 0) continue; + } else { + if ((ssh_pkas[n].init == NULL) || + (ssh_pkas[n].init((char*)pka, key) != CRYPT_OK)) continue; + } + if ((err = ssh_pkas[n].decode(p, &cur_len, key)) != CRYPT_OK) { die(err); } - - if ((err = ed25519_set_key(privkey, 32, &privkey[32], 32, &key->u.ed25519)) != CRYPT_OK) { - die(err); - } - - key->id = PKA_ED25519; - } else if (XSTRCMP(pka, "ssh-rsa") == 0) { - void *tmp1, *tmp2; - if ((err = mp_init_multi(&tmp1, &tmp2, NULL)) != CRYPT_OK) { - die(err); - } - if ((err = rsa_init(&key->u.rsa)) != CRYPT_OK) { - die(err); - } - - cur_len = remaining; - if ((err = ssh_decode_sequence_multi(p, &cur_len, - LTC_SSHDATA_MPINT, key->u.rsa.N, - LTC_SSHDATA_MPINT, key->u.rsa.e, - LTC_SSHDATA_MPINT, key->u.rsa.d, - LTC_SSHDATA_MPINT, key->u.rsa.qP, - LTC_SSHDATA_MPINT, key->u.rsa.q, - LTC_SSHDATA_MPINT, key->u.rsa.p, - LTC_SSHDATA_EOL)) != CRYPT_OK) { - die(err); - } - - if ((err = mp_sub_d(key->u.rsa.p, 1, tmp1)) != CRYPT_OK) { die(err); } /* tmp1 = q-1 */ - if ((err = mp_sub_d(key->u.rsa.q, 1, tmp2)) != CRYPT_OK) { die(err); } /* tmp2 = p-1 */ - if ((err = mp_mod( key->u.rsa.d, tmp1, key->u.rsa.dP)) != CRYPT_OK) { die(err); } /* dP = d mod p-1 */ - if ((err = mp_mod( key->u.rsa.d, tmp2, key->u.rsa.dQ)) != CRYPT_OK) { die(err); } /* dQ = d mod q-1 */ - - mp_clear_multi(tmp2, tmp1, NULL); - } else { - DIE("unsupported pka"); + break; } + if (n == sizeof(ssh_pkas)/sizeof(ssh_pkas[0])) DIE("unsupported pka %s", pka); + p += cur_len; remaining -= cur_len; - cur_len = remaining; + if ((err = ssh_decode_sequence_multi(p, &cur_len, LTC_SSHDATA_STRING, comment, &commentlen, LTC_SSHDATA_EOL)) != CRYPT_OK) {