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