summaryrefslogtreecommitdiff
path: root/ssh-dss.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2014-07-02 15:28:02 +1000
committerDamien Miller <djm@mindrot.org>2014-07-02 15:28:02 +1000
commit8668706d0f52654fe64c0ca41a96113aeab8d2b8 (patch)
tree73e78e1ea3d39206e39870bbe0af17d6c430fb51 /ssh-dss.c
parent2cd7929250cf9e9f658d70dcd452f529ba08c942 (diff)
- djm@cvs.openbsd.org 2014/06/24 01:13:21
[Makefile.in auth-bsdauth.c auth-chall.c auth-options.c auth-rsa.c [auth2-none.c auth2-pubkey.c authfile.c authfile.h cipher-3des1.c [cipher-chachapoly.c cipher-chachapoly.h cipher.c cipher.h [digest-libc.c digest-openssl.c digest.h dns.c entropy.c hmac.h [hostfile.c key.c key.h krl.c monitor.c packet.c rsa.c rsa.h [ssh-add.c ssh-agent.c ssh-dss.c ssh-ecdsa.c ssh-ed25519.c [ssh-keygen.c ssh-pkcs11-client.c ssh-pkcs11-helper.c ssh-pkcs11.c [ssh-rsa.c sshbuf-misc.c sshbuf.h sshconnect.c sshconnect1.c [sshconnect2.c sshd.c sshkey.c sshkey.h [openbsd-compat/openssl-compat.c openbsd-compat/openssl-compat.h] New key API: refactor key-related functions to be more library-like, existing API is offered as a set of wrappers. with and ok markus@ Thanks also to Ben Hawkes, David Tomaschik, Ivan Fratric, Matthew Dempsky and Ron Bowes for a detailed review a few months ago. NB. This commit also removes portable OpenSSH support for OpenSSL <0.9.8e.
Diffstat (limited to 'ssh-dss.c')
-rw-r--r--ssh-dss.c237
1 files changed, 133 insertions, 104 deletions
diff --git a/ssh-dss.c b/ssh-dss.c
index 6b4abcb7d..02d1ec2d6 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 *
@@ -33,157 +33,186 @@
33#include <stdarg.h> 33#include <stdarg.h>
34#include <string.h> 34#include <string.h>
35 35
36#include "xmalloc.h" 36#include "sshbuf.h"
37#include "buffer.h"
38#include "compat.h" 37#include "compat.h"
39#include "log.h" 38#include "ssherr.h"
40#include "key.h"
41#include "digest.h" 39#include "digest.h"
40#define SSHKEY_INTERNAL
41#include "sshkey.h"
42 42
43#define INTBLOB_LEN 20 43#define INTBLOB_LEN 20
44#define SIGBLOB_LEN (2*INTBLOB_LEN) 44#define SIGBLOB_LEN (2*INTBLOB_LEN)
45 45
46int 46int
47ssh_dss_sign(const Key *key, u_char **sigp, u_int *lenp, 47ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
48 const u_char *data, u_int datalen) 48 const u_char *data, size_t datalen, u_int compat)
49{ 49{
50 DSA_SIG *sig; 50 DSA_SIG *sig = NULL;
51 u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; 51 u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN];
52 u_int rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 52 size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
53 Buffer b; 53 struct sshbuf *b = NULL;
54 54 int ret = SSH_ERR_INVALID_ARGUMENT;
55 if (key == NULL || key_type_plain(key->type) != KEY_DSA || 55
56 key->dsa == NULL) { 56 if (lenp != NULL)
57 error("%s: no DSA key", __func__); 57 *lenp = 0;
58 return -1; 58 if (sigp != NULL)
59 } 59 *sigp = NULL;
60 60
61 if (ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 61 if (key == NULL || key->dsa == NULL ||
62 digest, sizeof(digest)) != 0) { 62 sshkey_type_plain(key->type) != KEY_DSA)
63 error("%s: ssh_digest_memory failed", __func__); 63 return SSH_ERR_INVALID_ARGUMENT;
64 return -1; 64 if (dlen == 0)
65 } 65 return SSH_ERR_INTERNAL_ERROR;
66 66
67 sig = DSA_do_sign(digest, dlen, key->dsa); 67 if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
68 explicit_bzero(digest, sizeof(digest)); 68 digest, sizeof(digest))) != 0)
69 69 goto out;
70 if (sig == NULL) { 70
71 error("ssh_dss_sign: sign failed"); 71 if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) {
72 return -1; 72 ret = SSH_ERR_LIBCRYPTO_ERROR;
73 goto out;
73 } 74 }
74 75
75 rlen = BN_num_bytes(sig->r); 76 rlen = BN_num_bytes(sig->r);
76 slen = BN_num_bytes(sig->s); 77 slen = BN_num_bytes(sig->s);
77 if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { 78 if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
78 error("bad sig size %u %u", rlen, slen); 79 ret = SSH_ERR_INTERNAL_ERROR;
79 DSA_SIG_free(sig); 80 goto out;
80 return -1;
81 } 81 }
82 explicit_bzero(sigblob, SIGBLOB_LEN); 82 explicit_bzero(sigblob, SIGBLOB_LEN);
83 BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen); 83 BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
84 BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen); 84 BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen);
85 DSA_SIG_free(sig);
86 85
87 if (datafellows & SSH_BUG_SIGBLOB) { 86 if (compat & SSH_BUG_SIGBLOB) {
88 if (lenp != NULL)
89 *lenp = SIGBLOB_LEN;
90 if (sigp != NULL) { 87 if (sigp != NULL) {
91 *sigp = xmalloc(SIGBLOB_LEN); 88 if ((*sigp = malloc(SIGBLOB_LEN)) == NULL) {
89 ret = SSH_ERR_ALLOC_FAIL;
90 goto out;
91 }
92 memcpy(*sigp, sigblob, SIGBLOB_LEN); 92 memcpy(*sigp, sigblob, SIGBLOB_LEN);
93 } 93 }
94 if (lenp != NULL)
95 *lenp = SIGBLOB_LEN;
96 ret = 0;
94 } else { 97 } else {
95 /* ietf-drafts */ 98 /* ietf-drafts */
96 buffer_init(&b); 99 if ((b = sshbuf_new()) == NULL) {
97 buffer_put_cstring(&b, "ssh-dss"); 100 ret = SSH_ERR_ALLOC_FAIL;
98 buffer_put_string(&b, sigblob, SIGBLOB_LEN); 101 goto out;
99 len = buffer_len(&b); 102 }
100 if (lenp != NULL) 103 if ((ret = sshbuf_put_cstring(b, "ssh-dss")) != 0 ||
101 *lenp = len; 104 (ret = sshbuf_put_string(b, sigblob, SIGBLOB_LEN)) != 0)
105 goto out;
106 len = sshbuf_len(b);
102 if (sigp != NULL) { 107 if (sigp != NULL) {
103 *sigp = xmalloc(len); 108 if ((*sigp = malloc(len)) == NULL) {
104 memcpy(*sigp, buffer_ptr(&b), len); 109 ret = SSH_ERR_ALLOC_FAIL;
110 goto out;
111 }
112 memcpy(*sigp, sshbuf_ptr(b), len);
105 } 113 }
106 buffer_free(&b); 114 if (lenp != NULL)
115 *lenp = len;
116 ret = 0;
107 } 117 }
108 return 0; 118 out:
119 explicit_bzero(digest, sizeof(digest));
120 if (sig != NULL)
121 DSA_SIG_free(sig);
122 if (b != NULL)
123 sshbuf_free(b);
124 return ret;
109} 125}
126
110int 127int
111ssh_dss_verify(const Key *key, const u_char *signature, u_int signaturelen, 128ssh_dss_verify(const struct sshkey *key,
112 const u_char *data, u_int datalen) 129 const u_char *signature, size_t signaturelen,
130 const u_char *data, size_t datalen, u_int compat)
113{ 131{
114 DSA_SIG *sig; 132 DSA_SIG *sig = NULL;
115 u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob; 133 u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL;
116 u_int len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); 134 size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
117 int rlen, ret; 135 int ret = SSH_ERR_INTERNAL_ERROR;
118 Buffer b; 136 struct sshbuf *b = NULL;
119 137 char *ktype = NULL;
120 if (key == NULL || key_type_plain(key->type) != KEY_DSA || 138
121 key->dsa == NULL) { 139 if (key == NULL || key->dsa == NULL ||
122 error("%s: no DSA key", __func__); 140 sshkey_type_plain(key->type) != KEY_DSA)
123 return -1; 141 return SSH_ERR_INVALID_ARGUMENT;
124 } 142 if (dlen == 0)
143 return SSH_ERR_INTERNAL_ERROR;
125 144
126 /* fetch signature */ 145 /* fetch signature */
127 if (datafellows & SSH_BUG_SIGBLOB) { 146 if (compat & SSH_BUG_SIGBLOB) {
128 sigblob = xmalloc(signaturelen); 147 if ((sigblob = malloc(signaturelen)) == NULL)
148 return SSH_ERR_ALLOC_FAIL;
129 memcpy(sigblob, signature, signaturelen); 149 memcpy(sigblob, signature, signaturelen);
130 len = signaturelen; 150 len = signaturelen;
131 } else { 151 } else {
132 /* ietf-drafts */ 152 /* ietf-drafts */
133 char *ktype; 153 if ((b = sshbuf_from(signature, signaturelen)) == NULL)
134 buffer_init(&b); 154 return SSH_ERR_ALLOC_FAIL;
135 buffer_append(&b, signature, signaturelen); 155 if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
136 ktype = buffer_get_cstring(&b, NULL); 156 sshbuf_get_string(b, &sigblob, &len) != 0) {
157 ret = SSH_ERR_INVALID_FORMAT;
158 goto out;
159 }
137 if (strcmp("ssh-dss", ktype) != 0) { 160 if (strcmp("ssh-dss", ktype) != 0) {
138 error("%s: cannot handle type %s", __func__, ktype); 161 ret = SSH_ERR_KEY_TYPE_MISMATCH;
139 buffer_free(&b); 162 goto out;
140 free(ktype);
141 return -1;
142 } 163 }
143 free(ktype); 164 if (sshbuf_len(b) != 0) {
144 sigblob = buffer_get_string(&b, &len); 165 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
145 rlen = buffer_len(&b); 166 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 } 167 }
153 } 168 }
154 169
155 if (len != SIGBLOB_LEN) { 170 if (len != SIGBLOB_LEN) {
156 fatal("bad sigbloblen %u != SIGBLOB_LEN", len); 171 ret = SSH_ERR_INVALID_FORMAT;
172 goto out;
157 } 173 }
158 174
159 /* parse signature */ 175 /* parse signature */
160 if ((sig = DSA_SIG_new()) == NULL) 176 if ((sig = DSA_SIG_new()) == NULL ||
161 fatal("%s: DSA_SIG_new failed", __func__); 177 (sig->r = BN_new()) == NULL ||
162 if ((sig->r = BN_new()) == NULL) 178 (sig->s = BN_new()) == NULL) {
163 fatal("%s: BN_new failed", __func__); 179 ret = SSH_ERR_ALLOC_FAIL;
164 if ((sig->s = BN_new()) == NULL) 180 goto out;
165 fatal("ssh_dss_verify: BN_new failed"); 181 }
166 if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) || 182 if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) ||
167 (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) 183 (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) {
168 fatal("%s: BN_bin2bn failed", __func__); 184 ret = SSH_ERR_LIBCRYPTO_ERROR;
169 185 goto out;
170 /* clean up */ 186 }
171 explicit_bzero(sigblob, len);
172 free(sigblob);
173 187
174 /* sha1 the data */ 188 /* sha1 the data */
175 if (ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, 189 if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
176 digest, sizeof(digest)) != 0) { 190 digest, sizeof(digest))) != 0)
177 error("%s: digest_memory failed", __func__); 191 goto out;
178 return -1; 192
193 switch (DSA_do_verify(digest, dlen, sig, key->dsa)) {
194 case 1:
195 ret = 0;
196 break;
197 case 0:
198 ret = SSH_ERR_SIGNATURE_INVALID;
199 goto out;
200 default:
201 ret = SSH_ERR_LIBCRYPTO_ERROR;
202 goto out;
179 } 203 }
180 204
181 ret = DSA_do_verify(digest, dlen, sig, key->dsa); 205 out:
182 explicit_bzero(digest, sizeof(digest)); 206 explicit_bzero(digest, sizeof(digest));
183 207 if (sig != NULL)
184 DSA_SIG_free(sig); 208 DSA_SIG_free(sig);
185 209 if (b != NULL)
186 debug("%s: signature %s", __func__, 210 sshbuf_free(b);
187 ret == 1 ? "correct" : ret == 0 ? "incorrect" : "error"); 211 if (ktype != NULL)
212 free(ktype);
213 if (sigblob != NULL) {
214 explicit_bzero(sigblob, len);
215 free(sigblob);
216 }
188 return ret; 217 return ret;
189} 218}