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