1 /* $NetBSD: ssh-rsa.c,v 1.15 2018/04/06 18:59:00 christos Exp $ */ 2 /* $OpenBSD: ssh-rsa.c,v 1.66 2018/02/14 16:27:24 jsing Exp $ */ 3 /* 4 * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include "includes.h" 20 __RCSID("$NetBSD: ssh-rsa.c,v 1.15 2018/04/06 18:59:00 christos Exp $"); 21 #include <sys/types.h> 22 23 #include <openssl/evp.h> 24 #include <openssl/err.h> 25 26 #include <string.h> 27 28 #include "sshbuf.h" 29 #include "compat.h" 30 #include "ssherr.h" 31 #define SSHKEY_INTERNAL 32 #include "sshkey.h" 33 #include "digest.h" 34 #include "log.h" 35 36 static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); 37 38 static const char * 39 rsa_hash_alg_ident(int hash_alg) 40 { 41 switch (hash_alg) { 42 case SSH_DIGEST_SHA1: 43 return "ssh-rsa"; 44 case SSH_DIGEST_SHA256: 45 return "rsa-sha2-256"; 46 case SSH_DIGEST_SHA512: 47 return "rsa-sha2-512"; 48 } 49 return NULL; 50 } 51 52 static int 53 rsa_hash_alg_from_ident(const char *ident) 54 { 55 if (strcmp(ident, "ssh-rsa") == 0 || 56 strcmp(ident, "ssh-rsa-cert-v01@openssh.com") == 0) 57 return SSH_DIGEST_SHA1; 58 if (strcmp(ident, "rsa-sha2-256") == 0) 59 return SSH_DIGEST_SHA256; 60 if (strcmp(ident, "rsa-sha2-512") == 0) 61 return SSH_DIGEST_SHA512; 62 return -1; 63 } 64 65 static int 66 rsa_hash_alg_nid(int type) 67 { 68 switch (type) { 69 case SSH_DIGEST_SHA1: 70 return NID_sha1; 71 case SSH_DIGEST_SHA256: 72 return NID_sha256; 73 case SSH_DIGEST_SHA512: 74 return NID_sha512; 75 default: 76 return -1; 77 } 78 } 79 80 int 81 ssh_rsa_generate_additional_parameters(struct sshkey *key) 82 { 83 RSA *rsa; 84 BIGNUM *aux = NULL; 85 BN_CTX *ctx = NULL; 86 int r; 87 88 if (key == NULL || key->rsa == NULL || 89 sshkey_type_plain(key->type) != KEY_RSA) 90 return SSH_ERR_INVALID_ARGUMENT; 91 92 if ((ctx = BN_CTX_new()) == NULL) 93 return SSH_ERR_ALLOC_FAIL; 94 if ((aux = BN_new()) == NULL) { 95 r = SSH_ERR_ALLOC_FAIL; 96 goto out; 97 } 98 rsa = key->rsa; 99 BN_set_flags(aux, BN_FLG_CONSTTIME); 100 101 { 102 const BIGNUM *q, *d, *p; 103 BIGNUM *dmq1=NULL, *dmp1=NULL; 104 if ((dmq1 = BN_new()) == NULL || 105 (dmp1 = BN_new()) == NULL ) { 106 r = SSH_ERR_ALLOC_FAIL; 107 goto out; 108 } 109 RSA_get0_key(rsa, NULL, NULL, &d); 110 RSA_get0_factors(rsa, &p, &q); 111 if ((BN_sub(aux, q, BN_value_one()) == 0) || 112 (BN_mod(dmq1, d, aux, ctx) == 0) || 113 (BN_sub(aux, p, BN_value_one()) == 0) || 114 (BN_mod(dmp1, d, aux, ctx) == 0) || 115 RSA_set0_crt_params(rsa, dmp1, dmq1, NULL) == 0) { 116 r = SSH_ERR_LIBCRYPTO_ERROR; 117 BN_clear_free(dmp1); 118 BN_clear_free(dmq1); 119 goto out; 120 } 121 } 122 r = 0; 123 out: 124 BN_clear_free(aux); 125 BN_CTX_free(ctx); 126 return r; 127 } 128 129 /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ 130 int 131 ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 132 const u_char *data, size_t datalen, const char *alg_ident) 133 { 134 u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; 135 size_t slen = 0; 136 u_int dlen, len; 137 int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR; 138 struct sshbuf *b = NULL; 139 140 if (lenp != NULL) 141 *lenp = 0; 142 if (sigp != NULL) 143 *sigp = NULL; 144 145 if (alg_ident == NULL || strlen(alg_ident) == 0) 146 hash_alg = SSH_DIGEST_SHA1; 147 else 148 hash_alg = rsa_hash_alg_from_ident(alg_ident); 149 if (key == NULL || key->rsa == NULL || hash_alg == -1 || 150 sshkey_type_plain(key->type) != KEY_RSA) 151 return SSH_ERR_INVALID_ARGUMENT; 152 if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) 153 return SSH_ERR_KEY_LENGTH; 154 slen = RSA_size(key->rsa); 155 if (slen == 0 || slen > SSHBUF_MAX_BIGNUM) 156 return SSH_ERR_INVALID_ARGUMENT; 157 158 /* hash the data */ 159 nid = rsa_hash_alg_nid(hash_alg); 160 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) 161 return SSH_ERR_INTERNAL_ERROR; 162 if ((ret = ssh_digest_memory(hash_alg, data, datalen, 163 digest, sizeof(digest))) != 0) 164 goto out; 165 166 if ((sig = malloc(slen)) == NULL) { 167 ret = SSH_ERR_ALLOC_FAIL; 168 goto out; 169 } 170 171 if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) { 172 ret = SSH_ERR_LIBCRYPTO_ERROR; 173 goto out; 174 } 175 if (len < slen) { 176 size_t diff = slen - len; 177 memmove(sig + diff, sig, len); 178 explicit_bzero(sig, diff); 179 } else if (len > slen) { 180 ret = SSH_ERR_INTERNAL_ERROR; 181 goto out; 182 } 183 /* encode signature */ 184 if ((b = sshbuf_new()) == NULL) { 185 ret = SSH_ERR_ALLOC_FAIL; 186 goto out; 187 } 188 if ((ret = sshbuf_put_cstring(b, rsa_hash_alg_ident(hash_alg))) != 0 || 189 (ret = sshbuf_put_string(b, sig, slen)) != 0) 190 goto out; 191 len = sshbuf_len(b); 192 if (sigp != NULL) { 193 if ((*sigp = malloc(len)) == NULL) { 194 ret = SSH_ERR_ALLOC_FAIL; 195 goto out; 196 } 197 memcpy(*sigp, sshbuf_ptr(b), len); 198 } 199 if (lenp != NULL) 200 *lenp = len; 201 ret = 0; 202 out: 203 explicit_bzero(digest, sizeof(digest)); 204 freezero(sig, slen); 205 sshbuf_free(b); 206 return ret; 207 } 208 209 int 210 ssh_rsa_verify(const struct sshkey *key, 211 const u_char *sig, size_t siglen, const u_char *data, size_t datalen, 212 const char *alg) 213 { 214 char *sigtype = NULL; 215 int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; 216 size_t len = 0, diff, modlen, dlen; 217 struct sshbuf *b = NULL; 218 u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; 219 220 if (key == NULL || key->rsa == NULL || 221 sshkey_type_plain(key->type) != KEY_RSA || 222 sig == NULL || siglen == 0) 223 return SSH_ERR_INVALID_ARGUMENT; 224 if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) 225 return SSH_ERR_KEY_LENGTH; 226 227 if ((b = sshbuf_from(sig, siglen)) == NULL) 228 return SSH_ERR_ALLOC_FAIL; 229 if (sshbuf_get_cstring(b, &sigtype, NULL) != 0) { 230 ret = SSH_ERR_INVALID_FORMAT; 231 goto out; 232 } 233 /* XXX djm: need cert types that reliably yield SHA-2 signatures */ 234 if (alg != NULL && strcmp(alg, sigtype) != 0 && 235 strcmp(alg, "ssh-rsa-cert-v01@openssh.com") != 0) { 236 error("%s: RSA signature type mismatch: " 237 "expected %s received %s", __func__, alg, sigtype); 238 ret = SSH_ERR_SIGNATURE_INVALID; 239 goto out; 240 } 241 if ((hash_alg = rsa_hash_alg_from_ident(sigtype)) == -1) { 242 ret = SSH_ERR_KEY_TYPE_MISMATCH; 243 goto out; 244 } 245 if (sshbuf_get_string(b, &sigblob, &len) != 0) { 246 ret = SSH_ERR_INVALID_FORMAT; 247 goto out; 248 } 249 if (sshbuf_len(b) != 0) { 250 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; 251 goto out; 252 } 253 /* RSA_verify expects a signature of RSA_size */ 254 modlen = RSA_size(key->rsa); 255 if (len > modlen) { 256 ret = SSH_ERR_KEY_BITS_MISMATCH; 257 goto out; 258 } else if (len < modlen) { 259 diff = modlen - len; 260 osigblob = sigblob; 261 if ((sigblob = realloc(sigblob, modlen)) == NULL) { 262 sigblob = osigblob; /* put it back for clear/free */ 263 ret = SSH_ERR_ALLOC_FAIL; 264 goto out; 265 } 266 memmove(sigblob + diff, sigblob, len); 267 explicit_bzero(sigblob, diff); 268 len = modlen; 269 } 270 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 271 ret = SSH_ERR_INTERNAL_ERROR; 272 goto out; 273 } 274 if ((ret = ssh_digest_memory(hash_alg, data, datalen, 275 digest, sizeof(digest))) != 0) 276 goto out; 277 278 ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, 279 key->rsa); 280 out: 281 freezero(sigblob, len); 282 free(sigtype); 283 sshbuf_free(b); 284 explicit_bzero(digest, sizeof(digest)); 285 return ret; 286 } 287 288 /* 289 * See: 290 * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ 291 * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn 292 */ 293 294 /* 295 * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) 296 * oiw(14) secsig(3) algorithms(2) 26 } 297 */ 298 static const u_char id_sha1[] = { 299 0x30, 0x21, /* type Sequence, length 0x21 (33) */ 300 0x30, 0x09, /* type Sequence, length 0x09 */ 301 0x06, 0x05, /* type OID, length 0x05 */ 302 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ 303 0x05, 0x00, /* NULL */ 304 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ 305 }; 306 307 /* 308 * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html 309 * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) 310 * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) 311 * id-sha256(1) } 312 */ 313 static const u_char id_sha256[] = { 314 0x30, 0x31, /* type Sequence, length 0x31 (49) */ 315 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ 316 0x06, 0x09, /* type OID, length 0x09 */ 317 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */ 318 0x05, 0x00, /* NULL */ 319 0x04, 0x20 /* Octet string, length 0x20 (32), followed by sha256 hash */ 320 }; 321 322 /* 323 * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html 324 * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) 325 * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) 326 * id-sha256(3) } 327 */ 328 static const u_char id_sha512[] = { 329 0x30, 0x51, /* type Sequence, length 0x51 (81) */ 330 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ 331 0x06, 0x09, /* type OID, length 0x09 */ 332 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */ 333 0x05, 0x00, /* NULL */ 334 0x04, 0x40 /* Octet string, length 0x40 (64), followed by sha512 hash */ 335 }; 336 337 static int 338 rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp) 339 { 340 switch (hash_alg) { 341 case SSH_DIGEST_SHA1: 342 *oidp = id_sha1; 343 *oidlenp = sizeof(id_sha1); 344 break; 345 case SSH_DIGEST_SHA256: 346 *oidp = id_sha256; 347 *oidlenp = sizeof(id_sha256); 348 break; 349 case SSH_DIGEST_SHA512: 350 *oidp = id_sha512; 351 *oidlenp = sizeof(id_sha512); 352 break; 353 default: 354 return SSH_ERR_INVALID_ARGUMENT; 355 } 356 return 0; 357 } 358 359 static int 360 openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, 361 u_char *sigbuf, size_t siglen, RSA *rsa) 362 { 363 size_t rsasize = 0, oidlen = 0, hlen = 0; 364 int ret, len, oidmatch, hashmatch; 365 const u_char *oid = NULL; 366 u_char *decrypted = NULL; 367 368 if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0) 369 return ret; 370 ret = SSH_ERR_INTERNAL_ERROR; 371 hlen = ssh_digest_bytes(hash_alg); 372 if (hashlen != hlen) { 373 ret = SSH_ERR_INVALID_ARGUMENT; 374 goto done; 375 } 376 rsasize = RSA_size(rsa); 377 if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || 378 siglen == 0 || siglen > rsasize) { 379 ret = SSH_ERR_INVALID_ARGUMENT; 380 goto done; 381 } 382 if ((decrypted = malloc(rsasize)) == NULL) { 383 ret = SSH_ERR_ALLOC_FAIL; 384 goto done; 385 } 386 if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, 387 RSA_PKCS1_PADDING)) < 0) { 388 ret = SSH_ERR_LIBCRYPTO_ERROR; 389 goto done; 390 } 391 if (len < 0 || (size_t)len != hlen + oidlen) { 392 ret = SSH_ERR_INVALID_FORMAT; 393 goto done; 394 } 395 oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; 396 hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; 397 if (!oidmatch || !hashmatch) { 398 ret = SSH_ERR_SIGNATURE_INVALID; 399 goto done; 400 } 401 ret = 0; 402 done: 403 freezero(decrypted, rsasize); 404 return ret; 405 } 406