summaryrefslogtreecommitdiffstats
path: root/ssh-rsa.c
diff options
context:
space:
mode:
authormarkus@openbsd.org <markus@openbsd.org>2015-12-04 17:41:28 +0100
committerDamien Miller <djm@mindrot.org>2015-12-07 02:38:58 +0100
commit76c9fbbe35aabc1db977fb78e827644345e9442e (patch)
treee7c85e7e1471f1bd00b3a50a58e315c055f40b86 /ssh-rsa.c
parentupstream commit (diff)
downloadopenssh-76c9fbbe35aabc1db977fb78e827644345e9442e.tar.xz
openssh-76c9fbbe35aabc1db977fb78e827644345e9442e.zip
upstream commit
implement SHA2-{256,512} for RSASSA-PKCS1-v1_5 signatures (user and host auth) based on draft-rsa-dsa-sha2-256-03.txt and draft-ssh-ext-info-04.txt; with & ok djm@ Upstream-ID: cf82ce532b2733e5c4b34bb7b7c94835632db309
Diffstat (limited to 'ssh-rsa.c')
-rw-r--r--ssh-rsa.c136
1 files changed, 113 insertions, 23 deletions
diff --git a/ssh-rsa.c b/ssh-rsa.c
index 08090d14e..81dab05b3 100644
--- a/ssh-rsa.c
+++ b/ssh-rsa.c
@@ -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 <markus@openbsd.org>
*
@@ -36,16 +36,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)
@@ -53,16 +97,17 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
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,
@@ -91,7 +136,7 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
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);
@@ -118,8 +163,7 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
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;
@@ -132,13 +176,13 @@ ssh_rsa_verify(const struct sshkey *key,
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;
}
@@ -167,7 +211,6 @@ ssh_rsa_verify(const struct sshkey *key,
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;
@@ -196,6 +239,7 @@ ssh_rsa_verify(const struct sshkey *key,
* 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 }
@@ -209,6 +253,58 @@ static const u_char id_sha1[] = {
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)
@@ -218,16 +314,10 @@ openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen,
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;