1 /* $OpenBSD: ssh-ed25519.c,v 1.4 2014/06/24 01:13:21 djm Exp $ */
3 * Copyright (c) 2013 Markus Friedl <markus@openbsd.org>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/types.h>
23 #include "crypto_api.h"
31 #define SSHKEY_INTERNAL
37 ssh_ed25519_sign(const struct sshkey
*key
, u_char
**sigp
, size_t *lenp
,
38 const u_char
*data
, size_t datalen
, u_int compat
)
42 unsigned long long smlen
;
44 struct sshbuf
*b
= NULL
;
52 sshkey_type_plain(key
->type
) != KEY_ED25519
||
53 key
->ed25519_sk
== NULL
||
54 datalen
>= INT_MAX
- crypto_sign_ed25519_BYTES
)
55 return SSH_ERR_INVALID_ARGUMENT
;
56 smlen
= slen
= datalen
+ crypto_sign_ed25519_BYTES
;
57 if ((sig
= malloc(slen
)) == NULL
)
58 return SSH_ERR_ALLOC_FAIL
;
60 if ((ret
= crypto_sign_ed25519(sig
, &smlen
, data
, datalen
,
61 key
->ed25519_sk
)) != 0 || smlen
<= datalen
) {
62 r
= SSH_ERR_INVALID_ARGUMENT
; /* XXX better error? */
65 /* encode signature */
66 if ((b
= sshbuf_new()) == NULL
) {
67 r
= SSH_ERR_ALLOC_FAIL
;
70 if ((r
= sshbuf_put_cstring(b
, "ssh-ed25519")) != 0 ||
71 (r
= sshbuf_put_string(b
, sig
, smlen
- datalen
)) != 0)
75 if ((*sigp
= malloc(len
)) == NULL
) {
76 r
= SSH_ERR_ALLOC_FAIL
;
79 memcpy(*sigp
, sshbuf_ptr(b
), len
);
88 explicit_bzero(sig
, slen
);
96 ssh_ed25519_verify(const struct sshkey
*key
,
97 const u_char
*signature
, size_t signaturelen
,
98 const u_char
*data
, size_t datalen
, u_int compat
)
100 struct sshbuf
*b
= NULL
;
102 const u_char
*sigblob
;
103 u_char
*sm
= NULL
, *m
= NULL
;
105 unsigned long long smlen
= 0, mlen
= 0;
109 sshkey_type_plain(key
->type
) != KEY_ED25519
||
110 key
->ed25519_pk
== NULL
||
111 datalen
>= INT_MAX
- crypto_sign_ed25519_BYTES
)
112 return SSH_ERR_INVALID_ARGUMENT
;
114 if ((b
= sshbuf_from(signature
, signaturelen
)) == 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)
119 if (strcmp("ssh-ed25519", ktype
) != 0) {
120 r
= SSH_ERR_KEY_TYPE_MISMATCH
;
123 if (sshbuf_len(b
) != 0) {
124 r
= SSH_ERR_UNEXPECTED_TRAILING_DATA
;
127 if (len
> crypto_sign_ed25519_BYTES
) {
128 r
= SSH_ERR_INVALID_FORMAT
;
131 if (datalen
>= SIZE_MAX
- len
)
132 return SSH_ERR_INVALID_ARGUMENT
;
133 smlen
= len
+ datalen
;
135 if ((sm
= malloc(smlen
)) == NULL
|| (m
= xmalloc(mlen
)) == NULL
) {
136 r
= SSH_ERR_ALLOC_FAIL
;
139 memcpy(sm
, sigblob
, len
);
140 memcpy(sm
+len
, data
, datalen
);
141 if ((ret
= crypto_sign_ed25519_open(m
, &mlen
, sm
, smlen
,
142 key
->ed25519_pk
)) != 0) {
143 debug2("%s: crypto_sign_ed25519_open failed: %d",
146 if (ret
!= 0 || mlen
!= datalen
) {
147 r
= SSH_ERR_SIGNATURE_INVALID
;
150 /* XXX compare 'm' and 'data' ? */
155 explicit_bzero(sm
, smlen
);
159 explicit_bzero(m
, smlen
); /* NB mlen may be invalid if r != 0 */