summaryrefslogtreecommitdiff
path: root/ssh-rsa.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2014-10-07 13:33:15 +0100
committerColin Watson <cjwatson@debian.org>2014-10-07 14:27:30 +0100
commitf0b009aea83e9ff3a50be30f51012099a5143c16 (patch)
tree3825e6f7e3b7ea4481d06ed89aba9a7a95150df5 /ssh-rsa.c
parent47f0bad4330b16ec3bad870fcf9839c196e42c12 (diff)
parent762c062828f5a8f6ed189ed6e44ad38fd92f8b36 (diff)
Merge 6.7p1.
* New upstream release (http://www.openssh.com/txt/release-6.7): - sshd(8): The default set of ciphers and MACs has been altered to remove unsafe algorithms. In particular, CBC ciphers and arcfour* are disabled by default. The full set of algorithms remains available if configured explicitly via the Ciphers and MACs sshd_config options. - ssh(1), sshd(8): Add support for Unix domain socket forwarding. A remote TCP port may be forwarded to a local Unix domain socket and vice versa or both ends may be a Unix domain socket (closes: #236718). - ssh(1), ssh-keygen(1): Add support for SSHFP DNS records for ED25519 key types. - sftp(1): Allow resumption of interrupted uploads. - ssh(1): When rekeying, skip file/DNS lookups of the hostkey if it is the same as the one sent during initial key exchange. - sshd(8): Allow explicit ::1 and 127.0.0.1 forwarding bind addresses when GatewayPorts=no; allows client to choose address family. - sshd(8): Add a sshd_config PermitUserRC option to control whether ~/.ssh/rc is executed, mirroring the no-user-rc authorized_keys option. - ssh(1): Add a %C escape sequence for LocalCommand and ControlPath that expands to a unique identifer based on a hash of the tuple of (local host, remote user, hostname, port). Helps avoid exceeding miserly pathname limits for Unix domain sockets in multiplexing control paths. - sshd(8): Make the "Too many authentication failures" message include the user, source address, port and protocol in a format similar to the authentication success / failure messages. - Use CLOCK_BOOTTIME in preference to CLOCK_MONOTONIC when it is available. It considers time spent suspended, thereby ensuring timeouts (e.g. for expiring agent keys) fire correctly (closes: #734553). - Use prctl() to prevent sftp-server from accessing /proc/self/{mem,maps}. * Restore TCP wrappers support, removed upstream in 6.7. It is true that dropping this reduces preauth attack surface in sshd. On the other hand, this support seems to be quite widely used, and abruptly dropping it (from the perspective of users who don't read openssh-unix-dev) could easily cause more serious problems in practice. It's not entirely clear what the right long-term answer for Debian is, but it at least probably doesn't involve dropping this feature shortly before a freeze. * Replace patch to disable OpenSSL version check with an updated version of Kurt Roeckx's patch from #732940 to just avoid checking the status field.
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}