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