diff options
Diffstat (limited to 'ssh-rsa.c')
-rw-r--r-- | ssh-rsa.c | 136 |
1 files changed, 113 insertions, 23 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-rsa.c,v 1.54 2015/09/09 00:52:44 djm Exp $ */ | 1 | /* $OpenBSD: ssh-rsa.c,v 1.55 2015/12/04 16:41:28 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> | 3 | * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> |
4 | * | 4 | * |
@@ -36,16 +36,60 @@ | |||
36 | 36 | ||
37 | static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); | 37 | static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); |
38 | 38 | ||
39 | static const char * | ||
40 | rsa_hash_alg_ident(int hash_alg) | ||
41 | { | ||
42 | switch (hash_alg) { | ||
43 | case SSH_DIGEST_SHA1: | ||
44 | return "ssh-rsa"; | ||
45 | case SSH_DIGEST_SHA256: | ||
46 | return "rsa-sha2-256"; | ||
47 | case SSH_DIGEST_SHA512: | ||
48 | return "rsa-sha2-512"; | ||
49 | } | ||
50 | return NULL; | ||
51 | } | ||
52 | |||
53 | static int | ||
54 | rsa_hash_alg_from_ident(const char *ident) | ||
55 | { | ||
56 | if (ident == NULL || strlen(ident) == 0) | ||
57 | return SSH_DIGEST_SHA1; | ||
58 | if (strcmp(ident, "ssh-rsa") == 0) | ||
59 | return SSH_DIGEST_SHA1; | ||
60 | if (strcmp(ident, "rsa-sha2-256") == 0) | ||
61 | return SSH_DIGEST_SHA256; | ||
62 | if (strcmp(ident, "rsa-sha2-512") == 0) | ||
63 | return SSH_DIGEST_SHA512; | ||
64 | if (strncmp(ident, "ssh-rsa-cert", strlen("ssh-rsa-cert")) == 0) | ||
65 | return SSH_DIGEST_SHA1; | ||
66 | return -1; | ||
67 | } | ||
68 | |||
69 | static int | ||
70 | rsa_hash_alg_nid(int type) | ||
71 | { | ||
72 | switch (type) { | ||
73 | case SSH_DIGEST_SHA1: | ||
74 | return NID_sha1; | ||
75 | case SSH_DIGEST_SHA256: | ||
76 | return NID_sha256; | ||
77 | case SSH_DIGEST_SHA512: | ||
78 | return NID_sha512; | ||
79 | default: | ||
80 | return -1; | ||
81 | } | ||
82 | } | ||
83 | |||
39 | /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ | 84 | /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ |
40 | int | 85 | int |
41 | ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, | 86 | ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
42 | const u_char *data, size_t datalen, u_int compat) | 87 | const u_char *data, size_t datalen, const char *alg_ident) |
43 | { | 88 | { |
44 | int hash_alg; | ||
45 | u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; | 89 | u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; |
46 | size_t slen; | 90 | size_t slen; |
47 | u_int dlen, len; | 91 | u_int dlen, len; |
48 | int nid, ret = SSH_ERR_INTERNAL_ERROR; | 92 | int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR; |
49 | struct sshbuf *b = NULL; | 93 | struct sshbuf *b = NULL; |
50 | 94 | ||
51 | if (lenp != NULL) | 95 | if (lenp != NULL) |
@@ -53,16 +97,17 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, | |||
53 | if (sigp != NULL) | 97 | if (sigp != NULL) |
54 | *sigp = NULL; | 98 | *sigp = NULL; |
55 | 99 | ||
56 | if (key == NULL || key->rsa == NULL || | 100 | hash_alg = rsa_hash_alg_from_ident(alg_ident); |
57 | sshkey_type_plain(key->type) != KEY_RSA) | 101 | if (key == NULL || key->rsa == NULL || hash_alg == -1 || |
102 | sshkey_type_plain(key->type) != KEY_RSA || | ||
103 | BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) | ||
58 | return SSH_ERR_INVALID_ARGUMENT; | 104 | return SSH_ERR_INVALID_ARGUMENT; |
59 | slen = RSA_size(key->rsa); | 105 | slen = RSA_size(key->rsa); |
60 | if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) | 106 | if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) |
61 | return SSH_ERR_INVALID_ARGUMENT; | 107 | return SSH_ERR_INVALID_ARGUMENT; |
62 | 108 | ||
63 | /* hash the data */ | 109 | /* hash the data */ |
64 | hash_alg = SSH_DIGEST_SHA1; | 110 | nid = rsa_hash_alg_nid(hash_alg); |
65 | nid = NID_sha1; | ||
66 | if ((dlen = ssh_digest_bytes(hash_alg)) == 0) | 111 | if ((dlen = ssh_digest_bytes(hash_alg)) == 0) |
67 | return SSH_ERR_INTERNAL_ERROR; | 112 | return SSH_ERR_INTERNAL_ERROR; |
68 | if ((ret = ssh_digest_memory(hash_alg, data, datalen, | 113 | 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, | |||
91 | ret = SSH_ERR_ALLOC_FAIL; | 136 | ret = SSH_ERR_ALLOC_FAIL; |
92 | goto out; | 137 | goto out; |
93 | } | 138 | } |
94 | if ((ret = sshbuf_put_cstring(b, "ssh-rsa")) != 0 || | 139 | if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 || |
95 | (ret = sshbuf_put_string(b, sig, slen)) != 0) | 140 | (ret = sshbuf_put_string(b, sig, slen)) != 0) |
96 | goto out; | 141 | goto out; |
97 | len = sshbuf_len(b); | 142 | len = sshbuf_len(b); |
@@ -118,8 +163,7 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, | |||
118 | 163 | ||
119 | int | 164 | int |
120 | ssh_rsa_verify(const struct sshkey *key, | 165 | ssh_rsa_verify(const struct sshkey *key, |
121 | const u_char *signature, size_t signaturelen, | 166 | const u_char *sig, size_t siglen, const u_char *data, size_t datalen) |
122 | const u_char *data, size_t datalen, u_int compat) | ||
123 | { | 167 | { |
124 | char *ktype = NULL; | 168 | char *ktype = NULL; |
125 | int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; | 169 | int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; |
@@ -132,13 +176,13 @@ ssh_rsa_verify(const struct sshkey *key, | |||
132 | BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) | 176 | BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) |
133 | return SSH_ERR_INVALID_ARGUMENT; | 177 | return SSH_ERR_INVALID_ARGUMENT; |
134 | 178 | ||
135 | if ((b = sshbuf_from(signature, signaturelen)) == NULL) | 179 | if ((b = sshbuf_from(sig, siglen)) == NULL) |
136 | return SSH_ERR_ALLOC_FAIL; | 180 | return SSH_ERR_ALLOC_FAIL; |
137 | if (sshbuf_get_cstring(b, &ktype, NULL) != 0) { | 181 | if (sshbuf_get_cstring(b, &ktype, NULL) != 0) { |
138 | ret = SSH_ERR_INVALID_FORMAT; | 182 | ret = SSH_ERR_INVALID_FORMAT; |
139 | goto out; | 183 | goto out; |
140 | } | 184 | } |
141 | if (strcmp("ssh-rsa", ktype) != 0) { | 185 | if ((hash_alg = rsa_hash_alg_from_ident(ktype)) == -1) { |
142 | ret = SSH_ERR_KEY_TYPE_MISMATCH; | 186 | ret = SSH_ERR_KEY_TYPE_MISMATCH; |
143 | goto out; | 187 | goto out; |
144 | } | 188 | } |
@@ -167,7 +211,6 @@ ssh_rsa_verify(const struct sshkey *key, | |||
167 | explicit_bzero(sigblob, diff); | 211 | explicit_bzero(sigblob, diff); |
168 | len = modlen; | 212 | len = modlen; |
169 | } | 213 | } |
170 | hash_alg = SSH_DIGEST_SHA1; | ||
171 | if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { | 214 | if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { |
172 | ret = SSH_ERR_INTERNAL_ERROR; | 215 | ret = SSH_ERR_INTERNAL_ERROR; |
173 | goto out; | 216 | goto out; |
@@ -196,6 +239,7 @@ ssh_rsa_verify(const struct sshkey *key, | |||
196 | * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ | 239 | * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ |
197 | * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn | 240 | * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn |
198 | */ | 241 | */ |
242 | |||
199 | /* | 243 | /* |
200 | * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) | 244 | * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) |
201 | * oiw(14) secsig(3) algorithms(2) 26 } | 245 | * oiw(14) secsig(3) algorithms(2) 26 } |
@@ -209,6 +253,58 @@ static const u_char id_sha1[] = { | |||
209 | 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ | 253 | 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ |
210 | }; | 254 | }; |
211 | 255 | ||
256 | /* | ||
257 | * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html | ||
258 | * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) | ||
259 | * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) | ||
260 | * id-sha256(1) } | ||
261 | */ | ||
262 | static const u_char id_sha256[] = { | ||
263 | 0x30, 0x31, /* type Sequence, length 0x31 (49) */ | ||
264 | 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ | ||
265 | 0x06, 0x09, /* type OID, length 0x09 */ | ||
266 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */ | ||
267 | 0x05, 0x00, /* NULL */ | ||
268 | 0x04, 0x20 /* Octet string, length 0x20 (32), followed by sha256 hash */ | ||
269 | }; | ||
270 | |||
271 | /* | ||
272 | * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html | ||
273 | * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) | ||
274 | * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) | ||
275 | * id-sha256(3) } | ||
276 | */ | ||
277 | static const u_char id_sha512[] = { | ||
278 | 0x30, 0x51, /* type Sequence, length 0x51 (81) */ | ||
279 | 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ | ||
280 | 0x06, 0x09, /* type OID, length 0x09 */ | ||
281 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */ | ||
282 | 0x05, 0x00, /* NULL */ | ||
283 | 0x04, 0x40 /* Octet string, length 0x40 (64), followed by sha512 hash */ | ||
284 | }; | ||
285 | |||
286 | static int | ||
287 | rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp) | ||
288 | { | ||
289 | switch (hash_alg) { | ||
290 | case SSH_DIGEST_SHA1: | ||
291 | *oidp = id_sha1; | ||
292 | *oidlenp = sizeof(id_sha1); | ||
293 | break; | ||
294 | case SSH_DIGEST_SHA256: | ||
295 | *oidp = id_sha256; | ||
296 | *oidlenp = sizeof(id_sha256); | ||
297 | break; | ||
298 | case SSH_DIGEST_SHA512: | ||
299 | *oidp = id_sha512; | ||
300 | *oidlenp = sizeof(id_sha512); | ||
301 | break; | ||
302 | default: | ||
303 | return SSH_ERR_INVALID_ARGUMENT; | ||
304 | } | ||
305 | return 0; | ||
306 | } | ||
307 | |||
212 | static int | 308 | static int |
213 | openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, | 309 | openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, |
214 | u_char *sigbuf, size_t siglen, RSA *rsa) | 310 | u_char *sigbuf, size_t siglen, RSA *rsa) |
@@ -218,16 +314,10 @@ openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, | |||
218 | const u_char *oid = NULL; | 314 | const u_char *oid = NULL; |
219 | u_char *decrypted = NULL; | 315 | u_char *decrypted = NULL; |
220 | 316 | ||
317 | if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0) | ||
318 | return ret; | ||
221 | ret = SSH_ERR_INTERNAL_ERROR; | 319 | ret = SSH_ERR_INTERNAL_ERROR; |
222 | switch (hash_alg) { | 320 | hlen = ssh_digest_bytes(hash_alg); |
223 | case SSH_DIGEST_SHA1: | ||
224 | oid = id_sha1; | ||
225 | oidlen = sizeof(id_sha1); | ||
226 | hlen = 20; | ||
227 | break; | ||
228 | default: | ||
229 | goto done; | ||
230 | } | ||
231 | if (hashlen != hlen) { | 321 | if (hashlen != hlen) { |
232 | ret = SSH_ERR_INVALID_ARGUMENT; | 322 | ret = SSH_ERR_INVALID_ARGUMENT; |
233 | goto done; | 323 | goto done; |