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