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