summaryrefslogtreecommitdiff
path: root/ssh-dss.c
diff options
context:
space:
mode:
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}