|
Lines 37-43
Link Here
|
| 37 |
|
37 |
|
| 38 |
#include "openbsd-compat/openssl-compat.h" |
38 |
#include "openbsd-compat/openssl-compat.h" |
| 39 |
|
39 |
|
| 40 |
static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); |
40 |
static int openssh_RSA_verify(int, const u_char *, size_t, u_char *, size_t, EVP_PKEY *); |
| 41 |
|
41 |
|
| 42 |
static const char * |
42 |
static const char * |
| 43 |
rsa_hash_alg_ident(int hash_alg) |
43 |
rsa_hash_alg_ident(int hash_alg) |
|
Lines 90-110
rsa_hash_id_from_keyname(const char *alg)
Link Here
|
| 90 |
return -1; |
90 |
return -1; |
| 91 |
} |
91 |
} |
| 92 |
|
92 |
|
| 93 |
static int |
|
|
| 94 |
rsa_hash_alg_nid(int type) |
| 95 |
{ |
| 96 |
switch (type) { |
| 97 |
case SSH_DIGEST_SHA1: |
| 98 |
return NID_sha1; |
| 99 |
case SSH_DIGEST_SHA256: |
| 100 |
return NID_sha256; |
| 101 |
case SSH_DIGEST_SHA512: |
| 102 |
return NID_sha512; |
| 103 |
default: |
| 104 |
return -1; |
| 105 |
} |
| 106 |
} |
| 107 |
|
| 108 |
int |
93 |
int |
| 109 |
ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp) |
94 |
ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp) |
| 110 |
{ |
95 |
{ |
|
Lines 164-174
int
Link Here
|
| 164 |
ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
149 |
ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
| 165 |
const u_char *data, size_t datalen, const char *alg_ident) |
150 |
const u_char *data, size_t datalen, const char *alg_ident) |
| 166 |
{ |
151 |
{ |
| 167 |
const BIGNUM *rsa_n; |
152 |
EVP_PKEY *pkey = NULL; |
| 168 |
u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; |
153 |
u_char *sig = NULL; |
| 169 |
size_t slen = 0; |
154 |
int len, slen = 0; |
| 170 |
u_int dlen, len; |
155 |
int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; |
| 171 |
int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR; |
|
|
| 172 |
struct sshbuf *b = NULL; |
156 |
struct sshbuf *b = NULL; |
| 173 |
|
157 |
|
| 174 |
if (lenp != NULL) |
158 |
if (lenp != NULL) |
|
Lines 180-212
ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
Link Here
|
| 180 |
hash_alg = SSH_DIGEST_SHA1; |
164 |
hash_alg = SSH_DIGEST_SHA1; |
| 181 |
else |
165 |
else |
| 182 |
hash_alg = rsa_hash_id_from_keyname(alg_ident); |
166 |
hash_alg = rsa_hash_id_from_keyname(alg_ident); |
|
|
167 |
|
| 183 |
if (key == NULL || key->rsa == NULL || hash_alg == -1 || |
168 |
if (key == NULL || key->rsa == NULL || hash_alg == -1 || |
| 184 |
sshkey_type_plain(key->type) != KEY_RSA) |
169 |
sshkey_type_plain(key->type) != KEY_RSA) |
| 185 |
return SSH_ERR_INVALID_ARGUMENT; |
170 |
return SSH_ERR_INVALID_ARGUMENT; |
| 186 |
RSA_get0_key(key->rsa, &rsa_n, NULL, NULL); |
|
|
| 187 |
if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) |
| 188 |
return SSH_ERR_KEY_LENGTH; |
| 189 |
slen = RSA_size(key->rsa); |
171 |
slen = RSA_size(key->rsa); |
| 190 |
if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) |
172 |
if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) |
| 191 |
return SSH_ERR_INVALID_ARGUMENT; |
173 |
return SSH_ERR_KEY_LENGTH; |
| 192 |
|
|
|
| 193 |
/* hash the data */ |
| 194 |
nid = rsa_hash_alg_nid(hash_alg); |
| 195 |
if ((dlen = ssh_digest_bytes(hash_alg)) == 0) |
| 196 |
return SSH_ERR_INTERNAL_ERROR; |
| 197 |
if ((ret = ssh_digest_memory(hash_alg, data, datalen, |
| 198 |
digest, sizeof(digest))) != 0) |
| 199 |
goto out; |
| 200 |
|
174 |
|
| 201 |
if ((sig = malloc(slen)) == NULL) { |
175 |
if ((pkey = EVP_PKEY_new()) == NULL || |
| 202 |
ret = SSH_ERR_ALLOC_FAIL; |
176 |
EVP_PKEY_set1_RSA(pkey, key->rsa) != 1) |
|
|
177 |
return SSH_ERR_ALLOC_FAIL; |
| 178 |
ret = sshkey_calculate_signature(pkey, hash_alg, &sig, &len, data, |
| 179 |
datalen); |
| 180 |
EVP_PKEY_free(pkey); |
| 181 |
if (ret < 0) { |
| 203 |
goto out; |
182 |
goto out; |
| 204 |
} |
183 |
} |
| 205 |
|
184 |
|
| 206 |
if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) { |
|
|
| 207 |
ret = SSH_ERR_LIBCRYPTO_ERROR; |
| 208 |
goto out; |
| 209 |
} |
| 210 |
if (len < slen) { |
185 |
if (len < slen) { |
| 211 |
size_t diff = slen - len; |
186 |
size_t diff = slen - len; |
| 212 |
memmove(sig + diff, sig, len); |
187 |
memmove(sig + diff, sig, len); |
|
Lines 215-220
ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
Link Here
|
| 215 |
ret = SSH_ERR_INTERNAL_ERROR; |
190 |
ret = SSH_ERR_INTERNAL_ERROR; |
| 216 |
goto out; |
191 |
goto out; |
| 217 |
} |
192 |
} |
|
|
193 |
|
| 218 |
/* encode signature */ |
194 |
/* encode signature */ |
| 219 |
if ((b = sshbuf_new()) == NULL) { |
195 |
if ((b = sshbuf_new()) == NULL) { |
| 220 |
ret = SSH_ERR_ALLOC_FAIL; |
196 |
ret = SSH_ERR_ALLOC_FAIL; |
|
Lines 235-241
ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
Link Here
|
| 235 |
*lenp = len; |
211 |
*lenp = len; |
| 236 |
ret = 0; |
212 |
ret = 0; |
| 237 |
out: |
213 |
out: |
| 238 |
explicit_bzero(digest, sizeof(digest)); |
|
|
| 239 |
freezero(sig, slen); |
214 |
freezero(sig, slen); |
| 240 |
sshbuf_free(b); |
215 |
sshbuf_free(b); |
| 241 |
return ret; |
216 |
return ret; |
|
Lines 246-255
ssh_rsa_verify(const struct sshkey *key,
Link Here
|
| 246 |
const u_char *sig, size_t siglen, const u_char *data, size_t datalen, |
221 |
const u_char *sig, size_t siglen, const u_char *data, size_t datalen, |
| 247 |
const char *alg) |
222 |
const char *alg) |
| 248 |
{ |
223 |
{ |
| 249 |
const BIGNUM *rsa_n; |
224 |
EVP_PKEY *pkey = NULL; |
| 250 |
char *sigtype = NULL; |
225 |
char *sigtype = NULL; |
| 251 |
int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR; |
226 |
int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR; |
| 252 |
size_t len = 0, diff, modlen, dlen; |
227 |
size_t len = 0, diff, modlen; |
| 253 |
struct sshbuf *b = NULL; |
228 |
struct sshbuf *b = NULL; |
| 254 |
u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; |
229 |
u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; |
| 255 |
|
230 |
|
|
Lines 257-264
ssh_rsa_verify(const struct sshkey *key,
Link Here
|
| 257 |
sshkey_type_plain(key->type) != KEY_RSA || |
232 |
sshkey_type_plain(key->type) != KEY_RSA || |
| 258 |
sig == NULL || siglen == 0) |
233 |
sig == NULL || siglen == 0) |
| 259 |
return SSH_ERR_INVALID_ARGUMENT; |
234 |
return SSH_ERR_INVALID_ARGUMENT; |
| 260 |
RSA_get0_key(key->rsa, &rsa_n, NULL, NULL); |
235 |
if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) |
| 261 |
if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) |
|
|
| 262 |
return SSH_ERR_KEY_LENGTH; |
236 |
return SSH_ERR_KEY_LENGTH; |
| 263 |
|
237 |
|
| 264 |
if ((b = sshbuf_from(sig, siglen)) == NULL) |
238 |
if ((b = sshbuf_from(sig, siglen)) == NULL) |
|
Lines 310-325
ssh_rsa_verify(const struct sshkey *key,
Link Here
|
| 310 |
explicit_bzero(sigblob, diff); |
284 |
explicit_bzero(sigblob, diff); |
| 311 |
len = modlen; |
285 |
len = modlen; |
| 312 |
} |
286 |
} |
| 313 |
if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { |
287 |
|
| 314 |
ret = SSH_ERR_INTERNAL_ERROR; |
288 |
if ((pkey = EVP_PKEY_new()) == NULL || |
|
|
289 |
EVP_PKEY_set1_RSA(pkey, key->rsa) != 1) { |
| 290 |
ret = SSH_ERR_ALLOC_FAIL; |
| 315 |
goto out; |
291 |
goto out; |
| 316 |
} |
292 |
} |
| 317 |
if ((ret = ssh_digest_memory(hash_alg, data, datalen, |
293 |
ret = openssh_RSA_verify(hash_alg, data, datalen, sigblob, len, pkey); |
| 318 |
digest, sizeof(digest))) != 0) |
294 |
EVP_PKEY_free(pkey); |
| 319 |
goto out; |
|
|
| 320 |
|
295 |
|
| 321 |
ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, |
|
|
| 322 |
key->rsa); |
| 323 |
out: |
296 |
out: |
| 324 |
freezero(sigblob, len); |
297 |
freezero(sigblob, len); |
| 325 |
free(sigtype); |
298 |
free(sigtype); |
|
Lines 328-449
ssh_rsa_verify(const struct sshkey *key,
Link Here
|
| 328 |
return ret; |
301 |
return ret; |
| 329 |
} |
302 |
} |
| 330 |
|
303 |
|
| 331 |
/* |
|
|
| 332 |
* See: |
| 333 |
* http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ |
| 334 |
* ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn |
| 335 |
*/ |
| 336 |
|
| 337 |
/* |
| 338 |
* id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) |
| 339 |
* oiw(14) secsig(3) algorithms(2) 26 } |
| 340 |
*/ |
| 341 |
static const u_char id_sha1[] = { |
| 342 |
0x30, 0x21, /* type Sequence, length 0x21 (33) */ |
| 343 |
0x30, 0x09, /* type Sequence, length 0x09 */ |
| 344 |
0x06, 0x05, /* type OID, length 0x05 */ |
| 345 |
0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ |
| 346 |
0x05, 0x00, /* NULL */ |
| 347 |
0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ |
| 348 |
}; |
| 349 |
|
| 350 |
/* |
| 351 |
* See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html |
| 352 |
* id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) |
| 353 |
* organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) |
| 354 |
* id-sha256(1) } |
| 355 |
*/ |
| 356 |
static const u_char id_sha256[] = { |
| 357 |
0x30, 0x31, /* type Sequence, length 0x31 (49) */ |
| 358 |
0x30, 0x0d, /* type Sequence, length 0x0d (13) */ |
| 359 |
0x06, 0x09, /* type OID, length 0x09 */ |
| 360 |
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */ |
| 361 |
0x05, 0x00, /* NULL */ |
| 362 |
0x04, 0x20 /* Octet string, length 0x20 (32), followed by sha256 hash */ |
| 363 |
}; |
| 364 |
|
| 365 |
/* |
| 366 |
* See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html |
| 367 |
* id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) |
| 368 |
* organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) |
| 369 |
* id-sha256(3) } |
| 370 |
*/ |
| 371 |
static const u_char id_sha512[] = { |
| 372 |
0x30, 0x51, /* type Sequence, length 0x51 (81) */ |
| 373 |
0x30, 0x0d, /* type Sequence, length 0x0d (13) */ |
| 374 |
0x06, 0x09, /* type OID, length 0x09 */ |
| 375 |
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */ |
| 376 |
0x05, 0x00, /* NULL */ |
| 377 |
0x04, 0x40 /* Octet string, length 0x40 (64), followed by sha512 hash */ |
| 378 |
}; |
| 379 |
|
| 380 |
static int |
304 |
static int |
| 381 |
rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp) |
305 |
openssh_RSA_verify(int hash_alg, const u_char *data, size_t datalen, |
|
|
306 |
u_char *sigbuf, size_t siglen, EVP_PKEY *pkey) |
| 382 |
{ |
307 |
{ |
| 383 |
switch (hash_alg) { |
308 |
size_t rsasize = 0; |
| 384 |
case SSH_DIGEST_SHA1: |
309 |
const RSA *rsa; |
| 385 |
*oidp = id_sha1; |
310 |
int ret; |
| 386 |
*oidlenp = sizeof(id_sha1); |
|
|
| 387 |
break; |
| 388 |
case SSH_DIGEST_SHA256: |
| 389 |
*oidp = id_sha256; |
| 390 |
*oidlenp = sizeof(id_sha256); |
| 391 |
break; |
| 392 |
case SSH_DIGEST_SHA512: |
| 393 |
*oidp = id_sha512; |
| 394 |
*oidlenp = sizeof(id_sha512); |
| 395 |
break; |
| 396 |
default: |
| 397 |
return SSH_ERR_INVALID_ARGUMENT; |
| 398 |
} |
| 399 |
return 0; |
| 400 |
} |
| 401 |
|
311 |
|
| 402 |
static int |
312 |
rsa = EVP_PKEY_get0_RSA(pkey); |
| 403 |
openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, |
|
|
| 404 |
u_char *sigbuf, size_t siglen, RSA *rsa) |
| 405 |
{ |
| 406 |
size_t rsasize = 0, oidlen = 0, hlen = 0; |
| 407 |
int ret, len, oidmatch, hashmatch; |
| 408 |
const u_char *oid = NULL; |
| 409 |
u_char *decrypted = NULL; |
| 410 |
|
| 411 |
if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0) |
| 412 |
return ret; |
| 413 |
ret = SSH_ERR_INTERNAL_ERROR; |
| 414 |
hlen = ssh_digest_bytes(hash_alg); |
| 415 |
if (hashlen != hlen) { |
| 416 |
ret = SSH_ERR_INVALID_ARGUMENT; |
| 417 |
goto done; |
| 418 |
} |
| 419 |
rsasize = RSA_size(rsa); |
313 |
rsasize = RSA_size(rsa); |
| 420 |
if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || |
314 |
if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || |
| 421 |
siglen == 0 || siglen > rsasize) { |
315 |
siglen == 0 || siglen > rsasize) { |
| 422 |
ret = SSH_ERR_INVALID_ARGUMENT; |
316 |
ret = SSH_ERR_INVALID_ARGUMENT; |
| 423 |
goto done; |
317 |
goto done; |
| 424 |
} |
318 |
} |
| 425 |
if ((decrypted = malloc(rsasize)) == NULL) { |
319 |
|
| 426 |
ret = SSH_ERR_ALLOC_FAIL; |
320 |
ret = sshkey_verify_signature(pkey, hash_alg, data, datalen, |
| 427 |
goto done; |
321 |
sigbuf, siglen); |
| 428 |
} |
322 |
|
| 429 |
if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, |
|
|
| 430 |
RSA_PKCS1_PADDING)) < 0) { |
| 431 |
ret = SSH_ERR_LIBCRYPTO_ERROR; |
| 432 |
goto done; |
| 433 |
} |
| 434 |
if (len < 0 || (size_t)len != hlen + oidlen) { |
| 435 |
ret = SSH_ERR_INVALID_FORMAT; |
| 436 |
goto done; |
| 437 |
} |
| 438 |
oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; |
| 439 |
hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; |
| 440 |
if (!oidmatch || !hashmatch) { |
| 441 |
ret = SSH_ERR_SIGNATURE_INVALID; |
| 442 |
goto done; |
| 443 |
} |
| 444 |
ret = 0; |
| 445 |
done: |
323 |
done: |
| 446 |
freezero(decrypted, rsasize); |
|
|
| 447 |
return ret; |
324 |
return ret; |
| 448 |
} |
325 |
} |
| 449 |
#endif /* WITH_OPENSSL */ |
326 |
#endif /* WITH_OPENSSL */ |