123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 |
- #include "includes.h"
- #include "dbutil.h"
- #include "crypto_desc.h"
- #include "ecc.h"
- #include "ecdsa.h"
- #include "signkey.h"
- #if DROPBEAR_ECDSA
- int signkey_is_ecdsa(enum signkey_type type)
- {
- return type == DROPBEAR_SIGNKEY_ECDSA_NISTP256
- || type == DROPBEAR_SIGNKEY_ECDSA_NISTP384
- || type == DROPBEAR_SIGNKEY_ECDSA_NISTP521;
- }
- enum signkey_type ecdsa_signkey_type(const ecc_key * key) {
- #if DROPBEAR_ECC_256
- if (key->dp == ecc_curve_nistp256.dp) {
- return DROPBEAR_SIGNKEY_ECDSA_NISTP256;
- }
- #endif
- #if DROPBEAR_ECC_384
- if (key->dp == ecc_curve_nistp384.dp) {
- return DROPBEAR_SIGNKEY_ECDSA_NISTP384;
- }
- #endif
- #if DROPBEAR_ECC_521
- if (key->dp == ecc_curve_nistp521.dp) {
- return DROPBEAR_SIGNKEY_ECDSA_NISTP521;
- }
- #endif
- return DROPBEAR_SIGNKEY_NONE;
- }
- ecc_key *gen_ecdsa_priv_key(unsigned int bit_size) {
- const ltc_ecc_set_type *dp = NULL; /* curve domain parameters */
- ecc_key *new_key = NULL;
- switch (bit_size) {
- #if DROPBEAR_ECC_256
- case 256:
- dp = ecc_curve_nistp256.dp;
- break;
- #endif
- #if DROPBEAR_ECC_384
- case 384:
- dp = ecc_curve_nistp384.dp;
- break;
- #endif
- #if DROPBEAR_ECC_521
- case 521:
- dp = ecc_curve_nistp521.dp;
- break;
- #endif
- }
- if (!dp) {
- dropbear_exit("Key size %d isn't valid. Try "
- #if DROPBEAR_ECC_256
- "256 "
- #endif
- #if DROPBEAR_ECC_384
- "384 "
- #endif
- #if DROPBEAR_ECC_521
- "521 "
- #endif
- , bit_size);
- }
- new_key = m_malloc(sizeof(*new_key));
- if (ecc_make_key_ex(NULL, dropbear_ltc_prng, new_key, dp) != CRYPT_OK) {
- dropbear_exit("ECC error");
- }
- return new_key;
- }
- ecc_key *buf_get_ecdsa_pub_key(buffer* buf) {
- unsigned char *key_ident = NULL, *identifier = NULL;
- unsigned int key_ident_len, identifier_len;
- buffer *q_buf = NULL;
- struct dropbear_ecc_curve **curve;
- ecc_key *new_key = NULL;
- /* string "ecdsa-sha2-[identifier]" or "sk-ecdsa-sha2-nistp256@openssh.com" */
- key_ident = (unsigned char*)buf_getstring(buf, &key_ident_len);
- /* string "[identifier]" */
- identifier = (unsigned char*)buf_getstring(buf, &identifier_len);
- if (strcmp (key_ident, "sk-ecdsa-sha2-nistp256@openssh.com") == 0) {
- if (strcmp (identifier, "nistp256") != 0) {
- TRACE(("mismatching identifiers"))
- goto out;
- }
- } else {
- if (key_ident_len != identifier_len + strlen ("ecdsa-sha2-")) {
- TRACE(("Bad identifier lengths"))
- goto out;
- }
- if (memcmp(&key_ident[strlen ("ecdsa-sha2-")], identifier, identifier_len) != 0) {
- TRACE(("mismatching identifiers"))
- goto out;
- }
- }
- for (curve = dropbear_ecc_curves; *curve; curve++) {
- if (memcmp(identifier, (char*)(*curve)->name, strlen((char*)(*curve)->name)) == 0) {
- break;
- }
- }
- if (!*curve) {
- TRACE(("couldn't match ecc curve"))
- goto out;
- }
- /* string Q */
- q_buf = buf_getstringbuf(buf);
- new_key = buf_get_ecc_raw_pubkey(q_buf, *curve);
- out:
- m_free(key_ident);
- m_free(identifier);
- if (q_buf) {
- buf_free(q_buf);
- q_buf = NULL;
- }
- TRACE(("leave buf_get_ecdsa_pub_key"))
- return new_key;
- }
- ecc_key *buf_get_ecdsa_priv_key(buffer *buf) {
- ecc_key *new_key = NULL;
- TRACE(("enter buf_get_ecdsa_priv_key"))
- new_key = buf_get_ecdsa_pub_key(buf);
- if (!new_key) {
- return NULL;
- }
- if (buf_getmpint(buf, new_key->k) != DROPBEAR_SUCCESS) {
- ecc_free(new_key);
- m_free(new_key);
- return NULL;
- }
- return new_key;
- }
- void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key) {
- struct dropbear_ecc_curve *curve = NULL;
- char key_ident[30];
- curve = curve_for_dp(key->dp);
- snprintf(key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
- buf_putstring(buf, key_ident, strlen(key_ident));
- buf_putstring(buf, curve->name, strlen(curve->name));
- buf_put_ecc_raw_pubkey_string(buf, key);
- }
- void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key) {
- buf_put_ecdsa_pub_key(buf, key);
- buf_putmpint(buf, key->k);
- }
- void buf_put_ecdsa_sign(buffer *buf, const ecc_key *key, const buffer *data_buf) {
- /* Based on libtomcrypt's ecc_sign_hash but without the asn1 */
- int err = DROPBEAR_FAILURE;
- struct dropbear_ecc_curve *curve = NULL;
- hash_state hs;
- unsigned char hash[64];
- void *e = NULL, *p = NULL, *s = NULL, *r;
- char key_ident[30];
- buffer *sigbuf = NULL;
- TRACE(("buf_put_ecdsa_sign"))
- curve = curve_for_dp(key->dp);
- if (ltc_init_multi(&r, &s, &p, &e, NULL) != CRYPT_OK) {
- goto out;
- }
- curve->hash_desc->init(&hs);
- curve->hash_desc->process(&hs, data_buf->data, data_buf->len);
- curve->hash_desc->done(&hs, hash);
- if (ltc_mp.unsigned_read(e, hash, curve->hash_desc->hashsize) != CRYPT_OK) {
- goto out;
- }
- if (ltc_mp.read_radix(p, (char *)key->dp->order, 16) != CRYPT_OK) {
- goto out;
- }
- for (;;) {
- ecc_key R_key; /* ephemeral key */
- if (ecc_make_key_ex(NULL, dropbear_ltc_prng, &R_key, key->dp) != CRYPT_OK) {
- goto out;
- }
- if (ltc_mp.mpdiv(R_key.pubkey.x, p, NULL, r) != CRYPT_OK) {
- goto out;
- }
- if (ltc_mp.compare_d(r, 0) == LTC_MP_EQ) {
- /* try again */
- ecc_free(&R_key);
- continue;
- }
- /* k = 1/k */
- if (ltc_mp.invmod(R_key.k, p, R_key.k) != CRYPT_OK) {
- goto out;
- }
- /* s = xr */
- if (ltc_mp.mulmod(key->k, r, p, s) != CRYPT_OK) {
- goto out;
- }
- /* s = e + xr */
- if (ltc_mp.add(e, s, s) != CRYPT_OK) {
- goto out;
- }
- if (ltc_mp.mpdiv(s, p, NULL, s) != CRYPT_OK) {
- goto out;
- }
- /* s = (e + xr)/k */
- if (ltc_mp.mulmod(s, R_key.k, p, s) != CRYPT_OK) {
- goto out;
- }
- ecc_free(&R_key);
- if (ltc_mp.compare_d(s, 0) != LTC_MP_EQ) {
- break;
- }
- }
- snprintf(key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name);
- buf_putstring(buf, key_ident, strlen(key_ident));
- /* enough for nistp521 */
- sigbuf = buf_new(200);
- buf_putmpint(sigbuf, (mp_int*)r);
- buf_putmpint(sigbuf, (mp_int*)s);
- buf_putbufstring(buf, sigbuf);
- err = DROPBEAR_SUCCESS;
- out:
- if (r && s && p && e) {
- ltc_deinit_multi(r, s, p, e, NULL);
- }
- if (sigbuf) {
- buf_free(sigbuf);
- }
- if (err == DROPBEAR_FAILURE) {
- dropbear_exit("ECC error");
- }
- }
- /* returns values in s and r
- returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
- static int buf_get_ecdsa_verify_params(buffer *buf,
- void *r, void* s) {
- int ret = DROPBEAR_FAILURE;
- unsigned int sig_len;
- unsigned int sig_pos;
- sig_len = buf_getint(buf);
- sig_pos = buf->pos;
- if (buf_getmpint(buf, r) != DROPBEAR_SUCCESS) {
- goto out;
- }
- if (buf_getmpint(buf, s) != DROPBEAR_SUCCESS) {
- goto out;
- }
- if (buf->pos - sig_pos != sig_len) {
- goto out;
- }
- ret = DROPBEAR_SUCCESS;
- out:
- return ret;
- }
- int buf_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf) {
- /* Based on libtomcrypt's ecc_verify_hash but without the asn1 */
- int ret = DROPBEAR_FAILURE;
- hash_state hs;
- struct dropbear_ecc_curve *curve = NULL;
- unsigned char hash[64];
- ecc_point *mG = NULL, *mQ = NULL;
- void *r = NULL, *s = NULL, *v = NULL, *w = NULL, *u1 = NULL, *u2 = NULL,
- *e = NULL, *p = NULL, *m = NULL;
- void *mp = NULL;
- /* verify
- *
- * w = s^-1 mod n
- * u1 = xw
- * u2 = rw
- * X = u1*G + u2*Q
- * v = X_x1 mod n
- * accept if v == r
- */
- TRACE(("buf_ecdsa_verify"))
- curve = curve_for_dp(key->dp);
- mG = ltc_ecc_new_point();
- mQ = ltc_ecc_new_point();
- if (ltc_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL) != CRYPT_OK
- || !mG
- || !mQ) {
- dropbear_exit("ECC error");
- }
- if (buf_get_ecdsa_verify_params(buf, r, s) != DROPBEAR_SUCCESS) {
- goto out;
- }
- curve->hash_desc->init(&hs);
- curve->hash_desc->process(&hs, data_buf->data, data_buf->len);
- curve->hash_desc->done(&hs, hash);
- if (ltc_mp.unsigned_read(e, hash, curve->hash_desc->hashsize) != CRYPT_OK) {
- goto out;
- }
- /* get the order */
- if (ltc_mp.read_radix(p, (char *)key->dp->order, 16) != CRYPT_OK) {
- goto out;
- }
- /* get the modulus */
- if (ltc_mp.read_radix(m, (char *)key->dp->prime, 16) != CRYPT_OK) {
- goto out;
- }
- /* check for zero */
- if (ltc_mp.compare_d(r, 0) == LTC_MP_EQ
- || ltc_mp.compare_d(s, 0) == LTC_MP_EQ
- || ltc_mp.compare(r, p) != LTC_MP_LT
- || ltc_mp.compare(s, p) != LTC_MP_LT) {
- goto out;
- }
- /* w = s^-1 mod n */
- if (ltc_mp.invmod(s, p, w) != CRYPT_OK) {
- goto out;
- }
- /* u1 = ew */
- if (ltc_mp.mulmod(e, w, p, u1) != CRYPT_OK) {
- goto out;
- }
- /* u2 = rw */
- if (ltc_mp.mulmod(r, w, p, u2) != CRYPT_OK) {
- goto out;
- }
- /* find mG and mQ */
- if (ltc_mp.read_radix(mG->x, (char *)key->dp->Gx, 16) != CRYPT_OK) {
- goto out;
- }
- if (ltc_mp.read_radix(mG->y, (char *)key->dp->Gy, 16) != CRYPT_OK) {
- goto out;
- }
- if (ltc_mp.set_int(mG->z, 1) != CRYPT_OK) {
- goto out;
- }
- if (ltc_mp.copy(key->pubkey.x, mQ->x) != CRYPT_OK
- || ltc_mp.copy(key->pubkey.y, mQ->y) != CRYPT_OK
- || ltc_mp.copy(key->pubkey.z, mQ->z) != CRYPT_OK) {
- goto out;
- }
- /* compute u1*mG + u2*mQ = mG */
- if (ltc_mp.ecc_mul2add == NULL) {
- if (ltc_mp.ecc_ptmul(u1, mG, mG, m, 0) != CRYPT_OK) {
- goto out;
- }
- if (ltc_mp.ecc_ptmul(u2, mQ, mQ, m, 0) != CRYPT_OK) {
- goto out;
- }
- /* find the montgomery mp */
- if (ltc_mp.montgomery_setup(m, &mp) != CRYPT_OK) {
- goto out;
- }
- /* add them */
- if (ltc_mp.ecc_ptadd(mQ, mG, mG, m, mp) != CRYPT_OK) {
- goto out;
- }
- /* reduce */
- if (ltc_mp.ecc_map(mG, m, mp) != CRYPT_OK) {
- goto out;
- }
- } else {
- /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
- if (ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m) != CRYPT_OK) {
- goto out;
- }
- }
- /* v = X_x1 mod n */
- if (ltc_mp.mpdiv(mG->x, p, NULL, v) != CRYPT_OK) {
- goto out;
- }
- /* does v == r */
- if (ltc_mp.compare(v, r) == LTC_MP_EQ) {
- ret = DROPBEAR_SUCCESS;
- }
- out:
- ltc_ecc_del_point(mG);
- ltc_ecc_del_point(mQ);
- ltc_deinit_multi(r, s, v, w, u1, u2, p, e, m, NULL);
- if (mp != NULL) {
- ltc_mp.montgomery_deinit(mp);
- }
- return ret;
- }
- #endif /* DROPBEAR_ECDSA */
|