xref: /freebsd-src/crypto/openssh/sshkey.c (revision 2a01feabb3d0fce30c4a1c4b883e50e09a457a96)
1190cef3dSDag-Erling Smørgrav /* $OpenBSD: sshkey.c,v 1.66 2018/07/03 13:20:25 djm Exp $ */
2a0ee8cc6SDag-Erling Smørgrav /*
3a0ee8cc6SDag-Erling Smørgrav  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
4a0ee8cc6SDag-Erling Smørgrav  * Copyright (c) 2008 Alexander von Gernler.  All rights reserved.
5a0ee8cc6SDag-Erling Smørgrav  * Copyright (c) 2010,2011 Damien Miller.  All rights reserved.
6a0ee8cc6SDag-Erling Smørgrav  *
7a0ee8cc6SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
8a0ee8cc6SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
9a0ee8cc6SDag-Erling Smørgrav  * are met:
10a0ee8cc6SDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
11a0ee8cc6SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer.
12a0ee8cc6SDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
13a0ee8cc6SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
14a0ee8cc6SDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
15a0ee8cc6SDag-Erling Smørgrav  *
16a0ee8cc6SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17a0ee8cc6SDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18a0ee8cc6SDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19a0ee8cc6SDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20a0ee8cc6SDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21a0ee8cc6SDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22a0ee8cc6SDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23a0ee8cc6SDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24a0ee8cc6SDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25a0ee8cc6SDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26a0ee8cc6SDag-Erling Smørgrav  */
27a0ee8cc6SDag-Erling Smørgrav 
28a0ee8cc6SDag-Erling Smørgrav #include "includes.h"
29a0ee8cc6SDag-Erling Smørgrav 
30a0ee8cc6SDag-Erling Smørgrav #include <sys/types.h>
31bc5531deSDag-Erling Smørgrav #include <netinet/in.h>
32a0ee8cc6SDag-Erling Smørgrav 
33bc5531deSDag-Erling Smørgrav #ifdef WITH_OPENSSL
34a0ee8cc6SDag-Erling Smørgrav #include <openssl/evp.h>
35a0ee8cc6SDag-Erling Smørgrav #include <openssl/err.h>
36a0ee8cc6SDag-Erling Smørgrav #include <openssl/pem.h>
37bc5531deSDag-Erling Smørgrav #endif
38a0ee8cc6SDag-Erling Smørgrav 
39a0ee8cc6SDag-Erling Smørgrav #include "crypto_api.h"
40a0ee8cc6SDag-Erling Smørgrav 
41a0ee8cc6SDag-Erling Smørgrav #include <errno.h>
42bc5531deSDag-Erling Smørgrav #include <limits.h>
43a0ee8cc6SDag-Erling Smørgrav #include <stdio.h>
44a0ee8cc6SDag-Erling Smørgrav #include <string.h>
45bc5531deSDag-Erling Smørgrav #include <resolv.h>
46a0ee8cc6SDag-Erling Smørgrav #ifdef HAVE_UTIL_H
47a0ee8cc6SDag-Erling Smørgrav #include <util.h>
48a0ee8cc6SDag-Erling Smørgrav #endif /* HAVE_UTIL_H */
49a0ee8cc6SDag-Erling Smørgrav 
50a0ee8cc6SDag-Erling Smørgrav #include "ssh2.h"
51a0ee8cc6SDag-Erling Smørgrav #include "ssherr.h"
52a0ee8cc6SDag-Erling Smørgrav #include "misc.h"
53a0ee8cc6SDag-Erling Smørgrav #include "sshbuf.h"
54a0ee8cc6SDag-Erling Smørgrav #include "cipher.h"
55a0ee8cc6SDag-Erling Smørgrav #include "digest.h"
56a0ee8cc6SDag-Erling Smørgrav #define SSHKEY_INTERNAL
57a0ee8cc6SDag-Erling Smørgrav #include "sshkey.h"
5847dd1d1bSDag-Erling Smørgrav #include "sshkey-xmss.h"
59bc5531deSDag-Erling Smørgrav #include "match.h"
60a0ee8cc6SDag-Erling Smørgrav 
6147dd1d1bSDag-Erling Smørgrav #include "xmss_fast.h"
6247dd1d1bSDag-Erling Smørgrav 
63*2a01feabSEd Maste #include "openbsd-compat/openssl-compat.h"
64*2a01feabSEd Maste 
65a0ee8cc6SDag-Erling Smørgrav /* openssh private key file format */
66a0ee8cc6SDag-Erling Smørgrav #define MARK_BEGIN		"-----BEGIN OPENSSH PRIVATE KEY-----\n"
67a0ee8cc6SDag-Erling Smørgrav #define MARK_END		"-----END OPENSSH PRIVATE KEY-----\n"
68a0ee8cc6SDag-Erling Smørgrav #define MARK_BEGIN_LEN		(sizeof(MARK_BEGIN) - 1)
69a0ee8cc6SDag-Erling Smørgrav #define MARK_END_LEN		(sizeof(MARK_END) - 1)
70a0ee8cc6SDag-Erling Smørgrav #define KDFNAME			"bcrypt"
71a0ee8cc6SDag-Erling Smørgrav #define AUTH_MAGIC		"openssh-key-v1"
72a0ee8cc6SDag-Erling Smørgrav #define SALT_LEN		16
734f52dfbbSDag-Erling Smørgrav #define DEFAULT_CIPHERNAME	"aes256-ctr"
74a0ee8cc6SDag-Erling Smørgrav #define	DEFAULT_ROUNDS		16
75a0ee8cc6SDag-Erling Smørgrav 
76a0ee8cc6SDag-Erling Smørgrav /* Version identification string for SSH v1 identity files. */
77a0ee8cc6SDag-Erling Smørgrav #define LEGACY_BEGIN		"SSH PRIVATE KEY FILE FORMAT 1.1\n"
78a0ee8cc6SDag-Erling Smørgrav 
7947dd1d1bSDag-Erling Smørgrav int	sshkey_private_serialize_opt(const struct sshkey *key,
8047dd1d1bSDag-Erling Smørgrav     struct sshbuf *buf, enum sshkey_serialize_rep);
81bc5531deSDag-Erling Smørgrav static int sshkey_from_blob_internal(struct sshbuf *buf,
82a0ee8cc6SDag-Erling Smørgrav     struct sshkey **keyp, int allow_cert);
83a0ee8cc6SDag-Erling Smørgrav 
84a0ee8cc6SDag-Erling Smørgrav /* Supported key types */
85a0ee8cc6SDag-Erling Smørgrav struct keytype {
86a0ee8cc6SDag-Erling Smørgrav 	const char *name;
87a0ee8cc6SDag-Erling Smørgrav 	const char *shortname;
88190cef3dSDag-Erling Smørgrav 	const char *sigalg;
89a0ee8cc6SDag-Erling Smørgrav 	int type;
90a0ee8cc6SDag-Erling Smørgrav 	int nid;
91a0ee8cc6SDag-Erling Smørgrav 	int cert;
92acc1a9efSDag-Erling Smørgrav 	int sigonly;
93a0ee8cc6SDag-Erling Smørgrav };
94a0ee8cc6SDag-Erling Smørgrav static const struct keytype keytypes[] = {
95190cef3dSDag-Erling Smørgrav 	{ "ssh-ed25519", "ED25519", NULL, KEY_ED25519, 0, 0, 0 },
96190cef3dSDag-Erling Smørgrav 	{ "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT", NULL,
97acc1a9efSDag-Erling Smørgrav 	    KEY_ED25519_CERT, 0, 1, 0 },
9847dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
99190cef3dSDag-Erling Smørgrav 	{ "ssh-xmss@openssh.com", "XMSS", NULL, KEY_XMSS, 0, 0, 0 },
100190cef3dSDag-Erling Smørgrav 	{ "ssh-xmss-cert-v01@openssh.com", "XMSS-CERT", NULL,
10147dd1d1bSDag-Erling Smørgrav 	    KEY_XMSS_CERT, 0, 1, 0 },
10247dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
103a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
104190cef3dSDag-Erling Smørgrav 	{ "ssh-rsa", "RSA", NULL, KEY_RSA, 0, 0, 0 },
105190cef3dSDag-Erling Smørgrav 	{ "rsa-sha2-256", "RSA", NULL, KEY_RSA, 0, 0, 1 },
106190cef3dSDag-Erling Smørgrav 	{ "rsa-sha2-512", "RSA", NULL, KEY_RSA, 0, 0, 1 },
107190cef3dSDag-Erling Smørgrav 	{ "ssh-dss", "DSA", NULL, KEY_DSA, 0, 0, 0 },
108a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_ECC
109190cef3dSDag-Erling Smørgrav 	{ "ecdsa-sha2-nistp256", "ECDSA", NULL,
110190cef3dSDag-Erling Smørgrav 	    KEY_ECDSA, NID_X9_62_prime256v1, 0, 0 },
111190cef3dSDag-Erling Smørgrav 	{ "ecdsa-sha2-nistp384", "ECDSA", NULL,
112190cef3dSDag-Erling Smørgrav 	    KEY_ECDSA, NID_secp384r1, 0, 0 },
113a0ee8cc6SDag-Erling Smørgrav #  ifdef OPENSSL_HAS_NISTP521
114190cef3dSDag-Erling Smørgrav 	{ "ecdsa-sha2-nistp521", "ECDSA", NULL,
115190cef3dSDag-Erling Smørgrav 	    KEY_ECDSA, NID_secp521r1, 0, 0 },
116a0ee8cc6SDag-Erling Smørgrav #  endif /* OPENSSL_HAS_NISTP521 */
117a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_ECC */
118190cef3dSDag-Erling Smørgrav 	{ "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", NULL,
119190cef3dSDag-Erling Smørgrav 	    KEY_RSA_CERT, 0, 1, 0 },
120190cef3dSDag-Erling Smørgrav 	{ "rsa-sha2-256-cert-v01@openssh.com", "RSA-CERT",
121190cef3dSDag-Erling Smørgrav 	    "ssh-rsa-sha2-256", KEY_RSA_CERT, 0, 1, 1 },
122190cef3dSDag-Erling Smørgrav 	{ "rsa-sha2-512-cert-v01@openssh.com", "RSA-CERT",
123190cef3dSDag-Erling Smørgrav 	    "ssh-rsa-sha2-512", KEY_RSA_CERT, 0, 1, 1 },
124190cef3dSDag-Erling Smørgrav 	{ "ssh-dss-cert-v01@openssh.com", "DSA-CERT", NULL,
125190cef3dSDag-Erling Smørgrav 	    KEY_DSA_CERT, 0, 1, 0 },
126190cef3dSDag-Erling Smørgrav 	{ "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", NULL,
127190cef3dSDag-Erling Smørgrav 	    KEY_RSA_CERT, 0, 1, 0 },
128190cef3dSDag-Erling Smørgrav 	{ "rsa-sha2-256-cert-v01@openssh.com", "RSA-CERT",
129190cef3dSDag-Erling Smørgrav 	    "ssh-rsa-sha2-256", KEY_RSA_CERT, 0, 1, 1 },
130190cef3dSDag-Erling Smørgrav 	{ "rsa-sha2-512-cert-v01@openssh.com", "RSA-CERT",
131190cef3dSDag-Erling Smørgrav 	    "ssh-rsa-sha2-512", KEY_RSA_CERT, 0, 1, 1 },
132190cef3dSDag-Erling Smørgrav 	{ "ssh-dss-cert-v01@openssh.com", "DSA-CERT", NULL,
133190cef3dSDag-Erling Smørgrav 	    KEY_DSA_CERT, 0, 1, 0 },
134a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_ECC
135190cef3dSDag-Erling Smørgrav 	{ "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT", NULL,
136acc1a9efSDag-Erling Smørgrav 	    KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1, 0 },
137190cef3dSDag-Erling Smørgrav 	{ "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT", NULL,
138acc1a9efSDag-Erling Smørgrav 	    KEY_ECDSA_CERT, NID_secp384r1, 1, 0 },
139a0ee8cc6SDag-Erling Smørgrav #  ifdef OPENSSL_HAS_NISTP521
140190cef3dSDag-Erling Smørgrav 	{ "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT", NULL,
141acc1a9efSDag-Erling Smørgrav 	   KEY_ECDSA_CERT, NID_secp521r1, 1, 0 },
142a0ee8cc6SDag-Erling Smørgrav #  endif /* OPENSSL_HAS_NISTP521 */
143a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_ECC */
144a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
145190cef3dSDag-Erling Smørgrav 	{ NULL, NULL, NULL, -1, -1, 0, 0 }
146a0ee8cc6SDag-Erling Smørgrav };
147a0ee8cc6SDag-Erling Smørgrav 
148a0ee8cc6SDag-Erling Smørgrav const char *
149a0ee8cc6SDag-Erling Smørgrav sshkey_type(const struct sshkey *k)
150a0ee8cc6SDag-Erling Smørgrav {
151a0ee8cc6SDag-Erling Smørgrav 	const struct keytype *kt;
152a0ee8cc6SDag-Erling Smørgrav 
153a0ee8cc6SDag-Erling Smørgrav 	for (kt = keytypes; kt->type != -1; kt++) {
154a0ee8cc6SDag-Erling Smørgrav 		if (kt->type == k->type)
155a0ee8cc6SDag-Erling Smørgrav 			return kt->shortname;
156a0ee8cc6SDag-Erling Smørgrav 	}
157a0ee8cc6SDag-Erling Smørgrav 	return "unknown";
158a0ee8cc6SDag-Erling Smørgrav }
159a0ee8cc6SDag-Erling Smørgrav 
160a0ee8cc6SDag-Erling Smørgrav static const char *
161a0ee8cc6SDag-Erling Smørgrav sshkey_ssh_name_from_type_nid(int type, int nid)
162a0ee8cc6SDag-Erling Smørgrav {
163a0ee8cc6SDag-Erling Smørgrav 	const struct keytype *kt;
164a0ee8cc6SDag-Erling Smørgrav 
165a0ee8cc6SDag-Erling Smørgrav 	for (kt = keytypes; kt->type != -1; kt++) {
166a0ee8cc6SDag-Erling Smørgrav 		if (kt->type == type && (kt->nid == 0 || kt->nid == nid))
167a0ee8cc6SDag-Erling Smørgrav 			return kt->name;
168a0ee8cc6SDag-Erling Smørgrav 	}
169a0ee8cc6SDag-Erling Smørgrav 	return "ssh-unknown";
170a0ee8cc6SDag-Erling Smørgrav }
171a0ee8cc6SDag-Erling Smørgrav 
172a0ee8cc6SDag-Erling Smørgrav int
173a0ee8cc6SDag-Erling Smørgrav sshkey_type_is_cert(int type)
174a0ee8cc6SDag-Erling Smørgrav {
175a0ee8cc6SDag-Erling Smørgrav 	const struct keytype *kt;
176a0ee8cc6SDag-Erling Smørgrav 
177a0ee8cc6SDag-Erling Smørgrav 	for (kt = keytypes; kt->type != -1; kt++) {
178a0ee8cc6SDag-Erling Smørgrav 		if (kt->type == type)
179a0ee8cc6SDag-Erling Smørgrav 			return kt->cert;
180a0ee8cc6SDag-Erling Smørgrav 	}
181a0ee8cc6SDag-Erling Smørgrav 	return 0;
182a0ee8cc6SDag-Erling Smørgrav }
183a0ee8cc6SDag-Erling Smørgrav 
184a0ee8cc6SDag-Erling Smørgrav const char *
185a0ee8cc6SDag-Erling Smørgrav sshkey_ssh_name(const struct sshkey *k)
186a0ee8cc6SDag-Erling Smørgrav {
187a0ee8cc6SDag-Erling Smørgrav 	return sshkey_ssh_name_from_type_nid(k->type, k->ecdsa_nid);
188a0ee8cc6SDag-Erling Smørgrav }
189a0ee8cc6SDag-Erling Smørgrav 
190a0ee8cc6SDag-Erling Smørgrav const char *
191a0ee8cc6SDag-Erling Smørgrav sshkey_ssh_name_plain(const struct sshkey *k)
192a0ee8cc6SDag-Erling Smørgrav {
193a0ee8cc6SDag-Erling Smørgrav 	return sshkey_ssh_name_from_type_nid(sshkey_type_plain(k->type),
194a0ee8cc6SDag-Erling Smørgrav 	    k->ecdsa_nid);
195a0ee8cc6SDag-Erling Smørgrav }
196a0ee8cc6SDag-Erling Smørgrav 
197a0ee8cc6SDag-Erling Smørgrav int
198a0ee8cc6SDag-Erling Smørgrav sshkey_type_from_name(const char *name)
199a0ee8cc6SDag-Erling Smørgrav {
200a0ee8cc6SDag-Erling Smørgrav 	const struct keytype *kt;
201a0ee8cc6SDag-Erling Smørgrav 
202a0ee8cc6SDag-Erling Smørgrav 	for (kt = keytypes; kt->type != -1; kt++) {
203a0ee8cc6SDag-Erling Smørgrav 		/* Only allow shortname matches for plain key types */
204a0ee8cc6SDag-Erling Smørgrav 		if ((kt->name != NULL && strcmp(name, kt->name) == 0) ||
205a0ee8cc6SDag-Erling Smørgrav 		    (!kt->cert && strcasecmp(kt->shortname, name) == 0))
206a0ee8cc6SDag-Erling Smørgrav 			return kt->type;
207a0ee8cc6SDag-Erling Smørgrav 	}
208a0ee8cc6SDag-Erling Smørgrav 	return KEY_UNSPEC;
209a0ee8cc6SDag-Erling Smørgrav }
210a0ee8cc6SDag-Erling Smørgrav 
211a0ee8cc6SDag-Erling Smørgrav int
212a0ee8cc6SDag-Erling Smørgrav sshkey_ecdsa_nid_from_name(const char *name)
213a0ee8cc6SDag-Erling Smørgrav {
214a0ee8cc6SDag-Erling Smørgrav 	const struct keytype *kt;
215a0ee8cc6SDag-Erling Smørgrav 
216a0ee8cc6SDag-Erling Smørgrav 	for (kt = keytypes; kt->type != -1; kt++) {
217a0ee8cc6SDag-Erling Smørgrav 		if (kt->type != KEY_ECDSA && kt->type != KEY_ECDSA_CERT)
218a0ee8cc6SDag-Erling Smørgrav 			continue;
219a0ee8cc6SDag-Erling Smørgrav 		if (kt->name != NULL && strcmp(name, kt->name) == 0)
220a0ee8cc6SDag-Erling Smørgrav 			return kt->nid;
221a0ee8cc6SDag-Erling Smørgrav 	}
222a0ee8cc6SDag-Erling Smørgrav 	return -1;
223a0ee8cc6SDag-Erling Smørgrav }
224a0ee8cc6SDag-Erling Smørgrav 
225a0ee8cc6SDag-Erling Smørgrav char *
226d93a896eSDag-Erling Smørgrav sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep)
227a0ee8cc6SDag-Erling Smørgrav {
228a0ee8cc6SDag-Erling Smørgrav 	char *tmp, *ret = NULL;
229a0ee8cc6SDag-Erling Smørgrav 	size_t nlen, rlen = 0;
230a0ee8cc6SDag-Erling Smørgrav 	const struct keytype *kt;
231a0ee8cc6SDag-Erling Smørgrav 
232a0ee8cc6SDag-Erling Smørgrav 	for (kt = keytypes; kt->type != -1; kt++) {
233d93a896eSDag-Erling Smørgrav 		if (kt->name == NULL)
234d93a896eSDag-Erling Smørgrav 			continue;
235d93a896eSDag-Erling Smørgrav 		if (!include_sigonly && kt->sigonly)
236a0ee8cc6SDag-Erling Smørgrav 			continue;
237a0ee8cc6SDag-Erling Smørgrav 		if ((certs_only && !kt->cert) || (plain_only && kt->cert))
238a0ee8cc6SDag-Erling Smørgrav 			continue;
239a0ee8cc6SDag-Erling Smørgrav 		if (ret != NULL)
240ca86bcf2SDag-Erling Smørgrav 			ret[rlen++] = sep;
241a0ee8cc6SDag-Erling Smørgrav 		nlen = strlen(kt->name);
242a0ee8cc6SDag-Erling Smørgrav 		if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
243a0ee8cc6SDag-Erling Smørgrav 			free(ret);
244a0ee8cc6SDag-Erling Smørgrav 			return NULL;
245a0ee8cc6SDag-Erling Smørgrav 		}
246a0ee8cc6SDag-Erling Smørgrav 		ret = tmp;
247a0ee8cc6SDag-Erling Smørgrav 		memcpy(ret + rlen, kt->name, nlen + 1);
248a0ee8cc6SDag-Erling Smørgrav 		rlen += nlen;
249a0ee8cc6SDag-Erling Smørgrav 	}
250a0ee8cc6SDag-Erling Smørgrav 	return ret;
251a0ee8cc6SDag-Erling Smørgrav }
252a0ee8cc6SDag-Erling Smørgrav 
253a0ee8cc6SDag-Erling Smørgrav int
254bc5531deSDag-Erling Smørgrav sshkey_names_valid2(const char *names, int allow_wildcard)
255a0ee8cc6SDag-Erling Smørgrav {
256a0ee8cc6SDag-Erling Smørgrav 	char *s, *cp, *p;
257bc5531deSDag-Erling Smørgrav 	const struct keytype *kt;
258bc5531deSDag-Erling Smørgrav 	int type;
259a0ee8cc6SDag-Erling Smørgrav 
260a0ee8cc6SDag-Erling Smørgrav 	if (names == NULL || strcmp(names, "") == 0)
261a0ee8cc6SDag-Erling Smørgrav 		return 0;
262a0ee8cc6SDag-Erling Smørgrav 	if ((s = cp = strdup(names)) == NULL)
263a0ee8cc6SDag-Erling Smørgrav 		return 0;
264a0ee8cc6SDag-Erling Smørgrav 	for ((p = strsep(&cp, ",")); p && *p != '\0';
265a0ee8cc6SDag-Erling Smørgrav 	    (p = strsep(&cp, ","))) {
266bc5531deSDag-Erling Smørgrav 		type = sshkey_type_from_name(p);
267bc5531deSDag-Erling Smørgrav 		if (type == KEY_UNSPEC) {
268bc5531deSDag-Erling Smørgrav 			if (allow_wildcard) {
269bc5531deSDag-Erling Smørgrav 				/*
270bc5531deSDag-Erling Smørgrav 				 * Try matching key types against the string.
271bc5531deSDag-Erling Smørgrav 				 * If any has a positive or negative match then
272bc5531deSDag-Erling Smørgrav 				 * the component is accepted.
273bc5531deSDag-Erling Smørgrav 				 */
274bc5531deSDag-Erling Smørgrav 				for (kt = keytypes; kt->type != -1; kt++) {
275bc5531deSDag-Erling Smørgrav 					if (match_pattern_list(kt->name,
276557f75e5SDag-Erling Smørgrav 					    p, 0) != 0)
277bc5531deSDag-Erling Smørgrav 						break;
278bc5531deSDag-Erling Smørgrav 				}
279bc5531deSDag-Erling Smørgrav 				if (kt->type != -1)
280bc5531deSDag-Erling Smørgrav 					continue;
281bc5531deSDag-Erling Smørgrav 			}
282a0ee8cc6SDag-Erling Smørgrav 			free(s);
283a0ee8cc6SDag-Erling Smørgrav 			return 0;
284a0ee8cc6SDag-Erling Smørgrav 		}
285a0ee8cc6SDag-Erling Smørgrav 	}
286a0ee8cc6SDag-Erling Smørgrav 	free(s);
287a0ee8cc6SDag-Erling Smørgrav 	return 1;
288a0ee8cc6SDag-Erling Smørgrav }
289a0ee8cc6SDag-Erling Smørgrav 
290a0ee8cc6SDag-Erling Smørgrav u_int
291a0ee8cc6SDag-Erling Smørgrav sshkey_size(const struct sshkey *k)
292a0ee8cc6SDag-Erling Smørgrav {
293*2a01feabSEd Maste #ifdef WITH_OPENSSL
294*2a01feabSEd Maste 	const BIGNUM *rsa_n, *dsa_p;
295*2a01feabSEd Maste #endif /* WITH_OPENSSL */
296*2a01feabSEd Maste 
297a0ee8cc6SDag-Erling Smørgrav 	switch (k->type) {
298a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
299a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
300a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA_CERT:
301*2a01feabSEd Maste 		if (k->rsa == NULL)
302*2a01feabSEd Maste 			return 0;
303*2a01feabSEd Maste 		RSA_get0_key(k->rsa, &rsa_n, NULL, NULL);
304*2a01feabSEd Maste 		return BN_num_bits(rsa_n);
305a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
306a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA_CERT:
307*2a01feabSEd Maste 		if (k->dsa == NULL)
308*2a01feabSEd Maste 			return 0;
309*2a01feabSEd Maste 		DSA_get0_pqg(k->dsa, &dsa_p, NULL, NULL);
310*2a01feabSEd Maste 		return BN_num_bits(dsa_p);
311a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
312a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA_CERT:
313a0ee8cc6SDag-Erling Smørgrav 		return sshkey_curve_nid_to_bits(k->ecdsa_nid);
314a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
315a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
316a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519_CERT:
31747dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
31847dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS_CERT:
319a0ee8cc6SDag-Erling Smørgrav 		return 256;	/* XXX */
320a0ee8cc6SDag-Erling Smørgrav 	}
321a0ee8cc6SDag-Erling Smørgrav 	return 0;
322a0ee8cc6SDag-Erling Smørgrav }
323a0ee8cc6SDag-Erling Smørgrav 
324a0ee8cc6SDag-Erling Smørgrav static int
325a0ee8cc6SDag-Erling Smørgrav sshkey_type_is_valid_ca(int type)
326a0ee8cc6SDag-Erling Smørgrav {
327a0ee8cc6SDag-Erling Smørgrav 	switch (type) {
328a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
329a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
330a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
331a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
33247dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
333a0ee8cc6SDag-Erling Smørgrav 		return 1;
334a0ee8cc6SDag-Erling Smørgrav 	default:
335a0ee8cc6SDag-Erling Smørgrav 		return 0;
336a0ee8cc6SDag-Erling Smørgrav 	}
337a0ee8cc6SDag-Erling Smørgrav }
338a0ee8cc6SDag-Erling Smørgrav 
339a0ee8cc6SDag-Erling Smørgrav int
340a0ee8cc6SDag-Erling Smørgrav sshkey_is_cert(const struct sshkey *k)
341a0ee8cc6SDag-Erling Smørgrav {
342a0ee8cc6SDag-Erling Smørgrav 	if (k == NULL)
343a0ee8cc6SDag-Erling Smørgrav 		return 0;
344a0ee8cc6SDag-Erling Smørgrav 	return sshkey_type_is_cert(k->type);
345a0ee8cc6SDag-Erling Smørgrav }
346a0ee8cc6SDag-Erling Smørgrav 
347a0ee8cc6SDag-Erling Smørgrav /* Return the cert-less equivalent to a certified key type */
348a0ee8cc6SDag-Erling Smørgrav int
349a0ee8cc6SDag-Erling Smørgrav sshkey_type_plain(int type)
350a0ee8cc6SDag-Erling Smørgrav {
351a0ee8cc6SDag-Erling Smørgrav 	switch (type) {
352a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA_CERT:
353a0ee8cc6SDag-Erling Smørgrav 		return KEY_RSA;
354a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA_CERT:
355a0ee8cc6SDag-Erling Smørgrav 		return KEY_DSA;
356a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA_CERT:
357a0ee8cc6SDag-Erling Smørgrav 		return KEY_ECDSA;
358a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519_CERT:
359a0ee8cc6SDag-Erling Smørgrav 		return KEY_ED25519;
36047dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS_CERT:
36147dd1d1bSDag-Erling Smørgrav 		return KEY_XMSS;
362a0ee8cc6SDag-Erling Smørgrav 	default:
363a0ee8cc6SDag-Erling Smørgrav 		return type;
364a0ee8cc6SDag-Erling Smørgrav 	}
365a0ee8cc6SDag-Erling Smørgrav }
366a0ee8cc6SDag-Erling Smørgrav 
367a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
368a0ee8cc6SDag-Erling Smørgrav /* XXX: these are really begging for a table-driven approach */
369a0ee8cc6SDag-Erling Smørgrav int
370a0ee8cc6SDag-Erling Smørgrav sshkey_curve_name_to_nid(const char *name)
371a0ee8cc6SDag-Erling Smørgrav {
372a0ee8cc6SDag-Erling Smørgrav 	if (strcmp(name, "nistp256") == 0)
373a0ee8cc6SDag-Erling Smørgrav 		return NID_X9_62_prime256v1;
374a0ee8cc6SDag-Erling Smørgrav 	else if (strcmp(name, "nistp384") == 0)
375a0ee8cc6SDag-Erling Smørgrav 		return NID_secp384r1;
376a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_NISTP521
377a0ee8cc6SDag-Erling Smørgrav 	else if (strcmp(name, "nistp521") == 0)
378a0ee8cc6SDag-Erling Smørgrav 		return NID_secp521r1;
379a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_NISTP521 */
380a0ee8cc6SDag-Erling Smørgrav 	else
381a0ee8cc6SDag-Erling Smørgrav 		return -1;
382a0ee8cc6SDag-Erling Smørgrav }
383a0ee8cc6SDag-Erling Smørgrav 
384a0ee8cc6SDag-Erling Smørgrav u_int
385a0ee8cc6SDag-Erling Smørgrav sshkey_curve_nid_to_bits(int nid)
386a0ee8cc6SDag-Erling Smørgrav {
387a0ee8cc6SDag-Erling Smørgrav 	switch (nid) {
388a0ee8cc6SDag-Erling Smørgrav 	case NID_X9_62_prime256v1:
389a0ee8cc6SDag-Erling Smørgrav 		return 256;
390a0ee8cc6SDag-Erling Smørgrav 	case NID_secp384r1:
391a0ee8cc6SDag-Erling Smørgrav 		return 384;
392a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_NISTP521
393a0ee8cc6SDag-Erling Smørgrav 	case NID_secp521r1:
394a0ee8cc6SDag-Erling Smørgrav 		return 521;
395a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_NISTP521 */
396a0ee8cc6SDag-Erling Smørgrav 	default:
397a0ee8cc6SDag-Erling Smørgrav 		return 0;
398a0ee8cc6SDag-Erling Smørgrav 	}
399a0ee8cc6SDag-Erling Smørgrav }
400a0ee8cc6SDag-Erling Smørgrav 
401a0ee8cc6SDag-Erling Smørgrav int
402a0ee8cc6SDag-Erling Smørgrav sshkey_ecdsa_bits_to_nid(int bits)
403a0ee8cc6SDag-Erling Smørgrav {
404a0ee8cc6SDag-Erling Smørgrav 	switch (bits) {
405a0ee8cc6SDag-Erling Smørgrav 	case 256:
406a0ee8cc6SDag-Erling Smørgrav 		return NID_X9_62_prime256v1;
407a0ee8cc6SDag-Erling Smørgrav 	case 384:
408a0ee8cc6SDag-Erling Smørgrav 		return NID_secp384r1;
409a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_NISTP521
410a0ee8cc6SDag-Erling Smørgrav 	case 521:
411a0ee8cc6SDag-Erling Smørgrav 		return NID_secp521r1;
412a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_NISTP521 */
413a0ee8cc6SDag-Erling Smørgrav 	default:
414a0ee8cc6SDag-Erling Smørgrav 		return -1;
415a0ee8cc6SDag-Erling Smørgrav 	}
416a0ee8cc6SDag-Erling Smørgrav }
417a0ee8cc6SDag-Erling Smørgrav 
418a0ee8cc6SDag-Erling Smørgrav const char *
419a0ee8cc6SDag-Erling Smørgrav sshkey_curve_nid_to_name(int nid)
420a0ee8cc6SDag-Erling Smørgrav {
421a0ee8cc6SDag-Erling Smørgrav 	switch (nid) {
422a0ee8cc6SDag-Erling Smørgrav 	case NID_X9_62_prime256v1:
423a0ee8cc6SDag-Erling Smørgrav 		return "nistp256";
424a0ee8cc6SDag-Erling Smørgrav 	case NID_secp384r1:
425a0ee8cc6SDag-Erling Smørgrav 		return "nistp384";
426a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_NISTP521
427a0ee8cc6SDag-Erling Smørgrav 	case NID_secp521r1:
428a0ee8cc6SDag-Erling Smørgrav 		return "nistp521";
429a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_NISTP521 */
430a0ee8cc6SDag-Erling Smørgrav 	default:
431a0ee8cc6SDag-Erling Smørgrav 		return NULL;
432a0ee8cc6SDag-Erling Smørgrav 	}
433a0ee8cc6SDag-Erling Smørgrav }
434a0ee8cc6SDag-Erling Smørgrav 
435a0ee8cc6SDag-Erling Smørgrav int
436a0ee8cc6SDag-Erling Smørgrav sshkey_ec_nid_to_hash_alg(int nid)
437a0ee8cc6SDag-Erling Smørgrav {
438a0ee8cc6SDag-Erling Smørgrav 	int kbits = sshkey_curve_nid_to_bits(nid);
439a0ee8cc6SDag-Erling Smørgrav 
440a0ee8cc6SDag-Erling Smørgrav 	if (kbits <= 0)
441a0ee8cc6SDag-Erling Smørgrav 		return -1;
442a0ee8cc6SDag-Erling Smørgrav 
443a0ee8cc6SDag-Erling Smørgrav 	/* RFC5656 section 6.2.1 */
444a0ee8cc6SDag-Erling Smørgrav 	if (kbits <= 256)
445a0ee8cc6SDag-Erling Smørgrav 		return SSH_DIGEST_SHA256;
446a0ee8cc6SDag-Erling Smørgrav 	else if (kbits <= 384)
447a0ee8cc6SDag-Erling Smørgrav 		return SSH_DIGEST_SHA384;
448a0ee8cc6SDag-Erling Smørgrav 	else
449a0ee8cc6SDag-Erling Smørgrav 		return SSH_DIGEST_SHA512;
450a0ee8cc6SDag-Erling Smørgrav }
451a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
452a0ee8cc6SDag-Erling Smørgrav 
453a0ee8cc6SDag-Erling Smørgrav static void
454a0ee8cc6SDag-Erling Smørgrav cert_free(struct sshkey_cert *cert)
455a0ee8cc6SDag-Erling Smørgrav {
456a0ee8cc6SDag-Erling Smørgrav 	u_int i;
457a0ee8cc6SDag-Erling Smørgrav 
458a0ee8cc6SDag-Erling Smørgrav 	if (cert == NULL)
459a0ee8cc6SDag-Erling Smørgrav 		return;
460a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(cert->certblob);
461a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(cert->critical);
462a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(cert->extensions);
463a0ee8cc6SDag-Erling Smørgrav 	free(cert->key_id);
464a0ee8cc6SDag-Erling Smørgrav 	for (i = 0; i < cert->nprincipals; i++)
465a0ee8cc6SDag-Erling Smørgrav 		free(cert->principals[i]);
466a0ee8cc6SDag-Erling Smørgrav 	free(cert->principals);
467a0ee8cc6SDag-Erling Smørgrav 	sshkey_free(cert->signature_key);
46847dd1d1bSDag-Erling Smørgrav 	freezero(cert, sizeof(*cert));
469a0ee8cc6SDag-Erling Smørgrav }
470a0ee8cc6SDag-Erling Smørgrav 
471a0ee8cc6SDag-Erling Smørgrav static struct sshkey_cert *
472a0ee8cc6SDag-Erling Smørgrav cert_new(void)
473a0ee8cc6SDag-Erling Smørgrav {
474a0ee8cc6SDag-Erling Smørgrav 	struct sshkey_cert *cert;
475a0ee8cc6SDag-Erling Smørgrav 
476a0ee8cc6SDag-Erling Smørgrav 	if ((cert = calloc(1, sizeof(*cert))) == NULL)
477a0ee8cc6SDag-Erling Smørgrav 		return NULL;
478a0ee8cc6SDag-Erling Smørgrav 	if ((cert->certblob = sshbuf_new()) == NULL ||
479a0ee8cc6SDag-Erling Smørgrav 	    (cert->critical = sshbuf_new()) == NULL ||
480a0ee8cc6SDag-Erling Smørgrav 	    (cert->extensions = sshbuf_new()) == NULL) {
481a0ee8cc6SDag-Erling Smørgrav 		cert_free(cert);
482a0ee8cc6SDag-Erling Smørgrav 		return NULL;
483a0ee8cc6SDag-Erling Smørgrav 	}
484a0ee8cc6SDag-Erling Smørgrav 	cert->key_id = NULL;
485a0ee8cc6SDag-Erling Smørgrav 	cert->principals = NULL;
486a0ee8cc6SDag-Erling Smørgrav 	cert->signature_key = NULL;
487a0ee8cc6SDag-Erling Smørgrav 	return cert;
488a0ee8cc6SDag-Erling Smørgrav }
489a0ee8cc6SDag-Erling Smørgrav 
490a0ee8cc6SDag-Erling Smørgrav struct sshkey *
491a0ee8cc6SDag-Erling Smørgrav sshkey_new(int type)
492a0ee8cc6SDag-Erling Smørgrav {
493a0ee8cc6SDag-Erling Smørgrav 	struct sshkey *k;
494a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
495a0ee8cc6SDag-Erling Smørgrav 	RSA *rsa;
496a0ee8cc6SDag-Erling Smørgrav 	DSA *dsa;
497a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
498a0ee8cc6SDag-Erling Smørgrav 
499a0ee8cc6SDag-Erling Smørgrav 	if ((k = calloc(1, sizeof(*k))) == NULL)
500a0ee8cc6SDag-Erling Smørgrav 		return NULL;
501a0ee8cc6SDag-Erling Smørgrav 	k->type = type;
502a0ee8cc6SDag-Erling Smørgrav 	k->ecdsa = NULL;
503a0ee8cc6SDag-Erling Smørgrav 	k->ecdsa_nid = -1;
504a0ee8cc6SDag-Erling Smørgrav 	k->dsa = NULL;
505a0ee8cc6SDag-Erling Smørgrav 	k->rsa = NULL;
506a0ee8cc6SDag-Erling Smørgrav 	k->cert = NULL;
507a0ee8cc6SDag-Erling Smørgrav 	k->ed25519_sk = NULL;
508a0ee8cc6SDag-Erling Smørgrav 	k->ed25519_pk = NULL;
50947dd1d1bSDag-Erling Smørgrav 	k->xmss_sk = NULL;
51047dd1d1bSDag-Erling Smørgrav 	k->xmss_pk = NULL;
511a0ee8cc6SDag-Erling Smørgrav 	switch (k->type) {
512a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
513a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
514a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA_CERT:
515*2a01feabSEd Maste 		if ((rsa = RSA_new()) == NULL) {
516a0ee8cc6SDag-Erling Smørgrav 			free(k);
517a0ee8cc6SDag-Erling Smørgrav 			return NULL;
518a0ee8cc6SDag-Erling Smørgrav 		}
519a0ee8cc6SDag-Erling Smørgrav 		k->rsa = rsa;
520a0ee8cc6SDag-Erling Smørgrav 		break;
521a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
522a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA_CERT:
523*2a01feabSEd Maste 		if ((dsa = DSA_new()) == NULL) {
524a0ee8cc6SDag-Erling Smørgrav 			free(k);
525a0ee8cc6SDag-Erling Smørgrav 			return NULL;
526a0ee8cc6SDag-Erling Smørgrav 		}
527a0ee8cc6SDag-Erling Smørgrav 		k->dsa = dsa;
528a0ee8cc6SDag-Erling Smørgrav 		break;
529a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
530a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA_CERT:
531a0ee8cc6SDag-Erling Smørgrav 		/* Cannot do anything until we know the group */
532a0ee8cc6SDag-Erling Smørgrav 		break;
533a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
534a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
535a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519_CERT:
53647dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
53747dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS_CERT:
538a0ee8cc6SDag-Erling Smørgrav 		/* no need to prealloc */
539a0ee8cc6SDag-Erling Smørgrav 		break;
540a0ee8cc6SDag-Erling Smørgrav 	case KEY_UNSPEC:
541a0ee8cc6SDag-Erling Smørgrav 		break;
542a0ee8cc6SDag-Erling Smørgrav 	default:
543a0ee8cc6SDag-Erling Smørgrav 		free(k);
544a0ee8cc6SDag-Erling Smørgrav 		return NULL;
545a0ee8cc6SDag-Erling Smørgrav 	}
546a0ee8cc6SDag-Erling Smørgrav 
547a0ee8cc6SDag-Erling Smørgrav 	if (sshkey_is_cert(k)) {
548a0ee8cc6SDag-Erling Smørgrav 		if ((k->cert = cert_new()) == NULL) {
549a0ee8cc6SDag-Erling Smørgrav 			sshkey_free(k);
550a0ee8cc6SDag-Erling Smørgrav 			return NULL;
551a0ee8cc6SDag-Erling Smørgrav 		}
552a0ee8cc6SDag-Erling Smørgrav 	}
553a0ee8cc6SDag-Erling Smørgrav 
554a0ee8cc6SDag-Erling Smørgrav 	return k;
555a0ee8cc6SDag-Erling Smørgrav }
556a0ee8cc6SDag-Erling Smørgrav 
557*2a01feabSEd Maste /* XXX garbage-collect this API */
558a0ee8cc6SDag-Erling Smørgrav struct sshkey *
559a0ee8cc6SDag-Erling Smørgrav sshkey_new_private(int type)
560a0ee8cc6SDag-Erling Smørgrav {
561a0ee8cc6SDag-Erling Smørgrav 	struct sshkey *k = sshkey_new(type);
562a0ee8cc6SDag-Erling Smørgrav 
563a0ee8cc6SDag-Erling Smørgrav 	if (k == NULL)
564a0ee8cc6SDag-Erling Smørgrav 		return NULL;
565a0ee8cc6SDag-Erling Smørgrav 	return k;
566a0ee8cc6SDag-Erling Smørgrav }
567a0ee8cc6SDag-Erling Smørgrav 
568a0ee8cc6SDag-Erling Smørgrav void
569a0ee8cc6SDag-Erling Smørgrav sshkey_free(struct sshkey *k)
570a0ee8cc6SDag-Erling Smørgrav {
571a0ee8cc6SDag-Erling Smørgrav 	if (k == NULL)
572a0ee8cc6SDag-Erling Smørgrav 		return;
573a0ee8cc6SDag-Erling Smørgrav 	switch (k->type) {
574a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
575a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
576a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA_CERT:
577a0ee8cc6SDag-Erling Smørgrav 		RSA_free(k->rsa);
578a0ee8cc6SDag-Erling Smørgrav 		k->rsa = NULL;
579a0ee8cc6SDag-Erling Smørgrav 		break;
580a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
581a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA_CERT:
582a0ee8cc6SDag-Erling Smørgrav 		DSA_free(k->dsa);
583a0ee8cc6SDag-Erling Smørgrav 		k->dsa = NULL;
584a0ee8cc6SDag-Erling Smørgrav 		break;
585a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_ECC
586a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
587a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA_CERT:
588a0ee8cc6SDag-Erling Smørgrav 		EC_KEY_free(k->ecdsa);
589a0ee8cc6SDag-Erling Smørgrav 		k->ecdsa = NULL;
590a0ee8cc6SDag-Erling Smørgrav 		break;
591a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_ECC */
592a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
593a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
594a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519_CERT:
59547dd1d1bSDag-Erling Smørgrav 		freezero(k->ed25519_pk, ED25519_PK_SZ);
596a0ee8cc6SDag-Erling Smørgrav 		k->ed25519_pk = NULL;
59747dd1d1bSDag-Erling Smørgrav 		freezero(k->ed25519_sk, ED25519_SK_SZ);
598a0ee8cc6SDag-Erling Smørgrav 		k->ed25519_sk = NULL;
599a0ee8cc6SDag-Erling Smørgrav 		break;
60047dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
60147dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
60247dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS_CERT:
60347dd1d1bSDag-Erling Smørgrav 		freezero(k->xmss_pk, sshkey_xmss_pklen(k));
60447dd1d1bSDag-Erling Smørgrav 		k->xmss_pk = NULL;
60547dd1d1bSDag-Erling Smørgrav 		freezero(k->xmss_sk, sshkey_xmss_sklen(k));
60647dd1d1bSDag-Erling Smørgrav 		k->xmss_sk = NULL;
60747dd1d1bSDag-Erling Smørgrav 		sshkey_xmss_free_state(k);
60847dd1d1bSDag-Erling Smørgrav 		free(k->xmss_name);
60947dd1d1bSDag-Erling Smørgrav 		k->xmss_name = NULL;
61047dd1d1bSDag-Erling Smørgrav 		free(k->xmss_filename);
61147dd1d1bSDag-Erling Smørgrav 		k->xmss_filename = NULL;
61247dd1d1bSDag-Erling Smørgrav 		break;
61347dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
614a0ee8cc6SDag-Erling Smørgrav 	case KEY_UNSPEC:
615a0ee8cc6SDag-Erling Smørgrav 		break;
616a0ee8cc6SDag-Erling Smørgrav 	default:
617a0ee8cc6SDag-Erling Smørgrav 		break;
618a0ee8cc6SDag-Erling Smørgrav 	}
619a0ee8cc6SDag-Erling Smørgrav 	if (sshkey_is_cert(k))
620a0ee8cc6SDag-Erling Smørgrav 		cert_free(k->cert);
62147dd1d1bSDag-Erling Smørgrav 	freezero(k, sizeof(*k));
622a0ee8cc6SDag-Erling Smørgrav }
623a0ee8cc6SDag-Erling Smørgrav 
624a0ee8cc6SDag-Erling Smørgrav static int
625a0ee8cc6SDag-Erling Smørgrav cert_compare(struct sshkey_cert *a, struct sshkey_cert *b)
626a0ee8cc6SDag-Erling Smørgrav {
627a0ee8cc6SDag-Erling Smørgrav 	if (a == NULL && b == NULL)
628a0ee8cc6SDag-Erling Smørgrav 		return 1;
629a0ee8cc6SDag-Erling Smørgrav 	if (a == NULL || b == NULL)
630a0ee8cc6SDag-Erling Smørgrav 		return 0;
631a0ee8cc6SDag-Erling Smørgrav 	if (sshbuf_len(a->certblob) != sshbuf_len(b->certblob))
632a0ee8cc6SDag-Erling Smørgrav 		return 0;
633a0ee8cc6SDag-Erling Smørgrav 	if (timingsafe_bcmp(sshbuf_ptr(a->certblob), sshbuf_ptr(b->certblob),
634a0ee8cc6SDag-Erling Smørgrav 	    sshbuf_len(a->certblob)) != 0)
635a0ee8cc6SDag-Erling Smørgrav 		return 0;
636a0ee8cc6SDag-Erling Smørgrav 	return 1;
637a0ee8cc6SDag-Erling Smørgrav }
638a0ee8cc6SDag-Erling Smørgrav 
639a0ee8cc6SDag-Erling Smørgrav /*
640a0ee8cc6SDag-Erling Smørgrav  * Compare public portions of key only, allowing comparisons between
641a0ee8cc6SDag-Erling Smørgrav  * certificates and plain keys too.
642a0ee8cc6SDag-Erling Smørgrav  */
643a0ee8cc6SDag-Erling Smørgrav int
644a0ee8cc6SDag-Erling Smørgrav sshkey_equal_public(const struct sshkey *a, const struct sshkey *b)
645a0ee8cc6SDag-Erling Smørgrav {
646*2a01feabSEd Maste #if defined(WITH_OPENSSL)
647*2a01feabSEd Maste 	const BIGNUM *rsa_e_a, *rsa_n_a;
648*2a01feabSEd Maste 	const BIGNUM *rsa_e_b, *rsa_n_b;
649*2a01feabSEd Maste 	const BIGNUM *dsa_p_a, *dsa_q_a, *dsa_g_a, *dsa_pub_key_a;
650*2a01feabSEd Maste 	const BIGNUM *dsa_p_b, *dsa_q_b, *dsa_g_b, *dsa_pub_key_b;
651*2a01feabSEd Maste # if defined(OPENSSL_HAS_ECC)
652a0ee8cc6SDag-Erling Smørgrav 	BN_CTX *bnctx;
653*2a01feabSEd Maste # endif /* OPENSSL_HAS_ECC */
654*2a01feabSEd Maste #endif /* WITH_OPENSSL */
655a0ee8cc6SDag-Erling Smørgrav 
656a0ee8cc6SDag-Erling Smørgrav 	if (a == NULL || b == NULL ||
657a0ee8cc6SDag-Erling Smørgrav 	    sshkey_type_plain(a->type) != sshkey_type_plain(b->type))
658a0ee8cc6SDag-Erling Smørgrav 		return 0;
659a0ee8cc6SDag-Erling Smørgrav 
660a0ee8cc6SDag-Erling Smørgrav 	switch (a->type) {
661a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
662a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA_CERT:
663a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
664*2a01feabSEd Maste 		if (a->rsa == NULL || b->rsa == NULL)
665*2a01feabSEd Maste 			return 0;
666*2a01feabSEd Maste 		RSA_get0_key(a->rsa, &rsa_n_a, &rsa_e_a, NULL);
667*2a01feabSEd Maste 		RSA_get0_key(b->rsa, &rsa_n_b, &rsa_e_b, NULL);
668*2a01feabSEd Maste 		return BN_cmp(rsa_e_a, rsa_e_b) == 0 &&
669*2a01feabSEd Maste 		    BN_cmp(rsa_n_a, rsa_n_b) == 0;
670a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA_CERT:
671a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
672*2a01feabSEd Maste 		if (a->dsa == NULL || b->dsa == NULL)
673*2a01feabSEd Maste 			return 0;
674*2a01feabSEd Maste 		DSA_get0_pqg(a->dsa, &dsa_p_a, &dsa_q_a, &dsa_g_a);
675*2a01feabSEd Maste 		DSA_get0_pqg(b->dsa, &dsa_p_b, &dsa_q_b, &dsa_g_b);
676*2a01feabSEd Maste 		DSA_get0_key(a->dsa, &dsa_pub_key_a, NULL);
677*2a01feabSEd Maste 		DSA_get0_key(b->dsa, &dsa_pub_key_b, NULL);
678*2a01feabSEd Maste 		return BN_cmp(dsa_p_a, dsa_p_b) == 0 &&
679*2a01feabSEd Maste 		    BN_cmp(dsa_q_a, dsa_q_b) == 0 &&
680*2a01feabSEd Maste 		    BN_cmp(dsa_g_a, dsa_g_b) == 0 &&
681*2a01feabSEd Maste 		    BN_cmp(dsa_pub_key_a, dsa_pub_key_b) == 0;
682a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_ECC
683a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA_CERT:
684a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
685a0ee8cc6SDag-Erling Smørgrav 		if (a->ecdsa == NULL || b->ecdsa == NULL ||
686a0ee8cc6SDag-Erling Smørgrav 		    EC_KEY_get0_public_key(a->ecdsa) == NULL ||
687a0ee8cc6SDag-Erling Smørgrav 		    EC_KEY_get0_public_key(b->ecdsa) == NULL)
688a0ee8cc6SDag-Erling Smørgrav 			return 0;
689a0ee8cc6SDag-Erling Smørgrav 		if ((bnctx = BN_CTX_new()) == NULL)
690a0ee8cc6SDag-Erling Smørgrav 			return 0;
691a0ee8cc6SDag-Erling Smørgrav 		if (EC_GROUP_cmp(EC_KEY_get0_group(a->ecdsa),
692a0ee8cc6SDag-Erling Smørgrav 		    EC_KEY_get0_group(b->ecdsa), bnctx) != 0 ||
693a0ee8cc6SDag-Erling Smørgrav 		    EC_POINT_cmp(EC_KEY_get0_group(a->ecdsa),
694a0ee8cc6SDag-Erling Smørgrav 		    EC_KEY_get0_public_key(a->ecdsa),
695a0ee8cc6SDag-Erling Smørgrav 		    EC_KEY_get0_public_key(b->ecdsa), bnctx) != 0) {
696a0ee8cc6SDag-Erling Smørgrav 			BN_CTX_free(bnctx);
697a0ee8cc6SDag-Erling Smørgrav 			return 0;
698a0ee8cc6SDag-Erling Smørgrav 		}
699a0ee8cc6SDag-Erling Smørgrav 		BN_CTX_free(bnctx);
700a0ee8cc6SDag-Erling Smørgrav 		return 1;
701a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_ECC */
702a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
703a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
704a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519_CERT:
705a0ee8cc6SDag-Erling Smørgrav 		return a->ed25519_pk != NULL && b->ed25519_pk != NULL &&
706a0ee8cc6SDag-Erling Smørgrav 		    memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0;
70747dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
70847dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
70947dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS_CERT:
71047dd1d1bSDag-Erling Smørgrav 		return a->xmss_pk != NULL && b->xmss_pk != NULL &&
71147dd1d1bSDag-Erling Smørgrav 		    sshkey_xmss_pklen(a) == sshkey_xmss_pklen(b) &&
71247dd1d1bSDag-Erling Smørgrav 		    memcmp(a->xmss_pk, b->xmss_pk, sshkey_xmss_pklen(a)) == 0;
71347dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
714a0ee8cc6SDag-Erling Smørgrav 	default:
715a0ee8cc6SDag-Erling Smørgrav 		return 0;
716a0ee8cc6SDag-Erling Smørgrav 	}
717a0ee8cc6SDag-Erling Smørgrav 	/* NOTREACHED */
718a0ee8cc6SDag-Erling Smørgrav }
719a0ee8cc6SDag-Erling Smørgrav 
720a0ee8cc6SDag-Erling Smørgrav int
721a0ee8cc6SDag-Erling Smørgrav sshkey_equal(const struct sshkey *a, const struct sshkey *b)
722a0ee8cc6SDag-Erling Smørgrav {
723a0ee8cc6SDag-Erling Smørgrav 	if (a == NULL || b == NULL || a->type != b->type)
724a0ee8cc6SDag-Erling Smørgrav 		return 0;
725a0ee8cc6SDag-Erling Smørgrav 	if (sshkey_is_cert(a)) {
726a0ee8cc6SDag-Erling Smørgrav 		if (!cert_compare(a->cert, b->cert))
727a0ee8cc6SDag-Erling Smørgrav 			return 0;
728a0ee8cc6SDag-Erling Smørgrav 	}
729a0ee8cc6SDag-Erling Smørgrav 	return sshkey_equal_public(a, b);
730a0ee8cc6SDag-Erling Smørgrav }
731a0ee8cc6SDag-Erling Smørgrav 
732a0ee8cc6SDag-Erling Smørgrav static int
73347dd1d1bSDag-Erling Smørgrav to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain,
73447dd1d1bSDag-Erling Smørgrav   enum sshkey_serialize_rep opts)
735a0ee8cc6SDag-Erling Smørgrav {
736a0ee8cc6SDag-Erling Smørgrav 	int type, ret = SSH_ERR_INTERNAL_ERROR;
737a0ee8cc6SDag-Erling Smørgrav 	const char *typename;
738*2a01feabSEd Maste #ifdef WITH_OPENSSL
739*2a01feabSEd Maste 	const BIGNUM *rsa_n, *rsa_e, *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
740*2a01feabSEd Maste #endif /* WITH_OPENSSL */
741a0ee8cc6SDag-Erling Smørgrav 
742a0ee8cc6SDag-Erling Smørgrav 	if (key == NULL)
743a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
744a0ee8cc6SDag-Erling Smørgrav 
745557f75e5SDag-Erling Smørgrav 	if (sshkey_is_cert(key)) {
746557f75e5SDag-Erling Smørgrav 		if (key->cert == NULL)
747557f75e5SDag-Erling Smørgrav 			return SSH_ERR_EXPECTED_CERT;
748557f75e5SDag-Erling Smørgrav 		if (sshbuf_len(key->cert->certblob) == 0)
749557f75e5SDag-Erling Smørgrav 			return SSH_ERR_KEY_LACKS_CERTBLOB;
750557f75e5SDag-Erling Smørgrav 	}
751a0ee8cc6SDag-Erling Smørgrav 	type = force_plain ? sshkey_type_plain(key->type) : key->type;
752a0ee8cc6SDag-Erling Smørgrav 	typename = sshkey_ssh_name_from_type_nid(type, key->ecdsa_nid);
753a0ee8cc6SDag-Erling Smørgrav 
754a0ee8cc6SDag-Erling Smørgrav 	switch (type) {
755a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
756a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA_CERT:
757a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA_CERT:
758a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA_CERT:
759a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
760a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519_CERT:
76147dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
76247dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS_CERT:
76347dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
764a0ee8cc6SDag-Erling Smørgrav 		/* Use the existing blob */
765a0ee8cc6SDag-Erling Smørgrav 		/* XXX modified flag? */
766a0ee8cc6SDag-Erling Smørgrav 		if ((ret = sshbuf_putb(b, key->cert->certblob)) != 0)
767a0ee8cc6SDag-Erling Smørgrav 			return ret;
768a0ee8cc6SDag-Erling Smørgrav 		break;
769a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
770a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
771a0ee8cc6SDag-Erling Smørgrav 		if (key->dsa == NULL)
772a0ee8cc6SDag-Erling Smørgrav 			return SSH_ERR_INVALID_ARGUMENT;
773*2a01feabSEd Maste 		DSA_get0_pqg(key->dsa, &dsa_p, &dsa_q, &dsa_g);
774*2a01feabSEd Maste 		DSA_get0_key(key->dsa, &dsa_pub_key, NULL);
775a0ee8cc6SDag-Erling Smørgrav 		if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
776*2a01feabSEd Maste 		    (ret = sshbuf_put_bignum2(b, dsa_p)) != 0 ||
777*2a01feabSEd Maste 		    (ret = sshbuf_put_bignum2(b, dsa_q)) != 0 ||
778*2a01feabSEd Maste 		    (ret = sshbuf_put_bignum2(b, dsa_g)) != 0 ||
779*2a01feabSEd Maste 		    (ret = sshbuf_put_bignum2(b, dsa_pub_key)) != 0)
780a0ee8cc6SDag-Erling Smørgrav 			return ret;
781a0ee8cc6SDag-Erling Smørgrav 		break;
782a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_ECC
783a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
784a0ee8cc6SDag-Erling Smørgrav 		if (key->ecdsa == NULL)
785a0ee8cc6SDag-Erling Smørgrav 			return SSH_ERR_INVALID_ARGUMENT;
786a0ee8cc6SDag-Erling Smørgrav 		if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
787a0ee8cc6SDag-Erling Smørgrav 		    (ret = sshbuf_put_cstring(b,
788a0ee8cc6SDag-Erling Smørgrav 		    sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 ||
789a0ee8cc6SDag-Erling Smørgrav 		    (ret = sshbuf_put_eckey(b, key->ecdsa)) != 0)
790a0ee8cc6SDag-Erling Smørgrav 			return ret;
791a0ee8cc6SDag-Erling Smørgrav 		break;
792a0ee8cc6SDag-Erling Smørgrav # endif
793a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
794a0ee8cc6SDag-Erling Smørgrav 		if (key->rsa == NULL)
795a0ee8cc6SDag-Erling Smørgrav 			return SSH_ERR_INVALID_ARGUMENT;
796*2a01feabSEd Maste 		RSA_get0_key(key->rsa, &rsa_n, &rsa_e, NULL);
797a0ee8cc6SDag-Erling Smørgrav 		if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
798*2a01feabSEd Maste 		    (ret = sshbuf_put_bignum2(b, rsa_e)) != 0 ||
799*2a01feabSEd Maste 		    (ret = sshbuf_put_bignum2(b, rsa_n)) != 0)
800a0ee8cc6SDag-Erling Smørgrav 			return ret;
801a0ee8cc6SDag-Erling Smørgrav 		break;
802a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
803a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
804a0ee8cc6SDag-Erling Smørgrav 		if (key->ed25519_pk == NULL)
805a0ee8cc6SDag-Erling Smørgrav 			return SSH_ERR_INVALID_ARGUMENT;
806a0ee8cc6SDag-Erling Smørgrav 		if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
807a0ee8cc6SDag-Erling Smørgrav 		    (ret = sshbuf_put_string(b,
808a0ee8cc6SDag-Erling Smørgrav 		    key->ed25519_pk, ED25519_PK_SZ)) != 0)
809a0ee8cc6SDag-Erling Smørgrav 			return ret;
810a0ee8cc6SDag-Erling Smørgrav 		break;
81147dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
81247dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
81347dd1d1bSDag-Erling Smørgrav 		if (key->xmss_name == NULL || key->xmss_pk == NULL ||
81447dd1d1bSDag-Erling Smørgrav 		    sshkey_xmss_pklen(key) == 0)
81547dd1d1bSDag-Erling Smørgrav 			return SSH_ERR_INVALID_ARGUMENT;
81647dd1d1bSDag-Erling Smørgrav 		if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
81747dd1d1bSDag-Erling Smørgrav 		    (ret = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
81847dd1d1bSDag-Erling Smørgrav 		    (ret = sshbuf_put_string(b,
81947dd1d1bSDag-Erling Smørgrav 		    key->xmss_pk, sshkey_xmss_pklen(key))) != 0 ||
82047dd1d1bSDag-Erling Smørgrav 		    (ret = sshkey_xmss_serialize_pk_info(key, b, opts)) != 0)
82147dd1d1bSDag-Erling Smørgrav 			return ret;
82247dd1d1bSDag-Erling Smørgrav 		break;
82347dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
824a0ee8cc6SDag-Erling Smørgrav 	default:
825a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_KEY_TYPE_UNKNOWN;
826a0ee8cc6SDag-Erling Smørgrav 	}
827a0ee8cc6SDag-Erling Smørgrav 	return 0;
828a0ee8cc6SDag-Erling Smørgrav }
829a0ee8cc6SDag-Erling Smørgrav 
830a0ee8cc6SDag-Erling Smørgrav int
831bc5531deSDag-Erling Smørgrav sshkey_putb(const struct sshkey *key, struct sshbuf *b)
832a0ee8cc6SDag-Erling Smørgrav {
83347dd1d1bSDag-Erling Smørgrav 	return to_blob_buf(key, b, 0, SSHKEY_SERIALIZE_DEFAULT);
834a0ee8cc6SDag-Erling Smørgrav }
835a0ee8cc6SDag-Erling Smørgrav 
836a0ee8cc6SDag-Erling Smørgrav int
83747dd1d1bSDag-Erling Smørgrav sshkey_puts_opts(const struct sshkey *key, struct sshbuf *b,
83847dd1d1bSDag-Erling Smørgrav     enum sshkey_serialize_rep opts)
839bc5531deSDag-Erling Smørgrav {
840bc5531deSDag-Erling Smørgrav 	struct sshbuf *tmp;
841bc5531deSDag-Erling Smørgrav 	int r;
842bc5531deSDag-Erling Smørgrav 
843bc5531deSDag-Erling Smørgrav 	if ((tmp = sshbuf_new()) == NULL)
844bc5531deSDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
84547dd1d1bSDag-Erling Smørgrav 	r = to_blob_buf(key, tmp, 0, opts);
846bc5531deSDag-Erling Smørgrav 	if (r == 0)
847bc5531deSDag-Erling Smørgrav 		r = sshbuf_put_stringb(b, tmp);
848bc5531deSDag-Erling Smørgrav 	sshbuf_free(tmp);
849bc5531deSDag-Erling Smørgrav 	return r;
850bc5531deSDag-Erling Smørgrav }
851bc5531deSDag-Erling Smørgrav 
852bc5531deSDag-Erling Smørgrav int
85347dd1d1bSDag-Erling Smørgrav sshkey_puts(const struct sshkey *key, struct sshbuf *b)
85447dd1d1bSDag-Erling Smørgrav {
85547dd1d1bSDag-Erling Smørgrav 	return sshkey_puts_opts(key, b, SSHKEY_SERIALIZE_DEFAULT);
85647dd1d1bSDag-Erling Smørgrav }
85747dd1d1bSDag-Erling Smørgrav 
85847dd1d1bSDag-Erling Smørgrav int
859bc5531deSDag-Erling Smørgrav sshkey_putb_plain(const struct sshkey *key, struct sshbuf *b)
860a0ee8cc6SDag-Erling Smørgrav {
86147dd1d1bSDag-Erling Smørgrav 	return to_blob_buf(key, b, 1, SSHKEY_SERIALIZE_DEFAULT);
862a0ee8cc6SDag-Erling Smørgrav }
863a0ee8cc6SDag-Erling Smørgrav 
864a0ee8cc6SDag-Erling Smørgrav static int
86547dd1d1bSDag-Erling Smørgrav to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain,
86647dd1d1bSDag-Erling Smørgrav     enum sshkey_serialize_rep opts)
867a0ee8cc6SDag-Erling Smørgrav {
868a0ee8cc6SDag-Erling Smørgrav 	int ret = SSH_ERR_INTERNAL_ERROR;
869a0ee8cc6SDag-Erling Smørgrav 	size_t len;
870a0ee8cc6SDag-Erling Smørgrav 	struct sshbuf *b = NULL;
871a0ee8cc6SDag-Erling Smørgrav 
872a0ee8cc6SDag-Erling Smørgrav 	if (lenp != NULL)
873a0ee8cc6SDag-Erling Smørgrav 		*lenp = 0;
874a0ee8cc6SDag-Erling Smørgrav 	if (blobp != NULL)
875a0ee8cc6SDag-Erling Smørgrav 		*blobp = NULL;
876a0ee8cc6SDag-Erling Smørgrav 	if ((b = sshbuf_new()) == NULL)
877a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
87847dd1d1bSDag-Erling Smørgrav 	if ((ret = to_blob_buf(key, b, force_plain, opts)) != 0)
879a0ee8cc6SDag-Erling Smørgrav 		goto out;
880a0ee8cc6SDag-Erling Smørgrav 	len = sshbuf_len(b);
881a0ee8cc6SDag-Erling Smørgrav 	if (lenp != NULL)
882a0ee8cc6SDag-Erling Smørgrav 		*lenp = len;
883a0ee8cc6SDag-Erling Smørgrav 	if (blobp != NULL) {
884a0ee8cc6SDag-Erling Smørgrav 		if ((*blobp = malloc(len)) == NULL) {
885a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_ALLOC_FAIL;
886a0ee8cc6SDag-Erling Smørgrav 			goto out;
887a0ee8cc6SDag-Erling Smørgrav 		}
888a0ee8cc6SDag-Erling Smørgrav 		memcpy(*blobp, sshbuf_ptr(b), len);
889a0ee8cc6SDag-Erling Smørgrav 	}
890a0ee8cc6SDag-Erling Smørgrav 	ret = 0;
891a0ee8cc6SDag-Erling Smørgrav  out:
892a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(b);
893a0ee8cc6SDag-Erling Smørgrav 	return ret;
894a0ee8cc6SDag-Erling Smørgrav }
895a0ee8cc6SDag-Erling Smørgrav 
896a0ee8cc6SDag-Erling Smørgrav int
897a0ee8cc6SDag-Erling Smørgrav sshkey_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
898a0ee8cc6SDag-Erling Smørgrav {
89947dd1d1bSDag-Erling Smørgrav 	return to_blob(key, blobp, lenp, 0, SSHKEY_SERIALIZE_DEFAULT);
900a0ee8cc6SDag-Erling Smørgrav }
901a0ee8cc6SDag-Erling Smørgrav 
902a0ee8cc6SDag-Erling Smørgrav int
903a0ee8cc6SDag-Erling Smørgrav sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
904a0ee8cc6SDag-Erling Smørgrav {
90547dd1d1bSDag-Erling Smørgrav 	return to_blob(key, blobp, lenp, 1, SSHKEY_SERIALIZE_DEFAULT);
906a0ee8cc6SDag-Erling Smørgrav }
907a0ee8cc6SDag-Erling Smørgrav 
908a0ee8cc6SDag-Erling Smørgrav int
909bc5531deSDag-Erling Smørgrav sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg,
910a0ee8cc6SDag-Erling Smørgrav     u_char **retp, size_t *lenp)
911a0ee8cc6SDag-Erling Smørgrav {
912a0ee8cc6SDag-Erling Smørgrav 	u_char *blob = NULL, *ret = NULL;
913a0ee8cc6SDag-Erling Smørgrav 	size_t blob_len = 0;
914bc5531deSDag-Erling Smørgrav 	int r = SSH_ERR_INTERNAL_ERROR;
915a0ee8cc6SDag-Erling Smørgrav 
916a0ee8cc6SDag-Erling Smørgrav 	if (retp != NULL)
917a0ee8cc6SDag-Erling Smørgrav 		*retp = NULL;
918a0ee8cc6SDag-Erling Smørgrav 	if (lenp != NULL)
919a0ee8cc6SDag-Erling Smørgrav 		*lenp = 0;
920bc5531deSDag-Erling Smørgrav 	if (ssh_digest_bytes(dgst_alg) == 0) {
921a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_INVALID_ARGUMENT;
922a0ee8cc6SDag-Erling Smørgrav 		goto out;
923a0ee8cc6SDag-Erling Smørgrav 	}
92447dd1d1bSDag-Erling Smørgrav 	if ((r = to_blob(k, &blob, &blob_len, 1, SSHKEY_SERIALIZE_DEFAULT))
92547dd1d1bSDag-Erling Smørgrav 	    != 0)
926a0ee8cc6SDag-Erling Smørgrav 		goto out;
927a0ee8cc6SDag-Erling Smørgrav 	if ((ret = calloc(1, SSH_DIGEST_MAX_LENGTH)) == NULL) {
928a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_ALLOC_FAIL;
929a0ee8cc6SDag-Erling Smørgrav 		goto out;
930a0ee8cc6SDag-Erling Smørgrav 	}
931bc5531deSDag-Erling Smørgrav 	if ((r = ssh_digest_memory(dgst_alg, blob, blob_len,
932a0ee8cc6SDag-Erling Smørgrav 	    ret, SSH_DIGEST_MAX_LENGTH)) != 0)
933a0ee8cc6SDag-Erling Smørgrav 		goto out;
934a0ee8cc6SDag-Erling Smørgrav 	/* success */
935a0ee8cc6SDag-Erling Smørgrav 	if (retp != NULL) {
936a0ee8cc6SDag-Erling Smørgrav 		*retp = ret;
937a0ee8cc6SDag-Erling Smørgrav 		ret = NULL;
938a0ee8cc6SDag-Erling Smørgrav 	}
939a0ee8cc6SDag-Erling Smørgrav 	if (lenp != NULL)
940bc5531deSDag-Erling Smørgrav 		*lenp = ssh_digest_bytes(dgst_alg);
941a0ee8cc6SDag-Erling Smørgrav 	r = 0;
942a0ee8cc6SDag-Erling Smørgrav  out:
943a0ee8cc6SDag-Erling Smørgrav 	free(ret);
944a0ee8cc6SDag-Erling Smørgrav 	if (blob != NULL) {
945a0ee8cc6SDag-Erling Smørgrav 		explicit_bzero(blob, blob_len);
946a0ee8cc6SDag-Erling Smørgrav 		free(blob);
947a0ee8cc6SDag-Erling Smørgrav 	}
948a0ee8cc6SDag-Erling Smørgrav 	return r;
949a0ee8cc6SDag-Erling Smørgrav }
950a0ee8cc6SDag-Erling Smørgrav 
951a0ee8cc6SDag-Erling Smørgrav static char *
952bc5531deSDag-Erling Smørgrav fingerprint_b64(const char *alg, u_char *dgst_raw, size_t dgst_raw_len)
953a0ee8cc6SDag-Erling Smørgrav {
954bc5531deSDag-Erling Smørgrav 	char *ret;
955bc5531deSDag-Erling Smørgrav 	size_t plen = strlen(alg) + 1;
956bc5531deSDag-Erling Smørgrav 	size_t rlen = ((dgst_raw_len + 2) / 3) * 4 + plen + 1;
957bc5531deSDag-Erling Smørgrav 	int r;
958a0ee8cc6SDag-Erling Smørgrav 
959bc5531deSDag-Erling Smørgrav 	if (dgst_raw_len > 65536 || (ret = calloc(1, rlen)) == NULL)
960a0ee8cc6SDag-Erling Smørgrav 		return NULL;
961bc5531deSDag-Erling Smørgrav 	strlcpy(ret, alg, rlen);
962bc5531deSDag-Erling Smørgrav 	strlcat(ret, ":", rlen);
963bc5531deSDag-Erling Smørgrav 	if (dgst_raw_len == 0)
964bc5531deSDag-Erling Smørgrav 		return ret;
965bc5531deSDag-Erling Smørgrav 	if ((r = b64_ntop(dgst_raw, dgst_raw_len,
966bc5531deSDag-Erling Smørgrav 	    ret + plen, rlen - plen)) == -1) {
96747dd1d1bSDag-Erling Smørgrav 		freezero(ret, rlen);
968bc5531deSDag-Erling Smørgrav 		return NULL;
969bc5531deSDag-Erling Smørgrav 	}
970bc5531deSDag-Erling Smørgrav 	/* Trim padding characters from end */
971bc5531deSDag-Erling Smørgrav 	ret[strcspn(ret, "=")] = '\0';
972bc5531deSDag-Erling Smørgrav 	return ret;
973a0ee8cc6SDag-Erling Smørgrav }
974a0ee8cc6SDag-Erling Smørgrav 
975bc5531deSDag-Erling Smørgrav static char *
976bc5531deSDag-Erling Smørgrav fingerprint_hex(const char *alg, u_char *dgst_raw, size_t dgst_raw_len)
977bc5531deSDag-Erling Smørgrav {
978bc5531deSDag-Erling Smørgrav 	char *retval, hex[5];
979bc5531deSDag-Erling Smørgrav 	size_t i, rlen = dgst_raw_len * 3 + strlen(alg) + 2;
980bc5531deSDag-Erling Smørgrav 
981bc5531deSDag-Erling Smørgrav 	if (dgst_raw_len > 65536 || (retval = calloc(1, rlen)) == NULL)
982bc5531deSDag-Erling Smørgrav 		return NULL;
983bc5531deSDag-Erling Smørgrav 	strlcpy(retval, alg, rlen);
984bc5531deSDag-Erling Smørgrav 	strlcat(retval, ":", rlen);
985bc5531deSDag-Erling Smørgrav 	for (i = 0; i < dgst_raw_len; i++) {
986bc5531deSDag-Erling Smørgrav 		snprintf(hex, sizeof(hex), "%s%02x",
987bc5531deSDag-Erling Smørgrav 		    i > 0 ? ":" : "", dgst_raw[i]);
988bc5531deSDag-Erling Smørgrav 		strlcat(retval, hex, rlen);
989bc5531deSDag-Erling Smørgrav 	}
990a0ee8cc6SDag-Erling Smørgrav 	return retval;
991a0ee8cc6SDag-Erling Smørgrav }
992a0ee8cc6SDag-Erling Smørgrav 
993a0ee8cc6SDag-Erling Smørgrav static char *
994a0ee8cc6SDag-Erling Smørgrav fingerprint_bubblebabble(u_char *dgst_raw, size_t dgst_raw_len)
995a0ee8cc6SDag-Erling Smørgrav {
996a0ee8cc6SDag-Erling Smørgrav 	char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
997a0ee8cc6SDag-Erling Smørgrav 	char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
998a0ee8cc6SDag-Erling Smørgrav 	    'n', 'p', 'r', 's', 't', 'v', 'z', 'x' };
999a0ee8cc6SDag-Erling Smørgrav 	u_int i, j = 0, rounds, seed = 1;
1000a0ee8cc6SDag-Erling Smørgrav 	char *retval;
1001a0ee8cc6SDag-Erling Smørgrav 
1002a0ee8cc6SDag-Erling Smørgrav 	rounds = (dgst_raw_len / 2) + 1;
1003a0ee8cc6SDag-Erling Smørgrav 	if ((retval = calloc(rounds, 6)) == NULL)
1004a0ee8cc6SDag-Erling Smørgrav 		return NULL;
1005a0ee8cc6SDag-Erling Smørgrav 	retval[j++] = 'x';
1006a0ee8cc6SDag-Erling Smørgrav 	for (i = 0; i < rounds; i++) {
1007a0ee8cc6SDag-Erling Smørgrav 		u_int idx0, idx1, idx2, idx3, idx4;
1008a0ee8cc6SDag-Erling Smørgrav 		if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) {
1009a0ee8cc6SDag-Erling Smørgrav 			idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) +
1010a0ee8cc6SDag-Erling Smørgrav 			    seed) % 6;
1011a0ee8cc6SDag-Erling Smørgrav 			idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15;
1012a0ee8cc6SDag-Erling Smørgrav 			idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) +
1013a0ee8cc6SDag-Erling Smørgrav 			    (seed / 6)) % 6;
1014a0ee8cc6SDag-Erling Smørgrav 			retval[j++] = vowels[idx0];
1015a0ee8cc6SDag-Erling Smørgrav 			retval[j++] = consonants[idx1];
1016a0ee8cc6SDag-Erling Smørgrav 			retval[j++] = vowels[idx2];
1017a0ee8cc6SDag-Erling Smørgrav 			if ((i + 1) < rounds) {
1018a0ee8cc6SDag-Erling Smørgrav 				idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15;
1019a0ee8cc6SDag-Erling Smørgrav 				idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15;
1020a0ee8cc6SDag-Erling Smørgrav 				retval[j++] = consonants[idx3];
1021a0ee8cc6SDag-Erling Smørgrav 				retval[j++] = '-';
1022a0ee8cc6SDag-Erling Smørgrav 				retval[j++] = consonants[idx4];
1023a0ee8cc6SDag-Erling Smørgrav 				seed = ((seed * 5) +
1024a0ee8cc6SDag-Erling Smørgrav 				    ((((u_int)(dgst_raw[2 * i])) * 7) +
1025a0ee8cc6SDag-Erling Smørgrav 				    ((u_int)(dgst_raw[(2 * i) + 1])))) % 36;
1026a0ee8cc6SDag-Erling Smørgrav 			}
1027a0ee8cc6SDag-Erling Smørgrav 		} else {
1028a0ee8cc6SDag-Erling Smørgrav 			idx0 = seed % 6;
1029a0ee8cc6SDag-Erling Smørgrav 			idx1 = 16;
1030a0ee8cc6SDag-Erling Smørgrav 			idx2 = seed / 6;
1031a0ee8cc6SDag-Erling Smørgrav 			retval[j++] = vowels[idx0];
1032a0ee8cc6SDag-Erling Smørgrav 			retval[j++] = consonants[idx1];
1033a0ee8cc6SDag-Erling Smørgrav 			retval[j++] = vowels[idx2];
1034a0ee8cc6SDag-Erling Smørgrav 		}
1035a0ee8cc6SDag-Erling Smørgrav 	}
1036a0ee8cc6SDag-Erling Smørgrav 	retval[j++] = 'x';
1037a0ee8cc6SDag-Erling Smørgrav 	retval[j++] = '\0';
1038a0ee8cc6SDag-Erling Smørgrav 	return retval;
1039a0ee8cc6SDag-Erling Smørgrav }
1040a0ee8cc6SDag-Erling Smørgrav 
1041a0ee8cc6SDag-Erling Smørgrav /*
1042a0ee8cc6SDag-Erling Smørgrav  * Draw an ASCII-Art representing the fingerprint so human brain can
1043a0ee8cc6SDag-Erling Smørgrav  * profit from its built-in pattern recognition ability.
1044a0ee8cc6SDag-Erling Smørgrav  * This technique is called "random art" and can be found in some
1045a0ee8cc6SDag-Erling Smørgrav  * scientific publications like this original paper:
1046a0ee8cc6SDag-Erling Smørgrav  *
1047a0ee8cc6SDag-Erling Smørgrav  * "Hash Visualization: a New Technique to improve Real-World Security",
1048a0ee8cc6SDag-Erling Smørgrav  * Perrig A. and Song D., 1999, International Workshop on Cryptographic
1049a0ee8cc6SDag-Erling Smørgrav  * Techniques and E-Commerce (CrypTEC '99)
1050a0ee8cc6SDag-Erling Smørgrav  * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
1051a0ee8cc6SDag-Erling Smørgrav  *
1052a0ee8cc6SDag-Erling Smørgrav  * The subject came up in a talk by Dan Kaminsky, too.
1053a0ee8cc6SDag-Erling Smørgrav  *
1054a0ee8cc6SDag-Erling Smørgrav  * If you see the picture is different, the key is different.
1055a0ee8cc6SDag-Erling Smørgrav  * If the picture looks the same, you still know nothing.
1056a0ee8cc6SDag-Erling Smørgrav  *
1057a0ee8cc6SDag-Erling Smørgrav  * The algorithm used here is a worm crawling over a discrete plane,
1058a0ee8cc6SDag-Erling Smørgrav  * leaving a trace (augmenting the field) everywhere it goes.
1059a0ee8cc6SDag-Erling Smørgrav  * Movement is taken from dgst_raw 2bit-wise.  Bumping into walls
1060a0ee8cc6SDag-Erling Smørgrav  * makes the respective movement vector be ignored for this turn.
1061a0ee8cc6SDag-Erling Smørgrav  * Graphs are not unambiguous, because circles in graphs can be
1062a0ee8cc6SDag-Erling Smørgrav  * walked in either direction.
1063a0ee8cc6SDag-Erling Smørgrav  */
1064a0ee8cc6SDag-Erling Smørgrav 
1065a0ee8cc6SDag-Erling Smørgrav /*
1066a0ee8cc6SDag-Erling Smørgrav  * Field sizes for the random art.  Have to be odd, so the starting point
1067a0ee8cc6SDag-Erling Smørgrav  * can be in the exact middle of the picture, and FLDBASE should be >=8 .
1068a0ee8cc6SDag-Erling Smørgrav  * Else pictures would be too dense, and drawing the frame would
1069a0ee8cc6SDag-Erling Smørgrav  * fail, too, because the key type would not fit in anymore.
1070a0ee8cc6SDag-Erling Smørgrav  */
1071a0ee8cc6SDag-Erling Smørgrav #define	FLDBASE		8
1072a0ee8cc6SDag-Erling Smørgrav #define	FLDSIZE_Y	(FLDBASE + 1)
1073a0ee8cc6SDag-Erling Smørgrav #define	FLDSIZE_X	(FLDBASE * 2 + 1)
1074a0ee8cc6SDag-Erling Smørgrav static char *
1075bc5531deSDag-Erling Smørgrav fingerprint_randomart(const char *alg, u_char *dgst_raw, size_t dgst_raw_len,
1076a0ee8cc6SDag-Erling Smørgrav     const struct sshkey *k)
1077a0ee8cc6SDag-Erling Smørgrav {
1078a0ee8cc6SDag-Erling Smørgrav 	/*
1079a0ee8cc6SDag-Erling Smørgrav 	 * Chars to be used after each other every time the worm
1080a0ee8cc6SDag-Erling Smørgrav 	 * intersects with itself.  Matter of taste.
1081a0ee8cc6SDag-Erling Smørgrav 	 */
1082a0ee8cc6SDag-Erling Smørgrav 	char	*augmentation_string = " .o+=*BOX@%&#/^SE";
1083bc5531deSDag-Erling Smørgrav 	char	*retval, *p, title[FLDSIZE_X], hash[FLDSIZE_X];
1084a0ee8cc6SDag-Erling Smørgrav 	u_char	 field[FLDSIZE_X][FLDSIZE_Y];
1085bc5531deSDag-Erling Smørgrav 	size_t	 i, tlen, hlen;
1086a0ee8cc6SDag-Erling Smørgrav 	u_int	 b;
1087a0ee8cc6SDag-Erling Smørgrav 	int	 x, y, r;
1088a0ee8cc6SDag-Erling Smørgrav 	size_t	 len = strlen(augmentation_string) - 1;
1089a0ee8cc6SDag-Erling Smørgrav 
1090a0ee8cc6SDag-Erling Smørgrav 	if ((retval = calloc((FLDSIZE_X + 3), (FLDSIZE_Y + 2))) == NULL)
1091a0ee8cc6SDag-Erling Smørgrav 		return NULL;
1092a0ee8cc6SDag-Erling Smørgrav 
1093a0ee8cc6SDag-Erling Smørgrav 	/* initialize field */
1094a0ee8cc6SDag-Erling Smørgrav 	memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
1095a0ee8cc6SDag-Erling Smørgrav 	x = FLDSIZE_X / 2;
1096a0ee8cc6SDag-Erling Smørgrav 	y = FLDSIZE_Y / 2;
1097a0ee8cc6SDag-Erling Smørgrav 
1098a0ee8cc6SDag-Erling Smørgrav 	/* process raw key */
1099a0ee8cc6SDag-Erling Smørgrav 	for (i = 0; i < dgst_raw_len; i++) {
1100a0ee8cc6SDag-Erling Smørgrav 		int input;
1101a0ee8cc6SDag-Erling Smørgrav 		/* each byte conveys four 2-bit move commands */
1102a0ee8cc6SDag-Erling Smørgrav 		input = dgst_raw[i];
1103a0ee8cc6SDag-Erling Smørgrav 		for (b = 0; b < 4; b++) {
1104a0ee8cc6SDag-Erling Smørgrav 			/* evaluate 2 bit, rest is shifted later */
1105a0ee8cc6SDag-Erling Smørgrav 			x += (input & 0x1) ? 1 : -1;
1106a0ee8cc6SDag-Erling Smørgrav 			y += (input & 0x2) ? 1 : -1;
1107a0ee8cc6SDag-Erling Smørgrav 
1108a0ee8cc6SDag-Erling Smørgrav 			/* assure we are still in bounds */
1109ca86bcf2SDag-Erling Smørgrav 			x = MAXIMUM(x, 0);
1110ca86bcf2SDag-Erling Smørgrav 			y = MAXIMUM(y, 0);
1111ca86bcf2SDag-Erling Smørgrav 			x = MINIMUM(x, FLDSIZE_X - 1);
1112ca86bcf2SDag-Erling Smørgrav 			y = MINIMUM(y, FLDSIZE_Y - 1);
1113a0ee8cc6SDag-Erling Smørgrav 
1114a0ee8cc6SDag-Erling Smørgrav 			/* augment the field */
1115a0ee8cc6SDag-Erling Smørgrav 			if (field[x][y] < len - 2)
1116a0ee8cc6SDag-Erling Smørgrav 				field[x][y]++;
1117a0ee8cc6SDag-Erling Smørgrav 			input = input >> 2;
1118a0ee8cc6SDag-Erling Smørgrav 		}
1119a0ee8cc6SDag-Erling Smørgrav 	}
1120a0ee8cc6SDag-Erling Smørgrav 
1121a0ee8cc6SDag-Erling Smørgrav 	/* mark starting point and end point*/
1122a0ee8cc6SDag-Erling Smørgrav 	field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;
1123a0ee8cc6SDag-Erling Smørgrav 	field[x][y] = len;
1124a0ee8cc6SDag-Erling Smørgrav 
1125a0ee8cc6SDag-Erling Smørgrav 	/* assemble title */
1126a0ee8cc6SDag-Erling Smørgrav 	r = snprintf(title, sizeof(title), "[%s %u]",
1127a0ee8cc6SDag-Erling Smørgrav 		sshkey_type(k), sshkey_size(k));
1128a0ee8cc6SDag-Erling Smørgrav 	/* If [type size] won't fit, then try [type]; fits "[ED25519-CERT]" */
1129a0ee8cc6SDag-Erling Smørgrav 	if (r < 0 || r > (int)sizeof(title))
1130bc5531deSDag-Erling Smørgrav 		r = snprintf(title, sizeof(title), "[%s]", sshkey_type(k));
1131bc5531deSDag-Erling Smørgrav 	tlen = (r <= 0) ? 0 : strlen(title);
1132bc5531deSDag-Erling Smørgrav 
1133bc5531deSDag-Erling Smørgrav 	/* assemble hash ID. */
1134bc5531deSDag-Erling Smørgrav 	r = snprintf(hash, sizeof(hash), "[%s]", alg);
1135bc5531deSDag-Erling Smørgrav 	hlen = (r <= 0) ? 0 : strlen(hash);
1136a0ee8cc6SDag-Erling Smørgrav 
1137a0ee8cc6SDag-Erling Smørgrav 	/* output upper border */
1138a0ee8cc6SDag-Erling Smørgrav 	p = retval;
1139a0ee8cc6SDag-Erling Smørgrav 	*p++ = '+';
1140a0ee8cc6SDag-Erling Smørgrav 	for (i = 0; i < (FLDSIZE_X - tlen) / 2; i++)
1141a0ee8cc6SDag-Erling Smørgrav 		*p++ = '-';
1142a0ee8cc6SDag-Erling Smørgrav 	memcpy(p, title, tlen);
1143a0ee8cc6SDag-Erling Smørgrav 	p += tlen;
1144bc5531deSDag-Erling Smørgrav 	for (i += tlen; i < FLDSIZE_X; i++)
1145a0ee8cc6SDag-Erling Smørgrav 		*p++ = '-';
1146a0ee8cc6SDag-Erling Smørgrav 	*p++ = '+';
1147a0ee8cc6SDag-Erling Smørgrav 	*p++ = '\n';
1148a0ee8cc6SDag-Erling Smørgrav 
1149a0ee8cc6SDag-Erling Smørgrav 	/* output content */
1150a0ee8cc6SDag-Erling Smørgrav 	for (y = 0; y < FLDSIZE_Y; y++) {
1151a0ee8cc6SDag-Erling Smørgrav 		*p++ = '|';
1152a0ee8cc6SDag-Erling Smørgrav 		for (x = 0; x < FLDSIZE_X; x++)
1153ca86bcf2SDag-Erling Smørgrav 			*p++ = augmentation_string[MINIMUM(field[x][y], len)];
1154a0ee8cc6SDag-Erling Smørgrav 		*p++ = '|';
1155a0ee8cc6SDag-Erling Smørgrav 		*p++ = '\n';
1156a0ee8cc6SDag-Erling Smørgrav 	}
1157a0ee8cc6SDag-Erling Smørgrav 
1158a0ee8cc6SDag-Erling Smørgrav 	/* output lower border */
1159a0ee8cc6SDag-Erling Smørgrav 	*p++ = '+';
1160bc5531deSDag-Erling Smørgrav 	for (i = 0; i < (FLDSIZE_X - hlen) / 2; i++)
1161bc5531deSDag-Erling Smørgrav 		*p++ = '-';
1162bc5531deSDag-Erling Smørgrav 	memcpy(p, hash, hlen);
1163bc5531deSDag-Erling Smørgrav 	p += hlen;
1164bc5531deSDag-Erling Smørgrav 	for (i += hlen; i < FLDSIZE_X; i++)
1165a0ee8cc6SDag-Erling Smørgrav 		*p++ = '-';
1166a0ee8cc6SDag-Erling Smørgrav 	*p++ = '+';
1167a0ee8cc6SDag-Erling Smørgrav 
1168a0ee8cc6SDag-Erling Smørgrav 	return retval;
1169a0ee8cc6SDag-Erling Smørgrav }
1170a0ee8cc6SDag-Erling Smørgrav 
1171a0ee8cc6SDag-Erling Smørgrav char *
1172bc5531deSDag-Erling Smørgrav sshkey_fingerprint(const struct sshkey *k, int dgst_alg,
1173a0ee8cc6SDag-Erling Smørgrav     enum sshkey_fp_rep dgst_rep)
1174a0ee8cc6SDag-Erling Smørgrav {
1175a0ee8cc6SDag-Erling Smørgrav 	char *retval = NULL;
1176a0ee8cc6SDag-Erling Smørgrav 	u_char *dgst_raw;
1177a0ee8cc6SDag-Erling Smørgrav 	size_t dgst_raw_len;
1178a0ee8cc6SDag-Erling Smørgrav 
1179bc5531deSDag-Erling Smørgrav 	if (sshkey_fingerprint_raw(k, dgst_alg, &dgst_raw, &dgst_raw_len) != 0)
1180a0ee8cc6SDag-Erling Smørgrav 		return NULL;
1181a0ee8cc6SDag-Erling Smørgrav 	switch (dgst_rep) {
1182bc5531deSDag-Erling Smørgrav 	case SSH_FP_DEFAULT:
1183bc5531deSDag-Erling Smørgrav 		if (dgst_alg == SSH_DIGEST_MD5) {
1184bc5531deSDag-Erling Smørgrav 			retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg),
1185bc5531deSDag-Erling Smørgrav 			    dgst_raw, dgst_raw_len);
1186bc5531deSDag-Erling Smørgrav 		} else {
1187bc5531deSDag-Erling Smørgrav 			retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg),
1188bc5531deSDag-Erling Smørgrav 			    dgst_raw, dgst_raw_len);
1189bc5531deSDag-Erling Smørgrav 		}
1190bc5531deSDag-Erling Smørgrav 		break;
1191a0ee8cc6SDag-Erling Smørgrav 	case SSH_FP_HEX:
1192bc5531deSDag-Erling Smørgrav 		retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg),
1193bc5531deSDag-Erling Smørgrav 		    dgst_raw, dgst_raw_len);
1194bc5531deSDag-Erling Smørgrav 		break;
1195bc5531deSDag-Erling Smørgrav 	case SSH_FP_BASE64:
1196bc5531deSDag-Erling Smørgrav 		retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg),
1197bc5531deSDag-Erling Smørgrav 		    dgst_raw, dgst_raw_len);
1198a0ee8cc6SDag-Erling Smørgrav 		break;
1199a0ee8cc6SDag-Erling Smørgrav 	case SSH_FP_BUBBLEBABBLE:
1200a0ee8cc6SDag-Erling Smørgrav 		retval = fingerprint_bubblebabble(dgst_raw, dgst_raw_len);
1201a0ee8cc6SDag-Erling Smørgrav 		break;
1202a0ee8cc6SDag-Erling Smørgrav 	case SSH_FP_RANDOMART:
1203bc5531deSDag-Erling Smørgrav 		retval = fingerprint_randomart(ssh_digest_alg_name(dgst_alg),
1204bc5531deSDag-Erling Smørgrav 		    dgst_raw, dgst_raw_len, k);
1205a0ee8cc6SDag-Erling Smørgrav 		break;
1206a0ee8cc6SDag-Erling Smørgrav 	default:
1207a0ee8cc6SDag-Erling Smørgrav 		explicit_bzero(dgst_raw, dgst_raw_len);
1208a0ee8cc6SDag-Erling Smørgrav 		free(dgst_raw);
1209a0ee8cc6SDag-Erling Smørgrav 		return NULL;
1210a0ee8cc6SDag-Erling Smørgrav 	}
1211a0ee8cc6SDag-Erling Smørgrav 	explicit_bzero(dgst_raw, dgst_raw_len);
1212a0ee8cc6SDag-Erling Smørgrav 	free(dgst_raw);
1213a0ee8cc6SDag-Erling Smørgrav 	return retval;
1214a0ee8cc6SDag-Erling Smørgrav }
1215a0ee8cc6SDag-Erling Smørgrav 
121647dd1d1bSDag-Erling Smørgrav static int
121747dd1d1bSDag-Erling Smørgrav peek_type_nid(const char *s, size_t l, int *nid)
121847dd1d1bSDag-Erling Smørgrav {
121947dd1d1bSDag-Erling Smørgrav 	const struct keytype *kt;
1220a0ee8cc6SDag-Erling Smørgrav 
122147dd1d1bSDag-Erling Smørgrav 	for (kt = keytypes; kt->type != -1; kt++) {
122247dd1d1bSDag-Erling Smørgrav 		if (kt->name == NULL || strlen(kt->name) != l)
122347dd1d1bSDag-Erling Smørgrav 			continue;
122447dd1d1bSDag-Erling Smørgrav 		if (memcmp(s, kt->name, l) == 0) {
122547dd1d1bSDag-Erling Smørgrav 			*nid = -1;
122647dd1d1bSDag-Erling Smørgrav 			if (kt->type == KEY_ECDSA || kt->type == KEY_ECDSA_CERT)
122747dd1d1bSDag-Erling Smørgrav 				*nid = kt->nid;
122847dd1d1bSDag-Erling Smørgrav 			return kt->type;
122947dd1d1bSDag-Erling Smørgrav 		}
123047dd1d1bSDag-Erling Smørgrav 	}
123147dd1d1bSDag-Erling Smørgrav 	return KEY_UNSPEC;
123247dd1d1bSDag-Erling Smørgrav }
123347dd1d1bSDag-Erling Smørgrav 
123447dd1d1bSDag-Erling Smørgrav /* XXX this can now be made const char * */
1235a0ee8cc6SDag-Erling Smørgrav int
1236a0ee8cc6SDag-Erling Smørgrav sshkey_read(struct sshkey *ret, char **cpp)
1237a0ee8cc6SDag-Erling Smørgrav {
1238a0ee8cc6SDag-Erling Smørgrav 	struct sshkey *k;
123947dd1d1bSDag-Erling Smørgrav 	char *cp, *blobcopy;
124047dd1d1bSDag-Erling Smørgrav 	size_t space;
1241a0ee8cc6SDag-Erling Smørgrav 	int r, type, curve_nid = -1;
1242a0ee8cc6SDag-Erling Smørgrav 	struct sshbuf *blob;
1243a0ee8cc6SDag-Erling Smørgrav 
1244d93a896eSDag-Erling Smørgrav 	if (ret == NULL)
1245d93a896eSDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
1246d93a896eSDag-Erling Smørgrav 
1247a0ee8cc6SDag-Erling Smørgrav 	switch (ret->type) {
1248a0ee8cc6SDag-Erling Smørgrav 	case KEY_UNSPEC:
1249a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
1250a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
1251a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
1252a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
1253a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA_CERT:
1254a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA_CERT:
1255a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA_CERT:
1256a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519_CERT:
125747dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
125847dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
125947dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS_CERT:
126047dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
126147dd1d1bSDag-Erling Smørgrav 		break; /* ok */
126247dd1d1bSDag-Erling Smørgrav 	default:
126347dd1d1bSDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
126447dd1d1bSDag-Erling Smørgrav 	}
126547dd1d1bSDag-Erling Smørgrav 
126647dd1d1bSDag-Erling Smørgrav 	/* Decode type */
126747dd1d1bSDag-Erling Smørgrav 	cp = *cpp;
126847dd1d1bSDag-Erling Smørgrav 	space = strcspn(cp, " \t");
126947dd1d1bSDag-Erling Smørgrav 	if (space == strlen(cp))
1270a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_FORMAT;
127147dd1d1bSDag-Erling Smørgrav 	if ((type = peek_type_nid(cp, space, &curve_nid)) == KEY_UNSPEC)
1272a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_FORMAT;
127347dd1d1bSDag-Erling Smørgrav 
127447dd1d1bSDag-Erling Smørgrav 	/* skip whitespace */
127547dd1d1bSDag-Erling Smørgrav 	for (cp += space; *cp == ' ' || *cp == '\t'; cp++)
127647dd1d1bSDag-Erling Smørgrav 		;
1277a0ee8cc6SDag-Erling Smørgrav 	if (*cp == '\0')
1278a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_FORMAT;
1279bc5531deSDag-Erling Smørgrav 	if (ret->type != KEY_UNSPEC && ret->type != type)
1280a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_KEY_TYPE_MISMATCH;
1281a0ee8cc6SDag-Erling Smørgrav 	if ((blob = sshbuf_new()) == NULL)
1282a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
128347dd1d1bSDag-Erling Smørgrav 
128447dd1d1bSDag-Erling Smørgrav 	/* find end of keyblob and decode */
128547dd1d1bSDag-Erling Smørgrav 	space = strcspn(cp, " \t");
128647dd1d1bSDag-Erling Smørgrav 	if ((blobcopy = strndup(cp, space)) == NULL) {
128747dd1d1bSDag-Erling Smørgrav 		sshbuf_free(blob);
128847dd1d1bSDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
128947dd1d1bSDag-Erling Smørgrav 	}
129047dd1d1bSDag-Erling Smørgrav 	if ((r = sshbuf_b64tod(blob, blobcopy)) != 0) {
129147dd1d1bSDag-Erling Smørgrav 		free(blobcopy);
1292a0ee8cc6SDag-Erling Smørgrav 		sshbuf_free(blob);
1293a0ee8cc6SDag-Erling Smørgrav 		return r;
1294a0ee8cc6SDag-Erling Smørgrav 	}
129547dd1d1bSDag-Erling Smørgrav 	free(blobcopy);
129647dd1d1bSDag-Erling Smørgrav 	if ((r = sshkey_fromb(blob, &k)) != 0) {
1297a0ee8cc6SDag-Erling Smørgrav 		sshbuf_free(blob);
1298a0ee8cc6SDag-Erling Smørgrav 		return r;
1299a0ee8cc6SDag-Erling Smørgrav 	}
1300a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(blob);
130147dd1d1bSDag-Erling Smørgrav 
130247dd1d1bSDag-Erling Smørgrav 	/* skip whitespace and leave cp at start of comment */
130347dd1d1bSDag-Erling Smørgrav 	for (cp += space; *cp == ' ' || *cp == '\t'; cp++)
130447dd1d1bSDag-Erling Smørgrav 		;
130547dd1d1bSDag-Erling Smørgrav 
130647dd1d1bSDag-Erling Smørgrav 	/* ensure type of blob matches type at start of line */
1307a0ee8cc6SDag-Erling Smørgrav 	if (k->type != type) {
1308a0ee8cc6SDag-Erling Smørgrav 		sshkey_free(k);
1309a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_KEY_TYPE_MISMATCH;
1310a0ee8cc6SDag-Erling Smørgrav 	}
131147dd1d1bSDag-Erling Smørgrav 	if (sshkey_type_plain(type) == KEY_ECDSA && curve_nid != k->ecdsa_nid) {
1312a0ee8cc6SDag-Erling Smørgrav 		sshkey_free(k);
1313a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_EC_CURVE_MISMATCH;
1314a0ee8cc6SDag-Erling Smørgrav 	}
131547dd1d1bSDag-Erling Smørgrav 
131647dd1d1bSDag-Erling Smørgrav 	/* Fill in ret from parsed key */
1317bc5531deSDag-Erling Smørgrav 	ret->type = type;
1318a0ee8cc6SDag-Erling Smørgrav 	if (sshkey_is_cert(ret)) {
1319a0ee8cc6SDag-Erling Smørgrav 		if (!sshkey_is_cert(k)) {
1320a0ee8cc6SDag-Erling Smørgrav 			sshkey_free(k);
1321a0ee8cc6SDag-Erling Smørgrav 			return SSH_ERR_EXPECTED_CERT;
1322a0ee8cc6SDag-Erling Smørgrav 		}
1323a0ee8cc6SDag-Erling Smørgrav 		if (ret->cert != NULL)
1324a0ee8cc6SDag-Erling Smørgrav 			cert_free(ret->cert);
1325a0ee8cc6SDag-Erling Smørgrav 		ret->cert = k->cert;
1326a0ee8cc6SDag-Erling Smørgrav 		k->cert = NULL;
1327a0ee8cc6SDag-Erling Smørgrav 	}
1328acc1a9efSDag-Erling Smørgrav 	switch (sshkey_type_plain(ret->type)) {
1329a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
1330acc1a9efSDag-Erling Smørgrav 	case KEY_RSA:
1331a0ee8cc6SDag-Erling Smørgrav 		RSA_free(ret->rsa);
1332a0ee8cc6SDag-Erling Smørgrav 		ret->rsa = k->rsa;
1333a0ee8cc6SDag-Erling Smørgrav 		k->rsa = NULL;
1334a0ee8cc6SDag-Erling Smørgrav #ifdef DEBUG_PK
1335a0ee8cc6SDag-Erling Smørgrav 		RSA_print_fp(stderr, ret->rsa, 8);
1336a0ee8cc6SDag-Erling Smørgrav #endif
1337acc1a9efSDag-Erling Smørgrav 		break;
1338acc1a9efSDag-Erling Smørgrav 	case KEY_DSA:
1339a0ee8cc6SDag-Erling Smørgrav 		DSA_free(ret->dsa);
1340a0ee8cc6SDag-Erling Smørgrav 		ret->dsa = k->dsa;
1341a0ee8cc6SDag-Erling Smørgrav 		k->dsa = NULL;
1342a0ee8cc6SDag-Erling Smørgrav #ifdef DEBUG_PK
1343a0ee8cc6SDag-Erling Smørgrav 		DSA_print_fp(stderr, ret->dsa, 8);
1344a0ee8cc6SDag-Erling Smørgrav #endif
1345acc1a9efSDag-Erling Smørgrav 		break;
1346a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_ECC
1347acc1a9efSDag-Erling Smørgrav 	case KEY_ECDSA:
1348a0ee8cc6SDag-Erling Smørgrav 		EC_KEY_free(ret->ecdsa);
1349a0ee8cc6SDag-Erling Smørgrav 		ret->ecdsa = k->ecdsa;
1350a0ee8cc6SDag-Erling Smørgrav 		ret->ecdsa_nid = k->ecdsa_nid;
1351a0ee8cc6SDag-Erling Smørgrav 		k->ecdsa = NULL;
1352a0ee8cc6SDag-Erling Smørgrav 		k->ecdsa_nid = -1;
1353a0ee8cc6SDag-Erling Smørgrav #ifdef DEBUG_PK
1354a0ee8cc6SDag-Erling Smørgrav 		sshkey_dump_ec_key(ret->ecdsa);
1355a0ee8cc6SDag-Erling Smørgrav #endif
1356acc1a9efSDag-Erling Smørgrav 		break;
1357a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_ECC */
1358a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
1359acc1a9efSDag-Erling Smørgrav 	case KEY_ED25519:
136047dd1d1bSDag-Erling Smørgrav 		freezero(ret->ed25519_pk, ED25519_PK_SZ);
1361a0ee8cc6SDag-Erling Smørgrav 		ret->ed25519_pk = k->ed25519_pk;
1362a0ee8cc6SDag-Erling Smørgrav 		k->ed25519_pk = NULL;
1363a0ee8cc6SDag-Erling Smørgrav #ifdef DEBUG_PK
1364a0ee8cc6SDag-Erling Smørgrav 		/* XXX */
1365a0ee8cc6SDag-Erling Smørgrav #endif
1366acc1a9efSDag-Erling Smørgrav 		break;
136747dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
136847dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
136947dd1d1bSDag-Erling Smørgrav 		free(ret->xmss_pk);
137047dd1d1bSDag-Erling Smørgrav 		ret->xmss_pk = k->xmss_pk;
137147dd1d1bSDag-Erling Smørgrav 		k->xmss_pk = NULL;
137247dd1d1bSDag-Erling Smørgrav 		free(ret->xmss_state);
137347dd1d1bSDag-Erling Smørgrav 		ret->xmss_state = k->xmss_state;
137447dd1d1bSDag-Erling Smørgrav 		k->xmss_state = NULL;
137547dd1d1bSDag-Erling Smørgrav 		free(ret->xmss_name);
137647dd1d1bSDag-Erling Smørgrav 		ret->xmss_name = k->xmss_name;
137747dd1d1bSDag-Erling Smørgrav 		k->xmss_name = NULL;
137847dd1d1bSDag-Erling Smørgrav 		free(ret->xmss_filename);
137947dd1d1bSDag-Erling Smørgrav 		ret->xmss_filename = k->xmss_filename;
138047dd1d1bSDag-Erling Smørgrav 		k->xmss_filename = NULL;
138147dd1d1bSDag-Erling Smørgrav #ifdef DEBUG_PK
138247dd1d1bSDag-Erling Smørgrav 		/* XXX */
138347dd1d1bSDag-Erling Smørgrav #endif
1384a0ee8cc6SDag-Erling Smørgrav 		break;
138547dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
1386a0ee8cc6SDag-Erling Smørgrav 	default:
138747dd1d1bSDag-Erling Smørgrav 		sshkey_free(k);
138847dd1d1bSDag-Erling Smørgrav 		return SSH_ERR_INTERNAL_ERROR;
1389a0ee8cc6SDag-Erling Smørgrav 	}
139047dd1d1bSDag-Erling Smørgrav 	sshkey_free(k);
139147dd1d1bSDag-Erling Smørgrav 
139247dd1d1bSDag-Erling Smørgrav 	/* success */
139347dd1d1bSDag-Erling Smørgrav 	*cpp = cp;
139447dd1d1bSDag-Erling Smørgrav 	return 0;
1395a0ee8cc6SDag-Erling Smørgrav }
1396a0ee8cc6SDag-Erling Smørgrav 
139747dd1d1bSDag-Erling Smørgrav 
1398a0ee8cc6SDag-Erling Smørgrav int
1399557f75e5SDag-Erling Smørgrav sshkey_to_base64(const struct sshkey *key, char **b64p)
1400a0ee8cc6SDag-Erling Smørgrav {
1401557f75e5SDag-Erling Smørgrav 	int r = SSH_ERR_INTERNAL_ERROR;
1402557f75e5SDag-Erling Smørgrav 	struct sshbuf *b = NULL;
1403a0ee8cc6SDag-Erling Smørgrav 	char *uu = NULL;
1404557f75e5SDag-Erling Smørgrav 
1405557f75e5SDag-Erling Smørgrav 	if (b64p != NULL)
1406557f75e5SDag-Erling Smørgrav 		*b64p = NULL;
1407557f75e5SDag-Erling Smørgrav 	if ((b = sshbuf_new()) == NULL)
1408557f75e5SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
1409557f75e5SDag-Erling Smørgrav 	if ((r = sshkey_putb(key, b)) != 0)
1410557f75e5SDag-Erling Smørgrav 		goto out;
1411557f75e5SDag-Erling Smørgrav 	if ((uu = sshbuf_dtob64(b)) == NULL) {
1412557f75e5SDag-Erling Smørgrav 		r = SSH_ERR_ALLOC_FAIL;
1413557f75e5SDag-Erling Smørgrav 		goto out;
1414557f75e5SDag-Erling Smørgrav 	}
1415557f75e5SDag-Erling Smørgrav 	/* Success */
1416557f75e5SDag-Erling Smørgrav 	if (b64p != NULL) {
1417557f75e5SDag-Erling Smørgrav 		*b64p = uu;
1418557f75e5SDag-Erling Smørgrav 		uu = NULL;
1419557f75e5SDag-Erling Smørgrav 	}
1420557f75e5SDag-Erling Smørgrav 	r = 0;
1421557f75e5SDag-Erling Smørgrav  out:
1422557f75e5SDag-Erling Smørgrav 	sshbuf_free(b);
1423557f75e5SDag-Erling Smørgrav 	free(uu);
1424557f75e5SDag-Erling Smørgrav 	return r;
1425557f75e5SDag-Erling Smørgrav }
1426557f75e5SDag-Erling Smørgrav 
14274f52dfbbSDag-Erling Smørgrav int
1428557f75e5SDag-Erling Smørgrav sshkey_format_text(const struct sshkey *key, struct sshbuf *b)
1429557f75e5SDag-Erling Smørgrav {
1430557f75e5SDag-Erling Smørgrav 	int r = SSH_ERR_INTERNAL_ERROR;
1431557f75e5SDag-Erling Smørgrav 	char *uu = NULL;
1432557f75e5SDag-Erling Smørgrav 
1433557f75e5SDag-Erling Smørgrav 	if ((r = sshkey_to_base64(key, &uu)) != 0)
1434557f75e5SDag-Erling Smørgrav 		goto out;
1435557f75e5SDag-Erling Smørgrav 	if ((r = sshbuf_putf(b, "%s %s",
1436557f75e5SDag-Erling Smørgrav 	    sshkey_ssh_name(key), uu)) != 0)
1437557f75e5SDag-Erling Smørgrav 		goto out;
1438557f75e5SDag-Erling Smørgrav 	r = 0;
1439557f75e5SDag-Erling Smørgrav  out:
1440557f75e5SDag-Erling Smørgrav 	free(uu);
1441557f75e5SDag-Erling Smørgrav 	return r;
1442557f75e5SDag-Erling Smørgrav }
1443557f75e5SDag-Erling Smørgrav 
1444557f75e5SDag-Erling Smørgrav int
1445557f75e5SDag-Erling Smørgrav sshkey_write(const struct sshkey *key, FILE *f)
1446557f75e5SDag-Erling Smørgrav {
1447557f75e5SDag-Erling Smørgrav 	struct sshbuf *b = NULL;
1448557f75e5SDag-Erling Smørgrav 	int r = SSH_ERR_INTERNAL_ERROR;
1449557f75e5SDag-Erling Smørgrav 
1450557f75e5SDag-Erling Smørgrav 	if ((b = sshbuf_new()) == NULL)
1451557f75e5SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
1452557f75e5SDag-Erling Smørgrav 	if ((r = sshkey_format_text(key, b)) != 0)
1453557f75e5SDag-Erling Smørgrav 		goto out;
1454557f75e5SDag-Erling Smørgrav 	if (fwrite(sshbuf_ptr(b), sshbuf_len(b), 1, f) != 1) {
1455557f75e5SDag-Erling Smørgrav 		if (feof(f))
1456557f75e5SDag-Erling Smørgrav 			errno = EPIPE;
1457557f75e5SDag-Erling Smørgrav 		r = SSH_ERR_SYSTEM_ERROR;
1458557f75e5SDag-Erling Smørgrav 		goto out;
1459557f75e5SDag-Erling Smørgrav 	}
1460557f75e5SDag-Erling Smørgrav 	/* Success */
1461557f75e5SDag-Erling Smørgrav 	r = 0;
1462557f75e5SDag-Erling Smørgrav  out:
1463557f75e5SDag-Erling Smørgrav 	sshbuf_free(b);
1464557f75e5SDag-Erling Smørgrav 	return r;
1465a0ee8cc6SDag-Erling Smørgrav }
1466a0ee8cc6SDag-Erling Smørgrav 
1467a0ee8cc6SDag-Erling Smørgrav const char *
1468a0ee8cc6SDag-Erling Smørgrav sshkey_cert_type(const struct sshkey *k)
1469a0ee8cc6SDag-Erling Smørgrav {
1470a0ee8cc6SDag-Erling Smørgrav 	switch (k->cert->type) {
1471a0ee8cc6SDag-Erling Smørgrav 	case SSH2_CERT_TYPE_USER:
1472a0ee8cc6SDag-Erling Smørgrav 		return "user";
1473a0ee8cc6SDag-Erling Smørgrav 	case SSH2_CERT_TYPE_HOST:
1474a0ee8cc6SDag-Erling Smørgrav 		return "host";
1475a0ee8cc6SDag-Erling Smørgrav 	default:
1476a0ee8cc6SDag-Erling Smørgrav 		return "unknown";
1477a0ee8cc6SDag-Erling Smørgrav 	}
1478a0ee8cc6SDag-Erling Smørgrav }
1479a0ee8cc6SDag-Erling Smørgrav 
1480a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
1481a0ee8cc6SDag-Erling Smørgrav static int
1482a0ee8cc6SDag-Erling Smørgrav rsa_generate_private_key(u_int bits, RSA **rsap)
1483a0ee8cc6SDag-Erling Smørgrav {
1484a0ee8cc6SDag-Erling Smørgrav 	RSA *private = NULL;
1485a0ee8cc6SDag-Erling Smørgrav 	BIGNUM *f4 = NULL;
1486a0ee8cc6SDag-Erling Smørgrav 	int ret = SSH_ERR_INTERNAL_ERROR;
1487a0ee8cc6SDag-Erling Smørgrav 
14884f52dfbbSDag-Erling Smørgrav 	if (rsap == NULL)
1489a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
14904f52dfbbSDag-Erling Smørgrav 	if (bits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
14914f52dfbbSDag-Erling Smørgrav 	    bits > SSHBUF_MAX_BIGNUM * 8)
14924f52dfbbSDag-Erling Smørgrav 		return SSH_ERR_KEY_LENGTH;
1493a0ee8cc6SDag-Erling Smørgrav 	*rsap = NULL;
1494a0ee8cc6SDag-Erling Smørgrav 	if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) {
1495a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_ALLOC_FAIL;
1496a0ee8cc6SDag-Erling Smørgrav 		goto out;
1497a0ee8cc6SDag-Erling Smørgrav 	}
1498a0ee8cc6SDag-Erling Smørgrav 	if (!BN_set_word(f4, RSA_F4) ||
1499a0ee8cc6SDag-Erling Smørgrav 	    !RSA_generate_key_ex(private, bits, f4, NULL)) {
1500a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
1501a0ee8cc6SDag-Erling Smørgrav 		goto out;
1502a0ee8cc6SDag-Erling Smørgrav 	}
1503a0ee8cc6SDag-Erling Smørgrav 	*rsap = private;
1504a0ee8cc6SDag-Erling Smørgrav 	private = NULL;
1505a0ee8cc6SDag-Erling Smørgrav 	ret = 0;
1506a0ee8cc6SDag-Erling Smørgrav  out:
1507a0ee8cc6SDag-Erling Smørgrav 	RSA_free(private);
1508a0ee8cc6SDag-Erling Smørgrav 	BN_free(f4);
1509a0ee8cc6SDag-Erling Smørgrav 	return ret;
1510a0ee8cc6SDag-Erling Smørgrav }
1511a0ee8cc6SDag-Erling Smørgrav 
1512a0ee8cc6SDag-Erling Smørgrav static int
1513a0ee8cc6SDag-Erling Smørgrav dsa_generate_private_key(u_int bits, DSA **dsap)
1514a0ee8cc6SDag-Erling Smørgrav {
1515a0ee8cc6SDag-Erling Smørgrav 	DSA *private;
1516a0ee8cc6SDag-Erling Smørgrav 	int ret = SSH_ERR_INTERNAL_ERROR;
1517a0ee8cc6SDag-Erling Smørgrav 
15184f52dfbbSDag-Erling Smørgrav 	if (dsap == NULL)
1519a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
15204f52dfbbSDag-Erling Smørgrav 	if (bits != 1024)
15214f52dfbbSDag-Erling Smørgrav 		return SSH_ERR_KEY_LENGTH;
1522a0ee8cc6SDag-Erling Smørgrav 	if ((private = DSA_new()) == NULL) {
1523a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_ALLOC_FAIL;
1524a0ee8cc6SDag-Erling Smørgrav 		goto out;
1525a0ee8cc6SDag-Erling Smørgrav 	}
1526a0ee8cc6SDag-Erling Smørgrav 	*dsap = NULL;
1527a0ee8cc6SDag-Erling Smørgrav 	if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL,
1528a0ee8cc6SDag-Erling Smørgrav 	    NULL, NULL) || !DSA_generate_key(private)) {
1529a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
1530a0ee8cc6SDag-Erling Smørgrav 		goto out;
1531a0ee8cc6SDag-Erling Smørgrav 	}
1532a0ee8cc6SDag-Erling Smørgrav 	*dsap = private;
1533a0ee8cc6SDag-Erling Smørgrav 	private = NULL;
1534a0ee8cc6SDag-Erling Smørgrav 	ret = 0;
1535a0ee8cc6SDag-Erling Smørgrav  out:
1536a0ee8cc6SDag-Erling Smørgrav 	DSA_free(private);
1537a0ee8cc6SDag-Erling Smørgrav 	return ret;
1538a0ee8cc6SDag-Erling Smørgrav }
1539a0ee8cc6SDag-Erling Smørgrav 
1540a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_ECC
1541a0ee8cc6SDag-Erling Smørgrav int
1542a0ee8cc6SDag-Erling Smørgrav sshkey_ecdsa_key_to_nid(EC_KEY *k)
1543a0ee8cc6SDag-Erling Smørgrav {
1544a0ee8cc6SDag-Erling Smørgrav 	EC_GROUP *eg;
1545a0ee8cc6SDag-Erling Smørgrav 	int nids[] = {
1546a0ee8cc6SDag-Erling Smørgrav 		NID_X9_62_prime256v1,
1547a0ee8cc6SDag-Erling Smørgrav 		NID_secp384r1,
1548a0ee8cc6SDag-Erling Smørgrav #  ifdef OPENSSL_HAS_NISTP521
1549a0ee8cc6SDag-Erling Smørgrav 		NID_secp521r1,
1550a0ee8cc6SDag-Erling Smørgrav #  endif /* OPENSSL_HAS_NISTP521 */
1551a0ee8cc6SDag-Erling Smørgrav 		-1
1552a0ee8cc6SDag-Erling Smørgrav 	};
1553a0ee8cc6SDag-Erling Smørgrav 	int nid;
1554a0ee8cc6SDag-Erling Smørgrav 	u_int i;
1555a0ee8cc6SDag-Erling Smørgrav 	BN_CTX *bnctx;
1556a0ee8cc6SDag-Erling Smørgrav 	const EC_GROUP *g = EC_KEY_get0_group(k);
1557a0ee8cc6SDag-Erling Smørgrav 
1558a0ee8cc6SDag-Erling Smørgrav 	/*
1559a0ee8cc6SDag-Erling Smørgrav 	 * The group may be stored in a ASN.1 encoded private key in one of two
1560a0ee8cc6SDag-Erling Smørgrav 	 * ways: as a "named group", which is reconstituted by ASN.1 object ID
1561a0ee8cc6SDag-Erling Smørgrav 	 * or explicit group parameters encoded into the key blob. Only the
1562a0ee8cc6SDag-Erling Smørgrav 	 * "named group" case sets the group NID for us, but we can figure
1563a0ee8cc6SDag-Erling Smørgrav 	 * it out for the other case by comparing against all the groups that
1564a0ee8cc6SDag-Erling Smørgrav 	 * are supported.
1565a0ee8cc6SDag-Erling Smørgrav 	 */
1566a0ee8cc6SDag-Erling Smørgrav 	if ((nid = EC_GROUP_get_curve_name(g)) > 0)
1567a0ee8cc6SDag-Erling Smørgrav 		return nid;
1568a0ee8cc6SDag-Erling Smørgrav 	if ((bnctx = BN_CTX_new()) == NULL)
1569a0ee8cc6SDag-Erling Smørgrav 		return -1;
1570a0ee8cc6SDag-Erling Smørgrav 	for (i = 0; nids[i] != -1; i++) {
1571a0ee8cc6SDag-Erling Smørgrav 		if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL) {
1572a0ee8cc6SDag-Erling Smørgrav 			BN_CTX_free(bnctx);
1573a0ee8cc6SDag-Erling Smørgrav 			return -1;
1574a0ee8cc6SDag-Erling Smørgrav 		}
1575a0ee8cc6SDag-Erling Smørgrav 		if (EC_GROUP_cmp(g, eg, bnctx) == 0)
1576a0ee8cc6SDag-Erling Smørgrav 			break;
1577a0ee8cc6SDag-Erling Smørgrav 		EC_GROUP_free(eg);
1578a0ee8cc6SDag-Erling Smørgrav 	}
1579a0ee8cc6SDag-Erling Smørgrav 	BN_CTX_free(bnctx);
1580a0ee8cc6SDag-Erling Smørgrav 	if (nids[i] != -1) {
1581a0ee8cc6SDag-Erling Smørgrav 		/* Use the group with the NID attached */
1582a0ee8cc6SDag-Erling Smørgrav 		EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE);
1583a0ee8cc6SDag-Erling Smørgrav 		if (EC_KEY_set_group(k, eg) != 1) {
1584a0ee8cc6SDag-Erling Smørgrav 			EC_GROUP_free(eg);
1585a0ee8cc6SDag-Erling Smørgrav 			return -1;
1586a0ee8cc6SDag-Erling Smørgrav 		}
1587a0ee8cc6SDag-Erling Smørgrav 	}
1588a0ee8cc6SDag-Erling Smørgrav 	return nids[i];
1589a0ee8cc6SDag-Erling Smørgrav }
1590a0ee8cc6SDag-Erling Smørgrav 
1591a0ee8cc6SDag-Erling Smørgrav static int
1592a0ee8cc6SDag-Erling Smørgrav ecdsa_generate_private_key(u_int bits, int *nid, EC_KEY **ecdsap)
1593a0ee8cc6SDag-Erling Smørgrav {
1594a0ee8cc6SDag-Erling Smørgrav 	EC_KEY *private;
1595a0ee8cc6SDag-Erling Smørgrav 	int ret = SSH_ERR_INTERNAL_ERROR;
1596a0ee8cc6SDag-Erling Smørgrav 
15974f52dfbbSDag-Erling Smørgrav 	if (nid == NULL || ecdsap == NULL)
1598a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
15994f52dfbbSDag-Erling Smørgrav 	if ((*nid = sshkey_ecdsa_bits_to_nid(bits)) == -1)
16004f52dfbbSDag-Erling Smørgrav 		return SSH_ERR_KEY_LENGTH;
1601a0ee8cc6SDag-Erling Smørgrav 	*ecdsap = NULL;
1602a0ee8cc6SDag-Erling Smørgrav 	if ((private = EC_KEY_new_by_curve_name(*nid)) == NULL) {
1603a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_ALLOC_FAIL;
1604a0ee8cc6SDag-Erling Smørgrav 		goto out;
1605a0ee8cc6SDag-Erling Smørgrav 	}
1606a0ee8cc6SDag-Erling Smørgrav 	if (EC_KEY_generate_key(private) != 1) {
1607a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
1608a0ee8cc6SDag-Erling Smørgrav 		goto out;
1609a0ee8cc6SDag-Erling Smørgrav 	}
1610a0ee8cc6SDag-Erling Smørgrav 	EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE);
1611a0ee8cc6SDag-Erling Smørgrav 	*ecdsap = private;
1612a0ee8cc6SDag-Erling Smørgrav 	private = NULL;
1613a0ee8cc6SDag-Erling Smørgrav 	ret = 0;
1614a0ee8cc6SDag-Erling Smørgrav  out:
1615a0ee8cc6SDag-Erling Smørgrav 	EC_KEY_free(private);
1616a0ee8cc6SDag-Erling Smørgrav 	return ret;
1617a0ee8cc6SDag-Erling Smørgrav }
1618a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_ECC */
1619a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
1620a0ee8cc6SDag-Erling Smørgrav 
1621a0ee8cc6SDag-Erling Smørgrav int
1622a0ee8cc6SDag-Erling Smørgrav sshkey_generate(int type, u_int bits, struct sshkey **keyp)
1623a0ee8cc6SDag-Erling Smørgrav {
1624a0ee8cc6SDag-Erling Smørgrav 	struct sshkey *k;
1625a0ee8cc6SDag-Erling Smørgrav 	int ret = SSH_ERR_INTERNAL_ERROR;
1626a0ee8cc6SDag-Erling Smørgrav 
1627a0ee8cc6SDag-Erling Smørgrav 	if (keyp == NULL)
1628a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
1629a0ee8cc6SDag-Erling Smørgrav 	*keyp = NULL;
1630a0ee8cc6SDag-Erling Smørgrav 	if ((k = sshkey_new(KEY_UNSPEC)) == NULL)
1631a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
1632a0ee8cc6SDag-Erling Smørgrav 	switch (type) {
1633a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
1634a0ee8cc6SDag-Erling Smørgrav 		if ((k->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL ||
1635a0ee8cc6SDag-Erling Smørgrav 		    (k->ed25519_sk = malloc(ED25519_SK_SZ)) == NULL) {
1636a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_ALLOC_FAIL;
1637a0ee8cc6SDag-Erling Smørgrav 			break;
1638a0ee8cc6SDag-Erling Smørgrav 		}
1639a0ee8cc6SDag-Erling Smørgrav 		crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk);
1640a0ee8cc6SDag-Erling Smørgrav 		ret = 0;
1641a0ee8cc6SDag-Erling Smørgrav 		break;
164247dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
164347dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
164447dd1d1bSDag-Erling Smørgrav 		ret = sshkey_xmss_generate_private_key(k, bits);
164547dd1d1bSDag-Erling Smørgrav 		break;
164647dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
1647a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
1648a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
1649a0ee8cc6SDag-Erling Smørgrav 		ret = dsa_generate_private_key(bits, &k->dsa);
1650a0ee8cc6SDag-Erling Smørgrav 		break;
1651a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_ECC
1652a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
1653a0ee8cc6SDag-Erling Smørgrav 		ret = ecdsa_generate_private_key(bits, &k->ecdsa_nid,
1654a0ee8cc6SDag-Erling Smørgrav 		    &k->ecdsa);
1655a0ee8cc6SDag-Erling Smørgrav 		break;
1656a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_ECC */
1657a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
1658a0ee8cc6SDag-Erling Smørgrav 		ret = rsa_generate_private_key(bits, &k->rsa);
1659a0ee8cc6SDag-Erling Smørgrav 		break;
1660a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
1661a0ee8cc6SDag-Erling Smørgrav 	default:
1662a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_INVALID_ARGUMENT;
1663a0ee8cc6SDag-Erling Smørgrav 	}
1664a0ee8cc6SDag-Erling Smørgrav 	if (ret == 0) {
1665a0ee8cc6SDag-Erling Smørgrav 		k->type = type;
1666a0ee8cc6SDag-Erling Smørgrav 		*keyp = k;
1667a0ee8cc6SDag-Erling Smørgrav 	} else
1668a0ee8cc6SDag-Erling Smørgrav 		sshkey_free(k);
1669a0ee8cc6SDag-Erling Smørgrav 	return ret;
1670a0ee8cc6SDag-Erling Smørgrav }
1671a0ee8cc6SDag-Erling Smørgrav 
1672a0ee8cc6SDag-Erling Smørgrav int
1673a0ee8cc6SDag-Erling Smørgrav sshkey_cert_copy(const struct sshkey *from_key, struct sshkey *to_key)
1674a0ee8cc6SDag-Erling Smørgrav {
1675a0ee8cc6SDag-Erling Smørgrav 	u_int i;
1676a0ee8cc6SDag-Erling Smørgrav 	const struct sshkey_cert *from;
1677a0ee8cc6SDag-Erling Smørgrav 	struct sshkey_cert *to;
1678a0ee8cc6SDag-Erling Smørgrav 	int ret = SSH_ERR_INTERNAL_ERROR;
1679a0ee8cc6SDag-Erling Smørgrav 
1680a0ee8cc6SDag-Erling Smørgrav 	if (to_key->cert != NULL) {
1681a0ee8cc6SDag-Erling Smørgrav 		cert_free(to_key->cert);
1682a0ee8cc6SDag-Erling Smørgrav 		to_key->cert = NULL;
1683a0ee8cc6SDag-Erling Smørgrav 	}
1684a0ee8cc6SDag-Erling Smørgrav 
1685a0ee8cc6SDag-Erling Smørgrav 	if ((from = from_key->cert) == NULL)
1686a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
1687a0ee8cc6SDag-Erling Smørgrav 
1688a0ee8cc6SDag-Erling Smørgrav 	if ((to = to_key->cert = cert_new()) == NULL)
1689a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
1690a0ee8cc6SDag-Erling Smørgrav 
1691a0ee8cc6SDag-Erling Smørgrav 	if ((ret = sshbuf_putb(to->certblob, from->certblob)) != 0 ||
1692a0ee8cc6SDag-Erling Smørgrav 	    (ret = sshbuf_putb(to->critical, from->critical)) != 0 ||
1693acc1a9efSDag-Erling Smørgrav 	    (ret = sshbuf_putb(to->extensions, from->extensions)) != 0)
1694a0ee8cc6SDag-Erling Smørgrav 		return ret;
1695a0ee8cc6SDag-Erling Smørgrav 
1696a0ee8cc6SDag-Erling Smørgrav 	to->serial = from->serial;
1697a0ee8cc6SDag-Erling Smørgrav 	to->type = from->type;
1698a0ee8cc6SDag-Erling Smørgrav 	if (from->key_id == NULL)
1699a0ee8cc6SDag-Erling Smørgrav 		to->key_id = NULL;
1700a0ee8cc6SDag-Erling Smørgrav 	else if ((to->key_id = strdup(from->key_id)) == NULL)
1701a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
1702a0ee8cc6SDag-Erling Smørgrav 	to->valid_after = from->valid_after;
1703a0ee8cc6SDag-Erling Smørgrav 	to->valid_before = from->valid_before;
1704a0ee8cc6SDag-Erling Smørgrav 	if (from->signature_key == NULL)
1705a0ee8cc6SDag-Erling Smørgrav 		to->signature_key = NULL;
1706a0ee8cc6SDag-Erling Smørgrav 	else if ((ret = sshkey_from_private(from->signature_key,
1707a0ee8cc6SDag-Erling Smørgrav 	    &to->signature_key)) != 0)
1708a0ee8cc6SDag-Erling Smørgrav 		return ret;
1709a0ee8cc6SDag-Erling Smørgrav 
1710a0ee8cc6SDag-Erling Smørgrav 	if (from->nprincipals > SSHKEY_CERT_MAX_PRINCIPALS)
1711a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
1712a0ee8cc6SDag-Erling Smørgrav 	if (from->nprincipals > 0) {
1713a0ee8cc6SDag-Erling Smørgrav 		if ((to->principals = calloc(from->nprincipals,
1714a0ee8cc6SDag-Erling Smørgrav 		    sizeof(*to->principals))) == NULL)
1715a0ee8cc6SDag-Erling Smørgrav 			return SSH_ERR_ALLOC_FAIL;
1716a0ee8cc6SDag-Erling Smørgrav 		for (i = 0; i < from->nprincipals; i++) {
1717a0ee8cc6SDag-Erling Smørgrav 			to->principals[i] = strdup(from->principals[i]);
1718a0ee8cc6SDag-Erling Smørgrav 			if (to->principals[i] == NULL) {
1719a0ee8cc6SDag-Erling Smørgrav 				to->nprincipals = i;
1720a0ee8cc6SDag-Erling Smørgrav 				return SSH_ERR_ALLOC_FAIL;
1721a0ee8cc6SDag-Erling Smørgrav 			}
1722a0ee8cc6SDag-Erling Smørgrav 		}
1723a0ee8cc6SDag-Erling Smørgrav 	}
1724a0ee8cc6SDag-Erling Smørgrav 	to->nprincipals = from->nprincipals;
1725a0ee8cc6SDag-Erling Smørgrav 	return 0;
1726a0ee8cc6SDag-Erling Smørgrav }
1727a0ee8cc6SDag-Erling Smørgrav 
1728a0ee8cc6SDag-Erling Smørgrav int
1729a0ee8cc6SDag-Erling Smørgrav sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
1730a0ee8cc6SDag-Erling Smørgrav {
1731a0ee8cc6SDag-Erling Smørgrav 	struct sshkey *n = NULL;
1732*2a01feabSEd Maste 	int r = SSH_ERR_INTERNAL_ERROR;
1733*2a01feabSEd Maste #ifdef WITH_OPENSSL
1734*2a01feabSEd Maste 	const BIGNUM *rsa_n, *rsa_e;
1735*2a01feabSEd Maste 	BIGNUM *rsa_n_dup = NULL, *rsa_e_dup = NULL;
1736*2a01feabSEd Maste 	const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
1737*2a01feabSEd Maste 	BIGNUM *dsa_p_dup = NULL, *dsa_q_dup = NULL, *dsa_g_dup = NULL;
1738*2a01feabSEd Maste 	BIGNUM *dsa_pub_key_dup = NULL;
1739*2a01feabSEd Maste #endif /* WITH_OPENSSL */
1740a0ee8cc6SDag-Erling Smørgrav 
1741a0ee8cc6SDag-Erling Smørgrav 	*pkp = NULL;
1742a0ee8cc6SDag-Erling Smørgrav 	switch (k->type) {
1743a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
1744a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
1745a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA_CERT:
1746*2a01feabSEd Maste 		if ((n = sshkey_new(k->type)) == NULL) {
1747*2a01feabSEd Maste 			r = SSH_ERR_ALLOC_FAIL;
1748*2a01feabSEd Maste 			goto out;
1749a0ee8cc6SDag-Erling Smørgrav 		}
1750*2a01feabSEd Maste 
1751*2a01feabSEd Maste 		DSA_get0_pqg(k->dsa, &dsa_p, &dsa_q, &dsa_g);
1752*2a01feabSEd Maste 		DSA_get0_key(k->dsa, &dsa_pub_key, NULL);
1753*2a01feabSEd Maste 		if ((dsa_p_dup = BN_dup(dsa_p)) == NULL ||
1754*2a01feabSEd Maste 		    (dsa_q_dup = BN_dup(dsa_q)) == NULL ||
1755*2a01feabSEd Maste 		    (dsa_g_dup = BN_dup(dsa_g)) == NULL ||
1756*2a01feabSEd Maste 		    (dsa_pub_key_dup = BN_dup(dsa_pub_key)) == NULL) {
1757*2a01feabSEd Maste 			r = SSH_ERR_ALLOC_FAIL;
1758*2a01feabSEd Maste 			goto out;
1759*2a01feabSEd Maste 		}
1760*2a01feabSEd Maste 		if (!DSA_set0_pqg(n->dsa, dsa_p_dup, dsa_q_dup, dsa_g_dup)) {
1761*2a01feabSEd Maste 			r = SSH_ERR_LIBCRYPTO_ERROR;
1762*2a01feabSEd Maste 			goto out;
1763*2a01feabSEd Maste 		}
1764*2a01feabSEd Maste 		dsa_p_dup = dsa_q_dup = dsa_g_dup = NULL; /* transferred */
1765*2a01feabSEd Maste 		if (!DSA_set0_key(n->dsa, dsa_pub_key_dup, NULL)) {
1766*2a01feabSEd Maste 			r = SSH_ERR_LIBCRYPTO_ERROR;
1767*2a01feabSEd Maste 			goto out;
1768*2a01feabSEd Maste 		}
1769*2a01feabSEd Maste 		dsa_pub_key_dup = NULL; /* transferred */
1770*2a01feabSEd Maste 
1771a0ee8cc6SDag-Erling Smørgrav 		break;
1772a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_ECC
1773a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
1774a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA_CERT:
1775*2a01feabSEd Maste 		if ((n = sshkey_new(k->type)) == NULL) {
1776*2a01feabSEd Maste 			r = SSH_ERR_ALLOC_FAIL;
1777*2a01feabSEd Maste 			goto out;
1778*2a01feabSEd Maste 		}
1779a0ee8cc6SDag-Erling Smørgrav 		n->ecdsa_nid = k->ecdsa_nid;
1780a0ee8cc6SDag-Erling Smørgrav 		n->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
1781a0ee8cc6SDag-Erling Smørgrav 		if (n->ecdsa == NULL) {
1782*2a01feabSEd Maste 			r = SSH_ERR_ALLOC_FAIL;
1783*2a01feabSEd Maste 			goto out;
1784a0ee8cc6SDag-Erling Smørgrav 		}
1785a0ee8cc6SDag-Erling Smørgrav 		if (EC_KEY_set_public_key(n->ecdsa,
1786a0ee8cc6SDag-Erling Smørgrav 		    EC_KEY_get0_public_key(k->ecdsa)) != 1) {
1787*2a01feabSEd Maste 			r = SSH_ERR_LIBCRYPTO_ERROR;
1788*2a01feabSEd Maste 			goto out;
1789a0ee8cc6SDag-Erling Smørgrav 		}
1790a0ee8cc6SDag-Erling Smørgrav 		break;
1791a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_ECC */
1792a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
1793a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA_CERT:
1794*2a01feabSEd Maste 		if ((n = sshkey_new(k->type)) == NULL) {
1795*2a01feabSEd Maste 			r = SSH_ERR_ALLOC_FAIL;
1796*2a01feabSEd Maste 			goto out;
1797a0ee8cc6SDag-Erling Smørgrav 		}
1798*2a01feabSEd Maste 		RSA_get0_key(k->rsa, &rsa_n, &rsa_e, NULL);
1799*2a01feabSEd Maste 		if ((rsa_n_dup = BN_dup(rsa_n)) == NULL ||
1800*2a01feabSEd Maste 		    (rsa_e_dup = BN_dup(rsa_e)) == NULL) {
1801*2a01feabSEd Maste 			r = SSH_ERR_ALLOC_FAIL;
1802*2a01feabSEd Maste 			goto out;
1803*2a01feabSEd Maste 		}
1804*2a01feabSEd Maste 		if (!RSA_set0_key(n->rsa, rsa_n_dup, rsa_e_dup, NULL)) {
1805*2a01feabSEd Maste 			r = SSH_ERR_LIBCRYPTO_ERROR;
1806*2a01feabSEd Maste 			goto out;
1807*2a01feabSEd Maste 		}
1808*2a01feabSEd Maste 		rsa_n_dup = rsa_e_dup = NULL; /* transferred */
1809a0ee8cc6SDag-Erling Smørgrav 		break;
1810a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
1811a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
1812a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519_CERT:
1813*2a01feabSEd Maste 		if ((n = sshkey_new(k->type)) == NULL) {
1814*2a01feabSEd Maste 			r = SSH_ERR_ALLOC_FAIL;
1815*2a01feabSEd Maste 			goto out;
1816*2a01feabSEd Maste 		}
1817a0ee8cc6SDag-Erling Smørgrav 		if (k->ed25519_pk != NULL) {
1818a0ee8cc6SDag-Erling Smørgrav 			if ((n->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) {
1819*2a01feabSEd Maste 				r = SSH_ERR_ALLOC_FAIL;
1820*2a01feabSEd Maste 				goto out;
1821a0ee8cc6SDag-Erling Smørgrav 			}
1822a0ee8cc6SDag-Erling Smørgrav 			memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
1823a0ee8cc6SDag-Erling Smørgrav 		}
1824a0ee8cc6SDag-Erling Smørgrav 		break;
182547dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
182647dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
182747dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS_CERT:
1828*2a01feabSEd Maste 		if ((n = sshkey_new(k->type)) == NULL) {
1829*2a01feabSEd Maste 			r = SSH_ERR_ALLOC_FAIL;
1830*2a01feabSEd Maste 			goto out;
183147dd1d1bSDag-Erling Smørgrav 		}
1832*2a01feabSEd Maste 		if ((r = sshkey_xmss_init(n, k->xmss_name)) != 0)
1833*2a01feabSEd Maste 			goto out;
183447dd1d1bSDag-Erling Smørgrav 		if (k->xmss_pk != NULL) {
183547dd1d1bSDag-Erling Smørgrav 			size_t pklen = sshkey_xmss_pklen(k);
183647dd1d1bSDag-Erling Smørgrav 			if (pklen == 0 || sshkey_xmss_pklen(n) != pklen) {
1837*2a01feabSEd Maste 				r = SSH_ERR_INTERNAL_ERROR;
1838*2a01feabSEd Maste 				goto out;
183947dd1d1bSDag-Erling Smørgrav 			}
184047dd1d1bSDag-Erling Smørgrav 			if ((n->xmss_pk = malloc(pklen)) == NULL) {
1841*2a01feabSEd Maste 				r = SSH_ERR_ALLOC_FAIL;
1842*2a01feabSEd Maste 				goto out;
184347dd1d1bSDag-Erling Smørgrav 			}
184447dd1d1bSDag-Erling Smørgrav 			memcpy(n->xmss_pk, k->xmss_pk, pklen);
184547dd1d1bSDag-Erling Smørgrav 		}
184647dd1d1bSDag-Erling Smørgrav 		break;
184747dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
1848a0ee8cc6SDag-Erling Smørgrav 	default:
1849*2a01feabSEd Maste 		r = SSH_ERR_KEY_TYPE_UNKNOWN;
1850*2a01feabSEd Maste 		goto out;
1851a0ee8cc6SDag-Erling Smørgrav 	}
1852*2a01feabSEd Maste 	if (sshkey_is_cert(k) && (r = sshkey_cert_copy(k, n)) != 0)
1853*2a01feabSEd Maste 		goto out;
1854*2a01feabSEd Maste 	/* success */
1855a0ee8cc6SDag-Erling Smørgrav 	*pkp = n;
1856*2a01feabSEd Maste 	n = NULL;
1857*2a01feabSEd Maste 	r = 0;
1858*2a01feabSEd Maste  out:
1859*2a01feabSEd Maste 	sshkey_free(n);
1860*2a01feabSEd Maste #ifdef WITH_OPENSSL
1861*2a01feabSEd Maste 	BN_clear_free(rsa_n_dup);
1862*2a01feabSEd Maste 	BN_clear_free(rsa_e_dup);
1863*2a01feabSEd Maste 	BN_clear_free(dsa_p_dup);
1864*2a01feabSEd Maste 	BN_clear_free(dsa_q_dup);
1865*2a01feabSEd Maste 	BN_clear_free(dsa_g_dup);
1866*2a01feabSEd Maste 	BN_clear_free(dsa_pub_key_dup);
1867*2a01feabSEd Maste #endif
1868*2a01feabSEd Maste 
1869*2a01feabSEd Maste 	return r;
1870a0ee8cc6SDag-Erling Smørgrav }
1871a0ee8cc6SDag-Erling Smørgrav 
1872a0ee8cc6SDag-Erling Smørgrav static int
1873bc5531deSDag-Erling Smørgrav cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf)
1874a0ee8cc6SDag-Erling Smørgrav {
1875bc5531deSDag-Erling Smørgrav 	struct sshbuf *principals = NULL, *crit = NULL;
1876bc5531deSDag-Erling Smørgrav 	struct sshbuf *exts = NULL, *ca = NULL;
1877bc5531deSDag-Erling Smørgrav 	u_char *sig = NULL;
1878bc5531deSDag-Erling Smørgrav 	size_t signed_len = 0, slen = 0, kidlen = 0;
1879a0ee8cc6SDag-Erling Smørgrav 	int ret = SSH_ERR_INTERNAL_ERROR;
1880a0ee8cc6SDag-Erling Smørgrav 
1881a0ee8cc6SDag-Erling Smørgrav 	/* Copy the entire key blob for verification and later serialisation */
1882bc5531deSDag-Erling Smørgrav 	if ((ret = sshbuf_putb(key->cert->certblob, certbuf)) != 0)
1883a0ee8cc6SDag-Erling Smørgrav 		return ret;
1884a0ee8cc6SDag-Erling Smørgrav 
1885eccfee6eSDag-Erling Smørgrav 	/* Parse body of certificate up to signature */
1886eccfee6eSDag-Erling Smørgrav 	if ((ret = sshbuf_get_u64(b, &key->cert->serial)) != 0 ||
1887a0ee8cc6SDag-Erling Smørgrav 	    (ret = sshbuf_get_u32(b, &key->cert->type)) != 0 ||
1888a0ee8cc6SDag-Erling Smørgrav 	    (ret = sshbuf_get_cstring(b, &key->cert->key_id, &kidlen)) != 0 ||
1889bc5531deSDag-Erling Smørgrav 	    (ret = sshbuf_froms(b, &principals)) != 0 ||
1890a0ee8cc6SDag-Erling Smørgrav 	    (ret = sshbuf_get_u64(b, &key->cert->valid_after)) != 0 ||
1891a0ee8cc6SDag-Erling Smørgrav 	    (ret = sshbuf_get_u64(b, &key->cert->valid_before)) != 0 ||
1892bc5531deSDag-Erling Smørgrav 	    (ret = sshbuf_froms(b, &crit)) != 0 ||
1893eccfee6eSDag-Erling Smørgrav 	    (ret = sshbuf_froms(b, &exts)) != 0 ||
1894a0ee8cc6SDag-Erling Smørgrav 	    (ret = sshbuf_get_string_direct(b, NULL, NULL)) != 0 ||
1895bc5531deSDag-Erling Smørgrav 	    (ret = sshbuf_froms(b, &ca)) != 0) {
1896a0ee8cc6SDag-Erling Smørgrav 		/* XXX debug print error for ret */
1897a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_INVALID_FORMAT;
1898a0ee8cc6SDag-Erling Smørgrav 		goto out;
1899a0ee8cc6SDag-Erling Smørgrav 	}
1900a0ee8cc6SDag-Erling Smørgrav 
1901a0ee8cc6SDag-Erling Smørgrav 	/* Signature is left in the buffer so we can calculate this length */
1902a0ee8cc6SDag-Erling Smørgrav 	signed_len = sshbuf_len(key->cert->certblob) - sshbuf_len(b);
1903a0ee8cc6SDag-Erling Smørgrav 
1904a0ee8cc6SDag-Erling Smørgrav 	if ((ret = sshbuf_get_string(b, &sig, &slen)) != 0) {
1905a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_INVALID_FORMAT;
1906a0ee8cc6SDag-Erling Smørgrav 		goto out;
1907a0ee8cc6SDag-Erling Smørgrav 	}
1908a0ee8cc6SDag-Erling Smørgrav 
1909a0ee8cc6SDag-Erling Smørgrav 	if (key->cert->type != SSH2_CERT_TYPE_USER &&
1910a0ee8cc6SDag-Erling Smørgrav 	    key->cert->type != SSH2_CERT_TYPE_HOST) {
1911a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_KEY_CERT_UNKNOWN_TYPE;
1912a0ee8cc6SDag-Erling Smørgrav 		goto out;
1913a0ee8cc6SDag-Erling Smørgrav 	}
1914a0ee8cc6SDag-Erling Smørgrav 
1915bc5531deSDag-Erling Smørgrav 	/* Parse principals section */
1916bc5531deSDag-Erling Smørgrav 	while (sshbuf_len(principals) > 0) {
1917bc5531deSDag-Erling Smørgrav 		char *principal = NULL;
1918bc5531deSDag-Erling Smørgrav 		char **oprincipals = NULL;
1919bc5531deSDag-Erling Smørgrav 
1920a0ee8cc6SDag-Erling Smørgrav 		if (key->cert->nprincipals >= SSHKEY_CERT_MAX_PRINCIPALS) {
1921a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_FORMAT;
1922a0ee8cc6SDag-Erling Smørgrav 			goto out;
1923a0ee8cc6SDag-Erling Smørgrav 		}
1924bc5531deSDag-Erling Smørgrav 		if ((ret = sshbuf_get_cstring(principals, &principal,
1925bc5531deSDag-Erling Smørgrav 		    NULL)) != 0) {
1926a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_FORMAT;
1927a0ee8cc6SDag-Erling Smørgrav 			goto out;
1928a0ee8cc6SDag-Erling Smørgrav 		}
1929a0ee8cc6SDag-Erling Smørgrav 		oprincipals = key->cert->principals;
19304f52dfbbSDag-Erling Smørgrav 		key->cert->principals = recallocarray(key->cert->principals,
19314f52dfbbSDag-Erling Smørgrav 		    key->cert->nprincipals, key->cert->nprincipals + 1,
19324f52dfbbSDag-Erling Smørgrav 		    sizeof(*key->cert->principals));
1933a0ee8cc6SDag-Erling Smørgrav 		if (key->cert->principals == NULL) {
1934a0ee8cc6SDag-Erling Smørgrav 			free(principal);
1935a0ee8cc6SDag-Erling Smørgrav 			key->cert->principals = oprincipals;
1936a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_ALLOC_FAIL;
1937a0ee8cc6SDag-Erling Smørgrav 			goto out;
1938a0ee8cc6SDag-Erling Smørgrav 		}
1939a0ee8cc6SDag-Erling Smørgrav 		key->cert->principals[key->cert->nprincipals++] = principal;
1940a0ee8cc6SDag-Erling Smørgrav 	}
1941a0ee8cc6SDag-Erling Smørgrav 
1942bc5531deSDag-Erling Smørgrav 	/*
1943bc5531deSDag-Erling Smørgrav 	 * Stash a copies of the critical options and extensions sections
1944bc5531deSDag-Erling Smørgrav 	 * for later use.
1945bc5531deSDag-Erling Smørgrav 	 */
1946bc5531deSDag-Erling Smørgrav 	if ((ret = sshbuf_putb(key->cert->critical, crit)) != 0 ||
1947bc5531deSDag-Erling Smørgrav 	    (exts != NULL &&
1948bc5531deSDag-Erling Smørgrav 	    (ret = sshbuf_putb(key->cert->extensions, exts)) != 0))
1949a0ee8cc6SDag-Erling Smørgrav 		goto out;
1950a0ee8cc6SDag-Erling Smørgrav 
1951bc5531deSDag-Erling Smørgrav 	/*
1952bc5531deSDag-Erling Smørgrav 	 * Validate critical options and extensions sections format.
1953bc5531deSDag-Erling Smørgrav 	 */
1954bc5531deSDag-Erling Smørgrav 	while (sshbuf_len(crit) != 0) {
1955bc5531deSDag-Erling Smørgrav 		if ((ret = sshbuf_get_string_direct(crit, NULL, NULL)) != 0 ||
1956bc5531deSDag-Erling Smørgrav 		    (ret = sshbuf_get_string_direct(crit, NULL, NULL)) != 0) {
1957bc5531deSDag-Erling Smørgrav 			sshbuf_reset(key->cert->critical);
1958a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_FORMAT;
1959a0ee8cc6SDag-Erling Smørgrav 			goto out;
1960a0ee8cc6SDag-Erling Smørgrav 		}
1961a0ee8cc6SDag-Erling Smørgrav 	}
1962bc5531deSDag-Erling Smørgrav 	while (exts != NULL && sshbuf_len(exts) != 0) {
1963bc5531deSDag-Erling Smørgrav 		if ((ret = sshbuf_get_string_direct(exts, NULL, NULL)) != 0 ||
1964bc5531deSDag-Erling Smørgrav 		    (ret = sshbuf_get_string_direct(exts, NULL, NULL)) != 0) {
1965bc5531deSDag-Erling Smørgrav 			sshbuf_reset(key->cert->extensions);
1966a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_FORMAT;
1967a0ee8cc6SDag-Erling Smørgrav 			goto out;
1968a0ee8cc6SDag-Erling Smørgrav 		}
1969a0ee8cc6SDag-Erling Smørgrav 	}
1970a0ee8cc6SDag-Erling Smørgrav 
1971bc5531deSDag-Erling Smørgrav 	/* Parse CA key and check signature */
1972bc5531deSDag-Erling Smørgrav 	if (sshkey_from_blob_internal(ca, &key->cert->signature_key, 0) != 0) {
1973a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
1974a0ee8cc6SDag-Erling Smørgrav 		goto out;
1975a0ee8cc6SDag-Erling Smørgrav 	}
1976a0ee8cc6SDag-Erling Smørgrav 	if (!sshkey_type_is_valid_ca(key->cert->signature_key->type)) {
1977a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
1978a0ee8cc6SDag-Erling Smørgrav 		goto out;
1979a0ee8cc6SDag-Erling Smørgrav 	}
1980a0ee8cc6SDag-Erling Smørgrav 	if ((ret = sshkey_verify(key->cert->signature_key, sig, slen,
198147dd1d1bSDag-Erling Smørgrav 	    sshbuf_ptr(key->cert->certblob), signed_len, NULL, 0)) != 0)
1982a0ee8cc6SDag-Erling Smørgrav 		goto out;
1983a0ee8cc6SDag-Erling Smørgrav 
1984bc5531deSDag-Erling Smørgrav 	/* Success */
1985bc5531deSDag-Erling Smørgrav 	ret = 0;
1986a0ee8cc6SDag-Erling Smørgrav  out:
1987bc5531deSDag-Erling Smørgrav 	sshbuf_free(ca);
1988bc5531deSDag-Erling Smørgrav 	sshbuf_free(crit);
1989bc5531deSDag-Erling Smørgrav 	sshbuf_free(exts);
1990bc5531deSDag-Erling Smørgrav 	sshbuf_free(principals);
1991a0ee8cc6SDag-Erling Smørgrav 	free(sig);
1992a0ee8cc6SDag-Erling Smørgrav 	return ret;
1993a0ee8cc6SDag-Erling Smørgrav }
1994a0ee8cc6SDag-Erling Smørgrav 
1995*2a01feabSEd Maste #ifdef WITH_OPENSSL
1996*2a01feabSEd Maste static int
1997*2a01feabSEd Maste check_rsa_length(const RSA *rsa)
1998*2a01feabSEd Maste {
1999*2a01feabSEd Maste 	const BIGNUM *rsa_n;
2000*2a01feabSEd Maste 
2001*2a01feabSEd Maste 	RSA_get0_key(rsa, &rsa_n, NULL, NULL);
2002*2a01feabSEd Maste 	if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
2003*2a01feabSEd Maste 		return SSH_ERR_KEY_LENGTH;
2004*2a01feabSEd Maste 	return 0;
2005*2a01feabSEd Maste }
2006*2a01feabSEd Maste #endif
2007*2a01feabSEd Maste 
2008a0ee8cc6SDag-Erling Smørgrav static int
2009bc5531deSDag-Erling Smørgrav sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
2010bc5531deSDag-Erling Smørgrav     int allow_cert)
2011a0ee8cc6SDag-Erling Smørgrav {
2012bc5531deSDag-Erling Smørgrav 	int type, ret = SSH_ERR_INTERNAL_ERROR;
201347dd1d1bSDag-Erling Smørgrav 	char *ktype = NULL, *curve = NULL, *xmss_name = NULL;
2014a0ee8cc6SDag-Erling Smørgrav 	struct sshkey *key = NULL;
2015a0ee8cc6SDag-Erling Smørgrav 	size_t len;
2016a0ee8cc6SDag-Erling Smørgrav 	u_char *pk = NULL;
2017bc5531deSDag-Erling Smørgrav 	struct sshbuf *copy;
2018*2a01feabSEd Maste #if defined(WITH_OPENSSL)
2019*2a01feabSEd Maste 	BIGNUM *rsa_n = NULL, *rsa_e = NULL;
2020*2a01feabSEd Maste 	BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_pub_key = NULL;
2021*2a01feabSEd Maste # if defined(OPENSSL_HAS_ECC)
2022a0ee8cc6SDag-Erling Smørgrav 	EC_POINT *q = NULL;
2023*2a01feabSEd Maste # endif /* OPENSSL_HAS_ECC */
2024*2a01feabSEd Maste #endif /* WITH_OPENSSL */
2025a0ee8cc6SDag-Erling Smørgrav 
2026a0ee8cc6SDag-Erling Smørgrav #ifdef DEBUG_PK /* XXX */
2027bc5531deSDag-Erling Smørgrav 	sshbuf_dump(b, stderr);
2028a0ee8cc6SDag-Erling Smørgrav #endif
2029076ad2f8SDag-Erling Smørgrav 	if (keyp != NULL)
2030a0ee8cc6SDag-Erling Smørgrav 		*keyp = NULL;
2031bc5531deSDag-Erling Smørgrav 	if ((copy = sshbuf_fromb(b)) == NULL) {
2032bc5531deSDag-Erling Smørgrav 		ret = SSH_ERR_ALLOC_FAIL;
2033bc5531deSDag-Erling Smørgrav 		goto out;
2034bc5531deSDag-Erling Smørgrav 	}
2035a0ee8cc6SDag-Erling Smørgrav 	if (sshbuf_get_cstring(b, &ktype, NULL) != 0) {
2036a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_INVALID_FORMAT;
2037a0ee8cc6SDag-Erling Smørgrav 		goto out;
2038a0ee8cc6SDag-Erling Smørgrav 	}
2039a0ee8cc6SDag-Erling Smørgrav 
2040a0ee8cc6SDag-Erling Smørgrav 	type = sshkey_type_from_name(ktype);
2041a0ee8cc6SDag-Erling Smørgrav 	if (!allow_cert && sshkey_type_is_cert(type)) {
2042a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
2043a0ee8cc6SDag-Erling Smørgrav 		goto out;
2044a0ee8cc6SDag-Erling Smørgrav 	}
2045a0ee8cc6SDag-Erling Smørgrav 	switch (type) {
2046a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
2047a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA_CERT:
2048bc5531deSDag-Erling Smørgrav 		/* Skip nonce */
2049a0ee8cc6SDag-Erling Smørgrav 		if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
2050a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_FORMAT;
2051a0ee8cc6SDag-Erling Smørgrav 			goto out;
2052a0ee8cc6SDag-Erling Smørgrav 		}
2053a0ee8cc6SDag-Erling Smørgrav 		/* FALLTHROUGH */
2054a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
2055a0ee8cc6SDag-Erling Smørgrav 		if ((key = sshkey_new(type)) == NULL) {
2056a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_ALLOC_FAIL;
2057a0ee8cc6SDag-Erling Smørgrav 			goto out;
2058a0ee8cc6SDag-Erling Smørgrav 		}
2059*2a01feabSEd Maste 		if ((rsa_e = BN_new()) == NULL ||
2060*2a01feabSEd Maste 		    (rsa_n = BN_new()) == NULL) {
2061*2a01feabSEd Maste 			ret = SSH_ERR_ALLOC_FAIL;
2062*2a01feabSEd Maste 			goto out;
2063*2a01feabSEd Maste 		}
2064*2a01feabSEd Maste 		if (sshbuf_get_bignum2(b, rsa_e) != 0 ||
2065*2a01feabSEd Maste 		    sshbuf_get_bignum2(b, rsa_n) != 0) {
2066a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_FORMAT;
2067a0ee8cc6SDag-Erling Smørgrav 			goto out;
2068a0ee8cc6SDag-Erling Smørgrav 		}
2069*2a01feabSEd Maste 		if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, NULL)) {
2070*2a01feabSEd Maste 			ret = SSH_ERR_LIBCRYPTO_ERROR;
20714f52dfbbSDag-Erling Smørgrav 			goto out;
20724f52dfbbSDag-Erling Smørgrav 		}
2073*2a01feabSEd Maste 		rsa_n = rsa_e = NULL; /* transferred */
2074*2a01feabSEd Maste 		if ((ret = check_rsa_length(key->rsa)) != 0)
2075*2a01feabSEd Maste 			goto out;
2076a0ee8cc6SDag-Erling Smørgrav #ifdef DEBUG_PK
2077a0ee8cc6SDag-Erling Smørgrav 		RSA_print_fp(stderr, key->rsa, 8);
2078a0ee8cc6SDag-Erling Smørgrav #endif
2079a0ee8cc6SDag-Erling Smørgrav 		break;
2080a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA_CERT:
2081bc5531deSDag-Erling Smørgrav 		/* Skip nonce */
2082a0ee8cc6SDag-Erling Smørgrav 		if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
2083a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_FORMAT;
2084a0ee8cc6SDag-Erling Smørgrav 			goto out;
2085a0ee8cc6SDag-Erling Smørgrav 		}
2086a0ee8cc6SDag-Erling Smørgrav 		/* FALLTHROUGH */
2087a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
2088a0ee8cc6SDag-Erling Smørgrav 		if ((key = sshkey_new(type)) == NULL) {
2089a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_ALLOC_FAIL;
2090a0ee8cc6SDag-Erling Smørgrav 			goto out;
2091a0ee8cc6SDag-Erling Smørgrav 		}
2092*2a01feabSEd Maste 		if ((dsa_p = BN_new()) == NULL ||
2093*2a01feabSEd Maste 		    (dsa_q = BN_new()) == NULL ||
2094*2a01feabSEd Maste 		    (dsa_g = BN_new()) == NULL ||
2095*2a01feabSEd Maste 		    (dsa_pub_key = BN_new()) == NULL) {
2096*2a01feabSEd Maste 			ret = SSH_ERR_ALLOC_FAIL;
2097*2a01feabSEd Maste 			goto out;
2098*2a01feabSEd Maste 		}
2099*2a01feabSEd Maste 		if (sshbuf_get_bignum2(b, dsa_p) != 0 ||
2100*2a01feabSEd Maste 		    sshbuf_get_bignum2(b, dsa_q) != 0 ||
2101*2a01feabSEd Maste 		    sshbuf_get_bignum2(b, dsa_g) != 0 ||
2102*2a01feabSEd Maste 		    sshbuf_get_bignum2(b, dsa_pub_key) != 0) {
2103a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_FORMAT;
2104a0ee8cc6SDag-Erling Smørgrav 			goto out;
2105a0ee8cc6SDag-Erling Smørgrav 		}
2106*2a01feabSEd Maste 		if (!DSA_set0_pqg(key->dsa, dsa_p, dsa_q, dsa_g)) {
2107*2a01feabSEd Maste 			ret = SSH_ERR_LIBCRYPTO_ERROR;
2108*2a01feabSEd Maste 			goto out;
2109*2a01feabSEd Maste 		}
2110*2a01feabSEd Maste 		dsa_p = dsa_q = dsa_g = NULL; /* transferred */
2111*2a01feabSEd Maste 		if (!DSA_set0_key(key->dsa, dsa_pub_key, NULL)) {
2112*2a01feabSEd Maste 			ret = SSH_ERR_LIBCRYPTO_ERROR;
2113*2a01feabSEd Maste 			goto out;
2114*2a01feabSEd Maste 		}
2115*2a01feabSEd Maste 		dsa_pub_key = NULL; /* transferred */
2116a0ee8cc6SDag-Erling Smørgrav #ifdef DEBUG_PK
2117a0ee8cc6SDag-Erling Smørgrav 		DSA_print_fp(stderr, key->dsa, 8);
2118a0ee8cc6SDag-Erling Smørgrav #endif
2119a0ee8cc6SDag-Erling Smørgrav 		break;
2120a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA_CERT:
2121bc5531deSDag-Erling Smørgrav 		/* Skip nonce */
2122a0ee8cc6SDag-Erling Smørgrav 		if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
2123a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_FORMAT;
2124a0ee8cc6SDag-Erling Smørgrav 			goto out;
2125a0ee8cc6SDag-Erling Smørgrav 		}
2126a0ee8cc6SDag-Erling Smørgrav 		/* FALLTHROUGH */
2127a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_ECC
2128a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
2129a0ee8cc6SDag-Erling Smørgrav 		if ((key = sshkey_new(type)) == NULL) {
2130a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_ALLOC_FAIL;
2131a0ee8cc6SDag-Erling Smørgrav 			goto out;
2132a0ee8cc6SDag-Erling Smørgrav 		}
2133bc5531deSDag-Erling Smørgrav 		key->ecdsa_nid = sshkey_ecdsa_nid_from_name(ktype);
2134a0ee8cc6SDag-Erling Smørgrav 		if (sshbuf_get_cstring(b, &curve, NULL) != 0) {
2135a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_FORMAT;
2136a0ee8cc6SDag-Erling Smørgrav 			goto out;
2137a0ee8cc6SDag-Erling Smørgrav 		}
2138a0ee8cc6SDag-Erling Smørgrav 		if (key->ecdsa_nid != sshkey_curve_name_to_nid(curve)) {
2139a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_EC_CURVE_MISMATCH;
2140a0ee8cc6SDag-Erling Smørgrav 			goto out;
2141a0ee8cc6SDag-Erling Smørgrav 		}
2142a0ee8cc6SDag-Erling Smørgrav 		EC_KEY_free(key->ecdsa);
2143a0ee8cc6SDag-Erling Smørgrav 		if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid))
2144a0ee8cc6SDag-Erling Smørgrav 		    == NULL) {
2145a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_EC_CURVE_INVALID;
2146a0ee8cc6SDag-Erling Smørgrav 			goto out;
2147a0ee8cc6SDag-Erling Smørgrav 		}
2148a0ee8cc6SDag-Erling Smørgrav 		if ((q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL) {
2149a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_ALLOC_FAIL;
2150a0ee8cc6SDag-Erling Smørgrav 			goto out;
2151a0ee8cc6SDag-Erling Smørgrav 		}
2152a0ee8cc6SDag-Erling Smørgrav 		if (sshbuf_get_ec(b, q, EC_KEY_get0_group(key->ecdsa)) != 0) {
2153a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_FORMAT;
2154a0ee8cc6SDag-Erling Smørgrav 			goto out;
2155a0ee8cc6SDag-Erling Smørgrav 		}
2156a0ee8cc6SDag-Erling Smørgrav 		if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa),
2157a0ee8cc6SDag-Erling Smørgrav 		    q) != 0) {
2158a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_KEY_INVALID_EC_VALUE;
2159a0ee8cc6SDag-Erling Smørgrav 			goto out;
2160a0ee8cc6SDag-Erling Smørgrav 		}
2161a0ee8cc6SDag-Erling Smørgrav 		if (EC_KEY_set_public_key(key->ecdsa, q) != 1) {
2162a0ee8cc6SDag-Erling Smørgrav 			/* XXX assume it is a allocation error */
2163a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_ALLOC_FAIL;
2164a0ee8cc6SDag-Erling Smørgrav 			goto out;
2165a0ee8cc6SDag-Erling Smørgrav 		}
2166a0ee8cc6SDag-Erling Smørgrav #ifdef DEBUG_PK
2167a0ee8cc6SDag-Erling Smørgrav 		sshkey_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q);
2168a0ee8cc6SDag-Erling Smørgrav #endif
2169a0ee8cc6SDag-Erling Smørgrav 		break;
2170a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_ECC */
2171a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
2172a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519_CERT:
2173bc5531deSDag-Erling Smørgrav 		/* Skip nonce */
2174a0ee8cc6SDag-Erling Smørgrav 		if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
2175a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_FORMAT;
2176a0ee8cc6SDag-Erling Smørgrav 			goto out;
2177a0ee8cc6SDag-Erling Smørgrav 		}
2178a0ee8cc6SDag-Erling Smørgrav 		/* FALLTHROUGH */
2179a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
2180a0ee8cc6SDag-Erling Smørgrav 		if ((ret = sshbuf_get_string(b, &pk, &len)) != 0)
2181a0ee8cc6SDag-Erling Smørgrav 			goto out;
2182a0ee8cc6SDag-Erling Smørgrav 		if (len != ED25519_PK_SZ) {
2183a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_FORMAT;
2184a0ee8cc6SDag-Erling Smørgrav 			goto out;
2185a0ee8cc6SDag-Erling Smørgrav 		}
2186a0ee8cc6SDag-Erling Smørgrav 		if ((key = sshkey_new(type)) == NULL) {
2187a0ee8cc6SDag-Erling Smørgrav 			ret = SSH_ERR_ALLOC_FAIL;
2188a0ee8cc6SDag-Erling Smørgrav 			goto out;
2189a0ee8cc6SDag-Erling Smørgrav 		}
2190a0ee8cc6SDag-Erling Smørgrav 		key->ed25519_pk = pk;
2191a0ee8cc6SDag-Erling Smørgrav 		pk = NULL;
2192a0ee8cc6SDag-Erling Smørgrav 		break;
219347dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
219447dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS_CERT:
219547dd1d1bSDag-Erling Smørgrav 		/* Skip nonce */
219647dd1d1bSDag-Erling Smørgrav 		if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
219747dd1d1bSDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_FORMAT;
219847dd1d1bSDag-Erling Smørgrav 			goto out;
219947dd1d1bSDag-Erling Smørgrav 		}
220047dd1d1bSDag-Erling Smørgrav 		/* FALLTHROUGH */
220147dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
220247dd1d1bSDag-Erling Smørgrav 		if ((ret = sshbuf_get_cstring(b, &xmss_name, NULL)) != 0)
220347dd1d1bSDag-Erling Smørgrav 			goto out;
220447dd1d1bSDag-Erling Smørgrav 		if ((key = sshkey_new(type)) == NULL) {
220547dd1d1bSDag-Erling Smørgrav 			ret = SSH_ERR_ALLOC_FAIL;
220647dd1d1bSDag-Erling Smørgrav 			goto out;
220747dd1d1bSDag-Erling Smørgrav 		}
220847dd1d1bSDag-Erling Smørgrav 		if ((ret = sshkey_xmss_init(key, xmss_name)) != 0)
220947dd1d1bSDag-Erling Smørgrav 			goto out;
221047dd1d1bSDag-Erling Smørgrav 		if ((ret = sshbuf_get_string(b, &pk, &len)) != 0)
221147dd1d1bSDag-Erling Smørgrav 			goto out;
221247dd1d1bSDag-Erling Smørgrav 		if (len == 0 || len != sshkey_xmss_pklen(key)) {
221347dd1d1bSDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_FORMAT;
221447dd1d1bSDag-Erling Smørgrav 			goto out;
221547dd1d1bSDag-Erling Smørgrav 		}
221647dd1d1bSDag-Erling Smørgrav 		key->xmss_pk = pk;
221747dd1d1bSDag-Erling Smørgrav 		pk = NULL;
221847dd1d1bSDag-Erling Smørgrav 		if (type != KEY_XMSS_CERT &&
221947dd1d1bSDag-Erling Smørgrav 		    (ret = sshkey_xmss_deserialize_pk_info(key, b)) != 0)
222047dd1d1bSDag-Erling Smørgrav 			goto out;
222147dd1d1bSDag-Erling Smørgrav 		break;
222247dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
2223a0ee8cc6SDag-Erling Smørgrav 	case KEY_UNSPEC:
2224a0ee8cc6SDag-Erling Smørgrav 	default:
2225a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_KEY_TYPE_UNKNOWN;
2226a0ee8cc6SDag-Erling Smørgrav 		goto out;
2227a0ee8cc6SDag-Erling Smørgrav 	}
2228a0ee8cc6SDag-Erling Smørgrav 
2229a0ee8cc6SDag-Erling Smørgrav 	/* Parse certificate potion */
2230bc5531deSDag-Erling Smørgrav 	if (sshkey_is_cert(key) && (ret = cert_parse(b, key, copy)) != 0)
2231a0ee8cc6SDag-Erling Smørgrav 		goto out;
2232a0ee8cc6SDag-Erling Smørgrav 
2233a0ee8cc6SDag-Erling Smørgrav 	if (key != NULL && sshbuf_len(b) != 0) {
2234a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_INVALID_FORMAT;
2235a0ee8cc6SDag-Erling Smørgrav 		goto out;
2236a0ee8cc6SDag-Erling Smørgrav 	}
2237a0ee8cc6SDag-Erling Smørgrav 	ret = 0;
2238076ad2f8SDag-Erling Smørgrav 	if (keyp != NULL) {
2239a0ee8cc6SDag-Erling Smørgrav 		*keyp = key;
2240a0ee8cc6SDag-Erling Smørgrav 		key = NULL;
2241076ad2f8SDag-Erling Smørgrav 	}
2242a0ee8cc6SDag-Erling Smørgrav  out:
2243bc5531deSDag-Erling Smørgrav 	sshbuf_free(copy);
2244a0ee8cc6SDag-Erling Smørgrav 	sshkey_free(key);
224547dd1d1bSDag-Erling Smørgrav 	free(xmss_name);
2246a0ee8cc6SDag-Erling Smørgrav 	free(ktype);
2247a0ee8cc6SDag-Erling Smørgrav 	free(curve);
2248a0ee8cc6SDag-Erling Smørgrav 	free(pk);
2249*2a01feabSEd Maste #if defined(WITH_OPENSSL)
2250*2a01feabSEd Maste 	BN_clear_free(rsa_n);
2251*2a01feabSEd Maste 	BN_clear_free(rsa_e);
2252*2a01feabSEd Maste 	BN_clear_free(dsa_p);
2253*2a01feabSEd Maste 	BN_clear_free(dsa_q);
2254*2a01feabSEd Maste 	BN_clear_free(dsa_g);
2255*2a01feabSEd Maste 	BN_clear_free(dsa_pub_key);
2256*2a01feabSEd Maste # if defined(OPENSSL_HAS_ECC)
2257a0ee8cc6SDag-Erling Smørgrav 	EC_POINT_free(q);
2258*2a01feabSEd Maste # endif /* OPENSSL_HAS_ECC */
2259*2a01feabSEd Maste #endif /* WITH_OPENSSL */
2260a0ee8cc6SDag-Erling Smørgrav 	return ret;
2261a0ee8cc6SDag-Erling Smørgrav }
2262a0ee8cc6SDag-Erling Smørgrav 
2263a0ee8cc6SDag-Erling Smørgrav int
2264a0ee8cc6SDag-Erling Smørgrav sshkey_from_blob(const u_char *blob, size_t blen, struct sshkey **keyp)
2265a0ee8cc6SDag-Erling Smørgrav {
2266bc5531deSDag-Erling Smørgrav 	struct sshbuf *b;
2267bc5531deSDag-Erling Smørgrav 	int r;
2268bc5531deSDag-Erling Smørgrav 
2269bc5531deSDag-Erling Smørgrav 	if ((b = sshbuf_from(blob, blen)) == NULL)
2270bc5531deSDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
2271bc5531deSDag-Erling Smørgrav 	r = sshkey_from_blob_internal(b, keyp, 1);
2272bc5531deSDag-Erling Smørgrav 	sshbuf_free(b);
2273bc5531deSDag-Erling Smørgrav 	return r;
2274bc5531deSDag-Erling Smørgrav }
2275bc5531deSDag-Erling Smørgrav 
2276bc5531deSDag-Erling Smørgrav int
2277bc5531deSDag-Erling Smørgrav sshkey_fromb(struct sshbuf *b, struct sshkey **keyp)
2278bc5531deSDag-Erling Smørgrav {
2279bc5531deSDag-Erling Smørgrav 	return sshkey_from_blob_internal(b, keyp, 1);
2280bc5531deSDag-Erling Smørgrav }
2281bc5531deSDag-Erling Smørgrav 
2282bc5531deSDag-Erling Smørgrav int
2283bc5531deSDag-Erling Smørgrav sshkey_froms(struct sshbuf *buf, struct sshkey **keyp)
2284bc5531deSDag-Erling Smørgrav {
2285bc5531deSDag-Erling Smørgrav 	struct sshbuf *b;
2286bc5531deSDag-Erling Smørgrav 	int r;
2287bc5531deSDag-Erling Smørgrav 
2288bc5531deSDag-Erling Smørgrav 	if ((r = sshbuf_froms(buf, &b)) != 0)
2289bc5531deSDag-Erling Smørgrav 		return r;
2290bc5531deSDag-Erling Smørgrav 	r = sshkey_from_blob_internal(b, keyp, 1);
2291bc5531deSDag-Erling Smørgrav 	sshbuf_free(b);
2292bc5531deSDag-Erling Smørgrav 	return r;
2293a0ee8cc6SDag-Erling Smørgrav }
2294a0ee8cc6SDag-Erling Smørgrav 
2295190cef3dSDag-Erling Smørgrav static int
2296190cef3dSDag-Erling Smørgrav get_sigtype(const u_char *sig, size_t siglen, char **sigtypep)
229747dd1d1bSDag-Erling Smørgrav {
229847dd1d1bSDag-Erling Smørgrav 	int r;
229947dd1d1bSDag-Erling Smørgrav 	struct sshbuf *b = NULL;
230047dd1d1bSDag-Erling Smørgrav 	char *sigtype = NULL;
230147dd1d1bSDag-Erling Smørgrav 
230247dd1d1bSDag-Erling Smørgrav 	if (sigtypep != NULL)
230347dd1d1bSDag-Erling Smørgrav 		*sigtypep = NULL;
230447dd1d1bSDag-Erling Smørgrav 	if ((b = sshbuf_from(sig, siglen)) == NULL)
230547dd1d1bSDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
230647dd1d1bSDag-Erling Smørgrav 	if ((r = sshbuf_get_cstring(b, &sigtype, NULL)) != 0)
230747dd1d1bSDag-Erling Smørgrav 		goto out;
230847dd1d1bSDag-Erling Smørgrav 	/* success */
230947dd1d1bSDag-Erling Smørgrav 	if (sigtypep != NULL) {
231047dd1d1bSDag-Erling Smørgrav 		*sigtypep = sigtype;
231147dd1d1bSDag-Erling Smørgrav 		sigtype = NULL;
231247dd1d1bSDag-Erling Smørgrav 	}
231347dd1d1bSDag-Erling Smørgrav 	r = 0;
231447dd1d1bSDag-Erling Smørgrav  out:
231547dd1d1bSDag-Erling Smørgrav 	free(sigtype);
231647dd1d1bSDag-Erling Smørgrav 	sshbuf_free(b);
231747dd1d1bSDag-Erling Smørgrav 	return r;
231847dd1d1bSDag-Erling Smørgrav }
231947dd1d1bSDag-Erling Smørgrav 
2320190cef3dSDag-Erling Smørgrav /*
2321190cef3dSDag-Erling Smørgrav  * Returns the expected signature algorithm for a given public key algorithm.
2322190cef3dSDag-Erling Smørgrav  */
2323190cef3dSDag-Erling Smørgrav const char *
2324190cef3dSDag-Erling Smørgrav sshkey_sigalg_by_name(const char *name)
2325190cef3dSDag-Erling Smørgrav {
2326190cef3dSDag-Erling Smørgrav 	const struct keytype *kt;
2327190cef3dSDag-Erling Smørgrav 
2328190cef3dSDag-Erling Smørgrav 	for (kt = keytypes; kt->type != -1; kt++) {
2329190cef3dSDag-Erling Smørgrav 		if (strcmp(kt->name, name) != 0)
2330190cef3dSDag-Erling Smørgrav 			continue;
2331190cef3dSDag-Erling Smørgrav 		if (kt->sigalg != NULL)
2332190cef3dSDag-Erling Smørgrav 			return kt->sigalg;
2333190cef3dSDag-Erling Smørgrav 		if (!kt->cert)
2334190cef3dSDag-Erling Smørgrav 			return kt->name;
2335190cef3dSDag-Erling Smørgrav 		return sshkey_ssh_name_from_type_nid(
2336190cef3dSDag-Erling Smørgrav 		    sshkey_type_plain(kt->type), kt->nid);
2337190cef3dSDag-Erling Smørgrav 	}
2338190cef3dSDag-Erling Smørgrav 	return NULL;
2339190cef3dSDag-Erling Smørgrav }
2340190cef3dSDag-Erling Smørgrav 
2341190cef3dSDag-Erling Smørgrav /*
2342190cef3dSDag-Erling Smørgrav  * Verifies that the signature algorithm appearing inside the signature blob
2343190cef3dSDag-Erling Smørgrav  * matches that which was requested.
2344190cef3dSDag-Erling Smørgrav  */
2345190cef3dSDag-Erling Smørgrav int
2346190cef3dSDag-Erling Smørgrav sshkey_check_sigtype(const u_char *sig, size_t siglen,
2347190cef3dSDag-Erling Smørgrav     const char *requested_alg)
2348190cef3dSDag-Erling Smørgrav {
2349190cef3dSDag-Erling Smørgrav 	const char *expected_alg;
2350190cef3dSDag-Erling Smørgrav 	char *sigtype = NULL;
2351190cef3dSDag-Erling Smørgrav 	int r;
2352190cef3dSDag-Erling Smørgrav 
2353190cef3dSDag-Erling Smørgrav 	if (requested_alg == NULL)
2354190cef3dSDag-Erling Smørgrav 		return 0;
2355190cef3dSDag-Erling Smørgrav 	if ((expected_alg = sshkey_sigalg_by_name(requested_alg)) == NULL)
2356190cef3dSDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
2357190cef3dSDag-Erling Smørgrav 	if ((r = get_sigtype(sig, siglen, &sigtype)) != 0)
2358190cef3dSDag-Erling Smørgrav 		return r;
2359190cef3dSDag-Erling Smørgrav 	r = strcmp(expected_alg, sigtype) == 0;
2360190cef3dSDag-Erling Smørgrav 	free(sigtype);
2361190cef3dSDag-Erling Smørgrav 	return r ? 0 : SSH_ERR_SIGN_ALG_UNSUPPORTED;
2362190cef3dSDag-Erling Smørgrav }
2363190cef3dSDag-Erling Smørgrav 
236447dd1d1bSDag-Erling Smørgrav int
2365a0ee8cc6SDag-Erling Smørgrav sshkey_sign(const struct sshkey *key,
2366a0ee8cc6SDag-Erling Smørgrav     u_char **sigp, size_t *lenp,
2367acc1a9efSDag-Erling Smørgrav     const u_char *data, size_t datalen, const char *alg, u_int compat)
2368a0ee8cc6SDag-Erling Smørgrav {
2369a0ee8cc6SDag-Erling Smørgrav 	if (sigp != NULL)
2370a0ee8cc6SDag-Erling Smørgrav 		*sigp = NULL;
2371a0ee8cc6SDag-Erling Smørgrav 	if (lenp != NULL)
2372a0ee8cc6SDag-Erling Smørgrav 		*lenp = 0;
2373a0ee8cc6SDag-Erling Smørgrav 	if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE)
2374a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
2375a0ee8cc6SDag-Erling Smørgrav 	switch (key->type) {
2376a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
2377a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA_CERT:
2378a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
2379a0ee8cc6SDag-Erling Smørgrav 		return ssh_dss_sign(key, sigp, lenp, data, datalen, compat);
2380a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_ECC
2381a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA_CERT:
2382a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
2383a0ee8cc6SDag-Erling Smørgrav 		return ssh_ecdsa_sign(key, sigp, lenp, data, datalen, compat);
2384a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_ECC */
2385a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA_CERT:
2386a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
2387acc1a9efSDag-Erling Smørgrav 		return ssh_rsa_sign(key, sigp, lenp, data, datalen, alg);
2388a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
2389a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
2390a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519_CERT:
2391a0ee8cc6SDag-Erling Smørgrav 		return ssh_ed25519_sign(key, sigp, lenp, data, datalen, compat);
239247dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
239347dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
239447dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS_CERT:
239547dd1d1bSDag-Erling Smørgrav 		return ssh_xmss_sign(key, sigp, lenp, data, datalen, compat);
239647dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
2397a0ee8cc6SDag-Erling Smørgrav 	default:
2398a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_KEY_TYPE_UNKNOWN;
2399a0ee8cc6SDag-Erling Smørgrav 	}
2400a0ee8cc6SDag-Erling Smørgrav }
2401a0ee8cc6SDag-Erling Smørgrav 
2402a0ee8cc6SDag-Erling Smørgrav /*
2403a0ee8cc6SDag-Erling Smørgrav  * ssh_key_verify returns 0 for a correct signature  and < 0 on error.
240447dd1d1bSDag-Erling Smørgrav  * If "alg" specified, then the signature must use that algorithm.
2405a0ee8cc6SDag-Erling Smørgrav  */
2406a0ee8cc6SDag-Erling Smørgrav int
2407a0ee8cc6SDag-Erling Smørgrav sshkey_verify(const struct sshkey *key,
2408a0ee8cc6SDag-Erling Smørgrav     const u_char *sig, size_t siglen,
240947dd1d1bSDag-Erling Smørgrav     const u_char *data, size_t dlen, const char *alg, u_int compat)
2410a0ee8cc6SDag-Erling Smørgrav {
2411bc5531deSDag-Erling Smørgrav 	if (siglen == 0 || dlen > SSH_KEY_MAX_SIGN_DATA_SIZE)
2412a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
2413a0ee8cc6SDag-Erling Smørgrav 	switch (key->type) {
2414a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
2415a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA_CERT:
2416a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
2417a0ee8cc6SDag-Erling Smørgrav 		return ssh_dss_verify(key, sig, siglen, data, dlen, compat);
2418a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_ECC
2419a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA_CERT:
2420a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
2421a0ee8cc6SDag-Erling Smørgrav 		return ssh_ecdsa_verify(key, sig, siglen, data, dlen, compat);
2422a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_ECC */
2423a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA_CERT:
2424a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
242547dd1d1bSDag-Erling Smørgrav 		return ssh_rsa_verify(key, sig, siglen, data, dlen, alg);
2426a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
2427a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
2428a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519_CERT:
2429a0ee8cc6SDag-Erling Smørgrav 		return ssh_ed25519_verify(key, sig, siglen, data, dlen, compat);
243047dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
243147dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
243247dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS_CERT:
243347dd1d1bSDag-Erling Smørgrav 		return ssh_xmss_verify(key, sig, siglen, data, dlen, compat);
243447dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
2435a0ee8cc6SDag-Erling Smørgrav 	default:
2436a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_KEY_TYPE_UNKNOWN;
2437a0ee8cc6SDag-Erling Smørgrav 	}
2438a0ee8cc6SDag-Erling Smørgrav }
2439a0ee8cc6SDag-Erling Smørgrav 
2440a0ee8cc6SDag-Erling Smørgrav /* Convert a plain key to their _CERT equivalent */
2441a0ee8cc6SDag-Erling Smørgrav int
2442eccfee6eSDag-Erling Smørgrav sshkey_to_certified(struct sshkey *k)
2443a0ee8cc6SDag-Erling Smørgrav {
2444a0ee8cc6SDag-Erling Smørgrav 	int newtype;
2445a0ee8cc6SDag-Erling Smørgrav 
2446a0ee8cc6SDag-Erling Smørgrav 	switch (k->type) {
2447a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
2448a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
2449eccfee6eSDag-Erling Smørgrav 		newtype = KEY_RSA_CERT;
2450a0ee8cc6SDag-Erling Smørgrav 		break;
2451a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
2452eccfee6eSDag-Erling Smørgrav 		newtype = KEY_DSA_CERT;
2453a0ee8cc6SDag-Erling Smørgrav 		break;
2454a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
2455a0ee8cc6SDag-Erling Smørgrav 		newtype = KEY_ECDSA_CERT;
2456a0ee8cc6SDag-Erling Smørgrav 		break;
2457a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
2458a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
2459a0ee8cc6SDag-Erling Smørgrav 		newtype = KEY_ED25519_CERT;
2460a0ee8cc6SDag-Erling Smørgrav 		break;
246147dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
246247dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
246347dd1d1bSDag-Erling Smørgrav 		newtype = KEY_XMSS_CERT;
246447dd1d1bSDag-Erling Smørgrav 		break;
246547dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
2466a0ee8cc6SDag-Erling Smørgrav 	default:
2467a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
2468a0ee8cc6SDag-Erling Smørgrav 	}
2469a0ee8cc6SDag-Erling Smørgrav 	if ((k->cert = cert_new()) == NULL)
2470a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
2471a0ee8cc6SDag-Erling Smørgrav 	k->type = newtype;
2472a0ee8cc6SDag-Erling Smørgrav 	return 0;
2473a0ee8cc6SDag-Erling Smørgrav }
2474a0ee8cc6SDag-Erling Smørgrav 
2475a0ee8cc6SDag-Erling Smørgrav /* Convert a certificate to its raw key equivalent */
2476a0ee8cc6SDag-Erling Smørgrav int
2477a0ee8cc6SDag-Erling Smørgrav sshkey_drop_cert(struct sshkey *k)
2478a0ee8cc6SDag-Erling Smørgrav {
2479a0ee8cc6SDag-Erling Smørgrav 	if (!sshkey_type_is_cert(k->type))
2480a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_KEY_TYPE_UNKNOWN;
2481a0ee8cc6SDag-Erling Smørgrav 	cert_free(k->cert);
2482a0ee8cc6SDag-Erling Smørgrav 	k->cert = NULL;
2483a0ee8cc6SDag-Erling Smørgrav 	k->type = sshkey_type_plain(k->type);
2484a0ee8cc6SDag-Erling Smørgrav 	return 0;
2485a0ee8cc6SDag-Erling Smørgrav }
2486a0ee8cc6SDag-Erling Smørgrav 
2487a0ee8cc6SDag-Erling Smørgrav /* Sign a certified key, (re-)generating the signed certblob. */
2488a0ee8cc6SDag-Erling Smørgrav int
24894f52dfbbSDag-Erling Smørgrav sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg,
24904f52dfbbSDag-Erling Smørgrav     sshkey_certify_signer *signer, void *signer_ctx)
2491a0ee8cc6SDag-Erling Smørgrav {
2492a0ee8cc6SDag-Erling Smørgrav 	struct sshbuf *principals = NULL;
2493a0ee8cc6SDag-Erling Smørgrav 	u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32];
2494a0ee8cc6SDag-Erling Smørgrav 	size_t i, ca_len, sig_len;
2495a0ee8cc6SDag-Erling Smørgrav 	int ret = SSH_ERR_INTERNAL_ERROR;
2496a0ee8cc6SDag-Erling Smørgrav 	struct sshbuf *cert;
2497*2a01feabSEd Maste #ifdef WITH_OPENSSL
2498*2a01feabSEd Maste 	const BIGNUM *rsa_n, *rsa_e, *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key;
2499*2a01feabSEd Maste #endif /* WITH_OPENSSL */
2500a0ee8cc6SDag-Erling Smørgrav 
2501a0ee8cc6SDag-Erling Smørgrav 	if (k == NULL || k->cert == NULL ||
2502a0ee8cc6SDag-Erling Smørgrav 	    k->cert->certblob == NULL || ca == NULL)
2503a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
2504a0ee8cc6SDag-Erling Smørgrav 	if (!sshkey_is_cert(k))
2505a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_KEY_TYPE_UNKNOWN;
2506a0ee8cc6SDag-Erling Smørgrav 	if (!sshkey_type_is_valid_ca(ca->type))
2507a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
2508a0ee8cc6SDag-Erling Smørgrav 
2509a0ee8cc6SDag-Erling Smørgrav 	if ((ret = sshkey_to_blob(ca, &ca_blob, &ca_len)) != 0)
2510a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
2511a0ee8cc6SDag-Erling Smørgrav 
2512a0ee8cc6SDag-Erling Smørgrav 	cert = k->cert->certblob; /* for readability */
2513a0ee8cc6SDag-Erling Smørgrav 	sshbuf_reset(cert);
2514a0ee8cc6SDag-Erling Smørgrav 	if ((ret = sshbuf_put_cstring(cert, sshkey_ssh_name(k))) != 0)
2515a0ee8cc6SDag-Erling Smørgrav 		goto out;
2516a0ee8cc6SDag-Erling Smørgrav 
2517a0ee8cc6SDag-Erling Smørgrav 	/* -v01 certs put nonce first */
2518a0ee8cc6SDag-Erling Smørgrav 	arc4random_buf(&nonce, sizeof(nonce));
2519a0ee8cc6SDag-Erling Smørgrav 	if ((ret = sshbuf_put_string(cert, nonce, sizeof(nonce))) != 0)
2520a0ee8cc6SDag-Erling Smørgrav 		goto out;
2521a0ee8cc6SDag-Erling Smørgrav 
2522a0ee8cc6SDag-Erling Smørgrav 	/* XXX this substantially duplicates to_blob(); refactor */
2523a0ee8cc6SDag-Erling Smørgrav 	switch (k->type) {
2524a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
2525a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA_CERT:
2526*2a01feabSEd Maste 		DSA_get0_pqg(k->dsa, &dsa_p, &dsa_q, &dsa_g);
2527*2a01feabSEd Maste 		DSA_get0_key(k->dsa, &dsa_pub_key, NULL);
2528*2a01feabSEd Maste 		if ((ret = sshbuf_put_bignum2(cert, dsa_p)) != 0 ||
2529*2a01feabSEd Maste 		    (ret = sshbuf_put_bignum2(cert, dsa_q)) != 0 ||
2530*2a01feabSEd Maste 		    (ret = sshbuf_put_bignum2(cert, dsa_g)) != 0 ||
2531*2a01feabSEd Maste 		    (ret = sshbuf_put_bignum2(cert, dsa_pub_key)) != 0)
2532a0ee8cc6SDag-Erling Smørgrav 			goto out;
2533a0ee8cc6SDag-Erling Smørgrav 		break;
2534a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_ECC
2535a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA_CERT:
2536a0ee8cc6SDag-Erling Smørgrav 		if ((ret = sshbuf_put_cstring(cert,
2537a0ee8cc6SDag-Erling Smørgrav 		    sshkey_curve_nid_to_name(k->ecdsa_nid))) != 0 ||
2538a0ee8cc6SDag-Erling Smørgrav 		    (ret = sshbuf_put_ec(cert,
2539a0ee8cc6SDag-Erling Smørgrav 		    EC_KEY_get0_public_key(k->ecdsa),
2540a0ee8cc6SDag-Erling Smørgrav 		    EC_KEY_get0_group(k->ecdsa))) != 0)
2541a0ee8cc6SDag-Erling Smørgrav 			goto out;
2542a0ee8cc6SDag-Erling Smørgrav 		break;
2543a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_ECC */
2544a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA_CERT:
2545*2a01feabSEd Maste 		RSA_get0_key(k->rsa, &rsa_n, &rsa_e, NULL);
2546*2a01feabSEd Maste 		if ((ret = sshbuf_put_bignum2(cert, rsa_e)) != 0 ||
2547*2a01feabSEd Maste 		    (ret = sshbuf_put_bignum2(cert, rsa_n)) != 0)
2548a0ee8cc6SDag-Erling Smørgrav 			goto out;
2549a0ee8cc6SDag-Erling Smørgrav 		break;
2550a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
2551a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519_CERT:
2552a0ee8cc6SDag-Erling Smørgrav 		if ((ret = sshbuf_put_string(cert,
2553a0ee8cc6SDag-Erling Smørgrav 		    k->ed25519_pk, ED25519_PK_SZ)) != 0)
2554a0ee8cc6SDag-Erling Smørgrav 			goto out;
2555a0ee8cc6SDag-Erling Smørgrav 		break;
255647dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
255747dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS_CERT:
255847dd1d1bSDag-Erling Smørgrav 		if (k->xmss_name == NULL) {
255947dd1d1bSDag-Erling Smørgrav 			ret = SSH_ERR_INVALID_ARGUMENT;
256047dd1d1bSDag-Erling Smørgrav 			goto out;
256147dd1d1bSDag-Erling Smørgrav 		}
256247dd1d1bSDag-Erling Smørgrav 		if ((ret = sshbuf_put_cstring(cert, k->xmss_name)) ||
256347dd1d1bSDag-Erling Smørgrav 		    (ret = sshbuf_put_string(cert,
256447dd1d1bSDag-Erling Smørgrav 		    k->xmss_pk, sshkey_xmss_pklen(k))) != 0)
256547dd1d1bSDag-Erling Smørgrav 			goto out;
256647dd1d1bSDag-Erling Smørgrav 		break;
256747dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
2568a0ee8cc6SDag-Erling Smørgrav 	default:
2569a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_INVALID_ARGUMENT;
2570bc5531deSDag-Erling Smørgrav 		goto out;
2571a0ee8cc6SDag-Erling Smørgrav 	}
2572a0ee8cc6SDag-Erling Smørgrav 
2573eccfee6eSDag-Erling Smørgrav 	if ((ret = sshbuf_put_u64(cert, k->cert->serial)) != 0 ||
2574eccfee6eSDag-Erling Smørgrav 	    (ret = sshbuf_put_u32(cert, k->cert->type)) != 0 ||
2575a0ee8cc6SDag-Erling Smørgrav 	    (ret = sshbuf_put_cstring(cert, k->cert->key_id)) != 0)
2576a0ee8cc6SDag-Erling Smørgrav 		goto out;
2577a0ee8cc6SDag-Erling Smørgrav 
2578a0ee8cc6SDag-Erling Smørgrav 	if ((principals = sshbuf_new()) == NULL) {
2579a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_ALLOC_FAIL;
2580a0ee8cc6SDag-Erling Smørgrav 		goto out;
2581a0ee8cc6SDag-Erling Smørgrav 	}
2582a0ee8cc6SDag-Erling Smørgrav 	for (i = 0; i < k->cert->nprincipals; i++) {
2583a0ee8cc6SDag-Erling Smørgrav 		if ((ret = sshbuf_put_cstring(principals,
2584a0ee8cc6SDag-Erling Smørgrav 		    k->cert->principals[i])) != 0)
2585a0ee8cc6SDag-Erling Smørgrav 			goto out;
2586a0ee8cc6SDag-Erling Smørgrav 	}
2587a0ee8cc6SDag-Erling Smørgrav 	if ((ret = sshbuf_put_stringb(cert, principals)) != 0 ||
2588a0ee8cc6SDag-Erling Smørgrav 	    (ret = sshbuf_put_u64(cert, k->cert->valid_after)) != 0 ||
2589a0ee8cc6SDag-Erling Smørgrav 	    (ret = sshbuf_put_u64(cert, k->cert->valid_before)) != 0 ||
2590eccfee6eSDag-Erling Smørgrav 	    (ret = sshbuf_put_stringb(cert, k->cert->critical)) != 0 ||
2591eccfee6eSDag-Erling Smørgrav 	    (ret = sshbuf_put_stringb(cert, k->cert->extensions)) != 0 ||
2592eccfee6eSDag-Erling Smørgrav 	    (ret = sshbuf_put_string(cert, NULL, 0)) != 0 || /* Reserved */
2593a0ee8cc6SDag-Erling Smørgrav 	    (ret = sshbuf_put_string(cert, ca_blob, ca_len)) != 0)
2594a0ee8cc6SDag-Erling Smørgrav 		goto out;
2595a0ee8cc6SDag-Erling Smørgrav 
2596a0ee8cc6SDag-Erling Smørgrav 	/* Sign the whole mess */
25974f52dfbbSDag-Erling Smørgrav 	if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert),
25984f52dfbbSDag-Erling Smørgrav 	    sshbuf_len(cert), alg, 0, signer_ctx)) != 0)
2599a0ee8cc6SDag-Erling Smørgrav 		goto out;
2600a0ee8cc6SDag-Erling Smørgrav 
2601a0ee8cc6SDag-Erling Smørgrav 	/* Append signature and we are done */
2602a0ee8cc6SDag-Erling Smørgrav 	if ((ret = sshbuf_put_string(cert, sig_blob, sig_len)) != 0)
2603a0ee8cc6SDag-Erling Smørgrav 		goto out;
2604a0ee8cc6SDag-Erling Smørgrav 	ret = 0;
2605a0ee8cc6SDag-Erling Smørgrav  out:
2606a0ee8cc6SDag-Erling Smørgrav 	if (ret != 0)
2607a0ee8cc6SDag-Erling Smørgrav 		sshbuf_reset(cert);
2608a0ee8cc6SDag-Erling Smørgrav 	free(sig_blob);
2609a0ee8cc6SDag-Erling Smørgrav 	free(ca_blob);
2610a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(principals);
2611a0ee8cc6SDag-Erling Smørgrav 	return ret;
2612a0ee8cc6SDag-Erling Smørgrav }
2613a0ee8cc6SDag-Erling Smørgrav 
26144f52dfbbSDag-Erling Smørgrav static int
26154f52dfbbSDag-Erling Smørgrav default_key_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
26164f52dfbbSDag-Erling Smørgrav     const u_char *data, size_t datalen,
26174f52dfbbSDag-Erling Smørgrav     const char *alg, u_int compat, void *ctx)
26184f52dfbbSDag-Erling Smørgrav {
26194f52dfbbSDag-Erling Smørgrav 	if (ctx != NULL)
26204f52dfbbSDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
26214f52dfbbSDag-Erling Smørgrav 	return sshkey_sign(key, sigp, lenp, data, datalen, alg, compat);
26224f52dfbbSDag-Erling Smørgrav }
26234f52dfbbSDag-Erling Smørgrav 
26244f52dfbbSDag-Erling Smørgrav int
26254f52dfbbSDag-Erling Smørgrav sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg)
26264f52dfbbSDag-Erling Smørgrav {
26274f52dfbbSDag-Erling Smørgrav 	return sshkey_certify_custom(k, ca, alg, default_key_sign, NULL);
26284f52dfbbSDag-Erling Smørgrav }
26294f52dfbbSDag-Erling Smørgrav 
2630a0ee8cc6SDag-Erling Smørgrav int
2631a0ee8cc6SDag-Erling Smørgrav sshkey_cert_check_authority(const struct sshkey *k,
2632a0ee8cc6SDag-Erling Smørgrav     int want_host, int require_principal,
2633a0ee8cc6SDag-Erling Smørgrav     const char *name, const char **reason)
2634a0ee8cc6SDag-Erling Smørgrav {
2635a0ee8cc6SDag-Erling Smørgrav 	u_int i, principal_matches;
2636a0ee8cc6SDag-Erling Smørgrav 	time_t now = time(NULL);
2637a0ee8cc6SDag-Erling Smørgrav 
2638a0ee8cc6SDag-Erling Smørgrav 	if (reason != NULL)
2639a0ee8cc6SDag-Erling Smørgrav 		*reason = NULL;
2640a0ee8cc6SDag-Erling Smørgrav 
2641a0ee8cc6SDag-Erling Smørgrav 	if (want_host) {
2642a0ee8cc6SDag-Erling Smørgrav 		if (k->cert->type != SSH2_CERT_TYPE_HOST) {
2643a0ee8cc6SDag-Erling Smørgrav 			*reason = "Certificate invalid: not a host certificate";
2644a0ee8cc6SDag-Erling Smørgrav 			return SSH_ERR_KEY_CERT_INVALID;
2645a0ee8cc6SDag-Erling Smørgrav 		}
2646a0ee8cc6SDag-Erling Smørgrav 	} else {
2647a0ee8cc6SDag-Erling Smørgrav 		if (k->cert->type != SSH2_CERT_TYPE_USER) {
2648a0ee8cc6SDag-Erling Smørgrav 			*reason = "Certificate invalid: not a user certificate";
2649a0ee8cc6SDag-Erling Smørgrav 			return SSH_ERR_KEY_CERT_INVALID;
2650a0ee8cc6SDag-Erling Smørgrav 		}
2651a0ee8cc6SDag-Erling Smørgrav 	}
2652a0ee8cc6SDag-Erling Smørgrav 	if (now < 0) {
2653a0ee8cc6SDag-Erling Smørgrav 		/* yikes - system clock before epoch! */
2654a0ee8cc6SDag-Erling Smørgrav 		*reason = "Certificate invalid: not yet valid";
2655a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_KEY_CERT_INVALID;
2656a0ee8cc6SDag-Erling Smørgrav 	}
2657a0ee8cc6SDag-Erling Smørgrav 	if ((u_int64_t)now < k->cert->valid_after) {
2658a0ee8cc6SDag-Erling Smørgrav 		*reason = "Certificate invalid: not yet valid";
2659a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_KEY_CERT_INVALID;
2660a0ee8cc6SDag-Erling Smørgrav 	}
2661a0ee8cc6SDag-Erling Smørgrav 	if ((u_int64_t)now >= k->cert->valid_before) {
2662a0ee8cc6SDag-Erling Smørgrav 		*reason = "Certificate invalid: expired";
2663a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_KEY_CERT_INVALID;
2664a0ee8cc6SDag-Erling Smørgrav 	}
2665a0ee8cc6SDag-Erling Smørgrav 	if (k->cert->nprincipals == 0) {
2666a0ee8cc6SDag-Erling Smørgrav 		if (require_principal) {
2667a0ee8cc6SDag-Erling Smørgrav 			*reason = "Certificate lacks principal list";
2668a0ee8cc6SDag-Erling Smørgrav 			return SSH_ERR_KEY_CERT_INVALID;
2669a0ee8cc6SDag-Erling Smørgrav 		}
2670a0ee8cc6SDag-Erling Smørgrav 	} else if (name != NULL) {
2671a0ee8cc6SDag-Erling Smørgrav 		principal_matches = 0;
2672a0ee8cc6SDag-Erling Smørgrav 		for (i = 0; i < k->cert->nprincipals; i++) {
2673a0ee8cc6SDag-Erling Smørgrav 			if (strcmp(name, k->cert->principals[i]) == 0) {
2674a0ee8cc6SDag-Erling Smørgrav 				principal_matches = 1;
2675a0ee8cc6SDag-Erling Smørgrav 				break;
2676a0ee8cc6SDag-Erling Smørgrav 			}
2677a0ee8cc6SDag-Erling Smørgrav 		}
2678a0ee8cc6SDag-Erling Smørgrav 		if (!principal_matches) {
2679a0ee8cc6SDag-Erling Smørgrav 			*reason = "Certificate invalid: name is not a listed "
2680a0ee8cc6SDag-Erling Smørgrav 			    "principal";
2681a0ee8cc6SDag-Erling Smørgrav 			return SSH_ERR_KEY_CERT_INVALID;
2682a0ee8cc6SDag-Erling Smørgrav 		}
2683a0ee8cc6SDag-Erling Smørgrav 	}
2684a0ee8cc6SDag-Erling Smørgrav 	return 0;
2685a0ee8cc6SDag-Erling Smørgrav }
2686a0ee8cc6SDag-Erling Smørgrav 
2687acc1a9efSDag-Erling Smørgrav size_t
2688acc1a9efSDag-Erling Smørgrav sshkey_format_cert_validity(const struct sshkey_cert *cert, char *s, size_t l)
2689acc1a9efSDag-Erling Smørgrav {
2690acc1a9efSDag-Erling Smørgrav 	char from[32], to[32], ret[64];
2691acc1a9efSDag-Erling Smørgrav 	time_t tt;
2692acc1a9efSDag-Erling Smørgrav 	struct tm *tm;
2693acc1a9efSDag-Erling Smørgrav 
2694acc1a9efSDag-Erling Smørgrav 	*from = *to = '\0';
2695acc1a9efSDag-Erling Smørgrav 	if (cert->valid_after == 0 &&
2696acc1a9efSDag-Erling Smørgrav 	    cert->valid_before == 0xffffffffffffffffULL)
2697acc1a9efSDag-Erling Smørgrav 		return strlcpy(s, "forever", l);
2698acc1a9efSDag-Erling Smørgrav 
2699acc1a9efSDag-Erling Smørgrav 	if (cert->valid_after != 0) {
2700acc1a9efSDag-Erling Smørgrav 		/* XXX revisit INT_MAX in 2038 :) */
2701acc1a9efSDag-Erling Smørgrav 		tt = cert->valid_after > INT_MAX ?
2702acc1a9efSDag-Erling Smørgrav 		    INT_MAX : cert->valid_after;
2703acc1a9efSDag-Erling Smørgrav 		tm = localtime(&tt);
2704acc1a9efSDag-Erling Smørgrav 		strftime(from, sizeof(from), "%Y-%m-%dT%H:%M:%S", tm);
2705acc1a9efSDag-Erling Smørgrav 	}
2706acc1a9efSDag-Erling Smørgrav 	if (cert->valid_before != 0xffffffffffffffffULL) {
2707acc1a9efSDag-Erling Smørgrav 		/* XXX revisit INT_MAX in 2038 :) */
2708acc1a9efSDag-Erling Smørgrav 		tt = cert->valid_before > INT_MAX ?
2709acc1a9efSDag-Erling Smørgrav 		    INT_MAX : cert->valid_before;
2710acc1a9efSDag-Erling Smørgrav 		tm = localtime(&tt);
2711acc1a9efSDag-Erling Smørgrav 		strftime(to, sizeof(to), "%Y-%m-%dT%H:%M:%S", tm);
2712acc1a9efSDag-Erling Smørgrav 	}
2713acc1a9efSDag-Erling Smørgrav 
2714acc1a9efSDag-Erling Smørgrav 	if (cert->valid_after == 0)
2715acc1a9efSDag-Erling Smørgrav 		snprintf(ret, sizeof(ret), "before %s", to);
2716acc1a9efSDag-Erling Smørgrav 	else if (cert->valid_before == 0xffffffffffffffffULL)
2717acc1a9efSDag-Erling Smørgrav 		snprintf(ret, sizeof(ret), "after %s", from);
2718acc1a9efSDag-Erling Smørgrav 	else
2719acc1a9efSDag-Erling Smørgrav 		snprintf(ret, sizeof(ret), "from %s to %s", from, to);
2720acc1a9efSDag-Erling Smørgrav 
2721acc1a9efSDag-Erling Smørgrav 	return strlcpy(s, ret, l);
2722acc1a9efSDag-Erling Smørgrav }
2723acc1a9efSDag-Erling Smørgrav 
2724a0ee8cc6SDag-Erling Smørgrav int
272547dd1d1bSDag-Erling Smørgrav sshkey_private_serialize_opt(const struct sshkey *key, struct sshbuf *b,
272647dd1d1bSDag-Erling Smørgrav     enum sshkey_serialize_rep opts)
2727a0ee8cc6SDag-Erling Smørgrav {
2728a0ee8cc6SDag-Erling Smørgrav 	int r = SSH_ERR_INTERNAL_ERROR;
2729*2a01feabSEd Maste #ifdef WITH_OPENSSL
2730*2a01feabSEd Maste 	const BIGNUM *rsa_n, *rsa_e, *rsa_d, *rsa_iqmp, *rsa_p, *rsa_q;
2731*2a01feabSEd Maste 	const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key, *dsa_priv_key;
2732*2a01feabSEd Maste #endif /* WITH_OPENSSL */
2733a0ee8cc6SDag-Erling Smørgrav 
2734a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_put_cstring(b, sshkey_ssh_name(key))) != 0)
2735a0ee8cc6SDag-Erling Smørgrav 		goto out;
2736a0ee8cc6SDag-Erling Smørgrav 	switch (key->type) {
2737a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
2738a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
2739*2a01feabSEd Maste 		RSA_get0_key(key->rsa, &rsa_n, &rsa_e, &rsa_d);
2740*2a01feabSEd Maste 		RSA_get0_factors(key->rsa, &rsa_p, &rsa_q);
2741*2a01feabSEd Maste 		RSA_get0_crt_params(key->rsa, NULL, NULL, &rsa_iqmp);
2742*2a01feabSEd Maste 		if ((r = sshbuf_put_bignum2(b, rsa_n)) != 0 ||
2743*2a01feabSEd Maste 		    (r = sshbuf_put_bignum2(b, rsa_e)) != 0 ||
2744*2a01feabSEd Maste 		    (r = sshbuf_put_bignum2(b, rsa_d)) != 0 ||
2745*2a01feabSEd Maste 		    (r = sshbuf_put_bignum2(b, rsa_iqmp)) != 0 ||
2746*2a01feabSEd Maste 		    (r = sshbuf_put_bignum2(b, rsa_p)) != 0 ||
2747*2a01feabSEd Maste 		    (r = sshbuf_put_bignum2(b, rsa_q)) != 0)
2748a0ee8cc6SDag-Erling Smørgrav 			goto out;
2749a0ee8cc6SDag-Erling Smørgrav 		break;
2750a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA_CERT:
2751a0ee8cc6SDag-Erling Smørgrav 		if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
2752a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_INVALID_ARGUMENT;
2753a0ee8cc6SDag-Erling Smørgrav 			goto out;
2754a0ee8cc6SDag-Erling Smørgrav 		}
2755*2a01feabSEd Maste 		RSA_get0_key(key->rsa, NULL, NULL, &rsa_d);
2756*2a01feabSEd Maste 		RSA_get0_factors(key->rsa, &rsa_p, &rsa_q);
2757*2a01feabSEd Maste 		RSA_get0_crt_params(key->rsa, NULL, NULL, &rsa_iqmp);
2758a0ee8cc6SDag-Erling Smørgrav 		if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2759*2a01feabSEd Maste 		    (r = sshbuf_put_bignum2(b, rsa_d)) != 0 ||
2760*2a01feabSEd Maste 		    (r = sshbuf_put_bignum2(b, rsa_iqmp)) != 0 ||
2761*2a01feabSEd Maste 		    (r = sshbuf_put_bignum2(b, rsa_p)) != 0 ||
2762*2a01feabSEd Maste 		    (r = sshbuf_put_bignum2(b, rsa_q)) != 0)
2763a0ee8cc6SDag-Erling Smørgrav 			goto out;
2764a0ee8cc6SDag-Erling Smørgrav 		break;
2765a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
2766*2a01feabSEd Maste 		DSA_get0_pqg(key->dsa, &dsa_p, &dsa_q, &dsa_g);
2767*2a01feabSEd Maste 		DSA_get0_key(key->dsa, &dsa_pub_key, &dsa_priv_key);
2768*2a01feabSEd Maste 		if ((r = sshbuf_put_bignum2(b, dsa_p)) != 0 ||
2769*2a01feabSEd Maste 		    (r = sshbuf_put_bignum2(b, dsa_q)) != 0 ||
2770*2a01feabSEd Maste 		    (r = sshbuf_put_bignum2(b, dsa_g)) != 0 ||
2771*2a01feabSEd Maste 		    (r = sshbuf_put_bignum2(b, dsa_pub_key)) != 0 ||
2772*2a01feabSEd Maste 		    (r = sshbuf_put_bignum2(b, dsa_priv_key)) != 0)
2773a0ee8cc6SDag-Erling Smørgrav 			goto out;
2774a0ee8cc6SDag-Erling Smørgrav 		break;
2775a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA_CERT:
2776a0ee8cc6SDag-Erling Smørgrav 		if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
2777a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_INVALID_ARGUMENT;
2778a0ee8cc6SDag-Erling Smørgrav 			goto out;
2779a0ee8cc6SDag-Erling Smørgrav 		}
2780*2a01feabSEd Maste 		DSA_get0_key(key->dsa, NULL, &dsa_priv_key);
2781a0ee8cc6SDag-Erling Smørgrav 		if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2782*2a01feabSEd Maste 		    (r = sshbuf_put_bignum2(b, dsa_priv_key)) != 0)
2783a0ee8cc6SDag-Erling Smørgrav 			goto out;
2784a0ee8cc6SDag-Erling Smørgrav 		break;
2785a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_ECC
2786a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
2787a0ee8cc6SDag-Erling Smørgrav 		if ((r = sshbuf_put_cstring(b,
2788a0ee8cc6SDag-Erling Smørgrav 		    sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 ||
2789a0ee8cc6SDag-Erling Smørgrav 		    (r = sshbuf_put_eckey(b, key->ecdsa)) != 0 ||
2790a0ee8cc6SDag-Erling Smørgrav 		    (r = sshbuf_put_bignum2(b,
2791a0ee8cc6SDag-Erling Smørgrav 		    EC_KEY_get0_private_key(key->ecdsa))) != 0)
2792a0ee8cc6SDag-Erling Smørgrav 			goto out;
2793a0ee8cc6SDag-Erling Smørgrav 		break;
2794a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA_CERT:
2795a0ee8cc6SDag-Erling Smørgrav 		if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
2796a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_INVALID_ARGUMENT;
2797a0ee8cc6SDag-Erling Smørgrav 			goto out;
2798a0ee8cc6SDag-Erling Smørgrav 		}
2799a0ee8cc6SDag-Erling Smørgrav 		if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2800a0ee8cc6SDag-Erling Smørgrav 		    (r = sshbuf_put_bignum2(b,
2801a0ee8cc6SDag-Erling Smørgrav 		    EC_KEY_get0_private_key(key->ecdsa))) != 0)
2802a0ee8cc6SDag-Erling Smørgrav 			goto out;
2803a0ee8cc6SDag-Erling Smørgrav 		break;
2804a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_ECC */
2805a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
2806a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
2807a0ee8cc6SDag-Erling Smørgrav 		if ((r = sshbuf_put_string(b, key->ed25519_pk,
2808a0ee8cc6SDag-Erling Smørgrav 		    ED25519_PK_SZ)) != 0 ||
2809a0ee8cc6SDag-Erling Smørgrav 		    (r = sshbuf_put_string(b, key->ed25519_sk,
2810a0ee8cc6SDag-Erling Smørgrav 		    ED25519_SK_SZ)) != 0)
2811a0ee8cc6SDag-Erling Smørgrav 			goto out;
2812a0ee8cc6SDag-Erling Smørgrav 		break;
2813a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519_CERT:
2814a0ee8cc6SDag-Erling Smørgrav 		if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
2815a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_INVALID_ARGUMENT;
2816a0ee8cc6SDag-Erling Smørgrav 			goto out;
2817a0ee8cc6SDag-Erling Smørgrav 		}
2818a0ee8cc6SDag-Erling Smørgrav 		if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2819a0ee8cc6SDag-Erling Smørgrav 		    (r = sshbuf_put_string(b, key->ed25519_pk,
2820a0ee8cc6SDag-Erling Smørgrav 		    ED25519_PK_SZ)) != 0 ||
2821a0ee8cc6SDag-Erling Smørgrav 		    (r = sshbuf_put_string(b, key->ed25519_sk,
2822a0ee8cc6SDag-Erling Smørgrav 		    ED25519_SK_SZ)) != 0)
2823a0ee8cc6SDag-Erling Smørgrav 			goto out;
2824a0ee8cc6SDag-Erling Smørgrav 		break;
282547dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
282647dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
282747dd1d1bSDag-Erling Smørgrav 		if (key->xmss_name == NULL) {
282847dd1d1bSDag-Erling Smørgrav 			r = SSH_ERR_INVALID_ARGUMENT;
282947dd1d1bSDag-Erling Smørgrav 			goto out;
283047dd1d1bSDag-Erling Smørgrav 		}
283147dd1d1bSDag-Erling Smørgrav 		if ((r = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
283247dd1d1bSDag-Erling Smørgrav 		    (r = sshbuf_put_string(b, key->xmss_pk,
283347dd1d1bSDag-Erling Smørgrav 		    sshkey_xmss_pklen(key))) != 0 ||
283447dd1d1bSDag-Erling Smørgrav 		    (r = sshbuf_put_string(b, key->xmss_sk,
283547dd1d1bSDag-Erling Smørgrav 		    sshkey_xmss_sklen(key))) != 0 ||
283647dd1d1bSDag-Erling Smørgrav 		    (r = sshkey_xmss_serialize_state_opt(key, b, opts)) != 0)
283747dd1d1bSDag-Erling Smørgrav 			goto out;
283847dd1d1bSDag-Erling Smørgrav 		break;
283947dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS_CERT:
284047dd1d1bSDag-Erling Smørgrav 		if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0 ||
284147dd1d1bSDag-Erling Smørgrav 		    key->xmss_name == NULL) {
284247dd1d1bSDag-Erling Smørgrav 			r = SSH_ERR_INVALID_ARGUMENT;
284347dd1d1bSDag-Erling Smørgrav 			goto out;
284447dd1d1bSDag-Erling Smørgrav 		}
284547dd1d1bSDag-Erling Smørgrav 		if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
284647dd1d1bSDag-Erling Smørgrav 		    (r = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
284747dd1d1bSDag-Erling Smørgrav 		    (r = sshbuf_put_string(b, key->xmss_pk,
284847dd1d1bSDag-Erling Smørgrav 		    sshkey_xmss_pklen(key))) != 0 ||
284947dd1d1bSDag-Erling Smørgrav 		    (r = sshbuf_put_string(b, key->xmss_sk,
285047dd1d1bSDag-Erling Smørgrav 		    sshkey_xmss_sklen(key))) != 0 ||
285147dd1d1bSDag-Erling Smørgrav 		    (r = sshkey_xmss_serialize_state_opt(key, b, opts)) != 0)
285247dd1d1bSDag-Erling Smørgrav 			goto out;
285347dd1d1bSDag-Erling Smørgrav 		break;
285447dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
2855a0ee8cc6SDag-Erling Smørgrav 	default:
2856a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_INVALID_ARGUMENT;
2857a0ee8cc6SDag-Erling Smørgrav 		goto out;
2858a0ee8cc6SDag-Erling Smørgrav 	}
2859a0ee8cc6SDag-Erling Smørgrav 	/* success */
2860a0ee8cc6SDag-Erling Smørgrav 	r = 0;
2861a0ee8cc6SDag-Erling Smørgrav  out:
2862a0ee8cc6SDag-Erling Smørgrav 	return r;
2863a0ee8cc6SDag-Erling Smørgrav }
2864a0ee8cc6SDag-Erling Smørgrav 
2865a0ee8cc6SDag-Erling Smørgrav int
286647dd1d1bSDag-Erling Smørgrav sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b)
286747dd1d1bSDag-Erling Smørgrav {
286847dd1d1bSDag-Erling Smørgrav 	return sshkey_private_serialize_opt(key, b,
286947dd1d1bSDag-Erling Smørgrav 	    SSHKEY_SERIALIZE_DEFAULT);
287047dd1d1bSDag-Erling Smørgrav }
287147dd1d1bSDag-Erling Smørgrav 
287247dd1d1bSDag-Erling Smørgrav int
2873a0ee8cc6SDag-Erling Smørgrav sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
2874a0ee8cc6SDag-Erling Smørgrav {
287547dd1d1bSDag-Erling Smørgrav 	char *tname = NULL, *curve = NULL, *xmss_name = NULL;
2876a0ee8cc6SDag-Erling Smørgrav 	struct sshkey *k = NULL;
2877bc5531deSDag-Erling Smørgrav 	size_t pklen = 0, sklen = 0;
2878a0ee8cc6SDag-Erling Smørgrav 	int type, r = SSH_ERR_INTERNAL_ERROR;
2879a0ee8cc6SDag-Erling Smørgrav 	u_char *ed25519_pk = NULL, *ed25519_sk = NULL;
288047dd1d1bSDag-Erling Smørgrav 	u_char *xmss_pk = NULL, *xmss_sk = NULL;
2881a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
2882a0ee8cc6SDag-Erling Smørgrav 	BIGNUM *exponent = NULL;
2883*2a01feabSEd Maste 	BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
2884*2a01feabSEd Maste 	BIGNUM *rsa_iqmp = NULL, *rsa_p = NULL, *rsa_q = NULL;
2885*2a01feabSEd Maste 	BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL;
2886*2a01feabSEd Maste 	BIGNUM *dsa_pub_key = NULL, *dsa_priv_key = NULL;
2887a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
2888a0ee8cc6SDag-Erling Smørgrav 
2889a0ee8cc6SDag-Erling Smørgrav 	if (kp != NULL)
2890a0ee8cc6SDag-Erling Smørgrav 		*kp = NULL;
2891a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_get_cstring(buf, &tname, NULL)) != 0)
2892a0ee8cc6SDag-Erling Smørgrav 		goto out;
2893a0ee8cc6SDag-Erling Smørgrav 	type = sshkey_type_from_name(tname);
2894a0ee8cc6SDag-Erling Smørgrav 	switch (type) {
2895a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
2896a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
2897a0ee8cc6SDag-Erling Smørgrav 		if ((k = sshkey_new_private(type)) == NULL) {
2898a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_ALLOC_FAIL;
2899a0ee8cc6SDag-Erling Smørgrav 			goto out;
2900a0ee8cc6SDag-Erling Smørgrav 		}
2901*2a01feabSEd Maste 		if ((dsa_p = BN_new()) == NULL ||
2902*2a01feabSEd Maste 		    (dsa_q = BN_new()) == NULL ||
2903*2a01feabSEd Maste 		    (dsa_g = BN_new()) == NULL ||
2904*2a01feabSEd Maste 		    (dsa_pub_key = BN_new()) == NULL ||
2905*2a01feabSEd Maste 		    (dsa_priv_key = BN_new()) == NULL) {
2906*2a01feabSEd Maste 			r = SSH_ERR_ALLOC_FAIL;
2907a0ee8cc6SDag-Erling Smørgrav 			goto out;
2908*2a01feabSEd Maste 		}
2909*2a01feabSEd Maste 		if ((r = sshbuf_get_bignum2(buf, dsa_p)) != 0 ||
2910*2a01feabSEd Maste 		    (r = sshbuf_get_bignum2(buf, dsa_q)) != 0 ||
2911*2a01feabSEd Maste 		    (r = sshbuf_get_bignum2(buf, dsa_g)) != 0 ||
2912*2a01feabSEd Maste 		    (r = sshbuf_get_bignum2(buf, dsa_pub_key)) != 0 ||
2913*2a01feabSEd Maste 		    (r = sshbuf_get_bignum2(buf, dsa_priv_key)) != 0)
2914*2a01feabSEd Maste 			goto out;
2915*2a01feabSEd Maste 		if (!DSA_set0_pqg(k->dsa, dsa_p, dsa_q, dsa_g)) {
2916*2a01feabSEd Maste 			r = SSH_ERR_LIBCRYPTO_ERROR;
2917*2a01feabSEd Maste 			goto out;
2918*2a01feabSEd Maste 		}
2919*2a01feabSEd Maste 		dsa_p = dsa_q = dsa_g = NULL; /* transferred */
2920*2a01feabSEd Maste 		if (!DSA_set0_key(k->dsa, dsa_pub_key, dsa_priv_key)) {
2921*2a01feabSEd Maste 			r = SSH_ERR_LIBCRYPTO_ERROR;
2922*2a01feabSEd Maste 			goto out;
2923*2a01feabSEd Maste 		}
2924*2a01feabSEd Maste 		dsa_pub_key = dsa_priv_key = NULL; /* transferred */
2925a0ee8cc6SDag-Erling Smørgrav 		break;
2926a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA_CERT:
2927*2a01feabSEd Maste 		if ((dsa_priv_key = BN_new()) == NULL) {
2928*2a01feabSEd Maste 			r = SSH_ERR_ALLOC_FAIL;
2929a0ee8cc6SDag-Erling Smørgrav 			goto out;
2930*2a01feabSEd Maste 		}
2931*2a01feabSEd Maste 		if ((r = sshkey_froms(buf, &k)) != 0 ||
2932*2a01feabSEd Maste 		    (r = sshbuf_get_bignum2(buf, dsa_priv_key)) != 0)
2933*2a01feabSEd Maste 			goto out;
2934*2a01feabSEd Maste 		if (!DSA_set0_key(k->dsa, NULL, dsa_priv_key)) {
2935*2a01feabSEd Maste 			r = SSH_ERR_LIBCRYPTO_ERROR;
2936*2a01feabSEd Maste 			goto out;
2937*2a01feabSEd Maste 		}
2938*2a01feabSEd Maste 		dsa_priv_key = NULL; /* transferred */
2939a0ee8cc6SDag-Erling Smørgrav 		break;
2940a0ee8cc6SDag-Erling Smørgrav # ifdef OPENSSL_HAS_ECC
2941a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
2942a0ee8cc6SDag-Erling Smørgrav 		if ((k = sshkey_new_private(type)) == NULL) {
2943a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_ALLOC_FAIL;
2944a0ee8cc6SDag-Erling Smørgrav 			goto out;
2945a0ee8cc6SDag-Erling Smørgrav 		}
2946a0ee8cc6SDag-Erling Smørgrav 		if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) {
2947a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_INVALID_ARGUMENT;
2948a0ee8cc6SDag-Erling Smørgrav 			goto out;
2949a0ee8cc6SDag-Erling Smørgrav 		}
2950a0ee8cc6SDag-Erling Smørgrav 		if ((r = sshbuf_get_cstring(buf, &curve, NULL)) != 0)
2951a0ee8cc6SDag-Erling Smørgrav 			goto out;
2952a0ee8cc6SDag-Erling Smørgrav 		if (k->ecdsa_nid != sshkey_curve_name_to_nid(curve)) {
2953a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_EC_CURVE_MISMATCH;
2954a0ee8cc6SDag-Erling Smørgrav 			goto out;
2955a0ee8cc6SDag-Erling Smørgrav 		}
2956a0ee8cc6SDag-Erling Smørgrav 		k->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid);
2957a0ee8cc6SDag-Erling Smørgrav 		if (k->ecdsa  == NULL || (exponent = BN_new()) == NULL) {
2958a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_LIBCRYPTO_ERROR;
2959a0ee8cc6SDag-Erling Smørgrav 			goto out;
2960a0ee8cc6SDag-Erling Smørgrav 		}
2961a0ee8cc6SDag-Erling Smørgrav 		if ((r = sshbuf_get_eckey(buf, k->ecdsa)) != 0 ||
2962a0ee8cc6SDag-Erling Smørgrav 		    (r = sshbuf_get_bignum2(buf, exponent)))
2963a0ee8cc6SDag-Erling Smørgrav 			goto out;
2964a0ee8cc6SDag-Erling Smørgrav 		if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) {
2965a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_LIBCRYPTO_ERROR;
2966a0ee8cc6SDag-Erling Smørgrav 			goto out;
2967a0ee8cc6SDag-Erling Smørgrav 		}
2968a0ee8cc6SDag-Erling Smørgrav 		if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
2969acc1a9efSDag-Erling Smørgrav 		    EC_KEY_get0_public_key(k->ecdsa))) != 0 ||
2970a0ee8cc6SDag-Erling Smørgrav 		    (r = sshkey_ec_validate_private(k->ecdsa)) != 0)
2971a0ee8cc6SDag-Erling Smørgrav 			goto out;
2972a0ee8cc6SDag-Erling Smørgrav 		break;
2973a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA_CERT:
2974a0ee8cc6SDag-Erling Smørgrav 		if ((exponent = BN_new()) == NULL) {
2975a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_LIBCRYPTO_ERROR;
2976a0ee8cc6SDag-Erling Smørgrav 			goto out;
2977a0ee8cc6SDag-Erling Smørgrav 		}
2978bc5531deSDag-Erling Smørgrav 		if ((r = sshkey_froms(buf, &k)) != 0 ||
2979a0ee8cc6SDag-Erling Smørgrav 		    (r = sshbuf_get_bignum2(buf, exponent)) != 0)
2980a0ee8cc6SDag-Erling Smørgrav 			goto out;
2981a0ee8cc6SDag-Erling Smørgrav 		if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) {
2982a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_LIBCRYPTO_ERROR;
2983a0ee8cc6SDag-Erling Smørgrav 			goto out;
2984a0ee8cc6SDag-Erling Smørgrav 		}
2985a0ee8cc6SDag-Erling Smørgrav 		if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa),
2986acc1a9efSDag-Erling Smørgrav 		    EC_KEY_get0_public_key(k->ecdsa))) != 0 ||
2987a0ee8cc6SDag-Erling Smørgrav 		    (r = sshkey_ec_validate_private(k->ecdsa)) != 0)
2988a0ee8cc6SDag-Erling Smørgrav 			goto out;
2989a0ee8cc6SDag-Erling Smørgrav 		break;
2990a0ee8cc6SDag-Erling Smørgrav # endif /* OPENSSL_HAS_ECC */
2991a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
2992a0ee8cc6SDag-Erling Smørgrav 		if ((k = sshkey_new_private(type)) == NULL) {
2993a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_ALLOC_FAIL;
2994a0ee8cc6SDag-Erling Smørgrav 			goto out;
2995a0ee8cc6SDag-Erling Smørgrav 		}
2996*2a01feabSEd Maste 		if ((rsa_n = BN_new()) == NULL ||
2997*2a01feabSEd Maste 		    (rsa_e = BN_new()) == NULL ||
2998*2a01feabSEd Maste 		    (rsa_d = BN_new()) == NULL ||
2999*2a01feabSEd Maste 		    (rsa_iqmp = BN_new()) == NULL ||
3000*2a01feabSEd Maste 		    (rsa_p = BN_new()) == NULL ||
3001*2a01feabSEd Maste 		    (rsa_q = BN_new()) == NULL) {
3002*2a01feabSEd Maste 			r = SSH_ERR_ALLOC_FAIL;
30034f52dfbbSDag-Erling Smørgrav 			goto out;
30044f52dfbbSDag-Erling Smørgrav 		}
3005*2a01feabSEd Maste 		if ((r = sshbuf_get_bignum2(buf, rsa_n)) != 0 ||
3006*2a01feabSEd Maste 		    (r = sshbuf_get_bignum2(buf, rsa_e)) != 0 ||
3007*2a01feabSEd Maste 		    (r = sshbuf_get_bignum2(buf, rsa_d)) != 0 ||
3008*2a01feabSEd Maste 		    (r = sshbuf_get_bignum2(buf, rsa_iqmp)) != 0 ||
3009*2a01feabSEd Maste 		    (r = sshbuf_get_bignum2(buf, rsa_p)) != 0 ||
3010*2a01feabSEd Maste 		    (r = sshbuf_get_bignum2(buf, rsa_q)) != 0)
3011*2a01feabSEd Maste 			goto out;
3012*2a01feabSEd Maste 		if (!RSA_set0_key(k->rsa, rsa_n, rsa_e, rsa_d)) {
3013*2a01feabSEd Maste 			r = SSH_ERR_LIBCRYPTO_ERROR;
3014*2a01feabSEd Maste 			goto out;
3015*2a01feabSEd Maste 		}
3016*2a01feabSEd Maste 		rsa_n = rsa_e = rsa_d = NULL; /* transferred */
3017*2a01feabSEd Maste 		if (!RSA_set0_factors(k->rsa, rsa_p, rsa_q)) {
3018*2a01feabSEd Maste 			r = SSH_ERR_LIBCRYPTO_ERROR;
3019*2a01feabSEd Maste 			goto out;
3020*2a01feabSEd Maste 		}
3021*2a01feabSEd Maste 		rsa_p = rsa_q = NULL; /* transferred */
3022*2a01feabSEd Maste 		if ((r = check_rsa_length(k->rsa)) != 0)
3023*2a01feabSEd Maste 			goto out;
3024*2a01feabSEd Maste 		if ((r = ssh_rsa_complete_crt_parameters(k, rsa_iqmp)) != 0)
3025*2a01feabSEd Maste 			goto out;
3026a0ee8cc6SDag-Erling Smørgrav 		break;
3027a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA_CERT:
3028*2a01feabSEd Maste 		if ((rsa_d = BN_new()) == NULL ||
3029*2a01feabSEd Maste 		    (rsa_iqmp = BN_new()) == NULL ||
3030*2a01feabSEd Maste 		    (rsa_p = BN_new()) == NULL ||
3031*2a01feabSEd Maste 		    (rsa_q = BN_new()) == NULL) {
3032*2a01feabSEd Maste 			r = SSH_ERR_ALLOC_FAIL;
30334f52dfbbSDag-Erling Smørgrav 			goto out;
30344f52dfbbSDag-Erling Smørgrav 		}
3035*2a01feabSEd Maste 		if ((r = sshkey_froms(buf, &k)) != 0 ||
3036*2a01feabSEd Maste 		    (r = sshbuf_get_bignum2(buf, rsa_d)) != 0 ||
3037*2a01feabSEd Maste 		    (r = sshbuf_get_bignum2(buf, rsa_iqmp)) != 0 ||
3038*2a01feabSEd Maste 		    (r = sshbuf_get_bignum2(buf, rsa_p)) != 0 ||
3039*2a01feabSEd Maste 		    (r = sshbuf_get_bignum2(buf, rsa_q)) != 0)
3040*2a01feabSEd Maste 			goto out;
3041*2a01feabSEd Maste 		if (!RSA_set0_key(k->rsa, NULL, NULL, rsa_d)) {
3042*2a01feabSEd Maste 			r = SSH_ERR_LIBCRYPTO_ERROR;
3043*2a01feabSEd Maste 			goto out;
3044*2a01feabSEd Maste 		}
3045*2a01feabSEd Maste 		rsa_d = NULL; /* transferred */
3046*2a01feabSEd Maste 		if (!RSA_set0_factors(k->rsa, rsa_p, rsa_q)) {
3047*2a01feabSEd Maste 			r = SSH_ERR_LIBCRYPTO_ERROR;
3048*2a01feabSEd Maste 			goto out;
3049*2a01feabSEd Maste 		}
3050*2a01feabSEd Maste 		rsa_p = rsa_q = NULL; /* transferred */
3051*2a01feabSEd Maste 		if ((r = check_rsa_length(k->rsa)) != 0)
3052*2a01feabSEd Maste 			goto out;
3053*2a01feabSEd Maste 		if ((r = ssh_rsa_complete_crt_parameters(k, rsa_iqmp)) != 0)
3054*2a01feabSEd Maste 			goto out;
3055a0ee8cc6SDag-Erling Smørgrav 		break;
3056a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
3057a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
3058a0ee8cc6SDag-Erling Smørgrav 		if ((k = sshkey_new_private(type)) == NULL) {
3059a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_ALLOC_FAIL;
3060a0ee8cc6SDag-Erling Smørgrav 			goto out;
3061a0ee8cc6SDag-Erling Smørgrav 		}
3062a0ee8cc6SDag-Erling Smørgrav 		if ((r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 ||
3063a0ee8cc6SDag-Erling Smørgrav 		    (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0)
3064a0ee8cc6SDag-Erling Smørgrav 			goto out;
3065a0ee8cc6SDag-Erling Smørgrav 		if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) {
3066a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_INVALID_FORMAT;
3067a0ee8cc6SDag-Erling Smørgrav 			goto out;
3068a0ee8cc6SDag-Erling Smørgrav 		}
3069a0ee8cc6SDag-Erling Smørgrav 		k->ed25519_pk = ed25519_pk;
3070a0ee8cc6SDag-Erling Smørgrav 		k->ed25519_sk = ed25519_sk;
3071a0ee8cc6SDag-Erling Smørgrav 		ed25519_pk = ed25519_sk = NULL;
3072a0ee8cc6SDag-Erling Smørgrav 		break;
3073a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519_CERT:
3074bc5531deSDag-Erling Smørgrav 		if ((r = sshkey_froms(buf, &k)) != 0 ||
3075a0ee8cc6SDag-Erling Smørgrav 		    (r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 ||
3076a0ee8cc6SDag-Erling Smørgrav 		    (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0)
3077a0ee8cc6SDag-Erling Smørgrav 			goto out;
3078a0ee8cc6SDag-Erling Smørgrav 		if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) {
3079a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_INVALID_FORMAT;
3080a0ee8cc6SDag-Erling Smørgrav 			goto out;
3081a0ee8cc6SDag-Erling Smørgrav 		}
3082a0ee8cc6SDag-Erling Smørgrav 		k->ed25519_pk = ed25519_pk;
3083a0ee8cc6SDag-Erling Smørgrav 		k->ed25519_sk = ed25519_sk;
3084a0ee8cc6SDag-Erling Smørgrav 		ed25519_pk = ed25519_sk = NULL;
3085a0ee8cc6SDag-Erling Smørgrav 		break;
308647dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
308747dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
308847dd1d1bSDag-Erling Smørgrav 		if ((k = sshkey_new_private(type)) == NULL) {
308947dd1d1bSDag-Erling Smørgrav 			r = SSH_ERR_ALLOC_FAIL;
309047dd1d1bSDag-Erling Smørgrav 			goto out;
309147dd1d1bSDag-Erling Smørgrav 		}
309247dd1d1bSDag-Erling Smørgrav 		if ((r = sshbuf_get_cstring(buf, &xmss_name, NULL)) != 0 ||
309347dd1d1bSDag-Erling Smørgrav 		    (r = sshkey_xmss_init(k, xmss_name)) != 0 ||
309447dd1d1bSDag-Erling Smørgrav 		    (r = sshbuf_get_string(buf, &xmss_pk, &pklen)) != 0 ||
309547dd1d1bSDag-Erling Smørgrav 		    (r = sshbuf_get_string(buf, &xmss_sk, &sklen)) != 0)
309647dd1d1bSDag-Erling Smørgrav 			goto out;
309747dd1d1bSDag-Erling Smørgrav 		if (pklen != sshkey_xmss_pklen(k) ||
309847dd1d1bSDag-Erling Smørgrav 		    sklen != sshkey_xmss_sklen(k)) {
309947dd1d1bSDag-Erling Smørgrav 			r = SSH_ERR_INVALID_FORMAT;
310047dd1d1bSDag-Erling Smørgrav 			goto out;
310147dd1d1bSDag-Erling Smørgrav 		}
310247dd1d1bSDag-Erling Smørgrav 		k->xmss_pk = xmss_pk;
310347dd1d1bSDag-Erling Smørgrav 		k->xmss_sk = xmss_sk;
310447dd1d1bSDag-Erling Smørgrav 		xmss_pk = xmss_sk = NULL;
310547dd1d1bSDag-Erling Smørgrav 		/* optional internal state */
310647dd1d1bSDag-Erling Smørgrav 		if ((r = sshkey_xmss_deserialize_state_opt(k, buf)) != 0)
310747dd1d1bSDag-Erling Smørgrav 			goto out;
310847dd1d1bSDag-Erling Smørgrav 		break;
310947dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS_CERT:
311047dd1d1bSDag-Erling Smørgrav 		if ((r = sshkey_froms(buf, &k)) != 0 ||
311147dd1d1bSDag-Erling Smørgrav 		    (r = sshbuf_get_cstring(buf, &xmss_name, NULL)) != 0 ||
311247dd1d1bSDag-Erling Smørgrav 		    (r = sshbuf_get_string(buf, &xmss_pk, &pklen)) != 0 ||
311347dd1d1bSDag-Erling Smørgrav 		    (r = sshbuf_get_string(buf, &xmss_sk, &sklen)) != 0)
311447dd1d1bSDag-Erling Smørgrav 			goto out;
311547dd1d1bSDag-Erling Smørgrav 		if (strcmp(xmss_name, k->xmss_name)) {
311647dd1d1bSDag-Erling Smørgrav 			r = SSH_ERR_INVALID_FORMAT;
311747dd1d1bSDag-Erling Smørgrav 			goto out;
311847dd1d1bSDag-Erling Smørgrav 		}
311947dd1d1bSDag-Erling Smørgrav 		if (pklen != sshkey_xmss_pklen(k) ||
312047dd1d1bSDag-Erling Smørgrav 		    sklen != sshkey_xmss_sklen(k)) {
312147dd1d1bSDag-Erling Smørgrav 			r = SSH_ERR_INVALID_FORMAT;
312247dd1d1bSDag-Erling Smørgrav 			goto out;
312347dd1d1bSDag-Erling Smørgrav 		}
312447dd1d1bSDag-Erling Smørgrav 		k->xmss_pk = xmss_pk;
312547dd1d1bSDag-Erling Smørgrav 		k->xmss_sk = xmss_sk;
312647dd1d1bSDag-Erling Smørgrav 		xmss_pk = xmss_sk = NULL;
312747dd1d1bSDag-Erling Smørgrav 		/* optional internal state */
312847dd1d1bSDag-Erling Smørgrav 		if ((r = sshkey_xmss_deserialize_state_opt(k, buf)) != 0)
312947dd1d1bSDag-Erling Smørgrav 			goto out;
313047dd1d1bSDag-Erling Smørgrav 		break;
313147dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
3132a0ee8cc6SDag-Erling Smørgrav 	default:
3133a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_KEY_TYPE_UNKNOWN;
3134a0ee8cc6SDag-Erling Smørgrav 		goto out;
3135a0ee8cc6SDag-Erling Smørgrav 	}
3136a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
3137a0ee8cc6SDag-Erling Smørgrav 	/* enable blinding */
3138a0ee8cc6SDag-Erling Smørgrav 	switch (k->type) {
3139a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
3140a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA_CERT:
3141a0ee8cc6SDag-Erling Smørgrav 		if (RSA_blinding_on(k->rsa, NULL) != 1) {
3142a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_LIBCRYPTO_ERROR;
3143a0ee8cc6SDag-Erling Smørgrav 			goto out;
3144a0ee8cc6SDag-Erling Smørgrav 		}
3145a0ee8cc6SDag-Erling Smørgrav 		break;
3146a0ee8cc6SDag-Erling Smørgrav 	}
3147a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
3148a0ee8cc6SDag-Erling Smørgrav 	/* success */
3149a0ee8cc6SDag-Erling Smørgrav 	r = 0;
3150a0ee8cc6SDag-Erling Smørgrav 	if (kp != NULL) {
3151a0ee8cc6SDag-Erling Smørgrav 		*kp = k;
3152a0ee8cc6SDag-Erling Smørgrav 		k = NULL;
3153a0ee8cc6SDag-Erling Smørgrav 	}
3154a0ee8cc6SDag-Erling Smørgrav  out:
3155a0ee8cc6SDag-Erling Smørgrav 	free(tname);
3156a0ee8cc6SDag-Erling Smørgrav 	free(curve);
3157a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
3158a0ee8cc6SDag-Erling Smørgrav 	BN_clear_free(exponent);
3159*2a01feabSEd Maste 	BN_clear_free(dsa_p);
3160*2a01feabSEd Maste 	BN_clear_free(dsa_q);
3161*2a01feabSEd Maste 	BN_clear_free(dsa_g);
3162*2a01feabSEd Maste 	BN_clear_free(dsa_pub_key);
3163*2a01feabSEd Maste 	BN_clear_free(dsa_priv_key);
3164*2a01feabSEd Maste 	BN_clear_free(rsa_n);
3165*2a01feabSEd Maste 	BN_clear_free(rsa_e);
3166*2a01feabSEd Maste 	BN_clear_free(rsa_d);
3167*2a01feabSEd Maste 	BN_clear_free(rsa_p);
3168*2a01feabSEd Maste 	BN_clear_free(rsa_q);
3169*2a01feabSEd Maste 	BN_clear_free(rsa_iqmp);
3170a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
3171a0ee8cc6SDag-Erling Smørgrav 	sshkey_free(k);
317247dd1d1bSDag-Erling Smørgrav 	freezero(ed25519_pk, pklen);
317347dd1d1bSDag-Erling Smørgrav 	freezero(ed25519_sk, sklen);
317447dd1d1bSDag-Erling Smørgrav 	free(xmss_name);
317547dd1d1bSDag-Erling Smørgrav 	freezero(xmss_pk, pklen);
317647dd1d1bSDag-Erling Smørgrav 	freezero(xmss_sk, sklen);
3177a0ee8cc6SDag-Erling Smørgrav 	return r;
3178a0ee8cc6SDag-Erling Smørgrav }
3179a0ee8cc6SDag-Erling Smørgrav 
3180a0ee8cc6SDag-Erling Smørgrav #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
3181a0ee8cc6SDag-Erling Smørgrav int
3182a0ee8cc6SDag-Erling Smørgrav sshkey_ec_validate_public(const EC_GROUP *group, const EC_POINT *public)
3183a0ee8cc6SDag-Erling Smørgrav {
3184a0ee8cc6SDag-Erling Smørgrav 	BN_CTX *bnctx;
3185a0ee8cc6SDag-Erling Smørgrav 	EC_POINT *nq = NULL;
3186a0ee8cc6SDag-Erling Smørgrav 	BIGNUM *order, *x, *y, *tmp;
3187a0ee8cc6SDag-Erling Smørgrav 	int ret = SSH_ERR_KEY_INVALID_EC_VALUE;
3188a0ee8cc6SDag-Erling Smørgrav 
3189ca86bcf2SDag-Erling Smørgrav 	/*
3190ca86bcf2SDag-Erling Smørgrav 	 * NB. This assumes OpenSSL has already verified that the public
3191ca86bcf2SDag-Erling Smørgrav 	 * point lies on the curve. This is done by EC_POINT_oct2point()
3192ca86bcf2SDag-Erling Smørgrav 	 * implicitly calling EC_POINT_is_on_curve(). If this code is ever
3193ca86bcf2SDag-Erling Smørgrav 	 * reachable with public points not unmarshalled using
3194ca86bcf2SDag-Erling Smørgrav 	 * EC_POINT_oct2point then the caller will need to explicitly check.
3195ca86bcf2SDag-Erling Smørgrav 	 */
3196ca86bcf2SDag-Erling Smørgrav 
3197a0ee8cc6SDag-Erling Smørgrav 	if ((bnctx = BN_CTX_new()) == NULL)
3198a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
3199a0ee8cc6SDag-Erling Smørgrav 	BN_CTX_start(bnctx);
3200a0ee8cc6SDag-Erling Smørgrav 
3201a0ee8cc6SDag-Erling Smørgrav 	/*
3202a0ee8cc6SDag-Erling Smørgrav 	 * We shouldn't ever hit this case because bignum_get_ecpoint()
3203a0ee8cc6SDag-Erling Smørgrav 	 * refuses to load GF2m points.
3204a0ee8cc6SDag-Erling Smørgrav 	 */
3205a0ee8cc6SDag-Erling Smørgrav 	if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
3206a0ee8cc6SDag-Erling Smørgrav 	    NID_X9_62_prime_field)
3207a0ee8cc6SDag-Erling Smørgrav 		goto out;
3208a0ee8cc6SDag-Erling Smørgrav 
3209a0ee8cc6SDag-Erling Smørgrav 	/* Q != infinity */
3210a0ee8cc6SDag-Erling Smørgrav 	if (EC_POINT_is_at_infinity(group, public))
3211a0ee8cc6SDag-Erling Smørgrav 		goto out;
3212a0ee8cc6SDag-Erling Smørgrav 
3213a0ee8cc6SDag-Erling Smørgrav 	if ((x = BN_CTX_get(bnctx)) == NULL ||
3214a0ee8cc6SDag-Erling Smørgrav 	    (y = BN_CTX_get(bnctx)) == NULL ||
3215a0ee8cc6SDag-Erling Smørgrav 	    (order = BN_CTX_get(bnctx)) == NULL ||
3216a0ee8cc6SDag-Erling Smørgrav 	    (tmp = BN_CTX_get(bnctx)) == NULL) {
3217a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_ALLOC_FAIL;
3218a0ee8cc6SDag-Erling Smørgrav 		goto out;
3219a0ee8cc6SDag-Erling Smørgrav 	}
3220a0ee8cc6SDag-Erling Smørgrav 
3221a0ee8cc6SDag-Erling Smørgrav 	/* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */
3222a0ee8cc6SDag-Erling Smørgrav 	if (EC_GROUP_get_order(group, order, bnctx) != 1 ||
3223a0ee8cc6SDag-Erling Smørgrav 	    EC_POINT_get_affine_coordinates_GFp(group, public,
3224a0ee8cc6SDag-Erling Smørgrav 	    x, y, bnctx) != 1) {
3225a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
3226a0ee8cc6SDag-Erling Smørgrav 		goto out;
3227a0ee8cc6SDag-Erling Smørgrav 	}
3228a0ee8cc6SDag-Erling Smørgrav 	if (BN_num_bits(x) <= BN_num_bits(order) / 2 ||
3229a0ee8cc6SDag-Erling Smørgrav 	    BN_num_bits(y) <= BN_num_bits(order) / 2)
3230a0ee8cc6SDag-Erling Smørgrav 		goto out;
3231a0ee8cc6SDag-Erling Smørgrav 
3232a0ee8cc6SDag-Erling Smørgrav 	/* nQ == infinity (n == order of subgroup) */
3233a0ee8cc6SDag-Erling Smørgrav 	if ((nq = EC_POINT_new(group)) == NULL) {
3234a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_ALLOC_FAIL;
3235a0ee8cc6SDag-Erling Smørgrav 		goto out;
3236a0ee8cc6SDag-Erling Smørgrav 	}
3237a0ee8cc6SDag-Erling Smørgrav 	if (EC_POINT_mul(group, nq, NULL, public, order, bnctx) != 1) {
3238a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
3239a0ee8cc6SDag-Erling Smørgrav 		goto out;
3240a0ee8cc6SDag-Erling Smørgrav 	}
3241a0ee8cc6SDag-Erling Smørgrav 	if (EC_POINT_is_at_infinity(group, nq) != 1)
3242a0ee8cc6SDag-Erling Smørgrav 		goto out;
3243a0ee8cc6SDag-Erling Smørgrav 
3244a0ee8cc6SDag-Erling Smørgrav 	/* x < order - 1, y < order - 1 */
3245a0ee8cc6SDag-Erling Smørgrav 	if (!BN_sub(tmp, order, BN_value_one())) {
3246a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
3247a0ee8cc6SDag-Erling Smørgrav 		goto out;
3248a0ee8cc6SDag-Erling Smørgrav 	}
3249a0ee8cc6SDag-Erling Smørgrav 	if (BN_cmp(x, tmp) >= 0 || BN_cmp(y, tmp) >= 0)
3250a0ee8cc6SDag-Erling Smørgrav 		goto out;
3251a0ee8cc6SDag-Erling Smørgrav 	ret = 0;
3252a0ee8cc6SDag-Erling Smørgrav  out:
3253a0ee8cc6SDag-Erling Smørgrav 	BN_CTX_free(bnctx);
3254a0ee8cc6SDag-Erling Smørgrav 	EC_POINT_free(nq);
3255a0ee8cc6SDag-Erling Smørgrav 	return ret;
3256a0ee8cc6SDag-Erling Smørgrav }
3257a0ee8cc6SDag-Erling Smørgrav 
3258a0ee8cc6SDag-Erling Smørgrav int
3259a0ee8cc6SDag-Erling Smørgrav sshkey_ec_validate_private(const EC_KEY *key)
3260a0ee8cc6SDag-Erling Smørgrav {
3261a0ee8cc6SDag-Erling Smørgrav 	BN_CTX *bnctx;
3262a0ee8cc6SDag-Erling Smørgrav 	BIGNUM *order, *tmp;
3263a0ee8cc6SDag-Erling Smørgrav 	int ret = SSH_ERR_KEY_INVALID_EC_VALUE;
3264a0ee8cc6SDag-Erling Smørgrav 
3265a0ee8cc6SDag-Erling Smørgrav 	if ((bnctx = BN_CTX_new()) == NULL)
3266a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
3267a0ee8cc6SDag-Erling Smørgrav 	BN_CTX_start(bnctx);
3268a0ee8cc6SDag-Erling Smørgrav 
3269a0ee8cc6SDag-Erling Smørgrav 	if ((order = BN_CTX_get(bnctx)) == NULL ||
3270a0ee8cc6SDag-Erling Smørgrav 	    (tmp = BN_CTX_get(bnctx)) == NULL) {
3271a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_ALLOC_FAIL;
3272a0ee8cc6SDag-Erling Smørgrav 		goto out;
3273a0ee8cc6SDag-Erling Smørgrav 	}
3274a0ee8cc6SDag-Erling Smørgrav 
3275a0ee8cc6SDag-Erling Smørgrav 	/* log2(private) > log2(order)/2 */
3276a0ee8cc6SDag-Erling Smørgrav 	if (EC_GROUP_get_order(EC_KEY_get0_group(key), order, bnctx) != 1) {
3277a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
3278a0ee8cc6SDag-Erling Smørgrav 		goto out;
3279a0ee8cc6SDag-Erling Smørgrav 	}
3280a0ee8cc6SDag-Erling Smørgrav 	if (BN_num_bits(EC_KEY_get0_private_key(key)) <=
3281a0ee8cc6SDag-Erling Smørgrav 	    BN_num_bits(order) / 2)
3282a0ee8cc6SDag-Erling Smørgrav 		goto out;
3283a0ee8cc6SDag-Erling Smørgrav 
3284a0ee8cc6SDag-Erling Smørgrav 	/* private < order - 1 */
3285a0ee8cc6SDag-Erling Smørgrav 	if (!BN_sub(tmp, order, BN_value_one())) {
3286a0ee8cc6SDag-Erling Smørgrav 		ret = SSH_ERR_LIBCRYPTO_ERROR;
3287a0ee8cc6SDag-Erling Smørgrav 		goto out;
3288a0ee8cc6SDag-Erling Smørgrav 	}
3289a0ee8cc6SDag-Erling Smørgrav 	if (BN_cmp(EC_KEY_get0_private_key(key), tmp) >= 0)
3290a0ee8cc6SDag-Erling Smørgrav 		goto out;
3291a0ee8cc6SDag-Erling Smørgrav 	ret = 0;
3292a0ee8cc6SDag-Erling Smørgrav  out:
3293a0ee8cc6SDag-Erling Smørgrav 	BN_CTX_free(bnctx);
3294a0ee8cc6SDag-Erling Smørgrav 	return ret;
3295a0ee8cc6SDag-Erling Smørgrav }
3296a0ee8cc6SDag-Erling Smørgrav 
3297a0ee8cc6SDag-Erling Smørgrav void
3298a0ee8cc6SDag-Erling Smørgrav sshkey_dump_ec_point(const EC_GROUP *group, const EC_POINT *point)
3299a0ee8cc6SDag-Erling Smørgrav {
3300a0ee8cc6SDag-Erling Smørgrav 	BIGNUM *x, *y;
3301a0ee8cc6SDag-Erling Smørgrav 	BN_CTX *bnctx;
3302a0ee8cc6SDag-Erling Smørgrav 
3303a0ee8cc6SDag-Erling Smørgrav 	if (point == NULL) {
3304a0ee8cc6SDag-Erling Smørgrav 		fputs("point=(NULL)\n", stderr);
3305a0ee8cc6SDag-Erling Smørgrav 		return;
3306a0ee8cc6SDag-Erling Smørgrav 	}
3307a0ee8cc6SDag-Erling Smørgrav 	if ((bnctx = BN_CTX_new()) == NULL) {
3308a0ee8cc6SDag-Erling Smørgrav 		fprintf(stderr, "%s: BN_CTX_new failed\n", __func__);
3309a0ee8cc6SDag-Erling Smørgrav 		return;
3310a0ee8cc6SDag-Erling Smørgrav 	}
3311a0ee8cc6SDag-Erling Smørgrav 	BN_CTX_start(bnctx);
3312a0ee8cc6SDag-Erling Smørgrav 	if ((x = BN_CTX_get(bnctx)) == NULL ||
3313a0ee8cc6SDag-Erling Smørgrav 	    (y = BN_CTX_get(bnctx)) == NULL) {
3314a0ee8cc6SDag-Erling Smørgrav 		fprintf(stderr, "%s: BN_CTX_get failed\n", __func__);
3315a0ee8cc6SDag-Erling Smørgrav 		return;
3316a0ee8cc6SDag-Erling Smørgrav 	}
3317a0ee8cc6SDag-Erling Smørgrav 	if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
3318a0ee8cc6SDag-Erling Smørgrav 	    NID_X9_62_prime_field) {
3319a0ee8cc6SDag-Erling Smørgrav 		fprintf(stderr, "%s: group is not a prime field\n", __func__);
3320a0ee8cc6SDag-Erling Smørgrav 		return;
3321a0ee8cc6SDag-Erling Smørgrav 	}
3322a0ee8cc6SDag-Erling Smørgrav 	if (EC_POINT_get_affine_coordinates_GFp(group, point, x, y,
3323a0ee8cc6SDag-Erling Smørgrav 	    bnctx) != 1) {
3324a0ee8cc6SDag-Erling Smørgrav 		fprintf(stderr, "%s: EC_POINT_get_affine_coordinates_GFp\n",
3325a0ee8cc6SDag-Erling Smørgrav 		    __func__);
3326a0ee8cc6SDag-Erling Smørgrav 		return;
3327a0ee8cc6SDag-Erling Smørgrav 	}
3328a0ee8cc6SDag-Erling Smørgrav 	fputs("x=", stderr);
3329a0ee8cc6SDag-Erling Smørgrav 	BN_print_fp(stderr, x);
3330a0ee8cc6SDag-Erling Smørgrav 	fputs("\ny=", stderr);
3331a0ee8cc6SDag-Erling Smørgrav 	BN_print_fp(stderr, y);
3332a0ee8cc6SDag-Erling Smørgrav 	fputs("\n", stderr);
3333a0ee8cc6SDag-Erling Smørgrav 	BN_CTX_free(bnctx);
3334a0ee8cc6SDag-Erling Smørgrav }
3335a0ee8cc6SDag-Erling Smørgrav 
3336a0ee8cc6SDag-Erling Smørgrav void
3337a0ee8cc6SDag-Erling Smørgrav sshkey_dump_ec_key(const EC_KEY *key)
3338a0ee8cc6SDag-Erling Smørgrav {
3339a0ee8cc6SDag-Erling Smørgrav 	const BIGNUM *exponent;
3340a0ee8cc6SDag-Erling Smørgrav 
3341a0ee8cc6SDag-Erling Smørgrav 	sshkey_dump_ec_point(EC_KEY_get0_group(key),
3342a0ee8cc6SDag-Erling Smørgrav 	    EC_KEY_get0_public_key(key));
3343a0ee8cc6SDag-Erling Smørgrav 	fputs("exponent=", stderr);
3344a0ee8cc6SDag-Erling Smørgrav 	if ((exponent = EC_KEY_get0_private_key(key)) == NULL)
3345a0ee8cc6SDag-Erling Smørgrav 		fputs("(NULL)", stderr);
3346a0ee8cc6SDag-Erling Smørgrav 	else
3347a0ee8cc6SDag-Erling Smørgrav 		BN_print_fp(stderr, EC_KEY_get0_private_key(key));
3348a0ee8cc6SDag-Erling Smørgrav 	fputs("\n", stderr);
3349a0ee8cc6SDag-Erling Smørgrav }
3350a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
3351a0ee8cc6SDag-Erling Smørgrav 
3352a0ee8cc6SDag-Erling Smørgrav static int
3353a0ee8cc6SDag-Erling Smørgrav sshkey_private_to_blob2(const struct sshkey *prv, struct sshbuf *blob,
3354a0ee8cc6SDag-Erling Smørgrav     const char *passphrase, const char *comment, const char *ciphername,
3355a0ee8cc6SDag-Erling Smørgrav     int rounds)
3356a0ee8cc6SDag-Erling Smørgrav {
3357bc5531deSDag-Erling Smørgrav 	u_char *cp, *key = NULL, *pubkeyblob = NULL;
3358a0ee8cc6SDag-Erling Smørgrav 	u_char salt[SALT_LEN];
3359bc5531deSDag-Erling Smørgrav 	char *b64 = NULL;
3360a0ee8cc6SDag-Erling Smørgrav 	size_t i, pubkeylen, keylen, ivlen, blocksize, authlen;
3361a0ee8cc6SDag-Erling Smørgrav 	u_int check;
3362a0ee8cc6SDag-Erling Smørgrav 	int r = SSH_ERR_INTERNAL_ERROR;
3363ca86bcf2SDag-Erling Smørgrav 	struct sshcipher_ctx *ciphercontext = NULL;
3364a0ee8cc6SDag-Erling Smørgrav 	const struct sshcipher *cipher;
3365a0ee8cc6SDag-Erling Smørgrav 	const char *kdfname = KDFNAME;
3366a0ee8cc6SDag-Erling Smørgrav 	struct sshbuf *encoded = NULL, *encrypted = NULL, *kdf = NULL;
3367a0ee8cc6SDag-Erling Smørgrav 
3368a0ee8cc6SDag-Erling Smørgrav 	if (rounds <= 0)
3369a0ee8cc6SDag-Erling Smørgrav 		rounds = DEFAULT_ROUNDS;
3370a0ee8cc6SDag-Erling Smørgrav 	if (passphrase == NULL || !strlen(passphrase)) {
3371a0ee8cc6SDag-Erling Smørgrav 		ciphername = "none";
3372a0ee8cc6SDag-Erling Smørgrav 		kdfname = "none";
3373a0ee8cc6SDag-Erling Smørgrav 	} else if (ciphername == NULL)
3374a0ee8cc6SDag-Erling Smørgrav 		ciphername = DEFAULT_CIPHERNAME;
3375a0ee8cc6SDag-Erling Smørgrav 	if ((cipher = cipher_by_name(ciphername)) == NULL) {
33764f52dfbbSDag-Erling Smørgrav 		r = SSH_ERR_INVALID_ARGUMENT;
3377a0ee8cc6SDag-Erling Smørgrav 		goto out;
3378a0ee8cc6SDag-Erling Smørgrav 	}
3379a0ee8cc6SDag-Erling Smørgrav 
3380a0ee8cc6SDag-Erling Smørgrav 	if ((kdf = sshbuf_new()) == NULL ||
3381a0ee8cc6SDag-Erling Smørgrav 	    (encoded = sshbuf_new()) == NULL ||
3382a0ee8cc6SDag-Erling Smørgrav 	    (encrypted = sshbuf_new()) == NULL) {
3383a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_ALLOC_FAIL;
3384a0ee8cc6SDag-Erling Smørgrav 		goto out;
3385a0ee8cc6SDag-Erling Smørgrav 	}
3386a0ee8cc6SDag-Erling Smørgrav 	blocksize = cipher_blocksize(cipher);
3387a0ee8cc6SDag-Erling Smørgrav 	keylen = cipher_keylen(cipher);
3388a0ee8cc6SDag-Erling Smørgrav 	ivlen = cipher_ivlen(cipher);
3389a0ee8cc6SDag-Erling Smørgrav 	authlen = cipher_authlen(cipher);
3390a0ee8cc6SDag-Erling Smørgrav 	if ((key = calloc(1, keylen + ivlen)) == NULL) {
3391a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_ALLOC_FAIL;
3392a0ee8cc6SDag-Erling Smørgrav 		goto out;
3393a0ee8cc6SDag-Erling Smørgrav 	}
3394a0ee8cc6SDag-Erling Smørgrav 	if (strcmp(kdfname, "bcrypt") == 0) {
3395a0ee8cc6SDag-Erling Smørgrav 		arc4random_buf(salt, SALT_LEN);
3396a0ee8cc6SDag-Erling Smørgrav 		if (bcrypt_pbkdf(passphrase, strlen(passphrase),
3397a0ee8cc6SDag-Erling Smørgrav 		    salt, SALT_LEN, key, keylen + ivlen, rounds) < 0) {
3398a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_INVALID_ARGUMENT;
3399a0ee8cc6SDag-Erling Smørgrav 			goto out;
3400a0ee8cc6SDag-Erling Smørgrav 		}
3401a0ee8cc6SDag-Erling Smørgrav 		if ((r = sshbuf_put_string(kdf, salt, SALT_LEN)) != 0 ||
3402a0ee8cc6SDag-Erling Smørgrav 		    (r = sshbuf_put_u32(kdf, rounds)) != 0)
3403a0ee8cc6SDag-Erling Smørgrav 			goto out;
3404a0ee8cc6SDag-Erling Smørgrav 	} else if (strcmp(kdfname, "none") != 0) {
3405a0ee8cc6SDag-Erling Smørgrav 		/* Unsupported KDF type */
3406a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_KEY_UNKNOWN_CIPHER;
3407a0ee8cc6SDag-Erling Smørgrav 		goto out;
3408a0ee8cc6SDag-Erling Smørgrav 	}
3409a0ee8cc6SDag-Erling Smørgrav 	if ((r = cipher_init(&ciphercontext, cipher, key, keylen,
3410a0ee8cc6SDag-Erling Smørgrav 	    key + keylen, ivlen, 1)) != 0)
3411a0ee8cc6SDag-Erling Smørgrav 		goto out;
3412a0ee8cc6SDag-Erling Smørgrav 
3413a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_put(encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC))) != 0 ||
3414a0ee8cc6SDag-Erling Smørgrav 	    (r = sshbuf_put_cstring(encoded, ciphername)) != 0 ||
3415a0ee8cc6SDag-Erling Smørgrav 	    (r = sshbuf_put_cstring(encoded, kdfname)) != 0 ||
3416a0ee8cc6SDag-Erling Smørgrav 	    (r = sshbuf_put_stringb(encoded, kdf)) != 0 ||
3417a0ee8cc6SDag-Erling Smørgrav 	    (r = sshbuf_put_u32(encoded, 1)) != 0 ||	/* number of keys */
3418a0ee8cc6SDag-Erling Smørgrav 	    (r = sshkey_to_blob(prv, &pubkeyblob, &pubkeylen)) != 0 ||
3419a0ee8cc6SDag-Erling Smørgrav 	    (r = sshbuf_put_string(encoded, pubkeyblob, pubkeylen)) != 0)
3420a0ee8cc6SDag-Erling Smørgrav 		goto out;
3421a0ee8cc6SDag-Erling Smørgrav 
3422a0ee8cc6SDag-Erling Smørgrav 	/* set up the buffer that will be encrypted */
3423a0ee8cc6SDag-Erling Smørgrav 
3424a0ee8cc6SDag-Erling Smørgrav 	/* Random check bytes */
3425a0ee8cc6SDag-Erling Smørgrav 	check = arc4random();
3426a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_put_u32(encrypted, check)) != 0 ||
3427a0ee8cc6SDag-Erling Smørgrav 	    (r = sshbuf_put_u32(encrypted, check)) != 0)
3428a0ee8cc6SDag-Erling Smørgrav 		goto out;
3429a0ee8cc6SDag-Erling Smørgrav 
3430a0ee8cc6SDag-Erling Smørgrav 	/* append private key and comment*/
343147dd1d1bSDag-Erling Smørgrav 	if ((r = sshkey_private_serialize_opt(prv, encrypted,
343247dd1d1bSDag-Erling Smørgrav 	     SSHKEY_SERIALIZE_FULL)) != 0 ||
3433a0ee8cc6SDag-Erling Smørgrav 	    (r = sshbuf_put_cstring(encrypted, comment)) != 0)
3434a0ee8cc6SDag-Erling Smørgrav 		goto out;
3435a0ee8cc6SDag-Erling Smørgrav 
3436a0ee8cc6SDag-Erling Smørgrav 	/* padding */
3437a0ee8cc6SDag-Erling Smørgrav 	i = 0;
3438a0ee8cc6SDag-Erling Smørgrav 	while (sshbuf_len(encrypted) % blocksize) {
3439a0ee8cc6SDag-Erling Smørgrav 		if ((r = sshbuf_put_u8(encrypted, ++i & 0xff)) != 0)
3440a0ee8cc6SDag-Erling Smørgrav 			goto out;
3441a0ee8cc6SDag-Erling Smørgrav 	}
3442a0ee8cc6SDag-Erling Smørgrav 
3443a0ee8cc6SDag-Erling Smørgrav 	/* length in destination buffer */
3444a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_put_u32(encoded, sshbuf_len(encrypted))) != 0)
3445a0ee8cc6SDag-Erling Smørgrav 		goto out;
3446a0ee8cc6SDag-Erling Smørgrav 
3447a0ee8cc6SDag-Erling Smørgrav 	/* encrypt */
3448a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_reserve(encoded,
3449a0ee8cc6SDag-Erling Smørgrav 	    sshbuf_len(encrypted) + authlen, &cp)) != 0)
3450a0ee8cc6SDag-Erling Smørgrav 		goto out;
3451ca86bcf2SDag-Erling Smørgrav 	if ((r = cipher_crypt(ciphercontext, 0, cp,
3452a0ee8cc6SDag-Erling Smørgrav 	    sshbuf_ptr(encrypted), sshbuf_len(encrypted), 0, authlen)) != 0)
3453a0ee8cc6SDag-Erling Smørgrav 		goto out;
3454a0ee8cc6SDag-Erling Smørgrav 
3455a0ee8cc6SDag-Erling Smørgrav 	/* uuencode */
3456a0ee8cc6SDag-Erling Smørgrav 	if ((b64 = sshbuf_dtob64(encoded)) == NULL) {
3457a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_ALLOC_FAIL;
3458a0ee8cc6SDag-Erling Smørgrav 		goto out;
3459a0ee8cc6SDag-Erling Smørgrav 	}
3460a0ee8cc6SDag-Erling Smørgrav 
3461a0ee8cc6SDag-Erling Smørgrav 	sshbuf_reset(blob);
3462a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_put(blob, MARK_BEGIN, MARK_BEGIN_LEN)) != 0)
3463a0ee8cc6SDag-Erling Smørgrav 		goto out;
3464a0ee8cc6SDag-Erling Smørgrav 	for (i = 0; i < strlen(b64); i++) {
3465a0ee8cc6SDag-Erling Smørgrav 		if ((r = sshbuf_put_u8(blob, b64[i])) != 0)
3466a0ee8cc6SDag-Erling Smørgrav 			goto out;
3467a0ee8cc6SDag-Erling Smørgrav 		/* insert line breaks */
3468a0ee8cc6SDag-Erling Smørgrav 		if (i % 70 == 69 && (r = sshbuf_put_u8(blob, '\n')) != 0)
3469a0ee8cc6SDag-Erling Smørgrav 			goto out;
3470a0ee8cc6SDag-Erling Smørgrav 	}
3471a0ee8cc6SDag-Erling Smørgrav 	if (i % 70 != 69 && (r = sshbuf_put_u8(blob, '\n')) != 0)
3472a0ee8cc6SDag-Erling Smørgrav 		goto out;
3473a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_put(blob, MARK_END, MARK_END_LEN)) != 0)
3474a0ee8cc6SDag-Erling Smørgrav 		goto out;
3475a0ee8cc6SDag-Erling Smørgrav 
3476a0ee8cc6SDag-Erling Smørgrav 	/* success */
3477a0ee8cc6SDag-Erling Smørgrav 	r = 0;
3478a0ee8cc6SDag-Erling Smørgrav 
3479a0ee8cc6SDag-Erling Smørgrav  out:
3480a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(kdf);
3481a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(encoded);
3482a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(encrypted);
3483ca86bcf2SDag-Erling Smørgrav 	cipher_free(ciphercontext);
3484a0ee8cc6SDag-Erling Smørgrav 	explicit_bzero(salt, sizeof(salt));
3485a0ee8cc6SDag-Erling Smørgrav 	if (key != NULL) {
3486a0ee8cc6SDag-Erling Smørgrav 		explicit_bzero(key, keylen + ivlen);
3487a0ee8cc6SDag-Erling Smørgrav 		free(key);
3488a0ee8cc6SDag-Erling Smørgrav 	}
3489a0ee8cc6SDag-Erling Smørgrav 	if (pubkeyblob != NULL) {
3490a0ee8cc6SDag-Erling Smørgrav 		explicit_bzero(pubkeyblob, pubkeylen);
3491a0ee8cc6SDag-Erling Smørgrav 		free(pubkeyblob);
3492a0ee8cc6SDag-Erling Smørgrav 	}
3493a0ee8cc6SDag-Erling Smørgrav 	if (b64 != NULL) {
3494a0ee8cc6SDag-Erling Smørgrav 		explicit_bzero(b64, strlen(b64));
3495a0ee8cc6SDag-Erling Smørgrav 		free(b64);
3496a0ee8cc6SDag-Erling Smørgrav 	}
3497a0ee8cc6SDag-Erling Smørgrav 	return r;
3498a0ee8cc6SDag-Erling Smørgrav }
3499a0ee8cc6SDag-Erling Smørgrav 
3500a0ee8cc6SDag-Erling Smørgrav static int
3501a0ee8cc6SDag-Erling Smørgrav sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
3502a0ee8cc6SDag-Erling Smørgrav     struct sshkey **keyp, char **commentp)
3503a0ee8cc6SDag-Erling Smørgrav {
3504a0ee8cc6SDag-Erling Smørgrav 	char *comment = NULL, *ciphername = NULL, *kdfname = NULL;
3505a0ee8cc6SDag-Erling Smørgrav 	const struct sshcipher *cipher = NULL;
3506a0ee8cc6SDag-Erling Smørgrav 	const u_char *cp;
3507a0ee8cc6SDag-Erling Smørgrav 	int r = SSH_ERR_INTERNAL_ERROR;
3508a0ee8cc6SDag-Erling Smørgrav 	size_t encoded_len;
3509557f75e5SDag-Erling Smørgrav 	size_t i, keylen = 0, ivlen = 0, authlen = 0, slen = 0;
3510a0ee8cc6SDag-Erling Smørgrav 	struct sshbuf *encoded = NULL, *decoded = NULL;
3511a0ee8cc6SDag-Erling Smørgrav 	struct sshbuf *kdf = NULL, *decrypted = NULL;
3512ca86bcf2SDag-Erling Smørgrav 	struct sshcipher_ctx *ciphercontext = NULL;
3513a0ee8cc6SDag-Erling Smørgrav 	struct sshkey *k = NULL;
3514a0ee8cc6SDag-Erling Smørgrav 	u_char *key = NULL, *salt = NULL, *dp, pad, last;
3515a0ee8cc6SDag-Erling Smørgrav 	u_int blocksize, rounds, nkeys, encrypted_len, check1, check2;
3516a0ee8cc6SDag-Erling Smørgrav 
3517a0ee8cc6SDag-Erling Smørgrav 	if (keyp != NULL)
3518a0ee8cc6SDag-Erling Smørgrav 		*keyp = NULL;
3519a0ee8cc6SDag-Erling Smørgrav 	if (commentp != NULL)
3520a0ee8cc6SDag-Erling Smørgrav 		*commentp = NULL;
3521a0ee8cc6SDag-Erling Smørgrav 
3522a0ee8cc6SDag-Erling Smørgrav 	if ((encoded = sshbuf_new()) == NULL ||
3523a0ee8cc6SDag-Erling Smørgrav 	    (decoded = sshbuf_new()) == NULL ||
3524a0ee8cc6SDag-Erling Smørgrav 	    (decrypted = sshbuf_new()) == NULL) {
3525a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_ALLOC_FAIL;
3526a0ee8cc6SDag-Erling Smørgrav 		goto out;
3527a0ee8cc6SDag-Erling Smørgrav 	}
3528a0ee8cc6SDag-Erling Smørgrav 
3529a0ee8cc6SDag-Erling Smørgrav 	/* check preamble */
3530a0ee8cc6SDag-Erling Smørgrav 	cp = sshbuf_ptr(blob);
3531a0ee8cc6SDag-Erling Smørgrav 	encoded_len = sshbuf_len(blob);
3532a0ee8cc6SDag-Erling Smørgrav 	if (encoded_len < (MARK_BEGIN_LEN + MARK_END_LEN) ||
3533a0ee8cc6SDag-Erling Smørgrav 	    memcmp(cp, MARK_BEGIN, MARK_BEGIN_LEN) != 0) {
3534a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_INVALID_FORMAT;
3535a0ee8cc6SDag-Erling Smørgrav 		goto out;
3536a0ee8cc6SDag-Erling Smørgrav 	}
3537a0ee8cc6SDag-Erling Smørgrav 	cp += MARK_BEGIN_LEN;
3538a0ee8cc6SDag-Erling Smørgrav 	encoded_len -= MARK_BEGIN_LEN;
3539a0ee8cc6SDag-Erling Smørgrav 
3540a0ee8cc6SDag-Erling Smørgrav 	/* Look for end marker, removing whitespace as we go */
3541a0ee8cc6SDag-Erling Smørgrav 	while (encoded_len > 0) {
3542a0ee8cc6SDag-Erling Smørgrav 		if (*cp != '\n' && *cp != '\r') {
3543a0ee8cc6SDag-Erling Smørgrav 			if ((r = sshbuf_put_u8(encoded, *cp)) != 0)
3544a0ee8cc6SDag-Erling Smørgrav 				goto out;
3545a0ee8cc6SDag-Erling Smørgrav 		}
3546a0ee8cc6SDag-Erling Smørgrav 		last = *cp;
3547a0ee8cc6SDag-Erling Smørgrav 		encoded_len--;
3548a0ee8cc6SDag-Erling Smørgrav 		cp++;
3549a0ee8cc6SDag-Erling Smørgrav 		if (last == '\n') {
3550a0ee8cc6SDag-Erling Smørgrav 			if (encoded_len >= MARK_END_LEN &&
3551a0ee8cc6SDag-Erling Smørgrav 			    memcmp(cp, MARK_END, MARK_END_LEN) == 0) {
3552a0ee8cc6SDag-Erling Smørgrav 				/* \0 terminate */
3553a0ee8cc6SDag-Erling Smørgrav 				if ((r = sshbuf_put_u8(encoded, 0)) != 0)
3554a0ee8cc6SDag-Erling Smørgrav 					goto out;
3555a0ee8cc6SDag-Erling Smørgrav 				break;
3556a0ee8cc6SDag-Erling Smørgrav 			}
3557a0ee8cc6SDag-Erling Smørgrav 		}
3558a0ee8cc6SDag-Erling Smørgrav 	}
3559a0ee8cc6SDag-Erling Smørgrav 	if (encoded_len == 0) {
3560a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_INVALID_FORMAT;
3561a0ee8cc6SDag-Erling Smørgrav 		goto out;
3562a0ee8cc6SDag-Erling Smørgrav 	}
3563a0ee8cc6SDag-Erling Smørgrav 
3564a0ee8cc6SDag-Erling Smørgrav 	/* decode base64 */
3565bc5531deSDag-Erling Smørgrav 	if ((r = sshbuf_b64tod(decoded, (char *)sshbuf_ptr(encoded))) != 0)
3566a0ee8cc6SDag-Erling Smørgrav 		goto out;
3567a0ee8cc6SDag-Erling Smørgrav 
3568a0ee8cc6SDag-Erling Smørgrav 	/* check magic */
3569a0ee8cc6SDag-Erling Smørgrav 	if (sshbuf_len(decoded) < sizeof(AUTH_MAGIC) ||
3570a0ee8cc6SDag-Erling Smørgrav 	    memcmp(sshbuf_ptr(decoded), AUTH_MAGIC, sizeof(AUTH_MAGIC))) {
3571a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_INVALID_FORMAT;
3572a0ee8cc6SDag-Erling Smørgrav 		goto out;
3573a0ee8cc6SDag-Erling Smørgrav 	}
3574a0ee8cc6SDag-Erling Smørgrav 	/* parse public portion of key */
3575a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 ||
3576a0ee8cc6SDag-Erling Smørgrav 	    (r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 ||
3577a0ee8cc6SDag-Erling Smørgrav 	    (r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 ||
3578a0ee8cc6SDag-Erling Smørgrav 	    (r = sshbuf_froms(decoded, &kdf)) != 0 ||
3579a0ee8cc6SDag-Erling Smørgrav 	    (r = sshbuf_get_u32(decoded, &nkeys)) != 0 ||
3580a0ee8cc6SDag-Erling Smørgrav 	    (r = sshbuf_skip_string(decoded)) != 0 || /* pubkey */
3581a0ee8cc6SDag-Erling Smørgrav 	    (r = sshbuf_get_u32(decoded, &encrypted_len)) != 0)
3582a0ee8cc6SDag-Erling Smørgrav 		goto out;
3583a0ee8cc6SDag-Erling Smørgrav 
3584a0ee8cc6SDag-Erling Smørgrav 	if ((cipher = cipher_by_name(ciphername)) == NULL) {
3585a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_KEY_UNKNOWN_CIPHER;
3586a0ee8cc6SDag-Erling Smørgrav 		goto out;
3587a0ee8cc6SDag-Erling Smørgrav 	}
3588a0ee8cc6SDag-Erling Smørgrav 	if ((passphrase == NULL || strlen(passphrase) == 0) &&
3589a0ee8cc6SDag-Erling Smørgrav 	    strcmp(ciphername, "none") != 0) {
3590a0ee8cc6SDag-Erling Smørgrav 		/* passphrase required */
3591a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3592a0ee8cc6SDag-Erling Smørgrav 		goto out;
3593a0ee8cc6SDag-Erling Smørgrav 	}
3594a0ee8cc6SDag-Erling Smørgrav 	if (strcmp(kdfname, "none") != 0 && strcmp(kdfname, "bcrypt") != 0) {
3595a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_KEY_UNKNOWN_CIPHER;
3596a0ee8cc6SDag-Erling Smørgrav 		goto out;
3597a0ee8cc6SDag-Erling Smørgrav 	}
3598a0ee8cc6SDag-Erling Smørgrav 	if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) {
3599a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_INVALID_FORMAT;
3600a0ee8cc6SDag-Erling Smørgrav 		goto out;
3601a0ee8cc6SDag-Erling Smørgrav 	}
3602a0ee8cc6SDag-Erling Smørgrav 	if (nkeys != 1) {
3603a0ee8cc6SDag-Erling Smørgrav 		/* XXX only one key supported */
3604a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_INVALID_FORMAT;
3605a0ee8cc6SDag-Erling Smørgrav 		goto out;
3606a0ee8cc6SDag-Erling Smørgrav 	}
3607a0ee8cc6SDag-Erling Smørgrav 
3608a0ee8cc6SDag-Erling Smørgrav 	/* check size of encrypted key blob */
3609a0ee8cc6SDag-Erling Smørgrav 	blocksize = cipher_blocksize(cipher);
3610a0ee8cc6SDag-Erling Smørgrav 	if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) {
3611a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_INVALID_FORMAT;
3612a0ee8cc6SDag-Erling Smørgrav 		goto out;
3613a0ee8cc6SDag-Erling Smørgrav 	}
3614a0ee8cc6SDag-Erling Smørgrav 
3615a0ee8cc6SDag-Erling Smørgrav 	/* setup key */
3616a0ee8cc6SDag-Erling Smørgrav 	keylen = cipher_keylen(cipher);
3617a0ee8cc6SDag-Erling Smørgrav 	ivlen = cipher_ivlen(cipher);
3618557f75e5SDag-Erling Smørgrav 	authlen = cipher_authlen(cipher);
3619a0ee8cc6SDag-Erling Smørgrav 	if ((key = calloc(1, keylen + ivlen)) == NULL) {
3620a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_ALLOC_FAIL;
3621a0ee8cc6SDag-Erling Smørgrav 		goto out;
3622a0ee8cc6SDag-Erling Smørgrav 	}
3623a0ee8cc6SDag-Erling Smørgrav 	if (strcmp(kdfname, "bcrypt") == 0) {
3624a0ee8cc6SDag-Erling Smørgrav 		if ((r = sshbuf_get_string(kdf, &salt, &slen)) != 0 ||
3625a0ee8cc6SDag-Erling Smørgrav 		    (r = sshbuf_get_u32(kdf, &rounds)) != 0)
3626a0ee8cc6SDag-Erling Smørgrav 			goto out;
3627a0ee8cc6SDag-Erling Smørgrav 		if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen,
3628a0ee8cc6SDag-Erling Smørgrav 		    key, keylen + ivlen, rounds) < 0) {
3629a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_INVALID_FORMAT;
3630a0ee8cc6SDag-Erling Smørgrav 			goto out;
3631a0ee8cc6SDag-Erling Smørgrav 		}
3632a0ee8cc6SDag-Erling Smørgrav 	}
3633a0ee8cc6SDag-Erling Smørgrav 
3634557f75e5SDag-Erling Smørgrav 	/* check that an appropriate amount of auth data is present */
3635557f75e5SDag-Erling Smørgrav 	if (sshbuf_len(decoded) < encrypted_len + authlen) {
3636557f75e5SDag-Erling Smørgrav 		r = SSH_ERR_INVALID_FORMAT;
3637557f75e5SDag-Erling Smørgrav 		goto out;
3638557f75e5SDag-Erling Smørgrav 	}
3639557f75e5SDag-Erling Smørgrav 
3640a0ee8cc6SDag-Erling Smørgrav 	/* decrypt private portion of key */
3641a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_reserve(decrypted, encrypted_len, &dp)) != 0 ||
3642a0ee8cc6SDag-Erling Smørgrav 	    (r = cipher_init(&ciphercontext, cipher, key, keylen,
3643a0ee8cc6SDag-Erling Smørgrav 	    key + keylen, ivlen, 0)) != 0)
3644a0ee8cc6SDag-Erling Smørgrav 		goto out;
3645ca86bcf2SDag-Erling Smørgrav 	if ((r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(decoded),
3646557f75e5SDag-Erling Smørgrav 	    encrypted_len, 0, authlen)) != 0) {
3647a0ee8cc6SDag-Erling Smørgrav 		/* an integrity error here indicates an incorrect passphrase */
3648a0ee8cc6SDag-Erling Smørgrav 		if (r == SSH_ERR_MAC_INVALID)
3649a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3650a0ee8cc6SDag-Erling Smørgrav 		goto out;
3651a0ee8cc6SDag-Erling Smørgrav 	}
3652557f75e5SDag-Erling Smørgrav 	if ((r = sshbuf_consume(decoded, encrypted_len + authlen)) != 0)
3653a0ee8cc6SDag-Erling Smørgrav 		goto out;
3654a0ee8cc6SDag-Erling Smørgrav 	/* there should be no trailing data */
3655a0ee8cc6SDag-Erling Smørgrav 	if (sshbuf_len(decoded) != 0) {
3656a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_INVALID_FORMAT;
3657a0ee8cc6SDag-Erling Smørgrav 		goto out;
3658a0ee8cc6SDag-Erling Smørgrav 	}
3659a0ee8cc6SDag-Erling Smørgrav 
3660a0ee8cc6SDag-Erling Smørgrav 	/* check check bytes */
3661a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_get_u32(decrypted, &check1)) != 0 ||
3662a0ee8cc6SDag-Erling Smørgrav 	    (r = sshbuf_get_u32(decrypted, &check2)) != 0)
3663a0ee8cc6SDag-Erling Smørgrav 		goto out;
3664a0ee8cc6SDag-Erling Smørgrav 	if (check1 != check2) {
3665a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3666a0ee8cc6SDag-Erling Smørgrav 		goto out;
3667a0ee8cc6SDag-Erling Smørgrav 	}
3668a0ee8cc6SDag-Erling Smørgrav 
3669a0ee8cc6SDag-Erling Smørgrav 	/* Load the private key and comment */
3670a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 ||
3671a0ee8cc6SDag-Erling Smørgrav 	    (r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0)
3672a0ee8cc6SDag-Erling Smørgrav 		goto out;
3673a0ee8cc6SDag-Erling Smørgrav 
3674a0ee8cc6SDag-Erling Smørgrav 	/* Check deterministic padding */
3675a0ee8cc6SDag-Erling Smørgrav 	i = 0;
3676a0ee8cc6SDag-Erling Smørgrav 	while (sshbuf_len(decrypted)) {
3677a0ee8cc6SDag-Erling Smørgrav 		if ((r = sshbuf_get_u8(decrypted, &pad)) != 0)
3678a0ee8cc6SDag-Erling Smørgrav 			goto out;
3679a0ee8cc6SDag-Erling Smørgrav 		if (pad != (++i & 0xff)) {
3680a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_INVALID_FORMAT;
3681a0ee8cc6SDag-Erling Smørgrav 			goto out;
3682a0ee8cc6SDag-Erling Smørgrav 		}
3683a0ee8cc6SDag-Erling Smørgrav 	}
3684a0ee8cc6SDag-Erling Smørgrav 
3685a0ee8cc6SDag-Erling Smørgrav 	/* XXX decode pubkey and check against private */
3686a0ee8cc6SDag-Erling Smørgrav 
3687a0ee8cc6SDag-Erling Smørgrav 	/* success */
3688a0ee8cc6SDag-Erling Smørgrav 	r = 0;
3689a0ee8cc6SDag-Erling Smørgrav 	if (keyp != NULL) {
3690a0ee8cc6SDag-Erling Smørgrav 		*keyp = k;
3691a0ee8cc6SDag-Erling Smørgrav 		k = NULL;
3692a0ee8cc6SDag-Erling Smørgrav 	}
3693a0ee8cc6SDag-Erling Smørgrav 	if (commentp != NULL) {
3694a0ee8cc6SDag-Erling Smørgrav 		*commentp = comment;
3695a0ee8cc6SDag-Erling Smørgrav 		comment = NULL;
3696a0ee8cc6SDag-Erling Smørgrav 	}
3697a0ee8cc6SDag-Erling Smørgrav  out:
3698a0ee8cc6SDag-Erling Smørgrav 	pad = 0;
3699ca86bcf2SDag-Erling Smørgrav 	cipher_free(ciphercontext);
3700a0ee8cc6SDag-Erling Smørgrav 	free(ciphername);
3701a0ee8cc6SDag-Erling Smørgrav 	free(kdfname);
3702a0ee8cc6SDag-Erling Smørgrav 	free(comment);
3703a0ee8cc6SDag-Erling Smørgrav 	if (salt != NULL) {
3704a0ee8cc6SDag-Erling Smørgrav 		explicit_bzero(salt, slen);
3705a0ee8cc6SDag-Erling Smørgrav 		free(salt);
3706a0ee8cc6SDag-Erling Smørgrav 	}
3707a0ee8cc6SDag-Erling Smørgrav 	if (key != NULL) {
3708a0ee8cc6SDag-Erling Smørgrav 		explicit_bzero(key, keylen + ivlen);
3709a0ee8cc6SDag-Erling Smørgrav 		free(key);
3710a0ee8cc6SDag-Erling Smørgrav 	}
3711a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(encoded);
3712a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(decoded);
3713a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(kdf);
3714a0ee8cc6SDag-Erling Smørgrav 	sshbuf_free(decrypted);
3715a0ee8cc6SDag-Erling Smørgrav 	sshkey_free(k);
3716a0ee8cc6SDag-Erling Smørgrav 	return r;
3717a0ee8cc6SDag-Erling Smørgrav }
3718a0ee8cc6SDag-Erling Smørgrav 
3719a0ee8cc6SDag-Erling Smørgrav 
3720a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
3721a0ee8cc6SDag-Erling Smørgrav /* convert SSH v2 key in OpenSSL PEM format */
3722a0ee8cc6SDag-Erling Smørgrav static int
3723a0ee8cc6SDag-Erling Smørgrav sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *blob,
3724a0ee8cc6SDag-Erling Smørgrav     const char *_passphrase, const char *comment)
3725a0ee8cc6SDag-Erling Smørgrav {
3726a0ee8cc6SDag-Erling Smørgrav 	int success, r;
3727a0ee8cc6SDag-Erling Smørgrav 	int blen, len = strlen(_passphrase);
3728a0ee8cc6SDag-Erling Smørgrav 	u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
3729a0ee8cc6SDag-Erling Smørgrav 	const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL;
373047dd1d1bSDag-Erling Smørgrav 	char *bptr;
3731a0ee8cc6SDag-Erling Smørgrav 	BIO *bio = NULL;
3732a0ee8cc6SDag-Erling Smørgrav 
3733a0ee8cc6SDag-Erling Smørgrav 	if (len > 0 && len <= 4)
3734a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_PASSPHRASE_TOO_SHORT;
3735a0ee8cc6SDag-Erling Smørgrav 	if ((bio = BIO_new(BIO_s_mem())) == NULL)
3736a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
3737a0ee8cc6SDag-Erling Smørgrav 
3738a0ee8cc6SDag-Erling Smørgrav 	switch (key->type) {
3739a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
3740a0ee8cc6SDag-Erling Smørgrav 		success = PEM_write_bio_DSAPrivateKey(bio, key->dsa,
3741a0ee8cc6SDag-Erling Smørgrav 		    cipher, passphrase, len, NULL, NULL);
3742a0ee8cc6SDag-Erling Smørgrav 		break;
3743a0ee8cc6SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
3744a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
3745a0ee8cc6SDag-Erling Smørgrav 		success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa,
3746a0ee8cc6SDag-Erling Smørgrav 		    cipher, passphrase, len, NULL, NULL);
3747a0ee8cc6SDag-Erling Smørgrav 		break;
3748a0ee8cc6SDag-Erling Smørgrav #endif
3749a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
3750a0ee8cc6SDag-Erling Smørgrav 		success = PEM_write_bio_RSAPrivateKey(bio, key->rsa,
3751a0ee8cc6SDag-Erling Smørgrav 		    cipher, passphrase, len, NULL, NULL);
3752a0ee8cc6SDag-Erling Smørgrav 		break;
3753a0ee8cc6SDag-Erling Smørgrav 	default:
3754a0ee8cc6SDag-Erling Smørgrav 		success = 0;
3755a0ee8cc6SDag-Erling Smørgrav 		break;
3756a0ee8cc6SDag-Erling Smørgrav 	}
3757a0ee8cc6SDag-Erling Smørgrav 	if (success == 0) {
3758a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_LIBCRYPTO_ERROR;
3759a0ee8cc6SDag-Erling Smørgrav 		goto out;
3760a0ee8cc6SDag-Erling Smørgrav 	}
3761a0ee8cc6SDag-Erling Smørgrav 	if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) {
3762a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_INTERNAL_ERROR;
3763a0ee8cc6SDag-Erling Smørgrav 		goto out;
3764a0ee8cc6SDag-Erling Smørgrav 	}
3765a0ee8cc6SDag-Erling Smørgrav 	if ((r = sshbuf_put(blob, bptr, blen)) != 0)
3766a0ee8cc6SDag-Erling Smørgrav 		goto out;
3767a0ee8cc6SDag-Erling Smørgrav 	r = 0;
3768a0ee8cc6SDag-Erling Smørgrav  out:
3769a0ee8cc6SDag-Erling Smørgrav 	BIO_free(bio);
3770a0ee8cc6SDag-Erling Smørgrav 	return r;
3771a0ee8cc6SDag-Erling Smørgrav }
3772a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
3773a0ee8cc6SDag-Erling Smørgrav 
3774a0ee8cc6SDag-Erling Smørgrav /* Serialise "key" to buffer "blob" */
3775a0ee8cc6SDag-Erling Smørgrav int
3776a0ee8cc6SDag-Erling Smørgrav sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob,
3777a0ee8cc6SDag-Erling Smørgrav     const char *passphrase, const char *comment,
3778a0ee8cc6SDag-Erling Smørgrav     int force_new_format, const char *new_format_cipher, int new_format_rounds)
3779a0ee8cc6SDag-Erling Smørgrav {
3780a0ee8cc6SDag-Erling Smørgrav 	switch (key->type) {
3781bc5531deSDag-Erling Smørgrav #ifdef WITH_OPENSSL
3782a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
3783a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
3784a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
3785a0ee8cc6SDag-Erling Smørgrav 		if (force_new_format) {
3786a0ee8cc6SDag-Erling Smørgrav 			return sshkey_private_to_blob2(key, blob, passphrase,
3787a0ee8cc6SDag-Erling Smørgrav 			    comment, new_format_cipher, new_format_rounds);
3788a0ee8cc6SDag-Erling Smørgrav 		}
3789a0ee8cc6SDag-Erling Smørgrav 		return sshkey_private_pem_to_blob(key, blob,
3790a0ee8cc6SDag-Erling Smørgrav 		    passphrase, comment);
3791a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
3792a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
379347dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
379447dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
379547dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
3796a0ee8cc6SDag-Erling Smørgrav 		return sshkey_private_to_blob2(key, blob, passphrase,
3797a0ee8cc6SDag-Erling Smørgrav 		    comment, new_format_cipher, new_format_rounds);
3798a0ee8cc6SDag-Erling Smørgrav 	default:
3799a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_KEY_TYPE_UNKNOWN;
3800a0ee8cc6SDag-Erling Smørgrav 	}
3801a0ee8cc6SDag-Erling Smørgrav }
3802a0ee8cc6SDag-Erling Smørgrav 
3803a0ee8cc6SDag-Erling Smørgrav 
3804a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
3805bc5531deSDag-Erling Smørgrav static int
38064f52dfbbSDag-Erling Smørgrav translate_libcrypto_error(unsigned long pem_err)
38074f52dfbbSDag-Erling Smørgrav {
38084f52dfbbSDag-Erling Smørgrav 	int pem_reason = ERR_GET_REASON(pem_err);
38094f52dfbbSDag-Erling Smørgrav 
38104f52dfbbSDag-Erling Smørgrav 	switch (ERR_GET_LIB(pem_err)) {
38114f52dfbbSDag-Erling Smørgrav 	case ERR_LIB_PEM:
38124f52dfbbSDag-Erling Smørgrav 		switch (pem_reason) {
38134f52dfbbSDag-Erling Smørgrav 		case PEM_R_BAD_PASSWORD_READ:
38144f52dfbbSDag-Erling Smørgrav 		case PEM_R_PROBLEMS_GETTING_PASSWORD:
38154f52dfbbSDag-Erling Smørgrav 		case PEM_R_BAD_DECRYPT:
38164f52dfbbSDag-Erling Smørgrav 			return SSH_ERR_KEY_WRONG_PASSPHRASE;
38174f52dfbbSDag-Erling Smørgrav 		default:
38184f52dfbbSDag-Erling Smørgrav 			return SSH_ERR_INVALID_FORMAT;
38194f52dfbbSDag-Erling Smørgrav 		}
38204f52dfbbSDag-Erling Smørgrav 	case ERR_LIB_EVP:
38214f52dfbbSDag-Erling Smørgrav 		switch (pem_reason) {
38224f52dfbbSDag-Erling Smørgrav 		case EVP_R_BAD_DECRYPT:
38234f52dfbbSDag-Erling Smørgrav 			return SSH_ERR_KEY_WRONG_PASSPHRASE;
3824*2a01feabSEd Maste #ifdef EVP_R_BN_DECODE_ERROR
38254f52dfbbSDag-Erling Smørgrav 		case EVP_R_BN_DECODE_ERROR:
3826*2a01feabSEd Maste #endif
38274f52dfbbSDag-Erling Smørgrav 		case EVP_R_DECODE_ERROR:
38284f52dfbbSDag-Erling Smørgrav #ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR
38294f52dfbbSDag-Erling Smørgrav 		case EVP_R_PRIVATE_KEY_DECODE_ERROR:
38304f52dfbbSDag-Erling Smørgrav #endif
38314f52dfbbSDag-Erling Smørgrav 			return SSH_ERR_INVALID_FORMAT;
38324f52dfbbSDag-Erling Smørgrav 		default:
38334f52dfbbSDag-Erling Smørgrav 			return SSH_ERR_LIBCRYPTO_ERROR;
38344f52dfbbSDag-Erling Smørgrav 		}
38354f52dfbbSDag-Erling Smørgrav 	case ERR_LIB_ASN1:
38364f52dfbbSDag-Erling Smørgrav 		return SSH_ERR_INVALID_FORMAT;
38374f52dfbbSDag-Erling Smørgrav 	}
38384f52dfbbSDag-Erling Smørgrav 	return SSH_ERR_LIBCRYPTO_ERROR;
38394f52dfbbSDag-Erling Smørgrav }
38404f52dfbbSDag-Erling Smørgrav 
38414f52dfbbSDag-Erling Smørgrav static void
38424f52dfbbSDag-Erling Smørgrav clear_libcrypto_errors(void)
38434f52dfbbSDag-Erling Smørgrav {
38444f52dfbbSDag-Erling Smørgrav 	while (ERR_get_error() != 0)
38454f52dfbbSDag-Erling Smørgrav 		;
38464f52dfbbSDag-Erling Smørgrav }
38474f52dfbbSDag-Erling Smørgrav 
38484f52dfbbSDag-Erling Smørgrav /*
38494f52dfbbSDag-Erling Smørgrav  * Translate OpenSSL error codes to determine whether
38504f52dfbbSDag-Erling Smørgrav  * passphrase is required/incorrect.
38514f52dfbbSDag-Erling Smørgrav  */
38524f52dfbbSDag-Erling Smørgrav static int
38534f52dfbbSDag-Erling Smørgrav convert_libcrypto_error(void)
38544f52dfbbSDag-Erling Smørgrav {
38554f52dfbbSDag-Erling Smørgrav 	/*
38564f52dfbbSDag-Erling Smørgrav 	 * Some password errors are reported at the beginning
38574f52dfbbSDag-Erling Smørgrav 	 * of the error queue.
38584f52dfbbSDag-Erling Smørgrav 	 */
38594f52dfbbSDag-Erling Smørgrav 	if (translate_libcrypto_error(ERR_peek_error()) ==
38604f52dfbbSDag-Erling Smørgrav 	    SSH_ERR_KEY_WRONG_PASSPHRASE)
38614f52dfbbSDag-Erling Smørgrav 		return SSH_ERR_KEY_WRONG_PASSPHRASE;
38624f52dfbbSDag-Erling Smørgrav 	return translate_libcrypto_error(ERR_peek_last_error());
38634f52dfbbSDag-Erling Smørgrav }
38644f52dfbbSDag-Erling Smørgrav 
38654f52dfbbSDag-Erling Smørgrav static int
3866a0ee8cc6SDag-Erling Smørgrav sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
3867bc5531deSDag-Erling Smørgrav     const char *passphrase, struct sshkey **keyp)
3868a0ee8cc6SDag-Erling Smørgrav {
3869a0ee8cc6SDag-Erling Smørgrav 	EVP_PKEY *pk = NULL;
3870a0ee8cc6SDag-Erling Smørgrav 	struct sshkey *prv = NULL;
3871a0ee8cc6SDag-Erling Smørgrav 	BIO *bio = NULL;
3872a0ee8cc6SDag-Erling Smørgrav 	int r;
3873a0ee8cc6SDag-Erling Smørgrav 
3874076ad2f8SDag-Erling Smørgrav 	if (keyp != NULL)
3875a0ee8cc6SDag-Erling Smørgrav 		*keyp = NULL;
3876a0ee8cc6SDag-Erling Smørgrav 
3877a0ee8cc6SDag-Erling Smørgrav 	if ((bio = BIO_new(BIO_s_mem())) == NULL || sshbuf_len(blob) > INT_MAX)
3878a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
3879a0ee8cc6SDag-Erling Smørgrav 	if (BIO_write(bio, sshbuf_ptr(blob), sshbuf_len(blob)) !=
3880a0ee8cc6SDag-Erling Smørgrav 	    (int)sshbuf_len(blob)) {
3881a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_ALLOC_FAIL;
3882a0ee8cc6SDag-Erling Smørgrav 		goto out;
3883a0ee8cc6SDag-Erling Smørgrav 	}
3884a0ee8cc6SDag-Erling Smørgrav 
38854f52dfbbSDag-Erling Smørgrav 	clear_libcrypto_errors();
3886a0ee8cc6SDag-Erling Smørgrav 	if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL,
3887a0ee8cc6SDag-Erling Smørgrav 	    (char *)passphrase)) == NULL) {
38884f52dfbbSDag-Erling Smørgrav 		r = convert_libcrypto_error();
3889d93a896eSDag-Erling Smørgrav 		goto out;
3890a0ee8cc6SDag-Erling Smørgrav 	}
3891*2a01feabSEd Maste 	if (EVP_PKEY_base_id(pk) == EVP_PKEY_RSA &&
3892a0ee8cc6SDag-Erling Smørgrav 	    (type == KEY_UNSPEC || type == KEY_RSA)) {
3893a0ee8cc6SDag-Erling Smørgrav 		if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
3894a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_ALLOC_FAIL;
3895a0ee8cc6SDag-Erling Smørgrav 			goto out;
3896a0ee8cc6SDag-Erling Smørgrav 		}
3897a0ee8cc6SDag-Erling Smørgrav 		prv->rsa = EVP_PKEY_get1_RSA(pk);
3898a0ee8cc6SDag-Erling Smørgrav 		prv->type = KEY_RSA;
3899a0ee8cc6SDag-Erling Smørgrav #ifdef DEBUG_PK
3900a0ee8cc6SDag-Erling Smørgrav 		RSA_print_fp(stderr, prv->rsa, 8);
3901a0ee8cc6SDag-Erling Smørgrav #endif
3902a0ee8cc6SDag-Erling Smørgrav 		if (RSA_blinding_on(prv->rsa, NULL) != 1) {
3903a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_LIBCRYPTO_ERROR;
3904a0ee8cc6SDag-Erling Smørgrav 			goto out;
3905a0ee8cc6SDag-Erling Smørgrav 		}
3906*2a01feabSEd Maste 		if ((r = check_rsa_length(prv->rsa)) != 0)
39074f52dfbbSDag-Erling Smørgrav 			goto out;
3908*2a01feabSEd Maste 	} else if (EVP_PKEY_base_id(pk) == EVP_PKEY_DSA &&
3909a0ee8cc6SDag-Erling Smørgrav 	    (type == KEY_UNSPEC || type == KEY_DSA)) {
3910a0ee8cc6SDag-Erling Smørgrav 		if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
3911a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_ALLOC_FAIL;
3912a0ee8cc6SDag-Erling Smørgrav 			goto out;
3913a0ee8cc6SDag-Erling Smørgrav 		}
3914a0ee8cc6SDag-Erling Smørgrav 		prv->dsa = EVP_PKEY_get1_DSA(pk);
3915a0ee8cc6SDag-Erling Smørgrav 		prv->type = KEY_DSA;
3916a0ee8cc6SDag-Erling Smørgrav #ifdef DEBUG_PK
3917a0ee8cc6SDag-Erling Smørgrav 		DSA_print_fp(stderr, prv->dsa, 8);
3918a0ee8cc6SDag-Erling Smørgrav #endif
3919a0ee8cc6SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC
3920*2a01feabSEd Maste 	} else if (EVP_PKEY_base_id(pk) == EVP_PKEY_EC &&
3921a0ee8cc6SDag-Erling Smørgrav 	    (type == KEY_UNSPEC || type == KEY_ECDSA)) {
3922a0ee8cc6SDag-Erling Smørgrav 		if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
3923a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_ALLOC_FAIL;
3924a0ee8cc6SDag-Erling Smørgrav 			goto out;
3925a0ee8cc6SDag-Erling Smørgrav 		}
3926a0ee8cc6SDag-Erling Smørgrav 		prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk);
3927a0ee8cc6SDag-Erling Smørgrav 		prv->type = KEY_ECDSA;
3928a0ee8cc6SDag-Erling Smørgrav 		prv->ecdsa_nid = sshkey_ecdsa_key_to_nid(prv->ecdsa);
3929a0ee8cc6SDag-Erling Smørgrav 		if (prv->ecdsa_nid == -1 ||
3930a0ee8cc6SDag-Erling Smørgrav 		    sshkey_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
3931a0ee8cc6SDag-Erling Smørgrav 		    sshkey_ec_validate_public(EC_KEY_get0_group(prv->ecdsa),
3932a0ee8cc6SDag-Erling Smørgrav 		    EC_KEY_get0_public_key(prv->ecdsa)) != 0 ||
3933a0ee8cc6SDag-Erling Smørgrav 		    sshkey_ec_validate_private(prv->ecdsa) != 0) {
3934a0ee8cc6SDag-Erling Smørgrav 			r = SSH_ERR_INVALID_FORMAT;
3935a0ee8cc6SDag-Erling Smørgrav 			goto out;
3936a0ee8cc6SDag-Erling Smørgrav 		}
3937a0ee8cc6SDag-Erling Smørgrav # ifdef DEBUG_PK
3938a0ee8cc6SDag-Erling Smørgrav 		if (prv != NULL && prv->ecdsa != NULL)
3939a0ee8cc6SDag-Erling Smørgrav 			sshkey_dump_ec_key(prv->ecdsa);
3940a0ee8cc6SDag-Erling Smørgrav # endif
3941a0ee8cc6SDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */
3942a0ee8cc6SDag-Erling Smørgrav 	} else {
3943a0ee8cc6SDag-Erling Smørgrav 		r = SSH_ERR_INVALID_FORMAT;
3944a0ee8cc6SDag-Erling Smørgrav 		goto out;
3945a0ee8cc6SDag-Erling Smørgrav 	}
3946a0ee8cc6SDag-Erling Smørgrav 	r = 0;
3947076ad2f8SDag-Erling Smørgrav 	if (keyp != NULL) {
3948a0ee8cc6SDag-Erling Smørgrav 		*keyp = prv;
3949a0ee8cc6SDag-Erling Smørgrav 		prv = NULL;
3950076ad2f8SDag-Erling Smørgrav 	}
3951a0ee8cc6SDag-Erling Smørgrav  out:
3952a0ee8cc6SDag-Erling Smørgrav 	BIO_free(bio);
3953a0ee8cc6SDag-Erling Smørgrav 	EVP_PKEY_free(pk);
3954a0ee8cc6SDag-Erling Smørgrav 	sshkey_free(prv);
3955a0ee8cc6SDag-Erling Smørgrav 	return r;
3956a0ee8cc6SDag-Erling Smørgrav }
3957a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
3958a0ee8cc6SDag-Erling Smørgrav 
3959a0ee8cc6SDag-Erling Smørgrav int
3960a0ee8cc6SDag-Erling Smørgrav sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
3961a0ee8cc6SDag-Erling Smørgrav     const char *passphrase, struct sshkey **keyp, char **commentp)
3962a0ee8cc6SDag-Erling Smørgrav {
3963d93a896eSDag-Erling Smørgrav 	int r = SSH_ERR_INTERNAL_ERROR;
3964d93a896eSDag-Erling Smørgrav 
3965076ad2f8SDag-Erling Smørgrav 	if (keyp != NULL)
3966a0ee8cc6SDag-Erling Smørgrav 		*keyp = NULL;
3967a0ee8cc6SDag-Erling Smørgrav 	if (commentp != NULL)
3968a0ee8cc6SDag-Erling Smørgrav 		*commentp = NULL;
3969a0ee8cc6SDag-Erling Smørgrav 
3970a0ee8cc6SDag-Erling Smørgrav 	switch (type) {
3971bc5531deSDag-Erling Smørgrav #ifdef WITH_OPENSSL
3972a0ee8cc6SDag-Erling Smørgrav 	case KEY_DSA:
3973a0ee8cc6SDag-Erling Smørgrav 	case KEY_ECDSA:
3974a0ee8cc6SDag-Erling Smørgrav 	case KEY_RSA:
3975bc5531deSDag-Erling Smørgrav 		return sshkey_parse_private_pem_fileblob(blob, type,
3976bc5531deSDag-Erling Smørgrav 		    passphrase, keyp);
3977a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
3978a0ee8cc6SDag-Erling Smørgrav 	case KEY_ED25519:
397947dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
398047dd1d1bSDag-Erling Smørgrav 	case KEY_XMSS:
398147dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
3982a0ee8cc6SDag-Erling Smørgrav 		return sshkey_parse_private2(blob, type, passphrase,
3983a0ee8cc6SDag-Erling Smørgrav 		    keyp, commentp);
3984a0ee8cc6SDag-Erling Smørgrav 	case KEY_UNSPEC:
3985d93a896eSDag-Erling Smørgrav 		r = sshkey_parse_private2(blob, type, passphrase, keyp,
3986d93a896eSDag-Erling Smørgrav 		    commentp);
3987d93a896eSDag-Erling Smørgrav 		/* Do not fallback to PEM parser if only passphrase is wrong. */
3988d93a896eSDag-Erling Smørgrav 		if (r == 0 || r == SSH_ERR_KEY_WRONG_PASSPHRASE)
3989d93a896eSDag-Erling Smørgrav 			return r;
3990a0ee8cc6SDag-Erling Smørgrav #ifdef WITH_OPENSSL
3991bc5531deSDag-Erling Smørgrav 		return sshkey_parse_private_pem_fileblob(blob, type,
3992bc5531deSDag-Erling Smørgrav 		    passphrase, keyp);
3993a0ee8cc6SDag-Erling Smørgrav #else
3994a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_INVALID_FORMAT;
3995a0ee8cc6SDag-Erling Smørgrav #endif /* WITH_OPENSSL */
3996a0ee8cc6SDag-Erling Smørgrav 	default:
3997a0ee8cc6SDag-Erling Smørgrav 		return SSH_ERR_KEY_TYPE_UNKNOWN;
3998a0ee8cc6SDag-Erling Smørgrav 	}
3999a0ee8cc6SDag-Erling Smørgrav }
4000a0ee8cc6SDag-Erling Smørgrav 
4001a0ee8cc6SDag-Erling Smørgrav int
4002a0ee8cc6SDag-Erling Smørgrav sshkey_parse_private_fileblob(struct sshbuf *buffer, const char *passphrase,
4003acc1a9efSDag-Erling Smørgrav     struct sshkey **keyp, char **commentp)
4004a0ee8cc6SDag-Erling Smørgrav {
4005a0ee8cc6SDag-Erling Smørgrav 	if (keyp != NULL)
4006a0ee8cc6SDag-Erling Smørgrav 		*keyp = NULL;
4007a0ee8cc6SDag-Erling Smørgrav 	if (commentp != NULL)
4008a0ee8cc6SDag-Erling Smørgrav 		*commentp = NULL;
4009a0ee8cc6SDag-Erling Smørgrav 
4010acc1a9efSDag-Erling Smørgrav 	return sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC,
4011acc1a9efSDag-Erling Smørgrav 	    passphrase, keyp, commentp);
4012a0ee8cc6SDag-Erling Smørgrav }
401347dd1d1bSDag-Erling Smørgrav 
401447dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
401547dd1d1bSDag-Erling Smørgrav /*
401647dd1d1bSDag-Erling Smørgrav  * serialize the key with the current state and forward the state
401747dd1d1bSDag-Erling Smørgrav  * maxsign times.
401847dd1d1bSDag-Erling Smørgrav  */
401947dd1d1bSDag-Erling Smørgrav int
402047dd1d1bSDag-Erling Smørgrav sshkey_private_serialize_maxsign(const struct sshkey *k, struct sshbuf *b,
402147dd1d1bSDag-Erling Smørgrav     u_int32_t maxsign, sshkey_printfn *pr)
402247dd1d1bSDag-Erling Smørgrav {
402347dd1d1bSDag-Erling Smørgrav 	int r, rupdate;
402447dd1d1bSDag-Erling Smørgrav 
402547dd1d1bSDag-Erling Smørgrav 	if (maxsign == 0 ||
402647dd1d1bSDag-Erling Smørgrav 	    sshkey_type_plain(k->type) != KEY_XMSS)
402747dd1d1bSDag-Erling Smørgrav 		return sshkey_private_serialize_opt(k, b,
402847dd1d1bSDag-Erling Smørgrav 		    SSHKEY_SERIALIZE_DEFAULT);
402947dd1d1bSDag-Erling Smørgrav 	if ((r = sshkey_xmss_get_state(k, pr)) != 0 ||
403047dd1d1bSDag-Erling Smørgrav 	    (r = sshkey_private_serialize_opt(k, b,
403147dd1d1bSDag-Erling Smørgrav 	    SSHKEY_SERIALIZE_STATE)) != 0 ||
403247dd1d1bSDag-Erling Smørgrav 	    (r = sshkey_xmss_forward_state(k, maxsign)) != 0)
403347dd1d1bSDag-Erling Smørgrav 		goto out;
403447dd1d1bSDag-Erling Smørgrav 	r = 0;
403547dd1d1bSDag-Erling Smørgrav out:
403647dd1d1bSDag-Erling Smørgrav 	if ((rupdate = sshkey_xmss_update_state(k, pr)) != 0) {
403747dd1d1bSDag-Erling Smørgrav 		if (r == 0)
403847dd1d1bSDag-Erling Smørgrav 			r = rupdate;
403947dd1d1bSDag-Erling Smørgrav 	}
404047dd1d1bSDag-Erling Smørgrav 	return r;
404147dd1d1bSDag-Erling Smørgrav }
404247dd1d1bSDag-Erling Smørgrav 
404347dd1d1bSDag-Erling Smørgrav u_int32_t
404447dd1d1bSDag-Erling Smørgrav sshkey_signatures_left(const struct sshkey *k)
404547dd1d1bSDag-Erling Smørgrav {
404647dd1d1bSDag-Erling Smørgrav 	if (sshkey_type_plain(k->type) == KEY_XMSS)
404747dd1d1bSDag-Erling Smørgrav 		return sshkey_xmss_signatures_left(k);
404847dd1d1bSDag-Erling Smørgrav 	return 0;
404947dd1d1bSDag-Erling Smørgrav }
405047dd1d1bSDag-Erling Smørgrav 
405147dd1d1bSDag-Erling Smørgrav int
405247dd1d1bSDag-Erling Smørgrav sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign)
405347dd1d1bSDag-Erling Smørgrav {
405447dd1d1bSDag-Erling Smørgrav 	if (sshkey_type_plain(k->type) != KEY_XMSS)
405547dd1d1bSDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
405647dd1d1bSDag-Erling Smørgrav 	return sshkey_xmss_enable_maxsign(k, maxsign);
405747dd1d1bSDag-Erling Smørgrav }
405847dd1d1bSDag-Erling Smørgrav 
405947dd1d1bSDag-Erling Smørgrav int
406047dd1d1bSDag-Erling Smørgrav sshkey_set_filename(struct sshkey *k, const char *filename)
406147dd1d1bSDag-Erling Smørgrav {
406247dd1d1bSDag-Erling Smørgrav 	if (k == NULL)
406347dd1d1bSDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
406447dd1d1bSDag-Erling Smørgrav 	if (sshkey_type_plain(k->type) != KEY_XMSS)
406547dd1d1bSDag-Erling Smørgrav 		return 0;
406647dd1d1bSDag-Erling Smørgrav 	if (filename == NULL)
406747dd1d1bSDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
406847dd1d1bSDag-Erling Smørgrav 	if ((k->xmss_filename = strdup(filename)) == NULL)
406947dd1d1bSDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
407047dd1d1bSDag-Erling Smørgrav 	return 0;
407147dd1d1bSDag-Erling Smørgrav }
407247dd1d1bSDag-Erling Smørgrav #else
407347dd1d1bSDag-Erling Smørgrav int
407447dd1d1bSDag-Erling Smørgrav sshkey_private_serialize_maxsign(const struct sshkey *k, struct sshbuf *b,
407547dd1d1bSDag-Erling Smørgrav     u_int32_t maxsign, sshkey_printfn *pr)
407647dd1d1bSDag-Erling Smørgrav {
407747dd1d1bSDag-Erling Smørgrav 	return sshkey_private_serialize_opt(k, b, SSHKEY_SERIALIZE_DEFAULT);
407847dd1d1bSDag-Erling Smørgrav }
407947dd1d1bSDag-Erling Smørgrav 
408047dd1d1bSDag-Erling Smørgrav u_int32_t
408147dd1d1bSDag-Erling Smørgrav sshkey_signatures_left(const struct sshkey *k)
408247dd1d1bSDag-Erling Smørgrav {
408347dd1d1bSDag-Erling Smørgrav 	return 0;
408447dd1d1bSDag-Erling Smørgrav }
408547dd1d1bSDag-Erling Smørgrav 
408647dd1d1bSDag-Erling Smørgrav int
408747dd1d1bSDag-Erling Smørgrav sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign)
408847dd1d1bSDag-Erling Smørgrav {
408947dd1d1bSDag-Erling Smørgrav 	return SSH_ERR_INVALID_ARGUMENT;
409047dd1d1bSDag-Erling Smørgrav }
409147dd1d1bSDag-Erling Smørgrav 
409247dd1d1bSDag-Erling Smørgrav int
409347dd1d1bSDag-Erling Smørgrav sshkey_set_filename(struct sshkey *k, const char *filename)
409447dd1d1bSDag-Erling Smørgrav {
409547dd1d1bSDag-Erling Smørgrav 	if (k == NULL)
409647dd1d1bSDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
409747dd1d1bSDag-Erling Smørgrav 	return 0;
409847dd1d1bSDag-Erling Smørgrav }
409947dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
4100