summaryrefslogtreecommitdiff
path: root/ssh-dss.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-dss.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-dss.c')
-rw-r--r--ssh-dss.c238
1 files changed, 134 insertions, 104 deletions
diff --git a/ssh-dss.c b/ssh-dss.c
index 6b4abcb7d..9643d90d8 100644
--- a/ssh-dss.c
+++ b/ssh-dss.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-dss.c,v 1.31 2014/02/02 03:44:31 djm Exp $ */ 1/* $OpenBSD: ssh-dss.c,v 1.32 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -28,162 +28,192 @@
28#include <sys/types.h> 28#include <sys/types.h>
29 29
30#include <openssl/bn.h> 30#include <openssl/bn.h>
31#include <openssl/dsa.h>
31#include <openssl/evp.h> 32#include <openssl/evp.h>
32 33
33#include <stdarg.h> 34#include <stdarg.h>
34#include <string.h> 35#include <string.h>
35 36
36#include "xmalloc.h" 37#include "sshbuf.h"
37#include "buffer.h"
38#include "compat.h" 38#include "compat.h"
39#include "log.h" 39#include "ssherr.h"
40#include "key.h"
41#include "digest.h" 40#include "digest.h"
41#define SSHKEY_INTERNAL
42#include "sshkey.h"
42 43
43#define INTBLOB_LEN 20 44#define INTBLOB_LEN 20
44#define SIGBLOB_LEN (2*INTBLOB_LEN) 45#define SIGBLOB_LEN (2*INTBLOB_LEN)
45 46
46int 47int
47ssh_dss_sign(const Key *key, u_char **sigp, u_int *lenp, 48ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
48 const u_char *data, u_int datalen) 49 const u_char *data, size_t datalen, u_int compat)
49{ 50{
50 DSA_SIG *sig; 51 DSA_SIG *sig = NULL;
51 u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; 52 u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN];
52 u_int rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 53 size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
53 Buffer b; 54 struct sshbuf *b = NULL;
54 55 int ret = SSH_ERR_INVALID_ARGUMENT;
55 if (key == NULL || key_type_plain(key->type) != KEY_DSA || 56
56 key->dsa == NULL) { 57 if (lenp != NULL)
57 error("%s: no DSA key", __func__); 58 *lenp = 0;
58 return -1; 59 if (sigp != NULL)
59 } 60 *sigp = NULL;
60 61
61 if (ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 62 if (key == NULL || key->dsa == NULL ||
62 digest, sizeof(digest)) != 0) { 63 sshkey_type_plain(key->type) != KEY_DSA)
63 error("%s: ssh_digest_memory failed", __func__); 64 return SSH_ERR_INVALID_ARGUMENT;
64 return -1; 65 if (dlen == 0)
65 } 66 return SSH_ERR_INTERNAL_ERROR;
66 67
67 sig = DSA_do_sign(digest, dlen, key->dsa); 68 if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
68 explicit_bzero(digest, sizeof(digest)); 69 digest, sizeof(digest))) != 0)
69 70 goto out;
70 if (sig == NULL) { 71
71 error("ssh_dss_sign: sign failed"); 72 if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) {
72 return -1; 73 ret = SSH_ERR_LIBCRYPTO_ERROR;
74 goto out;
73 } 75 }
74 76
75 rlen = BN_num_bytes(sig->r); 77 rlen = BN_num_bytes(sig->r);
76 slen = BN_num_bytes(sig->s); 78 slen = BN_num_bytes(sig->s);
77 if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { 79 if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
78 error("bad sig size %u %u", rlen, slen); 80 ret = SSH_ERR_INTERNAL_ERROR;
79 DSA_SIG_free(sig); 81 goto out;
80 return -1;
81 } 82 }
82 explicit_bzero(sigblob, SIGBLOB_LEN); 83 explicit_bzero(sigblob, SIGBLOB_LEN);
83 BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen); 84 BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
84 BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen); 85 BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen);
85 DSA_SIG_free(sig);
86 86
87 if (datafellows & SSH_BUG_SIGBLOB) { 87 if (compat & SSH_BUG_SIGBLOB) {
88 if (lenp != NULL)
89 *lenp = SIGBLOB_LEN;
90 if (sigp != NULL) { 88 if (sigp != NULL) {
91 *sigp = xmalloc(SIGBLOB_LEN); 89 if ((*sigp = malloc(SIGBLOB_LEN)) == NULL) {
90 ret = SSH_ERR_ALLOC_FAIL;
91 goto out;
92 }
92 memcpy(*sigp, sigblob, SIGBLOB_LEN); 93 memcpy(*sigp, sigblob, SIGBLOB_LEN);
93 } 94 }
95 if (lenp != NULL)
96 *lenp = SIGBLOB_LEN;
97 ret = 0;
94 } else { 98 } else {
95 /* ietf-drafts */ 99 /* ietf-drafts */
96 buffer_init(&b); 100 if ((b = sshbuf_new()) == NULL) {
97 buffer_put_cstring(&b, "ssh-dss"); 101 ret = SSH_ERR_ALLOC_FAIL;
98 buffer_put_string(&b, sigblob, SIGBLOB_LEN); 102 goto out;
99 len = buffer_len(&b); 103 }
100 if (lenp != NULL) 104 if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 ||
101 *lenp = len; 105 (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0)
106 goto out;
107 len = sshbuf_len(b);
102 if (sigp != NULL) { 108 if (sigp != NULL) {
103 *sigp = xmalloc(len); 109 if ((*sigp = malloc(len)) == NULL) {
104 memcpy(*sigp, buffer_ptr(&b), len); 110 ret = SSH_ERR_ALLOC_FAIL;
111 goto out;
112 }
113 memcpy(*sigp, sshbuf_ptr(b), len);
105 } 114 }
106 buffer_free(&b); 115 if (lenp != NULL)
116 *lenp = len;
117 ret = 0;
107 } 118 }
108 return 0; 119 out:
120 explicit_bzero(digest, sizeof(digest));
121 if (sig != NULL)
122 DSA_SIG_free(sig);
123 if (b != NULL)
124 sshbuf_free(b);
125 return ret;
109} 126}
127
110int 128int
111ssh_dss_verify(const Key *key, const u_char *signature, u_int signaturelen, 129ssh_dss_verify(const struct sshkey *key,
112 const u_char *data, u_int datalen) 130 const u_char *signature, size_t signaturelen,
131 const u_char *data, size_t datalen, u_int compat)
113{ 132{
114 DSA_SIG *sig; 133 DSA_SIG *sig = NULL;
115 u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; 134 u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL;
116 u_int len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 135 size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
117 int rlen, ret; 136 int ret = SSH_ERR_INTERNAL_ERROR;
118 Buffer b; 137 struct sshbuf *b = NULL;
119 138 char *ktype = NULL;
120 if (key == NULL || key_type_plain(key->type) != KEY_DSA || 139
121 key->dsa == NULL) { 140 if (key == NULL || key->dsa == NULL ||
122 error("%s: no DSA key", __func__); 141 sshkey_type_plain(key->type) != KEY_DSA)
123 return -1; 142 return SSH_ERR_INVALID_ARGUMENT;
124 } 143 if (dlen == 0)
144 return SSH_ERR_INTERNAL_ERROR;
125 145
126 /* fetch signature */ 146 /* fetch signature */
127 if (datafellows & SSH_BUG_SIGBLOB) { 147 if (compat & SSH_BUG_SIGBLOB) {
128 sigblob = xmalloc(signaturelen); 148 if ((sigblob = malloc(signaturelen)) == NULL)
149 return SSH_ERR_ALLOC_FAIL;
129 memcpy(sigblob, signature, signaturelen); 150 memcpy(sigblob, signature, signaturelen);
130 len = signaturelen; 151 len = signaturelen;
131 } else { 152 } else {
132 /* ietf-drafts */ 153 /* ietf-drafts */
133 char *ktype; 154 if ((b = sshbuf_from(signature, signaturelen)) == NULL)
134 buffer_init(&b); 155 return SSH_ERR_ALLOC_FAIL;
135 buffer_append(&b, signature, signaturelen); 156 if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
136 ktype = buffer_get_cstring(&b, NULL); 157 sshbuf_get_string(b, &sigblob, &len) != 0) {
158 ret = SSH_ERR_INVALID_FORMAT;
159 goto out;
160 }
137 if (strcmp("ssh-dss", ktype) != 0) { 161 if (strcmp("ssh-dss", ktype) != 0) {
138 error("%s: cannot handle type %s", __func__, ktype); 162 ret = SSH_ERR_KEY_TYPE_MISMATCH;
139 buffer_free(&b); 163 goto out;
140 free(ktype);
141 return -1;
142 } 164 }
143 free(ktype); 165 if (sshbuf_len(b) != 0) {
144 sigblob = buffer_get_string(&b, &len); 166 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
145 rlen = buffer_len(&b); 167 goto out;
146 buffer_free(&b);
147 if (rlen != 0) {
148 error("%s: remaining bytes in signature %d",
149 __func__, rlen);
150 free(sigblob);
151 return -1;
152 } 168 }
153 } 169 }
154 170
155 if (len != SIGBLOB_LEN) { 171 if (len != SIGBLOB_LEN) {
156 fatal("bad sigbloblen %u != SIGBLOB_LEN", len); 172 ret = SSH_ERR_INVALID_FORMAT;
173 goto out;
157 } 174 }
158 175
159 /* parse signature */ 176 /* parse signature */
160 if ((sig = DSA_SIG_new()) == NULL) 177 if ((sig = DSA_SIG_new()) == NULL ||
161 fatal("%s: DSA_SIG_new failed", __func__); 178 (sig->r = BN_new()) == NULL ||
162 if ((sig->r = BN_new()) == NULL) 179 (sig->s = BN_new()) == NULL) {
163 fatal("%s: BN_new failed", __func__); 180 ret = SSH_ERR_ALLOC_FAIL;
164 if ((sig->s = BN_new()) == NULL) 181 goto out;
165 fatal("ssh_dss_verify: BN_new failed"); 182 }
166 if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) || 183 if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) ||
167 (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) 184 (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) {
168 fatal("%s: BN_bin2bn failed", __func__); 185 ret = SSH_ERR_LIBCRYPTO_ERROR;
169 186 goto out;
170 /* clean up */ 187 }
171 explicit_bzero(sigblob, len);
172 free(sigblob);
173 188
174 /* sha1 the data */ 189 /* sha1 the data */
175 if (ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 190 if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
176 digest, sizeof(digest)) != 0) { 191 digest, sizeof(digest))) != 0)
177 error("%s: digest_memory failed", __func__); 192 goto out;
178 return -1; 193
194 switch (DSA_do_verify(digest, dlen, sig, key->dsa)) {
195 case 1:
196 ret = 0;
197 break;
198 case 0:
199 ret = SSH_ERR_SIGNATURE_INVALID;
200 goto out;
201 default:
202 ret = SSH_ERR_LIBCRYPTO_ERROR;
203 goto out;
179 } 204 }
180 205
181 ret = DSA_do_verify(digest, dlen, sig, key->dsa); 206 out:
182 explicit_bzero(digest, sizeof(digest)); 207 explicit_bzero(digest, sizeof(digest));
183 208 if (sig != NULL)
184 DSA_SIG_free(sig); 209 DSA_SIG_free(sig);
185 210 if (b != NULL)
186 debug("%s: signature %s", __func__, 211 sshbuf_free(b);
187 ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); 212 if (ktype != NULL)
213 free(ktype);
214 if (sigblob != NULL) {
215 explicit_bzero(sigblob, len);
216 free(sigblob);
217 }
188 return ret; 218 return ret;
189} 219}