Merge openssh 7.5p1

BUG: 35443510
Change-Id: I2558fb80234e145c13ccb7a51859f2a5fd2e0324
diff --git a/ssh-rsa.c b/ssh-rsa.c
index cdc18a4..cde05df 100644
--- a/ssh-rsa.c
+++ b/ssh-rsa.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-rsa.c,v 1.53 2015/06/15 01:32:50 djm Exp $ */
+/* $OpenBSD: ssh-rsa.c,v 1.60 2016/09/12 23:39:34 djm Exp $ */
 /*
  * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
  *
@@ -36,16 +36,57 @@
 
 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 (strcmp(ident, "ssh-rsa") == 0 ||
+	    strcmp(ident, "ssh-rsa-cert-v01@openssh.com") == 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;
+	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 +94,20 @@
 	if (sigp != NULL)
 		*sigp = NULL;
 
-	if (key == NULL || key->rsa == NULL ||
-	    sshkey_type_plain(key->type) != KEY_RSA)
+	if (alg_ident == NULL || strlen(alg_ident) == 0)
+		hash_alg = SSH_DIGEST_SHA1;
+	else
+		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 @@
 		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);
@@ -111,15 +156,13 @@
 		explicit_bzero(sig, slen);
 		free(sig);
 	}
-	if (b != NULL)
-		sshbuf_free(b);
+	sshbuf_free(b);
 	return ret;
 }
 
 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;
@@ -129,16 +172,17 @@
 
 	if (key == NULL || key->rsa == NULL ||
 	    sshkey_type_plain(key->type) != KEY_RSA ||
-	    BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
+	    BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE ||
+	    sig == NULL || siglen == 0)
 		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 @@
 		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;
@@ -183,10 +226,8 @@
 		explicit_bzero(sigblob, len);
 		free(sigblob);
 	}
-	if (ktype != NULL)
-		free(ktype);
-	if (b != NULL)
-		sshbuf_free(b);
+	free(ktype);
+	sshbuf_free(b);
 	explicit_bzero(digest, sizeof(digest));
 	return ret;
 }
@@ -196,6 +237,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 }
@@ -209,25 +251,71 @@
 	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)
 {
-	size_t ret, rsasize = 0, oidlen = 0, hlen = 0;
-	int len, oidmatch, hashmatch;
+	size_t rsasize = 0, oidlen = 0, hlen = 0;
+	int ret, len, oidmatch, hashmatch;
 	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;