1 /* $OpenBSD: ssh-ed25519.c,v 1.9 2020/10/18 11:32:02 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"
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
);
93 ssh_ed25519_verify(const struct sshkey
*key
,
94 const u_char
*signature
, size_t signaturelen
,
95 const u_char
*data
, size_t datalen
, u_int compat
)
97 struct sshbuf
*b
= NULL
;
99 const u_char
*sigblob
;
100 u_char
*sm
= NULL
, *m
= NULL
;
102 unsigned long long smlen
= 0, mlen
= 0;
106 sshkey_type_plain(key
->type
) != KEY_ED25519
||
107 key
->ed25519_pk
== NULL
||
108 datalen
>= INT_MAX
- crypto_sign_ed25519_BYTES
||
109 signature
== NULL
|| signaturelen
== 0)
110 return SSH_ERR_INVALID_ARGUMENT
;
112 if ((b
= sshbuf_from(signature
, signaturelen
)) == NULL
)
113 return SSH_ERR_ALLOC_FAIL
;
114 if ((r
= sshbuf_get_cstring(b
, &ktype
, NULL
)) != 0 ||
115 (r
= sshbuf_get_string_direct(b
, &sigblob
, &len
)) != 0)
117 if (strcmp("ssh-ed25519", ktype
) != 0) {
118 r
= SSH_ERR_KEY_TYPE_MISMATCH
;
121 if (sshbuf_len(b
) != 0) {
122 r
= SSH_ERR_UNEXPECTED_TRAILING_DATA
;
125 if (len
> crypto_sign_ed25519_BYTES
) {
126 r
= SSH_ERR_INVALID_FORMAT
;
129 if (datalen
>= SIZE_MAX
- len
) {
130 r
= SSH_ERR_INVALID_ARGUMENT
;
133 smlen
= len
+ datalen
;
135 if ((sm
= malloc(smlen
)) == NULL
|| (m
= malloc(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_f("crypto_sign_ed25519_open failed: %d", ret
);
145 if (ret
!= 0 || mlen
!= datalen
) {
146 r
= SSH_ERR_SIGNATURE_INVALID
;
149 /* XXX compare 'm' and 'data' ? */
156 freezero(m
, smlen
); /* NB mlen may be invalid if r != 0 */