File: | src/usr.bin/ssh/ssh/../ssh-rsa.c |
Warning: | line 636, column 2 Value stored to 'ret' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ssh-rsa.c,v 1.79 2023/03/05 05:34:09 dtucker Exp $ */ |
2 | /* |
3 | * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> |
4 | * |
5 | * Permission to use, copy, modify, and distribute this software for any |
6 | * purpose with or without fee is hereby granted, provided that the above |
7 | * copyright notice and this permission notice appear in all copies. |
8 | * |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | */ |
17 | |
18 | #include <sys/types.h> |
19 | |
20 | #include <openssl/evp.h> |
21 | #include <openssl/err.h> |
22 | |
23 | #include <string.h> |
24 | |
25 | #include "sshbuf.h" |
26 | #include "ssherr.h" |
27 | #define SSHKEY_INTERNAL |
28 | #include "sshkey.h" |
29 | #include "digest.h" |
30 | #include "log.h" |
31 | |
32 | static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); |
33 | |
34 | static u_int |
35 | ssh_rsa_size(const struct sshkey *key) |
36 | { |
37 | const BIGNUM *rsa_n; |
38 | |
39 | if (key->rsa == NULL((void *)0)) |
40 | return 0; |
41 | RSA_get0_key(key->rsa, &rsa_n, NULL((void *)0), NULL((void *)0)); |
42 | return BN_num_bits(rsa_n); |
43 | } |
44 | |
45 | static int |
46 | ssh_rsa_alloc(struct sshkey *k) |
47 | { |
48 | if ((k->rsa = RSA_new()) == NULL((void *)0)) |
49 | return SSH_ERR_ALLOC_FAIL-2; |
50 | return 0; |
51 | } |
52 | |
53 | static void |
54 | ssh_rsa_cleanup(struct sshkey *k) |
55 | { |
56 | RSA_free(k->rsa); |
57 | k->rsa = NULL((void *)0); |
58 | } |
59 | |
60 | static int |
61 | ssh_rsa_equal(const struct sshkey *a, const struct sshkey *b) |
62 | { |
63 | const BIGNUM *rsa_e_a, *rsa_n_a; |
64 | const BIGNUM *rsa_e_b, *rsa_n_b; |
65 | |
66 | if (a->rsa == NULL((void *)0) || b->rsa == NULL((void *)0)) |
67 | return 0; |
68 | RSA_get0_key(a->rsa, &rsa_n_a, &rsa_e_a, NULL((void *)0)); |
69 | RSA_get0_key(b->rsa, &rsa_n_b, &rsa_e_b, NULL((void *)0)); |
70 | if (rsa_e_a == NULL((void *)0) || rsa_e_b == NULL((void *)0)) |
71 | return 0; |
72 | if (rsa_n_a == NULL((void *)0) || rsa_n_b == NULL((void *)0)) |
73 | return 0; |
74 | if (BN_cmp(rsa_e_a, rsa_e_b) != 0) |
75 | return 0; |
76 | if (BN_cmp(rsa_n_a, rsa_n_b) != 0) |
77 | return 0; |
78 | return 1; |
79 | } |
80 | |
81 | static int |
82 | ssh_rsa_serialize_public(const struct sshkey *key, struct sshbuf *b, |
83 | enum sshkey_serialize_rep opts) |
84 | { |
85 | int r; |
86 | const BIGNUM *rsa_n, *rsa_e; |
87 | |
88 | if (key->rsa == NULL((void *)0)) |
89 | return SSH_ERR_INVALID_ARGUMENT-10; |
90 | RSA_get0_key(key->rsa, &rsa_n, &rsa_e, NULL((void *)0)); |
91 | if ((r = sshbuf_put_bignum2(b, rsa_e)) != 0 || |
92 | (r = sshbuf_put_bignum2(b, rsa_n)) != 0) |
93 | return r; |
94 | |
95 | return 0; |
96 | } |
97 | |
98 | static int |
99 | ssh_rsa_serialize_private(const struct sshkey *key, struct sshbuf *b, |
100 | enum sshkey_serialize_rep opts) |
101 | { |
102 | int r; |
103 | const BIGNUM *rsa_n, *rsa_e, *rsa_d, *rsa_iqmp, *rsa_p, *rsa_q; |
104 | |
105 | RSA_get0_key(key->rsa, &rsa_n, &rsa_e, &rsa_d); |
106 | RSA_get0_factors(key->rsa, &rsa_p, &rsa_q); |
107 | RSA_get0_crt_params(key->rsa, NULL((void *)0), NULL((void *)0), &rsa_iqmp); |
108 | |
109 | if (!sshkey_is_cert(key)) { |
110 | /* Note: can't reuse ssh_rsa_serialize_public: e, n vs. n, e */ |
111 | if ((r = sshbuf_put_bignum2(b, rsa_n)) != 0 || |
112 | (r = sshbuf_put_bignum2(b, rsa_e)) != 0) |
113 | return r; |
114 | } |
115 | if ((r = sshbuf_put_bignum2(b, rsa_d)) != 0 || |
116 | (r = sshbuf_put_bignum2(b, rsa_iqmp)) != 0 || |
117 | (r = sshbuf_put_bignum2(b, rsa_p)) != 0 || |
118 | (r = sshbuf_put_bignum2(b, rsa_q)) != 0) |
119 | return r; |
120 | |
121 | return 0; |
122 | } |
123 | |
124 | static int |
125 | ssh_rsa_generate(struct sshkey *k, int bits) |
126 | { |
127 | RSA *private = NULL((void *)0); |
128 | BIGNUM *f4 = NULL((void *)0); |
129 | int ret = SSH_ERR_INTERNAL_ERROR-1; |
130 | |
131 | if (bits < SSH_RSA_MINIMUM_MODULUS_SIZE1024 || |
132 | bits > SSHBUF_MAX_BIGNUM(16384 / 8) * 8) |
133 | return SSH_ERR_KEY_LENGTH-56; |
134 | if ((private = RSA_new()) == NULL((void *)0) || (f4 = BN_new()) == NULL((void *)0)) { |
135 | ret = SSH_ERR_ALLOC_FAIL-2; |
136 | goto out; |
137 | } |
138 | if (!BN_set_word(f4, RSA_F40x10001L) || |
139 | !RSA_generate_key_ex(private, bits, f4, NULL((void *)0))) { |
140 | ret = SSH_ERR_LIBCRYPTO_ERROR-22; |
141 | goto out; |
142 | } |
143 | k->rsa = private; |
144 | private = NULL((void *)0); |
145 | ret = 0; |
146 | out: |
147 | RSA_free(private); |
148 | BN_free(f4); |
149 | return ret; |
150 | } |
151 | |
152 | static int |
153 | ssh_rsa_copy_public(const struct sshkey *from, struct sshkey *to) |
154 | { |
155 | const BIGNUM *rsa_n, *rsa_e; |
156 | BIGNUM *rsa_n_dup = NULL((void *)0), *rsa_e_dup = NULL((void *)0); |
157 | int r = SSH_ERR_INTERNAL_ERROR-1; |
158 | |
159 | RSA_get0_key(from->rsa, &rsa_n, &rsa_e, NULL((void *)0)); |
160 | if ((rsa_n_dup = BN_dup(rsa_n)) == NULL((void *)0) || |
161 | (rsa_e_dup = BN_dup(rsa_e)) == NULL((void *)0)) { |
162 | r = SSH_ERR_ALLOC_FAIL-2; |
163 | goto out; |
164 | } |
165 | if (!RSA_set0_key(to->rsa, rsa_n_dup, rsa_e_dup, NULL((void *)0))) { |
166 | r = SSH_ERR_LIBCRYPTO_ERROR-22; |
167 | goto out; |
168 | } |
169 | rsa_n_dup = rsa_e_dup = NULL((void *)0); /* transferred */ |
170 | /* success */ |
171 | r = 0; |
172 | out: |
173 | BN_clear_free(rsa_n_dup); |
174 | BN_clear_free(rsa_e_dup); |
175 | return r; |
176 | } |
177 | |
178 | static int |
179 | ssh_rsa_deserialize_public(const char *ktype, struct sshbuf *b, |
180 | struct sshkey *key) |
181 | { |
182 | int ret = SSH_ERR_INTERNAL_ERROR-1; |
183 | BIGNUM *rsa_n = NULL((void *)0), *rsa_e = NULL((void *)0); |
184 | |
185 | if (sshbuf_get_bignum2(b, &rsa_e) != 0 || |
186 | sshbuf_get_bignum2(b, &rsa_n) != 0) { |
187 | ret = SSH_ERR_INVALID_FORMAT-4; |
188 | goto out; |
189 | } |
190 | if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, NULL((void *)0))) { |
191 | ret = SSH_ERR_LIBCRYPTO_ERROR-22; |
192 | goto out; |
193 | } |
194 | rsa_n = rsa_e = NULL((void *)0); /* transferred */ |
195 | if ((ret = sshkey_check_rsa_length(key, 0)) != 0) |
196 | goto out; |
197 | #ifdef DEBUG_PK |
198 | RSA_print_fp(stderr(&__sF[2]), key->rsa, 8); |
199 | #endif |
200 | /* success */ |
201 | ret = 0; |
202 | out: |
203 | BN_clear_free(rsa_n); |
204 | BN_clear_free(rsa_e); |
205 | return ret; |
206 | } |
207 | |
208 | static int |
209 | ssh_rsa_deserialize_private(const char *ktype, struct sshbuf *b, |
210 | struct sshkey *key) |
211 | { |
212 | int r; |
213 | BIGNUM *rsa_n = NULL((void *)0), *rsa_e = NULL((void *)0), *rsa_d = NULL((void *)0); |
214 | BIGNUM *rsa_iqmp = NULL((void *)0), *rsa_p = NULL((void *)0), *rsa_q = NULL((void *)0); |
215 | |
216 | /* Note: can't reuse ssh_rsa_deserialize_public: e, n vs. n, e */ |
217 | if (!sshkey_is_cert(key)) { |
218 | if ((r = sshbuf_get_bignum2(b, &rsa_n)) != 0 || |
219 | (r = sshbuf_get_bignum2(b, &rsa_e)) != 0) |
220 | goto out; |
221 | if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, NULL((void *)0))) { |
222 | r = SSH_ERR_LIBCRYPTO_ERROR-22; |
223 | goto out; |
224 | } |
225 | rsa_n = rsa_e = NULL((void *)0); /* transferred */ |
226 | } |
227 | if ((r = sshbuf_get_bignum2(b, &rsa_d)) != 0 || |
228 | (r = sshbuf_get_bignum2(b, &rsa_iqmp)) != 0 || |
229 | (r = sshbuf_get_bignum2(b, &rsa_p)) != 0 || |
230 | (r = sshbuf_get_bignum2(b, &rsa_q)) != 0) |
231 | goto out; |
232 | if (!RSA_set0_key(key->rsa, NULL((void *)0), NULL((void *)0), rsa_d)) { |
233 | r = SSH_ERR_LIBCRYPTO_ERROR-22; |
234 | goto out; |
235 | } |
236 | rsa_d = NULL((void *)0); /* transferred */ |
237 | if (!RSA_set0_factors(key->rsa, rsa_p, rsa_q)) { |
238 | r = SSH_ERR_LIBCRYPTO_ERROR-22; |
239 | goto out; |
240 | } |
241 | rsa_p = rsa_q = NULL((void *)0); /* transferred */ |
242 | if ((r = sshkey_check_rsa_length(key, 0)) != 0) |
243 | goto out; |
244 | if ((r = ssh_rsa_complete_crt_parameters(key, rsa_iqmp)) != 0) |
245 | goto out; |
246 | if (RSA_blinding_on(key->rsa, NULL((void *)0)) != 1) { |
247 | r = SSH_ERR_LIBCRYPTO_ERROR-22; |
248 | goto out; |
249 | } |
250 | /* success */ |
251 | r = 0; |
252 | out: |
253 | BN_clear_free(rsa_n); |
254 | BN_clear_free(rsa_e); |
255 | BN_clear_free(rsa_d); |
256 | BN_clear_free(rsa_p); |
257 | BN_clear_free(rsa_q); |
258 | BN_clear_free(rsa_iqmp); |
259 | return r; |
260 | } |
261 | |
262 | static const char * |
263 | rsa_hash_alg_ident(int hash_alg) |
264 | { |
265 | switch (hash_alg) { |
266 | case SSH_DIGEST_SHA11: |
267 | return "ssh-rsa"; |
268 | case SSH_DIGEST_SHA2562: |
269 | return "rsa-sha2-256"; |
270 | case SSH_DIGEST_SHA5124: |
271 | return "rsa-sha2-512"; |
272 | } |
273 | return NULL((void *)0); |
274 | } |
275 | |
276 | /* |
277 | * Returns the hash algorithm ID for a given algorithm identifier as used |
278 | * inside the signature blob, |
279 | */ |
280 | static int |
281 | rsa_hash_id_from_ident(const char *ident) |
282 | { |
283 | if (strcmp(ident, "ssh-rsa") == 0) |
284 | return SSH_DIGEST_SHA11; |
285 | if (strcmp(ident, "rsa-sha2-256") == 0) |
286 | return SSH_DIGEST_SHA2562; |
287 | if (strcmp(ident, "rsa-sha2-512") == 0) |
288 | return SSH_DIGEST_SHA5124; |
289 | return -1; |
290 | } |
291 | |
292 | /* |
293 | * Return the hash algorithm ID for the specified key name. This includes |
294 | * all the cases of rsa_hash_id_from_ident() but also the certificate key |
295 | * types. |
296 | */ |
297 | static int |
298 | rsa_hash_id_from_keyname(const char *alg) |
299 | { |
300 | int r; |
301 | |
302 | if ((r = rsa_hash_id_from_ident(alg)) != -1) |
303 | return r; |
304 | if (strcmp(alg, "ssh-rsa-cert-v01@openssh.com") == 0) |
305 | return SSH_DIGEST_SHA11; |
306 | if (strcmp(alg, "rsa-sha2-256-cert-v01@openssh.com") == 0) |
307 | return SSH_DIGEST_SHA2562; |
308 | if (strcmp(alg, "rsa-sha2-512-cert-v01@openssh.com") == 0) |
309 | return SSH_DIGEST_SHA5124; |
310 | return -1; |
311 | } |
312 | |
313 | static int |
314 | rsa_hash_alg_nid(int type) |
315 | { |
316 | switch (type) { |
317 | case SSH_DIGEST_SHA11: |
318 | return NID_sha164; |
319 | case SSH_DIGEST_SHA2562: |
320 | return NID_sha256672; |
321 | case SSH_DIGEST_SHA5124: |
322 | return NID_sha512674; |
323 | default: |
324 | return -1; |
325 | } |
326 | } |
327 | |
328 | int |
329 | ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp) |
330 | { |
331 | const BIGNUM *rsa_p, *rsa_q, *rsa_d; |
332 | BIGNUM *aux = NULL((void *)0), *d_consttime = NULL((void *)0); |
333 | BIGNUM *rsa_dmq1 = NULL((void *)0), *rsa_dmp1 = NULL((void *)0), *rsa_iqmp = NULL((void *)0); |
334 | BN_CTX *ctx = NULL((void *)0); |
335 | int r; |
336 | |
337 | if (key == NULL((void *)0) || key->rsa == NULL((void *)0) || |
338 | sshkey_type_plain(key->type) != KEY_RSA) |
339 | return SSH_ERR_INVALID_ARGUMENT-10; |
340 | |
341 | RSA_get0_key(key->rsa, NULL((void *)0), NULL((void *)0), &rsa_d); |
342 | RSA_get0_factors(key->rsa, &rsa_p, &rsa_q); |
343 | |
344 | if ((ctx = BN_CTX_new()) == NULL((void *)0)) |
345 | return SSH_ERR_ALLOC_FAIL-2; |
346 | if ((aux = BN_new()) == NULL((void *)0) || |
347 | (rsa_dmq1 = BN_new()) == NULL((void *)0) || |
348 | (rsa_dmp1 = BN_new()) == NULL((void *)0)) |
349 | return SSH_ERR_ALLOC_FAIL-2; |
350 | if ((d_consttime = BN_dup(rsa_d)) == NULL((void *)0) || |
351 | (rsa_iqmp = BN_dup(iqmp)) == NULL((void *)0)) { |
352 | r = SSH_ERR_ALLOC_FAIL-2; |
353 | goto out; |
354 | } |
355 | BN_set_flags(aux, BN_FLG_CONSTTIME0x04); |
356 | BN_set_flags(d_consttime, BN_FLG_CONSTTIME0x04); |
357 | |
358 | if ((BN_sub(aux, rsa_q, BN_value_one()) == 0) || |
359 | (BN_mod(rsa_dmq1, d_consttime, aux, ctx)BN_div(((void *)0),(rsa_dmq1),(d_consttime),(aux),(ctx)) == 0) || |
360 | (BN_sub(aux, rsa_p, BN_value_one()) == 0) || |
361 | (BN_mod(rsa_dmp1, d_consttime, aux, ctx)BN_div(((void *)0),(rsa_dmp1),(d_consttime),(aux),(ctx)) == 0)) { |
362 | r = SSH_ERR_LIBCRYPTO_ERROR-22; |
363 | goto out; |
364 | } |
365 | if (!RSA_set0_crt_params(key->rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp)) { |
366 | r = SSH_ERR_LIBCRYPTO_ERROR-22; |
367 | goto out; |
368 | } |
369 | rsa_dmp1 = rsa_dmq1 = rsa_iqmp = NULL((void *)0); /* transferred */ |
370 | /* success */ |
371 | r = 0; |
372 | out: |
373 | BN_clear_free(aux); |
374 | BN_clear_free(d_consttime); |
375 | BN_clear_free(rsa_dmp1); |
376 | BN_clear_free(rsa_dmq1); |
377 | BN_clear_free(rsa_iqmp); |
378 | BN_CTX_free(ctx); |
379 | return r; |
380 | } |
381 | |
382 | /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ |
383 | static int |
384 | ssh_rsa_sign(struct sshkey *key, |
385 | u_char **sigp, size_t *lenp, |
386 | const u_char *data, size_t datalen, |
387 | const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) |
388 | { |
389 | const BIGNUM *rsa_n; |
390 | u_char digest[SSH_DIGEST_MAX_LENGTH64], *sig = NULL((void *)0); |
391 | size_t slen = 0; |
392 | u_int hlen, len; |
393 | int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR-1; |
394 | struct sshbuf *b = NULL((void *)0); |
395 | |
396 | if (lenp != NULL((void *)0)) |
397 | *lenp = 0; |
398 | if (sigp != NULL((void *)0)) |
399 | *sigp = NULL((void *)0); |
400 | |
401 | if (alg == NULL((void *)0) || strlen(alg) == 0) |
402 | hash_alg = SSH_DIGEST_SHA11; |
403 | else |
404 | hash_alg = rsa_hash_id_from_keyname(alg); |
405 | if (key == NULL((void *)0) || key->rsa == NULL((void *)0) || hash_alg == -1 || |
406 | sshkey_type_plain(key->type) != KEY_RSA) |
407 | return SSH_ERR_INVALID_ARGUMENT-10; |
408 | RSA_get0_key(key->rsa, &rsa_n, NULL((void *)0), NULL((void *)0)); |
409 | if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE1024) |
410 | return SSH_ERR_KEY_LENGTH-56; |
411 | slen = RSA_size(key->rsa); |
412 | if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM(16384 / 8)) |
413 | return SSH_ERR_INVALID_ARGUMENT-10; |
414 | |
415 | /* hash the data */ |
416 | nid = rsa_hash_alg_nid(hash_alg); |
417 | if ((hlen = ssh_digest_bytes(hash_alg)) == 0) |
418 | return SSH_ERR_INTERNAL_ERROR-1; |
419 | if ((ret = ssh_digest_memory(hash_alg, data, datalen, |
420 | digest, sizeof(digest))) != 0) |
421 | goto out; |
422 | |
423 | if ((sig = malloc(slen)) == NULL((void *)0)) { |
424 | ret = SSH_ERR_ALLOC_FAIL-2; |
425 | goto out; |
426 | } |
427 | |
428 | if (RSA_sign(nid, digest, hlen, sig, &len, key->rsa) != 1) { |
429 | ret = SSH_ERR_LIBCRYPTO_ERROR-22; |
430 | goto out; |
431 | } |
432 | if (len < slen) { |
433 | size_t diff = slen - len; |
434 | memmove(sig + diff, sig, len); |
435 | explicit_bzero(sig, diff); |
436 | } else if (len > slen) { |
437 | ret = SSH_ERR_INTERNAL_ERROR-1; |
438 | goto out; |
439 | } |
440 | /* encode signature */ |
441 | if ((b = sshbuf_new()) == NULL((void *)0)) { |
442 | ret = SSH_ERR_ALLOC_FAIL-2; |
443 | goto out; |
444 | } |
445 | if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 || |
446 | (ret = sshbuf_put_string(b, sig, slen)) != 0) |
447 | goto out; |
448 | len = sshbuf_len(b); |
449 | if (sigp != NULL((void *)0)) { |
450 | if ((*sigp = malloc(len)) == NULL((void *)0)) { |
451 | ret = SSH_ERR_ALLOC_FAIL-2; |
452 | goto out; |
453 | } |
454 | memcpy(*sigp, sshbuf_ptr(b), len); |
455 | } |
456 | if (lenp != NULL((void *)0)) |
457 | *lenp = len; |
458 | ret = 0; |
459 | out: |
460 | explicit_bzero(digest, sizeof(digest)); |
461 | freezero(sig, slen); |
462 | sshbuf_free(b); |
463 | return ret; |
464 | } |
465 | |
466 | static int |
467 | ssh_rsa_verify(const struct sshkey *key, |
468 | const u_char *sig, size_t siglen, |
469 | const u_char *data, size_t dlen, const char *alg, u_int compat, |
470 | struct sshkey_sig_details **detailsp) |
471 | { |
472 | const BIGNUM *rsa_n; |
473 | char *sigtype = NULL((void *)0); |
474 | int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR-1; |
475 | size_t len = 0, diff, modlen, hlen; |
476 | struct sshbuf *b = NULL((void *)0); |
477 | u_char digest[SSH_DIGEST_MAX_LENGTH64], *osigblob, *sigblob = NULL((void *)0); |
478 | |
479 | if (key == NULL((void *)0) || key->rsa == NULL((void *)0) || |
480 | sshkey_type_plain(key->type) != KEY_RSA || |
481 | sig == NULL((void *)0) || siglen == 0) |
482 | return SSH_ERR_INVALID_ARGUMENT-10; |
483 | RSA_get0_key(key->rsa, &rsa_n, NULL((void *)0), NULL((void *)0)); |
484 | if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE1024) |
485 | return SSH_ERR_KEY_LENGTH-56; |
486 | |
487 | if ((b = sshbuf_from(sig, siglen)) == NULL((void *)0)) |
488 | return SSH_ERR_ALLOC_FAIL-2; |
489 | if (sshbuf_get_cstring(b, &sigtype, NULL((void *)0)) != 0) { |
490 | ret = SSH_ERR_INVALID_FORMAT-4; |
491 | goto out; |
492 | } |
493 | if ((hash_alg = rsa_hash_id_from_ident(sigtype)) == -1) { |
494 | ret = SSH_ERR_KEY_TYPE_MISMATCH-13; |
495 | goto out; |
496 | } |
497 | /* |
498 | * Allow ssh-rsa-cert-v01 certs to generate SHA2 signatures for |
499 | * legacy reasons, but otherwise the signature type should match. |
500 | */ |
501 | if (alg != NULL((void *)0) && strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) { |
502 | if ((want_alg = rsa_hash_id_from_keyname(alg)) == -1) { |
503 | ret = SSH_ERR_INVALID_ARGUMENT-10; |
504 | goto out; |
505 | } |
506 | if (hash_alg != want_alg) { |
507 | ret = SSH_ERR_SIGNATURE_INVALID-21; |
508 | goto out; |
509 | } |
510 | } |
511 | if (sshbuf_get_string(b, &sigblob, &len) != 0) { |
512 | ret = SSH_ERR_INVALID_FORMAT-4; |
513 | goto out; |
514 | } |
515 | if (sshbuf_len(b) != 0) { |
516 | ret = SSH_ERR_UNEXPECTED_TRAILING_DATA-23; |
517 | goto out; |
518 | } |
519 | /* RSA_verify expects a signature of RSA_size */ |
520 | modlen = RSA_size(key->rsa); |
521 | if (len > modlen) { |
522 | ret = SSH_ERR_KEY_BITS_MISMATCH-11; |
523 | goto out; |
524 | } else if (len < modlen) { |
525 | diff = modlen - len; |
526 | osigblob = sigblob; |
527 | if ((sigblob = realloc(sigblob, modlen)) == NULL((void *)0)) { |
528 | sigblob = osigblob; /* put it back for clear/free */ |
529 | ret = SSH_ERR_ALLOC_FAIL-2; |
530 | goto out; |
531 | } |
532 | memmove(sigblob + diff, sigblob, len); |
533 | explicit_bzero(sigblob, diff); |
534 | len = modlen; |
535 | } |
536 | if ((hlen = ssh_digest_bytes(hash_alg)) == 0) { |
537 | ret = SSH_ERR_INTERNAL_ERROR-1; |
538 | goto out; |
539 | } |
540 | if ((ret = ssh_digest_memory(hash_alg, data, dlen, |
541 | digest, sizeof(digest))) != 0) |
542 | goto out; |
543 | |
544 | ret = openssh_RSA_verify(hash_alg, digest, hlen, sigblob, len, |
545 | key->rsa); |
546 | out: |
547 | freezero(sigblob, len); |
548 | free(sigtype); |
549 | sshbuf_free(b); |
550 | explicit_bzero(digest, sizeof(digest)); |
551 | return ret; |
552 | } |
553 | |
554 | /* |
555 | * See: |
556 | * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ |
557 | * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn |
558 | */ |
559 | |
560 | /* |
561 | * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) |
562 | * oiw(14) secsig(3) algorithms(2) 26 } |
563 | */ |
564 | static const u_char id_sha1[] = { |
565 | 0x30, 0x21, /* type Sequence, length 0x21 (33) */ |
566 | 0x30, 0x09, /* type Sequence, length 0x09 */ |
567 | 0x06, 0x05, /* type OID, length 0x05 */ |
568 | 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ |
569 | 0x05, 0x00, /* NULL */ |
570 | 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ |
571 | }; |
572 | |
573 | /* |
574 | * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html |
575 | * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) |
576 | * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) |
577 | * id-sha256(1) } |
578 | */ |
579 | static const u_char id_sha256[] = { |
580 | 0x30, 0x31, /* type Sequence, length 0x31 (49) */ |
581 | 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ |
582 | 0x06, 0x09, /* type OID, length 0x09 */ |
583 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */ |
584 | 0x05, 0x00, /* NULL */ |
585 | 0x04, 0x20 /* Octet string, length 0x20 (32), followed by sha256 hash */ |
586 | }; |
587 | |
588 | /* |
589 | * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html |
590 | * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) |
591 | * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) |
592 | * id-sha256(3) } |
593 | */ |
594 | static const u_char id_sha512[] = { |
595 | 0x30, 0x51, /* type Sequence, length 0x51 (81) */ |
596 | 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ |
597 | 0x06, 0x09, /* type OID, length 0x09 */ |
598 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */ |
599 | 0x05, 0x00, /* NULL */ |
600 | 0x04, 0x40 /* Octet string, length 0x40 (64), followed by sha512 hash */ |
601 | }; |
602 | |
603 | static int |
604 | rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp) |
605 | { |
606 | switch (hash_alg) { |
607 | case SSH_DIGEST_SHA11: |
608 | *oidp = id_sha1; |
609 | *oidlenp = sizeof(id_sha1); |
610 | break; |
611 | case SSH_DIGEST_SHA2562: |
612 | *oidp = id_sha256; |
613 | *oidlenp = sizeof(id_sha256); |
614 | break; |
615 | case SSH_DIGEST_SHA5124: |
616 | *oidp = id_sha512; |
617 | *oidlenp = sizeof(id_sha512); |
618 | break; |
619 | default: |
620 | return SSH_ERR_INVALID_ARGUMENT-10; |
621 | } |
622 | return 0; |
623 | } |
624 | |
625 | static int |
626 | openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, |
627 | u_char *sigbuf, size_t siglen, RSA *rsa) |
628 | { |
629 | size_t rsasize = 0, oidlen = 0, hlen = 0; |
630 | int ret, len, oidmatch, hashmatch; |
631 | const u_char *oid = NULL((void *)0); |
632 | u_char *decrypted = NULL((void *)0); |
633 | |
634 | if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0) |
635 | return ret; |
636 | ret = SSH_ERR_INTERNAL_ERROR-1; |
Value stored to 'ret' is never read | |
637 | hlen = ssh_digest_bytes(hash_alg); |
638 | if (hashlen != hlen) { |
639 | ret = SSH_ERR_INVALID_ARGUMENT-10; |
640 | goto done; |
641 | } |
642 | rsasize = RSA_size(rsa); |
643 | if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM(16384 / 8) || |
644 | siglen == 0 || siglen > rsasize) { |
645 | ret = SSH_ERR_INVALID_ARGUMENT-10; |
646 | goto done; |
647 | } |
648 | if ((decrypted = malloc(rsasize)) == NULL((void *)0)) { |
649 | ret = SSH_ERR_ALLOC_FAIL-2; |
650 | goto done; |
651 | } |
652 | if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, |
653 | RSA_PKCS1_PADDING1)) < 0) { |
654 | ret = SSH_ERR_LIBCRYPTO_ERROR-22; |
655 | goto done; |
656 | } |
657 | if (len < 0 || (size_t)len != hlen + oidlen) { |
658 | ret = SSH_ERR_INVALID_FORMAT-4; |
659 | goto done; |
660 | } |
661 | oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; |
662 | hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; |
663 | if (!oidmatch || !hashmatch) { |
664 | ret = SSH_ERR_SIGNATURE_INVALID-21; |
665 | goto done; |
666 | } |
667 | ret = 0; |
668 | done: |
669 | freezero(decrypted, rsasize); |
670 | return ret; |
671 | } |
672 | |
673 | static const struct sshkey_impl_funcs sshkey_rsa_funcs = { |
674 | /* .size = */ ssh_rsa_size, |
675 | /* .alloc = */ ssh_rsa_alloc, |
676 | /* .cleanup = */ ssh_rsa_cleanup, |
677 | /* .equal = */ ssh_rsa_equal, |
678 | /* .ssh_serialize_public = */ ssh_rsa_serialize_public, |
679 | /* .ssh_deserialize_public = */ ssh_rsa_deserialize_public, |
680 | /* .ssh_serialize_private = */ ssh_rsa_serialize_private, |
681 | /* .ssh_deserialize_private = */ ssh_rsa_deserialize_private, |
682 | /* .generate = */ ssh_rsa_generate, |
683 | /* .copy_public = */ ssh_rsa_copy_public, |
684 | /* .sign = */ ssh_rsa_sign, |
685 | /* .verify = */ ssh_rsa_verify, |
686 | }; |
687 | |
688 | const struct sshkey_impl sshkey_rsa_impl = { |
689 | /* .name = */ "ssh-rsa", |
690 | /* .shortname = */ "RSA", |
691 | /* .sigalg = */ NULL((void *)0), |
692 | /* .type = */ KEY_RSA, |
693 | /* .nid = */ 0, |
694 | /* .cert = */ 0, |
695 | /* .sigonly = */ 0, |
696 | /* .keybits = */ 0, |
697 | /* .funcs = */ &sshkey_rsa_funcs, |
698 | }; |
699 | |
700 | const struct sshkey_impl sshkey_rsa_cert_impl = { |
701 | /* .name = */ "ssh-rsa-cert-v01@openssh.com", |
702 | /* .shortname = */ "RSA-CERT", |
703 | /* .sigalg = */ NULL((void *)0), |
704 | /* .type = */ KEY_RSA_CERT, |
705 | /* .nid = */ 0, |
706 | /* .cert = */ 1, |
707 | /* .sigonly = */ 0, |
708 | /* .keybits = */ 0, |
709 | /* .funcs = */ &sshkey_rsa_funcs, |
710 | }; |
711 | |
712 | /* SHA2 signature algorithms */ |
713 | |
714 | const struct sshkey_impl sshkey_rsa_sha256_impl = { |
715 | /* .name = */ "rsa-sha2-256", |
716 | /* .shortname = */ "RSA", |
717 | /* .sigalg = */ NULL((void *)0), |
718 | /* .type = */ KEY_RSA, |
719 | /* .nid = */ 0, |
720 | /* .cert = */ 0, |
721 | /* .sigonly = */ 1, |
722 | /* .keybits = */ 0, |
723 | /* .funcs = */ &sshkey_rsa_funcs, |
724 | }; |
725 | |
726 | const struct sshkey_impl sshkey_rsa_sha512_impl = { |
727 | /* .name = */ "rsa-sha2-512", |
728 | /* .shortname = */ "RSA", |
729 | /* .sigalg = */ NULL((void *)0), |
730 | /* .type = */ KEY_RSA, |
731 | /* .nid = */ 0, |
732 | /* .cert = */ 0, |
733 | /* .sigonly = */ 1, |
734 | /* .keybits = */ 0, |
735 | /* .funcs = */ &sshkey_rsa_funcs, |
736 | }; |
737 | |
738 | const struct sshkey_impl sshkey_rsa_sha256_cert_impl = { |
739 | /* .name = */ "rsa-sha2-256-cert-v01@openssh.com", |
740 | /* .shortname = */ "RSA-CERT", |
741 | /* .sigalg = */ "rsa-sha2-256", |
742 | /* .type = */ KEY_RSA_CERT, |
743 | /* .nid = */ 0, |
744 | /* .cert = */ 1, |
745 | /* .sigonly = */ 1, |
746 | /* .keybits = */ 0, |
747 | /* .funcs = */ &sshkey_rsa_funcs, |
748 | }; |
749 | |
750 | const struct sshkey_impl sshkey_rsa_sha512_cert_impl = { |
751 | /* .name = */ "rsa-sha2-512-cert-v01@openssh.com", |
752 | /* .shortname = */ "RSA-CERT", |
753 | /* .sigalg = */ "rsa-sha2-512", |
754 | /* .type = */ KEY_RSA_CERT, |
755 | /* .nid = */ 0, |
756 | /* .cert = */ 1, |
757 | /* .sigonly = */ 1, |
758 | /* .keybits = */ 0, |
759 | /* .funcs = */ &sshkey_rsa_funcs, |
760 | }; |