summaryrefslogtreecommitdiff
path: root/ssh-rsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssh-rsa.c')
-rw-r--r--ssh-rsa.c260
1 files changed, 133 insertions, 127 deletions
diff --git a/ssh-rsa.c b/ssh-rsa.c
index c6f25b3ee..fec1953b4 100644
--- a/ssh-rsa.c
+++ b/ssh-rsa.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-rsa.c,v 1.51 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: ssh-rsa.c,v 1.52 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> 3 * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
4 * 4 *
@@ -25,163 +25,167 @@
25#include <stdarg.h> 25#include <stdarg.h>
26#include <string.h> 26#include <string.h>
27 27
28#include "xmalloc.h" 28#include "sshbuf.h"
29#include "log.h"
30#include "buffer.h"
31#include "key.h"
32#include "compat.h" 29#include "compat.h"
33#include "misc.h" 30#include "ssherr.h"
34#include "ssh.h" 31#define SSHKEY_INTERNAL
32#include "sshkey.h"
35#include "digest.h" 33#include "digest.h"
36 34
37static int openssh_RSA_verify(int, u_char *, u_int, u_char *, u_int, RSA *); 35static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *);
38 36
39/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */ 37/* RSASSA-PKCS1-v1_5 (PKCS #1 v2.0 signature) with SHA1 */
40int 38int
41ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, 39ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
42 const u_char *data, u_int datalen) 40 const u_char *data, size_t datalen, u_int compat)
43{ 41{
44 int hash_alg; 42 int hash_alg;
45 u_char digest[SSH_DIGEST_MAX_LENGTH], *sig; 43 u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL;
46 u_int slen, dlen, len; 44 size_t slen;
47 int ok, nid; 45 u_int dlen, len;
48 Buffer b; 46 int nid, ret = SSH_ERR_INTERNAL_ERROR;
47 struct sshbuf *b = NULL;
49 48
50 if (key == NULL || key_type_plain(key->type) != KEY_RSA || 49 if (lenp != NULL)
51 key->rsa == NULL) { 50 *lenp = 0;
52 error("%s: no RSA key", __func__); 51 if (sigp != NULL)
53 return -1; 52 *sigp = NULL;
54 } 53
54 if (key == NULL || key->rsa == NULL ||
55 sshkey_type_plain(key->type) != KEY_RSA)
56 return SSH_ERR_INVALID_ARGUMENT;
57 slen = RSA_size(key->rsa);
58 if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
59 return SSH_ERR_INVALID_ARGUMENT;
55 60
56 /* hash the data */ 61 /* hash the data */
57 hash_alg = SSH_DIGEST_SHA1; 62 hash_alg = SSH_DIGEST_SHA1;
58 nid = NID_sha1; 63 nid = NID_sha1;
59 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 64 if ((dlen = ssh_digest_bytes(hash_alg)) == 0)
60 error("%s: bad hash algorithm %d", __func__, hash_alg); 65 return SSH_ERR_INTERNAL_ERROR;
61 return -1; 66 if ((ret = ssh_digest_memory(hash_alg, data, datalen,
62 } 67 digest, sizeof(digest))) != 0)
63 if (ssh_digest_memory(hash_alg, data, datalen, 68 goto out;
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 69
75 if (ok != 1) { 70 if ((sig = malloc(slen)) == NULL) {
76 int ecode = ERR_get_error(); 71 ret = SSH_ERR_ALLOC_FAIL;
72 goto out;
73 }
77 74
78 error("%s: RSA_sign failed: %s", __func__, 75 if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) {
79 ERR_error_string(ecode, NULL)); 76 ret = SSH_ERR_LIBCRYPTO_ERROR;
80 free(sig); 77 goto out;
81 return -1;
82 } 78 }
83 if (len < slen) { 79 if (len < slen) {
84 u_int diff = slen - len; 80 size_t diff = slen - len;
85 debug("slen %u > len %u", slen, len);
86 memmove(sig + diff, sig, len); 81 memmove(sig + diff, sig, len);
87 explicit_bzero(sig, diff); 82 explicit_bzero(sig, diff);
88 } else if (len > slen) { 83 } else if (len > slen) {
89 error("%s: slen %u slen2 %u", __func__, slen, len); 84 ret = SSH_ERR_INTERNAL_ERROR;
90 free(sig); 85 goto out;
91 return -1;
92 } 86 }
93 /* encode signature */ 87 /* encode signature */
94 buffer_init(&b); 88 if ((b = sshbuf_new()) == NULL) {
95 buffer_put_cstring(&b, "ssh-rsa"); 89 ret = SSH_ERR_ALLOC_FAIL;
96 buffer_put_string(&b, sig, slen); 90 goto out;
97 len = buffer_len(&b); 91 }
92 if ((ret = sshbuf_put_cstring(b, "ssh-rsa")) != 0 ||
93 (ret = sshbuf_put_string(b, sig, slen)) != 0)
94 goto out;
95 len = sshbuf_len(b);
96 if (sigp != NULL) {
97 if ((*sigp = malloc(len)) == NULL) {
98 ret = SSH_ERR_ALLOC_FAIL;
99 goto out;
100 }
101 memcpy(*sigp, sshbuf_ptr(b), len);
102 }
98 if (lenp != NULL) 103 if (lenp != NULL)
99 *lenp = len; 104 *lenp = len;
100 if (sigp != NULL) { 105 ret = 0;
101 *sigp = xmalloc(len); 106 out:
102 memcpy(*sigp, buffer_ptr(&b), len); 107 explicit_bzero(digest, sizeof(digest));
108 if (sig != NULL) {
109 explicit_bzero(sig, slen);
110 free(sig);
103 } 111 }
104 buffer_free(&b); 112 if (b != NULL)
105 explicit_bzero(sig, slen); 113 sshbuf_free(b);
106 free(sig);
107
108 return 0; 114 return 0;
109} 115}
110 116
111int 117int
112ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, 118ssh_rsa_verify(const struct sshkey *key,
113 const u_char *data, u_int datalen) 119 const u_char *signature, size_t signaturelen,
120 const u_char *data, size_t datalen, u_int compat)
114{ 121{
115 Buffer b; 122 char *ktype = NULL;
116 int hash_alg; 123 int hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
117 char *ktype; 124 size_t len, diff, modlen, dlen;
118 u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; 125 struct sshbuf *b = NULL;
119 u_int len, dlen, modlen; 126 u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL;
120 int rlen, ret;
121 127
122 if (key == NULL || key_type_plain(key->type) != KEY_RSA || 128 if (key == NULL || key->rsa == NULL ||
123 key->rsa == NULL) { 129 sshkey_type_plain(key->type) != KEY_RSA ||
124 error("%s: no RSA key", __func__); 130 BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
125 return -1; 131 return SSH_ERR_INVALID_ARGUMENT;
126 }
127 132
128 if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { 133 if ((b = sshbuf_from(signature, signaturelen)) == NULL)
129 error("%s: RSA modulus too small: %d < minimum %d bits", 134 return SSH_ERR_ALLOC_FAIL;
130 __func__, BN_num_bits(key->rsa->n), 135 if (sshbuf_get_cstring(b, &ktype, NULL) != 0) {
131 SSH_RSA_MINIMUM_MODULUS_SIZE); 136 ret = SSH_ERR_INVALID_FORMAT;
132 return -1; 137 goto out;
133 } 138 }
134 buffer_init(&b);
135 buffer_append(&b, signature, signaturelen);
136 ktype = buffer_get_cstring(&b, NULL);
137 if (strcmp("ssh-rsa", ktype) != 0) { 139 if (strcmp("ssh-rsa", ktype) != 0) {
138 error("%s: cannot handle type %s", __func__, ktype); 140 ret = SSH_ERR_KEY_TYPE_MISMATCH;
139 buffer_free(&b); 141 goto out;
140 free(ktype);
141 return -1;
142 } 142 }
143 free(ktype); 143 if (sshbuf_get_string(b, &sigblob, &len) != 0) {
144 sigblob = buffer_get_string(&b, &len); 144 ret = SSH_ERR_INVALID_FORMAT;
145 rlen = buffer_len(&b); 145 goto out;
146 buffer_free(&b); 146 }
147 if (rlen != 0) { 147 if (sshbuf_len(b) != 0) {
148 error("%s: remaining bytes in signature %d", __func__, rlen); 148 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
149 free(sigblob); 149 goto out;
150 return -1;
151 } 150 }
152 /* RSA_verify expects a signature of RSA_size */ 151 /* RSA_verify expects a signature of RSA_size */
153 modlen = RSA_size(key->rsa); 152 modlen = RSA_size(key->rsa);
154 if (len > modlen) { 153 if (len > modlen) {
155 error("%s: len %u > modlen %u", __func__, len, modlen); 154 ret = SSH_ERR_KEY_BITS_MISMATCH;
156 free(sigblob); 155 goto out;
157 return -1;
158 } else if (len < modlen) { 156 } else if (len < modlen) {
159 u_int diff = modlen - len; 157 diff = modlen - len;
160 debug("%s: add padding: modlen %u > len %u", __func__, 158 osigblob = sigblob;
161 modlen, len); 159 if ((sigblob = realloc(sigblob, modlen)) == NULL) {
162 sigblob = xrealloc(sigblob, 1, modlen); 160 sigblob = osigblob; /* put it back for clear/free */
161 ret = SSH_ERR_ALLOC_FAIL;
162 goto out;
163 }
163 memmove(sigblob + diff, sigblob, len); 164 memmove(sigblob + diff, sigblob, len);
164 explicit_bzero(sigblob, diff); 165 explicit_bzero(sigblob, diff);
165 len = modlen; 166 len = modlen;
166 } 167 }
167 /* hash the data */
168 hash_alg = SSH_DIGEST_SHA1; 168 hash_alg = SSH_DIGEST_SHA1;
169 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 169 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
170 error("%s: bad hash algorithm %d", __func__, hash_alg); 170 ret = SSH_ERR_INTERNAL_ERROR;
171 return -1; 171 goto out;
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 } 172 }
173 if ((ret = ssh_digest_memory(hash_alg, data, datalen,
174 digest, sizeof(digest))) != 0)
175 goto out;
178 176
179 ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, 177 ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len,
180 key->rsa); 178 key->rsa);
179 out:
180 if (sigblob != NULL) {
181 explicit_bzero(sigblob, len);
182 free(sigblob);
183 }
184 if (ktype != NULL)
185 free(ktype);
186 if (b != NULL)
187 sshbuf_free(b);
181 explicit_bzero(digest, sizeof(digest)); 188 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; 189 return ret;
186} 190}
187 191
@@ -204,15 +208,15 @@ static const u_char id_sha1[] = {
204}; 208};
205 209
206static int 210static int
207openssh_RSA_verify(int hash_alg, u_char *hash, u_int hashlen, 211openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen,
208 u_char *sigbuf, u_int siglen, RSA *rsa) 212 u_char *sigbuf, size_t siglen, RSA *rsa)
209{ 213{
210 u_int ret, rsasize, oidlen = 0, hlen = 0; 214 size_t ret, rsasize = 0, oidlen = 0, hlen = 0;
211 int len, oidmatch, hashmatch; 215 int len, oidmatch, hashmatch;
212 const u_char *oid = NULL; 216 const u_char *oid = NULL;
213 u_char *decrypted = NULL; 217 u_char *decrypted = NULL;
214 218
215 ret = 0; 219 ret = SSH_ERR_INTERNAL_ERROR;
216 switch (hash_alg) { 220 switch (hash_alg) {
217 case SSH_DIGEST_SHA1: 221 case SSH_DIGEST_SHA1:
218 oid = id_sha1; 222 oid = id_sha1;
@@ -223,37 +227,39 @@ openssh_RSA_verify(int hash_alg, u_char *hash, u_int hashlen,
223 goto done; 227 goto done;
224 } 228 }
225 if (hashlen != hlen) { 229 if (hashlen != hlen) {
226 error("bad hashlen"); 230 ret = SSH_ERR_INVALID_ARGUMENT;
227 goto done; 231 goto done;
228 } 232 }
229 rsasize = RSA_size(rsa); 233 rsasize = RSA_size(rsa);
230 if (siglen == 0 || siglen > rsasize) { 234 if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM ||
231 error("bad siglen"); 235 siglen == 0 || siglen > rsasize) {
236 ret = SSH_ERR_INVALID_ARGUMENT;
237 goto done;
238 }
239 if ((decrypted = malloc(rsasize)) == NULL) {
240 ret = SSH_ERR_ALLOC_FAIL;
232 goto done; 241 goto done;
233 } 242 }
234 decrypted = xmalloc(rsasize);
235 if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, 243 if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
236 RSA_PKCS1_PADDING)) < 0) { 244 RSA_PKCS1_PADDING)) < 0) {
237 error("RSA_public_decrypt failed: %s", 245 ret = SSH_ERR_LIBCRYPTO_ERROR;
238 ERR_error_string(ERR_get_error(), NULL));
239 goto done; 246 goto done;
240 } 247 }
241 if (len < 0 || (u_int)len != hlen + oidlen) { 248 if (len < 0 || (size_t)len != hlen + oidlen) {
242 error("bad decrypted len: %d != %d + %d", len, hlen, oidlen); 249 ret = SSH_ERR_INVALID_FORMAT;
243 goto done; 250 goto done;
244 } 251 }
245 oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; 252 oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
246 hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; 253 hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
247 if (!oidmatch) { 254 if (!oidmatch || !hashmatch) {
248 error("oid mismatch"); 255 ret = SSH_ERR_SIGNATURE_INVALID;
249 goto done;
250 }
251 if (!hashmatch) {
252 error("hash mismatch");
253 goto done; 256 goto done;
254 } 257 }
255 ret = 1; 258 ret = 0;
256done: 259done:
257 free(decrypted); 260 if (decrypted) {
261 explicit_bzero(decrypted, rsasize);
262 free(decrypted);
263 }
258 return ret; 264 return ret;
259} 265}