summaryrefslogtreecommitdiff
path: root/ssh-ecdsa.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-ecdsa.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-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