1 /* $OpenBSD: ssh-rsa.c,v 1.51 2014/02/02 03:44:31 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 "xmalloc.h" 26 #include "log.h" 27 #include "buffer.h" 28 #include "key.h" 29 #include "compat.h" 30 #include "misc.h" 31 #include "ssh.h" 32 #include "digest.h" 33 34 static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *); 35 36 /* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ 37 int 38 ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, 39 const u_char *data, u_int datalen) 40 { 41 int hash_alg; 42 u_char digest[SSH_DIGEST_MAX_LENGTH], *sig; 43 u_int slen, dlen, len; 44 int ok, nid; 45 Buffer b; 46 47 if (key == NULL || key_type_plain(key->type) != KEY_RSA || 48 key->rsa == NULL) { 49 error("%s: no RSA key", __func__); 50 return -1; 51 } 52 53 /* hash the data */ 54 hash_alg = SSH_DIGEST_SHA1; 55 nid = NID_sha1; 56 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 57 error("%s: bad hash algorithm %d", __func__, hash_alg); 58 return -1; 59 } 60 if (ssh_digest_memory(hash_alg, data, datalen, 61 digest, sizeof(digest)) != 0) { 62 error("%s: ssh_digest_memory failed", __func__); 63 return -1; 64 } 65 66 slen = RSA_size(key->rsa); 67 sig = xmalloc(slen); 68 69 ok = RSA_sign(nid, digest, dlen, sig, &len, key->rsa); 70 explicit_bzero(digest, sizeof(digest)); 71 72 if (ok != 1) { 73 int ecode = ERR_get_error(); 74 75 error("%s: RSA_sign failed: %s", __func__, 76 ERR_error_string(ecode, NULL)); 77 free(sig); 78 return -1; 79 } 80 if (len < slen) { 81 u_int diff = slen - len; 82 debug("slen %u > len %u", slen, len); 83 memmove(sig + diff, sig, len); 84 explicit_bzero(sig, diff); 85 } else if (len > slen) { 86 error("%s: slen %u slen2 %u", __func__, slen, len); 87 free(sig); 88 return -1; 89 } 90 /* encode signature */ 91 buffer_init(&b); 92 buffer_put_cstring(&b, "ssh-rsa"); 93 buffer_put_string(&b, sig, slen); 94 len = buffer_len(&b); 95 if (lenp != NULL) 96 *lenp = len; 97 if (sigp != NULL) { 98 *sigp = xmalloc(len); 99 memcpy(*sigp, buffer_ptr(&b), len); 100 } 101 buffer_free(&b); 102 explicit_bzero(sig, slen); 103 free(sig); 104 105 return 0; 106 } 107 108 int 109 ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, 110 const u_char *data, u_int datalen) 111 { 112 Buffer b; 113 int hash_alg; 114 char *ktype; 115 u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; 116 u_int len, dlen, modlen; 117 int rlen, ret; 118 119 if (key == NULL || key_type_plain(key->type) != KEY_RSA || 120 key->rsa == NULL) { 121 error("%s: no RSA key", __func__); 122 return -1; 123 } 124 125 if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { 126 error("%s: RSA modulus too small: %d < minimum %d bits", 127 __func__, BN_num_bits(key->rsa->n), 128 SSH_RSA_MINIMUM_MODULUS_SIZE); 129 return -1; 130 } 131 buffer_init(&b); 132 buffer_append(&b, signature, signaturelen); 133 ktype = buffer_get_cstring(&b, NULL); 134 if (strcmp("ssh-rsa", ktype) != 0) { 135 error("%s: cannot handle type %s", __func__, ktype); 136 buffer_free(&b); 137 free(ktype); 138 return -1; 139 } 140 free(ktype); 141 sigblob = buffer_get_string(&b, &len); 142 rlen = buffer_len(&b); 143 buffer_free(&b); 144 if (rlen != 0) { 145 error("%s: remaining bytes in signature %d", __func__, rlen); 146 free(sigblob); 147 return -1; 148 } 149 /* RSA_verify expects a signature of RSA_size */ 150 modlen = RSA_size(key->rsa); 151 if (len > modlen) { 152 error("%s: len %u > modlen %u", __func__, len, modlen); 153 free(sigblob); 154 return -1; 155 } else if (len < modlen) { 156 u_int diff = modlen - len; 157 debug("%s: add padding: modlen %u > len %u", __func__, 158 modlen, len); 159 sigblob = xrealloc(sigblob, 1, modlen); 160 memmove(sigblob + diff, sigblob, len); 161 explicit_bzero(sigblob, diff); 162 len = modlen; 163 } 164 /* hash the data */ 165 hash_alg = SSH_DIGEST_SHA1; 166 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 167 error("%s: bad hash algorithm %d", __func__, hash_alg); 168 return -1; 169 } 170 if (ssh_digest_memory(hash_alg, data, datalen, 171 digest, sizeof(digest)) != 0) { 172 error("%s: ssh_digest_memory failed", __func__); 173 return -1; 174 } 175 176 ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, 177 key->rsa); 178 explicit_bzero(digest, sizeof(digest)); 179 explicit_bzero(sigblob, len); 180 free(sigblob); 181 debug("%s: signature %scorrect", __func__, (ret == 0) ? "in" : ""); 182 return ret; 183 } 184 185 /* 186 * See: 187 * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ 188 * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn 189 */ 190 /* 191 * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) 192 * oiw(14) secsig(3) algorithms(2) 26 } 193 */ 194 static const u_char id_sha1[] = { 195 0x30, 0x21, /* type Sequence, length 0x21 (33) */ 196 0x30, 0x09, /* type Sequence, length 0x09 */ 197 0x06, 0x05, /* type OID, length 0x05 */ 198 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ 199 0x05, 0x00, /* NULL */ 200 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ 201 }; 202 203 static int 204 openssh_RSA_verify(int hash_alg, u_char *hash, u_int hashlen, 205 u_char *sigbuf, u_int siglen, RSA *rsa) 206 { 207 u_int ret, rsasize, oidlen = 0, hlen = 0; 208 int len, oidmatch, hashmatch; 209 const u_char *oid = NULL; 210 u_char *decrypted = NULL; 211 212 ret = 0; 213 switch (hash_alg) { 214 case SSH_DIGEST_SHA1: 215 oid = id_sha1; 216 oidlen = sizeof(id_sha1); 217 hlen = 20; 218 break; 219 default: 220 goto done; 221 } 222 if (hashlen != hlen) { 223 error("bad hashlen"); 224 goto done; 225 } 226 rsasize = RSA_size(rsa); 227 if (siglen == 0 || siglen > rsasize) { 228 error("bad siglen"); 229 goto done; 230 } 231 decrypted = xmalloc(rsasize); 232 if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, 233 RSA_PKCS1_PADDING)) < 0) { 234 error("RSA_public_decrypt failed: %s", 235 ERR_error_string(ERR_get_error(), NULL)); 236 goto done; 237 } 238 if (len < 0 || (u_int)len != hlen + oidlen) { 239 error("bad decrypted len: %d != %d + %d", len, hlen, oidlen); 240 goto done; 241 } 242 oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; 243 hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; 244 if (!oidmatch) { 245 error("oid mismatch"); 246 goto done; 247 } 248 if (!hashmatch) { 249 error("hash mismatch"); 250 goto done; 251 } 252 ret = 1; 253 done: 254 free(decrypted); 255 return ret; 256 } 257