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