1 /* $OpenBSD: ssh-ed25519.c,v 1.6 2015/01/15 21:38:50 markus 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"
30 #define SSHKEY_INTERNAL
36 ssh_ed25519_sign(const struct sshkey
*key
, u_char
**sigp
, size_t *lenp
,
37 const u_char
*data
, size_t datalen
, u_int compat
)
41 unsigned long long smlen
;
43 struct sshbuf
*b
= NULL
;
51 sshkey_type_plain(key
->type
) != KEY_ED25519
||
52 key
->ed25519_sk
== NULL
||
53 datalen
>= INT_MAX
- crypto_sign_ed25519_BYTES
)
54 return SSH_ERR_INVALID_ARGUMENT
;
55 smlen
= slen
= datalen
+ crypto_sign_ed25519_BYTES
;
56 if ((sig
= malloc(slen
)) == NULL
)
57 return SSH_ERR_ALLOC_FAIL
;
59 if ((ret
= crypto_sign_ed25519(sig
, &smlen
, data
, datalen
,
60 key
->ed25519_sk
)) != 0 || smlen
<= datalen
) {
61 r
= SSH_ERR_INVALID_ARGUMENT
; /* XXX better error? */
64 /* encode signature */
65 if ((b
= sshbuf_new()) == NULL
) {
66 r
= SSH_ERR_ALLOC_FAIL
;
69 if ((r
= sshbuf_put_cstring(b
, "ssh-ed25519")) != 0 ||
70 (r
= sshbuf_put_string(b
, sig
, smlen
- datalen
)) != 0)
74 if ((*sigp
= malloc(len
)) == NULL
) {
75 r
= SSH_ERR_ALLOC_FAIL
;
78 memcpy(*sigp
, sshbuf_ptr(b
), len
);
87 explicit_bzero(sig
, slen
);
95 ssh_ed25519_verify(const struct sshkey
*key
,
96 const u_char
*signature
, size_t signaturelen
,
97 const u_char
*data
, size_t datalen
, u_int compat
)
99 struct sshbuf
*b
= NULL
;
101 const u_char
*sigblob
;
102 u_char
*sm
= NULL
, *m
= NULL
;
104 unsigned long long smlen
= 0, mlen
= 0;
108 sshkey_type_plain(key
->type
) != KEY_ED25519
||
109 key
->ed25519_pk
== NULL
||
110 datalen
>= INT_MAX
- crypto_sign_ed25519_BYTES
)
111 return SSH_ERR_INVALID_ARGUMENT
;
113 if ((b
= sshbuf_from(signature
, signaturelen
)) == NULL
)
114 return SSH_ERR_ALLOC_FAIL
;
115 if ((r
= sshbuf_get_cstring(b
, &ktype
, NULL
)) != 0 ||
116 (r
= sshbuf_get_string_direct(b
, &sigblob
, &len
)) != 0)
118 if (strcmp("ssh-ed25519", ktype
) != 0) {
119 r
= SSH_ERR_KEY_TYPE_MISMATCH
;
122 if (sshbuf_len(b
) != 0) {
123 r
= SSH_ERR_UNEXPECTED_TRAILING_DATA
;
126 if (len
> crypto_sign_ed25519_BYTES
) {
127 r
= SSH_ERR_INVALID_FORMAT
;
130 if (datalen
>= SIZE_MAX
- len
) {
131 r
= SSH_ERR_INVALID_ARGUMENT
;
134 smlen
= len
+ datalen
;
136 if ((sm
= malloc(smlen
)) == NULL
|| (m
= malloc(mlen
)) == NULL
) {
137 r
= SSH_ERR_ALLOC_FAIL
;
140 memcpy(sm
, sigblob
, len
);
141 memcpy(sm
+len
, data
, datalen
);
142 if ((ret
= crypto_sign_ed25519_open(m
, &mlen
, sm
, smlen
,
143 key
->ed25519_pk
)) != 0) {
144 debug2("%s: crypto_sign_ed25519_open failed: %d",
147 if (ret
!= 0 || mlen
!= datalen
) {
148 r
= SSH_ERR_SIGNATURE_INVALID
;
151 /* XXX compare 'm' and 'data' ? */
156 explicit_bzero(sm
, smlen
);
160 explicit_bzero(m
, smlen
); /* NB mlen may be invalid if r != 0 */