summaryrefslogtreecommitdiff
path: root/ssh-ecdsa.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-ecdsa.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-ecdsa.c')
-rw-r--r--ssh-ecdsa.c232
1 files changed, 123 insertions, 109 deletions
diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c
index 551c9c460..1119db045 100644
--- a/ssh-ecdsa.c
+++ b/ssh-ecdsa.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-ecdsa.c,v 1.10 2014/02/03 23:28:00 djm Exp $ */ 1/* $OpenBSD: ssh-ecdsa.c,v 1.11 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 * Copyright (c) 2010 Damien Miller. All rights reserved. 4 * Copyright (c) 2010 Damien Miller. All rights reserved.
@@ -37,141 +37,155 @@
37 37
38#include <string.h> 38#include <string.h>
39 39
40#include "xmalloc.h" 40#include "sshbuf.h"
41#include "buffer.h" 41#include "ssherr.h"
42#include "compat.h"
43#include "log.h"
44#include "key.h"
45#include "digest.h" 42#include "digest.h"
43#define SSHKEY_INTERNAL
44#include "sshkey.h"
46 45
46/* ARGSUSED */
47int 47int
48ssh_ecdsa_sign(const Key *key, u_char **sigp, u_int *lenp, 48ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
49 const u_char *data, u_int datalen) 49 const u_char *data, size_t datalen, u_int compat)
50{ 50{
51 ECDSA_SIG *sig; 51 ECDSA_SIG *sig = NULL;
52 int hash_alg; 52 int hash_alg;
53 u_char digest[SSH_DIGEST_MAX_LENGTH]; 53 u_char digest[SSH_DIGEST_MAX_LENGTH];
54 u_int len, dlen; 54 size_t len, dlen;
55 Buffer b, bb; 55 struct sshbuf *b = NULL, *bb = NULL;
56 int ret = SSH_ERR_INTERNAL_ERROR;
56 57
57 if (key == NULL || key_type_plain(key->type) != KEY_ECDSA || 58 if (lenp != NULL)
58 key->ecdsa == NULL) { 59 *lenp = 0;
59 error("%s: no ECDSA key", __func__); 60 if (sigp != NULL)
60 return -1; 61 *sigp = NULL;
62
63 if (key == NULL || key->ecdsa == NULL ||
64 sshkey_type_plain(key->type) != KEY_ECDSA)
65 return SSH_ERR_INVALID_ARGUMENT;
66
67 if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 ||
68 (dlen = ssh_digest_bytes(hash_alg)) == 0)
69 return SSH_ERR_INTERNAL_ERROR;
70 if ((ret = ssh_digest_memory(hash_alg, data, datalen,
71 digest, sizeof(digest))) != 0)
72 goto out;
73
74 if ((sig = ECDSA_do_sign(digest, dlen, key->ecdsa)) == NULL) {
75 ret = SSH_ERR_LIBCRYPTO_ERROR;
76 goto out;
61 } 77 }
62 78
63 hash_alg = key_ec_nid_to_hash_alg(key->ecdsa_nid); 79 if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) {
64 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { 80 ret = SSH_ERR_ALLOC_FAIL;
65 error("%s: bad hash algorithm %d", __func__, hash_alg); 81 goto out;
66 return -1;
67 }
68 if (ssh_digest_memory(hash_alg, data, datalen,
69 digest, sizeof(digest)) != 0) {
70 error("%s: digest_memory failed", __func__);
71 return -1;
72 } 82 }
73 83 if ((ret = sshbuf_put_bignum2(bb, sig->r)) != 0 ||
74 sig = ECDSA_do_sign(digest, dlen, key->ecdsa); 84 (ret = sshbuf_put_bignum2(bb, sig->s)) != 0)
75 explicit_bzero(digest, sizeof(digest)); 85 goto out;
76 86 if ((ret = sshbuf_put_cstring(b, sshkey_ssh_name_plain(key))) != 0 ||
77 if (sig == NULL) { 87 (ret = sshbuf_put_stringb(b, bb)) != 0)
78 error("%s: sign failed", __func__); 88 goto out;
79 return -1; 89 len = sshbuf_len(b);
90 if (sigp != NULL) {
91 if ((*sigp = malloc(len)) == NULL) {
92 ret = SSH_ERR_ALLOC_FAIL;
93 goto out;
94 }
95 memcpy(*sigp, sshbuf_ptr(b), len);
80 } 96 }
81
82 buffer_init(&bb);
83 buffer_put_bignum2(&bb, sig->r);
84 buffer_put_bignum2(&bb, sig->s);
85 ECDSA_SIG_free(sig);
86
87 buffer_init(&b);
88 buffer_put_cstring(&b, key_ssh_name_plain(key));
89 buffer_put_string(&b, buffer_ptr(&bb), buffer_len(&bb));
90 buffer_free(&bb);
91 len = buffer_len(&b);
92 if (lenp != NULL) 97 if (lenp != NULL)
93 *lenp = len; 98 *lenp = len;
94 if (sigp != NULL) { 99 ret = 0;
95 *sigp = xmalloc(len); 100 out:
96 memcpy(*sigp, buffer_ptr(&b), len); 101 explicit_bzero(digest, sizeof(digest));
97 } 102 if (b != NULL)
98 buffer_free(&b); 103 sshbuf_free(b);
99 104 if (bb != NULL)
100 return 0; 105 sshbuf_free(bb);
106 if (sig != NULL)
107 ECDSA_SIG_free(sig);
108 return ret;
101} 109}
110
111/* ARGSUSED */
102int 112int
103ssh_ecdsa_verify(const Key *key, const u_char *signature, u_int signaturelen, 113ssh_ecdsa_verify(const struct sshkey *key,
104 const u_char *data, u_int datalen) 114 const u_char *signature, size_t signaturelen,
115 const u_char *data, size_t datalen, u_int compat)
105{ 116{
106 ECDSA_SIG *sig; 117 ECDSA_SIG *sig = NULL;
107 int hash_alg; 118 int hash_alg;
108 u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; 119 u_char digest[SSH_DIGEST_MAX_LENGTH];
109 u_int len, dlen; 120 size_t dlen;
110 int rlen, ret; 121 int ret = SSH_ERR_INTERNAL_ERROR;
111 Buffer b, bb; 122 struct sshbuf *b = NULL, *sigbuf = NULL;
112 char *ktype; 123 char *ktype = NULL;
113 124
114 if (key == NULL || key_type_plain(key->type) != KEY_ECDSA || 125 if (key == NULL || key->ecdsa == NULL ||
115 key->ecdsa == NULL) { 126 sshkey_type_plain(key->type) != KEY_ECDSA)
116 error("%s: no ECDSA key", __func__); 127 return SSH_ERR_INVALID_ARGUMENT;
117 return -1; 128
118 } 129 if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 ||
130 (dlen = ssh_digest_bytes(hash_alg)) == 0)
131 return SSH_ERR_INTERNAL_ERROR;
119 132
120 /* fetch signature */ 133 /* fetch signature */
121 buffer_init(&b); 134 if ((b = sshbuf_from(signature, signaturelen)) == NULL)
122 buffer_append(&b, signature, signaturelen); 135 return SSH_ERR_ALLOC_FAIL;
123 ktype = buffer_get_string(&b, NULL); 136 if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
124 if (strcmp(key_ssh_name_plain(key), ktype) != 0) { 137 sshbuf_froms(b, &sigbuf) != 0) {
125 error("%s: cannot handle type %s", __func__, ktype); 138 ret = SSH_ERR_INVALID_FORMAT;
126 buffer_free(&b); 139 goto out;
127 free(ktype);
128 return -1;
129 } 140 }
130 free(ktype); 141 if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) {
131 sigblob = buffer_get_string(&b, &len); 142 ret = SSH_ERR_KEY_TYPE_MISMATCH;
132 rlen = buffer_len(&b); 143 goto out;
133 buffer_free(&b); 144 }
134 if (rlen != 0) { 145 if (sshbuf_len(b) != 0) {
135 error("%s: remaining bytes in signature %d", __func__, rlen); 146 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
136 free(sigblob); 147 goto out;
137 return -1;
138 } 148 }
139 149
140 /* parse signature */ 150 /* parse signature */
141 if ((sig = ECDSA_SIG_new()) == NULL) 151 if ((sig = ECDSA_SIG_new()) == NULL) {
142 fatal("%s: ECDSA_SIG_new failed", __func__); 152 ret = SSH_ERR_ALLOC_FAIL;
143 153 goto out;
144 buffer_init(&bb); 154 }
145 buffer_append(&bb, sigblob, len); 155 if (sshbuf_get_bignum2(sigbuf, sig->r) != 0 ||
146 buffer_get_bignum2(&bb, sig->r); 156 sshbuf_get_bignum2(sigbuf, sig->s) != 0) {
147 buffer_get_bignum2(&bb, sig->s); 157 ret = SSH_ERR_INVALID_FORMAT;
148 if (buffer_len(&bb) != 0) 158 goto out;
149 fatal("%s: remaining bytes in inner sigblob", __func__); 159 }
150 buffer_free(&bb); 160 if (sshbuf_len(sigbuf) != 0) {
151 161 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
152 /* clean up */ 162 goto out;
153 explicit_bzero(sigblob, len);
154 free(sigblob);
155
156 /* hash the data */
157 hash_alg = key_ec_nid_to_hash_alg(key->ecdsa_nid);
158 if ((dlen = ssh_digest_bytes(hash_alg)) == 0) {
159 error("%s: bad hash algorithm %d", __func__, hash_alg);
160 return -1;
161 } 163 }
162 if (ssh_digest_memory(hash_alg, data, datalen, 164 if ((ret = ssh_digest_memory(hash_alg, data, datalen,
163 digest, sizeof(digest)) != 0) { 165 digest, sizeof(digest))) != 0)
164 error("%s: digest_memory failed", __func__); 166 goto out;
165 return -1; 167
168 switch (ECDSA_do_verify(digest, dlen, sig, key->ecdsa)) {
169 case 1:
170 ret = 0;
171 break;
172 case 0:
173 ret = SSH_ERR_SIGNATURE_INVALID;
174 goto out;
175 default:
176 ret = SSH_ERR_LIBCRYPTO_ERROR;
177 goto out;
166 } 178 }
167 179
168 ret = ECDSA_do_verify(digest, dlen, sig, key->ecdsa); 180 out:
169 explicit_bzero(digest, sizeof(digest)); 181 explicit_bzero(digest, sizeof(digest));
170 182 if (sigbuf != NULL)
171 ECDSA_SIG_free(sig); 183 sshbuf_free(sigbuf);
172 184 if (b != NULL)
173 debug("%s: signature %s", __func__, 185 sshbuf_free(b);
174 ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); 186 if (sig != NULL)
187 ECDSA_SIG_free(sig);
188 free(ktype);
175 return ret; 189 return ret;
176} 190}
177 191