Re: Support for "ssh-rsa-sha256" and "ssh-dss-sha256" ?‏

Damien Miller djm at mindrot.org
Fri May 24 22:17:52 EST 2013


On Tue, 14 May 2013, Jeffrey Hawkins wrote:

> Functionality request for supporting Digital Signatures for RSA and DSS
> Public Key Algorithms in alignment with NIST SP800-131A.
> 
> I
> assume this has been asked before, but I could not find in the
> archives.   Support of "ssh-rsa-sha256" and "ssh-dss-sha256" public key
> algorithms for OpenSSH?  I know Suite B Algorithms and x509 SSH
> Extension Algorithms are supported, but not a path some folks (us) want
> to take.  Tectia supports similar algorithms  via their own extensions
> in commercial SSH.

Adding the signature code is easy (see below for a hacky diff - not for
use), it's going through and duplicating all the ssh-rsa code to support
ssh-rsa-sha256 and dealing with the corner cases that it tricky. E.g.
when we find a PEM RSA key on disk, do we load it as a ssh-rsa key, a
ssh-rsa-sha256 key or both? There are more difficulties to do with
certificates too when they are signed with RSA keys - should the
signature be ssh-rsa or ssh-rsa-sha256?

There are probably some other traps that haven't occurred to me yet :(

Please file a bug at https://bugzilla.mindrot.org/ so we can thrash this
out.

-d

Index: compat.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/compat.c,v
retrieving revision 1.81
diff -u -p -r1.81 compat.c
--- compat.c	17 May 2013 00:13:13 -0000	1.81
+++ compat.c	24 May 2013 12:01:33 -0000
@@ -93,6 +93,7 @@ compat_datafellows(const char *version)
 		{ "Sun_SSH_1.0*",	SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
 		{ "OpenSSH_4*",		0 },
 		{ "OpenSSH_5*",		SSH_NEW_OPENSSH|SSH_BUG_DYNAMIC_RPORT},
+		{ "OpenSSH_6.2xxx*",	SSH_NEW_OPENSSH|SSH_NEW_RSA_SHA2},
 		{ "OpenSSH*",		SSH_NEW_OPENSSH },
 		{ "*MindTerm*",		0 },
 		{ "2.1.0*",		SSH_BUG_SIGBLOB|SSH_BUG_HMAC|
Index: compat.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/compat.h,v
retrieving revision 1.43
diff -u -p -r1.43 compat.h
--- compat.h	23 Sep 2011 07:45:05 -0000	1.43
+++ compat.h	24 May 2013 12:01:33 -0000
@@ -59,6 +59,7 @@
 #define SSH_BUG_RFWD_ADDR	0x02000000
 #define SSH_NEW_OPENSSH		0x04000000
 #define SSH_BUG_DYNAMIC_RPORT	0x08000000
+#define SSH_NEW_RSA_SHA2	0x10000000
 
 void     enable_compat13(void);
 void     enable_compat20(void);
Index: ssh-rsa.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/ssh-rsa.c,v
retrieving revision 1.46
diff -u -p -r1.46 ssh-rsa.c
--- ssh-rsa.c	17 May 2013 00:13:14 -0000	1.46
+++ ssh-rsa.c	24 May 2013 12:01:33 -0000
@@ -32,7 +32,7 @@
 
 static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *);
 
-/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
+/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 or SHA256 */
 int
 ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp,
     const u_char *data, u_int datalen)
@@ -44,14 +44,28 @@ ssh_rsa_sign(const Key *key, u_char **si
 	int ok, nid;
 	Buffer b;
 
-	if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA &&
-	    key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) {
-		error("ssh_rsa_sign: no RSA key");
+	if (key == NULL || key->rsa == NULL) {
+		error("%s: no RSA key", __func__);
+		return -1;
+	}
+	nid = NID_sha1;
+	if ((datafellows & SSH_BUG_RSASIGMD5) != 0)
+		nid = NID_md5;
+	else if ((datafellows & SSH_NEW_RSA_SHA2) != 0) {
+		nid = NID_sha256;
+	}
+	switch (key->type) {
+	case KEY_RSA:
+	case KEY_RSA_CERT:
+	case KEY_RSA_CERT_V00:
+		break;
+	default:
+		error("%s: wrong type key %s (%d)",
+		    __func__, key_type(key), key->type);
 		return -1;
 	}
-	nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
 	if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
-		error("ssh_rsa_sign: EVP_get_digestbynid %d failed", nid);
+		error("%s: EVP_get_digestbynid %d failed", __func__, nid);
 		return -1;
 	}
 	EVP_DigestInit(&md, evp_md);
