=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/ssh-rsa.c,v retrieving revision 1.54 retrieving revision 1.55 diff -u -r1.54 -r1.55 --- src/usr.bin/ssh/ssh-rsa.c 2015/09/09 00:52:44 1.54 +++ src/usr.bin/ssh/ssh-rsa.c 2015/12/04 16:41:28 1.55 @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-rsa.c,v 1.54 2015/09/09 00:52:44 djm Exp $ */ +/* $OpenBSD: ssh-rsa.c,v 1.55 2015/12/04 16:41:28 markus Exp $ */ /* * Copyright (c) 2000, 2003 Markus Friedl * @@ -31,16 +31,60 @@ static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); +static const char * +rsa_hash_alg_ident(int hash_alg) +{ + switch (hash_alg) { + case SSH_DIGEST_SHA1: + return "ssh-rsa"; + case SSH_DIGEST_SHA256: + return "rsa-sha2-256"; + case SSH_DIGEST_SHA512: + return "rsa-sha2-512"; + } + return NULL; +} + +static int +rsa_hash_alg_from_ident(const char *ident) +{ + if (ident == NULL || strlen(ident) == 0) + return SSH_DIGEST_SHA1; + if (strcmp(ident, "ssh-rsa") == 0) + return SSH_DIGEST_SHA1; + if (strcmp(ident, "rsa-sha2-256") == 0) + return SSH_DIGEST_SHA256; + if (strcmp(ident, "rsa-sha2-512") == 0) + return SSH_DIGEST_SHA512; + if (strncmp(ident, "ssh-rsa-cert", strlen("ssh-rsa-cert")) == 0) + return SSH_DIGEST_SHA1; + return -1; +} + +static int +rsa_hash_alg_nid(int type) +{ + switch (type) { + case SSH_DIGEST_SHA1: + return NID_sha1; + case SSH_DIGEST_SHA256: + return NID_sha256; + case SSH_DIGEST_SHA512: + return NID_sha512; + default: + return -1; + } +} + /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ int ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, - const u_char *data, size_t datalen, u_int compat) + const u_char *data, size_t datalen, const char *alg_ident) { - int hash_alg; u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; size_t slen; u_int dlen, len; - int nid, ret = SSH_ERR_INTERNAL_ERROR; + int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR; struct sshbuf *b = NULL; if (lenp != NULL) @@ -48,16 +92,17 @@ if (sigp != NULL) *sigp = NULL; - if (key == NULL || key->rsa == NULL || - sshkey_type_plain(key->type) != KEY_RSA) + hash_alg = rsa_hash_alg_from_ident(alg_ident); + if (key == NULL || key->rsa == NULL || hash_alg == -1 || + sshkey_type_plain(key->type) != KEY_RSA || + BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) return SSH_ERR_INVALID_ARGUMENT; slen = RSA_size(key->rsa); if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) return SSH_ERR_INVALID_ARGUMENT; /* hash the data */ - hash_alg = SSH_DIGEST_SHA1; - nid = NID_sha1; + nid = rsa_hash_alg_nid(hash_alg); if ((dlen = ssh_digest_bytes(hash_alg)) == 0) return SSH_ERR_INTERNAL_ERROR; if ((ret = ssh_digest_memory(hash_alg, data, datalen, @@ -86,7 +131,7 @@ ret = SSH_ERR_ALLOC_FAIL; goto out; } - if ((ret = sshbuf_put_cstring(b, "ssh-rsa")) != 0 || + if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 || (ret = sshbuf_put_string(b, sig, slen)) != 0) goto out; len = sshbuf_len(b); @@ -113,8 +158,7 @@ int ssh_rsa_verify(const struct sshkey *key, - const u_char *signature, size_t signaturelen, - const u_char *data, size_t datalen, u_int compat) + const u_char *sig, size_t siglen, const u_char *data, size_t datalen) { char *ktype = NULL; int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; @@ -127,13 +171,13 @@ BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) return SSH_ERR_INVALID_ARGUMENT; - if ((b = sshbuf_from(signature, signaturelen)) == NULL) + if ((b = sshbuf_from(sig, siglen)) == NULL) return SSH_ERR_ALLOC_FAIL; if (sshbuf_get_cstring(b, &ktype, NULL) != 0) { ret = SSH_ERR_INVALID_FORMAT; goto out; } - if (strcmp("ssh-rsa", ktype) != 0) { + if ((hash_alg = rsa_hash_alg_from_ident(ktype)) == -1) { ret = SSH_ERR_KEY_TYPE_MISMATCH; goto out; } @@ -162,7 +206,6 @@ explicit_bzero(sigblob, diff); len = modlen; } - hash_alg = SSH_DIGEST_SHA1; if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { ret = SSH_ERR_INTERNAL_ERROR; goto out; @@ -191,6 +234,7 @@ * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn */ + /* * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) * oiw(14) secsig(3) algorithms(2) 26 } @@ -204,7 +248,59 @@ 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ }; +/* + * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html + * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) + * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) + * id-sha256(1) } + */ +static const u_char id_sha256[] = { + 0x30, 0x31, /* type Sequence, length 0x31 (49) */ + 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ + 0x06, 0x09, /* type OID, length 0x09 */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */ + 0x05, 0x00, /* NULL */ + 0x04, 0x20 /* Octet string, length 0x20 (32), followed by sha256 hash */ +}; + +/* + * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html + * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) + * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) + * id-sha256(3) } + */ +static const u_char id_sha512[] = { + 0x30, 0x51, /* type Sequence, length 0x51 (81) */ + 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ + 0x06, 0x09, /* type OID, length 0x09 */ + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */ + 0x05, 0x00, /* NULL */ + 0x04, 0x40 /* Octet string, length 0x40 (64), followed by sha512 hash */ +}; + static int +rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp) +{ + switch (hash_alg) { + case SSH_DIGEST_SHA1: + *oidp = id_sha1; + *oidlenp = sizeof(id_sha1); + break; + case SSH_DIGEST_SHA256: + *oidp = id_sha256; + *oidlenp = sizeof(id_sha256); + break; + case SSH_DIGEST_SHA512: + *oidp = id_sha512; + *oidlenp = sizeof(id_sha512); + break; + default: + return SSH_ERR_INVALID_ARGUMENT; + } + return 0; +} + +static int openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, u_char *sigbuf, size_t siglen, RSA *rsa) { @@ -213,16 +309,10 @@ const u_char *oid = NULL; u_char *decrypted = NULL; + if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0) + return ret; ret = SSH_ERR_INTERNAL_ERROR; - switch (hash_alg) { - case SSH_DIGEST_SHA1: - oid = id_sha1; - oidlen = sizeof(id_sha1); - hlen = 20; - break; - default: - goto done; - } + hlen = ssh_digest_bytes(hash_alg); if (hashlen != hlen) { ret = SSH_ERR_INVALID_ARGUMENT; goto done;