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