@@ -67,7 +81,7 @@ ssh_rsa_sign(const Key *key, u_char **si
 	if (ok != 1) {
 		int ecode = ERR_get_error();
 
-		error("ssh_rsa_sign: RSA_sign failed: %s",
+		error("%s: RSA_sign failed: %s", __func__,
 		    ERR_error_string(ecode, NULL));
 		free(sig);
 		return -1;
@@ -78,7 +92,7 @@ ssh_rsa_sign(const Key *key, u_char **si
 		memmove(sig + diff, sig, len);
 		memset(sig, 0, diff);
 	} else if (len > slen) {
-		error("ssh_rsa_sign: slen %u slen2 %u", slen, len);
+		error("%s: slen %u slen2 %u", __func__, slen, len);
 		free(sig);
 		return -1;
 	}
@@ -112,21 +126,37 @@ ssh_rsa_verify(const Key *key, const u_c
 	u_int len, dlen, modlen;
 	int rlen, ret, nid;
 
-	if (key == NULL || key->rsa == NULL || (key->type != KEY_RSA &&
-	    key->type != KEY_RSA_CERT && key->type != KEY_RSA_CERT_V00)) {
-		error("ssh_rsa_verify: no RSA key");
+	if (key == NULL || key->rsa == NULL) {
+		error("%s: no RSA key", __func__);
+		return -1;
+	}
+	nid = NID_sha1;
+	if ((datafellows & SSH_BUG_RSASIGMD5) != 0)
+		nid = NID_md5;
+	else if ((datafellows & SSH_NEW_RSA_SHA2) != 0) {
+		nid = NID_sha256;
+	}
+	switch (key->type) {
+	case KEY_RSA:
+	case KEY_RSA_CERT:
+	case KEY_RSA_CERT_V00:
+		break;
+	default:
+		error("%s: wrong type key %s (%d)",
+		    __func__, key_type(key), key->type);
 		return -1;
 	}
 	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
-		error("ssh_rsa_verify: RSA modulus too small: %d < minimum %d bits",
-		    BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE);
+		error("%s: RSA modulus too small: %d < minimum %d bits",
+		    __func__, BN_num_bits(key->rsa->n),
+		    SSH_RSA_MINIMUM_MODULUS_SIZE);
 		return -1;
 	}
 	buffer_init(&b);
 	buffer_append(&b, signature, signaturelen);
 	ktype = buffer_get_cstring(&b, NULL);
 	if (strcmp("ssh-rsa", ktype) != 0) {
-		error("ssh_rsa_verify: cannot handle type %s", ktype);
+		error("%s: cannot handle type %s", __func__, ktype);
 		buffer_free(&b);
 		free(ktype);
 		return -1;
@@ -136,28 +166,27 @@ ssh_rsa_verify(const Key *key, const u_c
 	rlen = buffer_len(&b);
 	buffer_free(&b);
 	if (rlen != 0) {
-		error("ssh_rsa_verify: remaining bytes in signature %d", rlen);
+		error("%s: remaining bytes in signature %d", __func__, rlen);
 		free(sigblob);
 		return -1;
 	}
 	/* RSA_verify expects a signature of RSA_size */
 	modlen = RSA_size(key->rsa);
 	if (len > modlen) {
-		error("ssh_rsa_verify: len %u > modlen %u", len, modlen);
+		error("%s: len %u > modlen %u", __func__, len, modlen);
 		free(sigblob);
 		return -1;
 	} else if (len < modlen) {
 		u_int diff = modlen - len;
-		debug("ssh_rsa_verify: add padding: modlen %u > len %u",
-		    modlen, len);
+		debug("%s: add padding: modlen %u > len %u",
+		    __func__, modlen, len);
 		sigblob = xrealloc(sigblob, 1, modlen);
 		memmove(sigblob + diff, sigblob, len);
 		memset(sigblob, 0, diff);
 		len = modlen;
 	}
-	nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1;
 	if ((evp_md = EVP_get_digestbynid(nid)) == NULL) {
-		error("ssh_rsa_verify: EVP_get_digestbynid %d failed", nid);
+		error("%s: EVP_get_digestbynid %d failed", __func__, nid);
 		free(sigblob);
 		return -1;
 	}
@@ -169,7 +198,7 @@ ssh_rsa_verify(const Key *key, const u_c
 	memset(digest, 'd', sizeof(digest));
 	memset(sigblob, 's', len);
 	free(sigblob);
-	debug("ssh_rsa_verify: signature %scorrect", (ret==0) ? "in" : "");
+	debug("%s: signature %scorrect", __func__, (ret==0) ? "in" : "");
 	return ret;
 }
 
@@ -196,12 +225,27 @@ static const u_char id_sha1[] = {
  */
 static const u_char id_md5[] = {
 	0x30, 0x20, /* type Sequence, length 0x20 (32) */
-	0x30, 0x0c, /* type Sequence, length 0x09 */
-	0x06, 0x08, /* type OID, length 0x05 */
+	0x30, 0x0c, /* type Sequence, length 0x0c (12) */
+	0x06, 0x08, /* type OID, length 0x08 */
 	0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* id-md5 */
 	0x05, 0x00, /* NULL */
 	0x04, 0x10  /* Octet string, length 0x10 (16), followed by md5 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 */
+};
+
 
 static int
 openssh_RSA_verify(int type, u_char *hash, u_int hashlen,
@@ -218,6 +262,11 @@ openssh_RSA_verify(int type, u_char *has
 		oid = id_sha1;
 		oidlen = sizeof(id_sha1);
 		hlen = 20;
+		break;
+	case NID_sha256:
+		oid = id_sha256;
+		oidlen = sizeof(id_sha256);
+		hlen = 32;
 		break;
 	case NID_md5:
 		oid = id_md5;
Index: version.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/version.h,v
retrieving revision 1.66
diff -u -p -r1.66 version.h
--- version.h	10 Feb 2013 21:19:34 -0000	1.66
+++ version.h	24 May 2013 12:01:33 -0000
@@ -1,3 +1,3 @@
 /* $OpenBSD: version.h,v 1.66 2013/02/10 21:19:34 markus Exp $ */
 
-#define SSH_VERSION	"OpenSSH_6.2"
+#define SSH_VERSION	"OpenSSH_6.2xxx"


More information about the openssh-unix-dev mailing list