summaryrefslogtreecommitdiff
path: root/ssh-ed25519.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-ed25519.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-ed25519.c')
-rw-r--r--ssh-ed25519.c183
1 files changed, 100 insertions, 83 deletions
diff --git a/ssh-ed25519.c b/ssh-ed25519.c
index 160d1f23b..cb87d4790 100644
--- a/ssh-ed25519.c
+++ b/ssh-ed25519.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-ed25519.c,v 1.3 2014/02/23 20:03:42 djm Exp $ */ 1/* $OpenBSD: ssh-ed25519.c,v 1.4 2014/06/24 01:13:21 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2013 Markus Friedl <markus@openbsd.org> 3 * Copyright (c) 2013 Markus Friedl <markus@openbsd.org>
4 * 4 *
@@ -18,132 +18,149 @@
18#include "includes.h" 18#include "includes.h"
19 19
20#include <sys/types.h> 20#include <sys/types.h>
21#include <limits.h>
21 22
22#include "crypto_api.h" 23#include "crypto_api.h"
23 24
24#include <limits.h>
25#include <string.h> 25#include <string.h>
26#include <stdarg.h> 26#include <stdarg.h>
27 27
28#include "xmalloc.h" 28#include "xmalloc.h"
29#include "log.h" 29#include "log.h"
30#include "buffer.h" 30#include "buffer.h"
31#include "key.h" 31#define SSHKEY_INTERNAL
32#include "sshkey.h"
33#include "ssherr.h"
32#include "ssh.h" 34#include "ssh.h"
33 35
34int 36int
35ssh_ed25519_sign(const Key *key, u_char **sigp, u_int *lenp, 37ssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
36 const u_char *data, u_int datalen) 38 const u_char *data, size_t datalen, u_int compat)
37{ 39{
38 u_char *sig; 40 u_char *sig = NULL;
39 u_int slen, len; 41 size_t slen = 0, len;
40 unsigned long long smlen; 42 unsigned long long smlen;
41 int ret; 43 int r, ret;
42 Buffer b; 44 struct sshbuf *b = NULL;
43 45
44 if (key == NULL || key_type_plain(key->type) != KEY_ED25519 || 46 if (lenp != NULL)
45 key->ed25519_sk == NULL) { 47 *lenp = 0;
46 error("%s: no ED25519 key", __func__); 48 if (sigp != NULL)
47 return -1; 49 *sigp = NULL;
48 }
49 50
50 if (datalen >= UINT_MAX - crypto_sign_ed25519_BYTES) { 51 if (key == NULL ||
51 error("%s: datalen %u too long", __func__, datalen); 52 sshkey_type_plain(key->type) != KEY_ED25519 ||
52 return -1; 53 key->ed25519_sk == NULL ||
53 } 54 datalen >= INT_MAX - crypto_sign_ed25519_BYTES)
55 return SSH_ERR_INVALID_ARGUMENT;
54 smlen = slen = datalen + crypto_sign_ed25519_BYTES; 56 smlen = slen = datalen + crypto_sign_ed25519_BYTES;
55 sig = xmalloc(slen); 57 if ((sig = malloc(slen)) == NULL)
58 return SSH_ERR_ALLOC_FAIL;
56 59
57 if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen, 60 if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen,
58 key->ed25519_sk)) != 0 || smlen <= datalen) { 61 key->ed25519_sk)) != 0 || smlen <= datalen) {
59 error("%s: crypto_sign_ed25519 failed: %d", __func__, ret); 62 r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */
60 free(sig); 63 goto out;
61 return -1;
62 } 64 }
63 /* encode signature */ 65 /* encode signature */
64 buffer_init(&b); 66 if ((b = sshbuf_new()) == NULL) {
65 buffer_put_cstring(&b, "ssh-ed25519"); 67 r = SSH_ERR_ALLOC_FAIL;
66 buffer_put_string(&b, sig, smlen - datalen); 68 goto out;
67 len = buffer_len(&b); 69 }
70 if ((r = sshbuf_put_cstring(b, "ssh-ed25519")) != 0 ||
71 (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0)
72 goto out;
73 len = sshbuf_len(b);
74 if (sigp != NULL) {
75 if ((*sigp = malloc(len)) == NULL) {
76 r = SSH_ERR_ALLOC_FAIL;
77 goto out;
78 }
79 memcpy(*sigp, sshbuf_ptr(b), len);
80 }
68 if (lenp != NULL) 81 if (lenp != NULL)
69 *lenp = len; 82 *lenp = len;
70 if (sigp != NULL) { 83 /* success */
71 *sigp = xmalloc(len); 84 r = 0;
72 memcpy(*sigp, buffer_ptr(&b), len); 85 out:
86 sshbuf_free(b);
87 if (sig != NULL) {
88 explicit_bzero(sig, slen);
89 free(sig);
73 } 90 }
74 buffer_free(&b);
75 explicit_bzero(sig, slen);
76 free(sig);
77 91
78 return 0; 92 return r;
79} 93}
80 94
81int 95int
82ssh_ed25519_verify(const Key *key, const u_char *signature, u_int signaturelen, 96ssh_ed25519_verify(const struct sshkey *key,
83 const u_char *data, u_int datalen) 97 const u_char *signature, size_t signaturelen,
98 const u_char *data, size_t datalen, u_int compat)
84{ 99{
85 Buffer b; 100 struct sshbuf *b = NULL;
86 char *ktype; 101 char *ktype = NULL;
87 u_char *sigblob, *sm, *m; 102 const u_char *sigblob;
88 u_int len; 103 u_char *sm = NULL, *m = NULL;
89 unsigned long long smlen, mlen; 104 size_t len;
90 int rlen, ret; 105 unsigned long long smlen = 0, mlen = 0;
106 int r, ret;
91 107
92 if (key == NULL || key_type_plain(key->type) != KEY_ED25519 || 108 if (key == NULL ||
93 key->ed25519_pk == NULL) { 109 sshkey_type_plain(key->type) != KEY_ED25519 ||
94 error("%s: no ED25519 key", __func__); 110 key->ed25519_pk == NULL ||
95 return -1; 111 datalen >= INT_MAX - crypto_sign_ed25519_BYTES)
96 } 112 return SSH_ERR_INVALID_ARGUMENT;
97 buffer_init(&b); 113
98 buffer_append(&b, signature, signaturelen); 114 if ((b = sshbuf_from(signature, signaturelen)) == NULL)
99 ktype = buffer_get_cstring(&b, NULL); 115 return SSH_ERR_ALLOC_FAIL;
116 if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 ||
117 (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0)
118 goto out;
100 if (strcmp("ssh-ed25519", ktype) != 0) { 119 if (strcmp("ssh-ed25519", ktype) != 0) {
101 error("%s: cannot handle type %s", __func__, ktype); 120 r = SSH_ERR_KEY_TYPE_MISMATCH;
102 buffer_free(&b); 121 goto out;
103 free(ktype);
104 return -1;
105 } 122 }
106 free(ktype); 123 if (sshbuf_len(b) != 0) {
107 sigblob = buffer_get_string(&b, &len); 124 r = SSH_ERR_UNEXPECTED_TRAILING_DATA;
108 rlen = buffer_len(&b); 125 goto out;
109 buffer_free(&b);
110 if (rlen != 0) {
111 error("%s: remaining bytes in signature %d", __func__, rlen);
112 free(sigblob);
113 return -1;
114 } 126 }
115 if (len > crypto_sign_ed25519_BYTES) { 127 if (len > crypto_sign_ed25519_BYTES) {
116 error("%s: len %u > crypto_sign_ed25519_BYTES %u", __func__, 128 r = SSH_ERR_INVALID_FORMAT;
117 len, crypto_sign_ed25519_BYTES); 129 goto out;
118 free(sigblob);
119 return -1;
120 } 130 }
131 if (datalen >= SIZE_MAX - len)
132 return SSH_ERR_INVALID_ARGUMENT;
121 smlen = len + datalen; 133 smlen = len + datalen;
122 sm = xmalloc(smlen); 134 mlen = smlen;
135 if ((sm = malloc(smlen)) == NULL || (m = xmalloc(mlen)) == NULL) {
136 r = SSH_ERR_ALLOC_FAIL;
137 goto out;
138 }
123 memcpy(sm, sigblob, len); 139 memcpy(sm, sigblob, len);
124 memcpy(sm+len, data, datalen); 140 memcpy(sm+len, data, datalen);
125 mlen = smlen;
126 m = xmalloc(mlen);
127 if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen, 141 if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen,
128 key->ed25519_pk)) != 0) { 142 key->ed25519_pk)) != 0) {
129 debug2("%s: crypto_sign_ed25519_open failed: %d", 143 debug2("%s: crypto_sign_ed25519_open failed: %d",
130 __func__, ret); 144 __func__, ret);
131 } 145 }
132 if (ret == 0 && mlen != datalen) { 146 if (ret != 0 || mlen != datalen) {
133 debug2("%s: crypto_sign_ed25519_open " 147 r = SSH_ERR_SIGNATURE_INVALID;
134 "mlen != datalen (%llu != %u)", __func__, mlen, datalen); 148 goto out;
135 ret = -1;
136 } 149 }
137 /* XXX compare 'm' and 'data' ? */ 150 /* XXX compare 'm' and 'data' ? */
138 151 /* success */
139 explicit_bzero(sigblob, len); 152 r = 0;
140 explicit_bzero(sm, smlen); 153 out:
141 explicit_bzero(m, smlen); /* NB. mlen may be invalid if ret != 0 */ 154 if (sm != NULL) {
142 free(sigblob); 155 explicit_bzero(sm, smlen);
143 free(sm); 156 free(sm);
144 free(m); 157 }
145 debug("%s: signature %scorrect", __func__, (ret != 0) ? "in" : ""); 158 if (m != NULL) {
146 159 explicit_bzero(m, smlen); /* NB mlen may be invalid if r != 0 */
147 /* translate return code carefully */ 160 free(m);
148 return (ret == 0) ? 1 : -1; 161 }
162 sshbuf_free(b);
163 free(ktype);
164 return r;
149} 165}
166