xref: /dflybsd-src/crypto/openssh/sshkey.c (revision ba1276acd1c8c22d225b1bcf370a14c878644f44)
1*ba1276acSMatthew Dillon /* $OpenBSD: sshkey.c,v 1.142 2024/01/11 01:45:36 djm Exp $ */
236e94dc5SPeter Avalos /*
336e94dc5SPeter Avalos  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
436e94dc5SPeter Avalos  * Copyright (c) 2008 Alexander von Gernler.  All rights reserved.
536e94dc5SPeter Avalos  * Copyright (c) 2010,2011 Damien Miller.  All rights reserved.
636e94dc5SPeter Avalos  *
736e94dc5SPeter Avalos  * Redistribution and use in source and binary forms, with or without
836e94dc5SPeter Avalos  * modification, are permitted provided that the following conditions
936e94dc5SPeter Avalos  * are met:
1036e94dc5SPeter Avalos  * 1. Redistributions of source code must retain the above copyright
1136e94dc5SPeter Avalos  *    notice, this list of conditions and the following disclaimer.
1236e94dc5SPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
1336e94dc5SPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
1436e94dc5SPeter Avalos  *    documentation and/or other materials provided with the distribution.
1536e94dc5SPeter Avalos  *
1636e94dc5SPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1736e94dc5SPeter Avalos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1836e94dc5SPeter Avalos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1936e94dc5SPeter Avalos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2036e94dc5SPeter Avalos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2136e94dc5SPeter Avalos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2236e94dc5SPeter Avalos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2336e94dc5SPeter Avalos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2436e94dc5SPeter Avalos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2536e94dc5SPeter Avalos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2636e94dc5SPeter Avalos  */
2736e94dc5SPeter Avalos 
2836e94dc5SPeter Avalos #include "includes.h"
2936e94dc5SPeter Avalos 
3036e94dc5SPeter Avalos #include <sys/types.h>
31e9778795SPeter Avalos #include <netinet/in.h>
3236e94dc5SPeter Avalos 
33e9778795SPeter Avalos #ifdef WITH_OPENSSL
3436e94dc5SPeter Avalos #include <openssl/evp.h>
3536e94dc5SPeter Avalos #include <openssl/err.h>
3636e94dc5SPeter Avalos #include <openssl/pem.h>
37e9778795SPeter Avalos #endif
3836e94dc5SPeter Avalos 
3936e94dc5SPeter Avalos #include "crypto_api.h"
4036e94dc5SPeter Avalos 
4136e94dc5SPeter Avalos #include <errno.h>
42e9778795SPeter Avalos #include <limits.h>
4336e94dc5SPeter Avalos #include <stdio.h>
44*ba1276acSMatthew Dillon #include <stdlib.h>
4536e94dc5SPeter Avalos #include <string.h>
46e9778795SPeter Avalos #include <resolv.h>
470cbfa66cSDaniel Fojt #include <time.h>
4836e94dc5SPeter Avalos #ifdef HAVE_UTIL_H
4936e94dc5SPeter Avalos #include <util.h>
5036e94dc5SPeter Avalos #endif /* HAVE_UTIL_H */
5136e94dc5SPeter Avalos 
5236e94dc5SPeter Avalos #include "ssh2.h"
5336e94dc5SPeter Avalos #include "ssherr.h"
5436e94dc5SPeter Avalos #include "misc.h"
5536e94dc5SPeter Avalos #include "sshbuf.h"
5636e94dc5SPeter Avalos #include "cipher.h"
5736e94dc5SPeter Avalos #include "digest.h"
5836e94dc5SPeter Avalos #define SSHKEY_INTERNAL
5936e94dc5SPeter Avalos #include "sshkey.h"
60e9778795SPeter Avalos #include "match.h"
610cbfa66cSDaniel Fojt #include "ssh-sk.h"
6236e94dc5SPeter Avalos 
630cbfa66cSDaniel Fojt #ifdef WITH_XMSS
640cbfa66cSDaniel Fojt #include "sshkey-xmss.h"
65664f4763Szrj #include "xmss_fast.h"
660cbfa66cSDaniel Fojt #endif
67664f4763Szrj 
68664f4763Szrj #include "openbsd-compat/openssl-compat.h"
69664f4763Szrj 
7036e94dc5SPeter Avalos /* openssh private key file format */
7136e94dc5SPeter Avalos #define MARK_BEGIN		"-----BEGIN OPENSSH PRIVATE KEY-----\n"
7236e94dc5SPeter Avalos #define MARK_END		"-----END OPENSSH PRIVATE KEY-----\n"
7336e94dc5SPeter Avalos #define MARK_BEGIN_LEN		(sizeof(MARK_BEGIN) - 1)
7436e94dc5SPeter Avalos #define MARK_END_LEN		(sizeof(MARK_END) - 1)
7536e94dc5SPeter Avalos #define KDFNAME			"bcrypt"
7636e94dc5SPeter Avalos #define AUTH_MAGIC		"openssh-key-v1"
7736e94dc5SPeter Avalos #define SALT_LEN		16
78ce74bacaSMatthew Dillon #define DEFAULT_CIPHERNAME	"aes256-ctr"
79*ba1276acSMatthew Dillon #define	DEFAULT_ROUNDS		24
8036e94dc5SPeter Avalos 
8136e94dc5SPeter Avalos /* Version identification string for SSH v1 identity files. */
8236e94dc5SPeter Avalos #define LEGACY_BEGIN		"SSH PRIVATE KEY FILE FORMAT 1.1\n"
8336e94dc5SPeter Avalos 
840cbfa66cSDaniel Fojt /*
850cbfa66cSDaniel Fojt  * Constants relating to "shielding" support; protection of keys expected
860cbfa66cSDaniel Fojt  * to remain in memory for long durations
870cbfa66cSDaniel Fojt  */
880cbfa66cSDaniel Fojt #define SSHKEY_SHIELD_PREKEY_LEN	(16 * 1024)
890cbfa66cSDaniel Fojt #define SSHKEY_SHIELD_CIPHER		"aes256-ctr" /* XXX want AES-EME* */
900cbfa66cSDaniel Fojt #define SSHKEY_SHIELD_PREKEY_HASH	SSH_DIGEST_SHA512
910cbfa66cSDaniel Fojt 
920cbfa66cSDaniel Fojt int	sshkey_private_serialize_opt(struct sshkey *key,
93664f4763Szrj     struct sshbuf *buf, enum sshkey_serialize_rep);
94e9778795SPeter Avalos static int sshkey_from_blob_internal(struct sshbuf *buf,
9536e94dc5SPeter Avalos     struct sshkey **keyp, int allow_cert);
9636e94dc5SPeter Avalos 
9736e94dc5SPeter Avalos /* Supported key types */
98*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_ed25519_impl;
99*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_ed25519_cert_impl;
100*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_ed25519_sk_impl;
101*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_ed25519_sk_cert_impl;
10236e94dc5SPeter Avalos #ifdef WITH_OPENSSL
10336e94dc5SPeter Avalos # ifdef OPENSSL_HAS_ECC
104ee116499SAntonio Huete Jimenez #  ifdef ENABLE_SK
105*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_ecdsa_sk_impl;
106*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_ecdsa_sk_cert_impl;
107*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_ecdsa_sk_webauthn_impl;
108ee116499SAntonio Huete Jimenez #  endif /* ENABLE_SK */
109*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_ecdsa_nistp256_impl;
110*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_ecdsa_nistp256_cert_impl;
111*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_ecdsa_nistp384_impl;
112*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_ecdsa_nistp384_cert_impl;
11336e94dc5SPeter Avalos #  ifdef OPENSSL_HAS_NISTP521
114*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_ecdsa_nistp521_impl;
115*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_ecdsa_nistp521_cert_impl;
11636e94dc5SPeter Avalos #  endif /* OPENSSL_HAS_NISTP521 */
11736e94dc5SPeter Avalos # endif /* OPENSSL_HAS_ECC */
118*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_rsa_impl;
119*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_rsa_cert_impl;
120*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_rsa_sha256_impl;
121*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_rsa_sha256_cert_impl;
122*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_rsa_sha512_impl;
123*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_rsa_sha512_cert_impl;
124*ba1276acSMatthew Dillon # ifdef WITH_DSA
125*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_dss_impl;
126*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_dsa_cert_impl;
127*ba1276acSMatthew Dillon # endif
12836e94dc5SPeter Avalos #endif /* WITH_OPENSSL */
129*ba1276acSMatthew Dillon #ifdef WITH_XMSS
130*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_xmss_impl;
131*ba1276acSMatthew Dillon extern const struct sshkey_impl sshkey_xmss_cert_impl;
132*ba1276acSMatthew Dillon #endif
133*ba1276acSMatthew Dillon 
134*ba1276acSMatthew Dillon const struct sshkey_impl * const keyimpls[] = {
135*ba1276acSMatthew Dillon 	&sshkey_ed25519_impl,
136*ba1276acSMatthew Dillon 	&sshkey_ed25519_cert_impl,
137*ba1276acSMatthew Dillon #ifdef ENABLE_SK
138*ba1276acSMatthew Dillon 	&sshkey_ed25519_sk_impl,
139*ba1276acSMatthew Dillon 	&sshkey_ed25519_sk_cert_impl,
140*ba1276acSMatthew Dillon #endif
141*ba1276acSMatthew Dillon #ifdef WITH_OPENSSL
142*ba1276acSMatthew Dillon # ifdef OPENSSL_HAS_ECC
143*ba1276acSMatthew Dillon 	&sshkey_ecdsa_nistp256_impl,
144*ba1276acSMatthew Dillon 	&sshkey_ecdsa_nistp256_cert_impl,
145*ba1276acSMatthew Dillon 	&sshkey_ecdsa_nistp384_impl,
146*ba1276acSMatthew Dillon 	&sshkey_ecdsa_nistp384_cert_impl,
147*ba1276acSMatthew Dillon #  ifdef OPENSSL_HAS_NISTP521
148*ba1276acSMatthew Dillon 	&sshkey_ecdsa_nistp521_impl,
149*ba1276acSMatthew Dillon 	&sshkey_ecdsa_nistp521_cert_impl,
150*ba1276acSMatthew Dillon #  endif /* OPENSSL_HAS_NISTP521 */
151*ba1276acSMatthew Dillon #  ifdef ENABLE_SK
152*ba1276acSMatthew Dillon 	&sshkey_ecdsa_sk_impl,
153*ba1276acSMatthew Dillon 	&sshkey_ecdsa_sk_cert_impl,
154*ba1276acSMatthew Dillon 	&sshkey_ecdsa_sk_webauthn_impl,
155*ba1276acSMatthew Dillon #  endif /* ENABLE_SK */
156*ba1276acSMatthew Dillon # endif /* OPENSSL_HAS_ECC */
157*ba1276acSMatthew Dillon # ifdef WITH_DSA
158*ba1276acSMatthew Dillon 	&sshkey_dss_impl,
159*ba1276acSMatthew Dillon 	&sshkey_dsa_cert_impl,
160*ba1276acSMatthew Dillon # endif
161*ba1276acSMatthew Dillon 	&sshkey_rsa_impl,
162*ba1276acSMatthew Dillon 	&sshkey_rsa_cert_impl,
163*ba1276acSMatthew Dillon 	&sshkey_rsa_sha256_impl,
164*ba1276acSMatthew Dillon 	&sshkey_rsa_sha256_cert_impl,
165*ba1276acSMatthew Dillon 	&sshkey_rsa_sha512_impl,
166*ba1276acSMatthew Dillon 	&sshkey_rsa_sha512_cert_impl,
167*ba1276acSMatthew Dillon #endif /* WITH_OPENSSL */
168*ba1276acSMatthew Dillon #ifdef WITH_XMSS
169*ba1276acSMatthew Dillon 	&sshkey_xmss_impl,
170*ba1276acSMatthew Dillon 	&sshkey_xmss_cert_impl,
171*ba1276acSMatthew Dillon #endif
172*ba1276acSMatthew Dillon 	NULL
17336e94dc5SPeter Avalos };
17436e94dc5SPeter Avalos 
175*ba1276acSMatthew Dillon static const struct sshkey_impl *
sshkey_impl_from_type(int type)176*ba1276acSMatthew Dillon sshkey_impl_from_type(int type)
177*ba1276acSMatthew Dillon {
178*ba1276acSMatthew Dillon 	int i;
179*ba1276acSMatthew Dillon 
180*ba1276acSMatthew Dillon 	for (i = 0; keyimpls[i] != NULL; i++) {
181*ba1276acSMatthew Dillon 		if (keyimpls[i]->type == type)
182*ba1276acSMatthew Dillon 			return keyimpls[i];
183*ba1276acSMatthew Dillon 	}
184*ba1276acSMatthew Dillon 	return NULL;
185*ba1276acSMatthew Dillon }
186*ba1276acSMatthew Dillon 
187*ba1276acSMatthew Dillon static const struct sshkey_impl *
sshkey_impl_from_type_nid(int type,int nid)188*ba1276acSMatthew Dillon sshkey_impl_from_type_nid(int type, int nid)
189*ba1276acSMatthew Dillon {
190*ba1276acSMatthew Dillon 	int i;
191*ba1276acSMatthew Dillon 
192*ba1276acSMatthew Dillon 	for (i = 0; keyimpls[i] != NULL; i++) {
193*ba1276acSMatthew Dillon 		if (keyimpls[i]->type == type &&
194*ba1276acSMatthew Dillon 		    (keyimpls[i]->nid == 0 || keyimpls[i]->nid == nid))
195*ba1276acSMatthew Dillon 			return keyimpls[i];
196*ba1276acSMatthew Dillon 	}
197*ba1276acSMatthew Dillon 	return NULL;
198*ba1276acSMatthew Dillon }
199*ba1276acSMatthew Dillon 
200*ba1276acSMatthew Dillon static const struct sshkey_impl *
sshkey_impl_from_key(const struct sshkey * k)201*ba1276acSMatthew Dillon sshkey_impl_from_key(const struct sshkey *k)
202*ba1276acSMatthew Dillon {
203*ba1276acSMatthew Dillon 	if (k == NULL)
204*ba1276acSMatthew Dillon 		return NULL;
205*ba1276acSMatthew Dillon 	return sshkey_impl_from_type_nid(k->type, k->ecdsa_nid);
206*ba1276acSMatthew Dillon }
207*ba1276acSMatthew Dillon 
20836e94dc5SPeter Avalos const char *
sshkey_type(const struct sshkey * k)20936e94dc5SPeter Avalos sshkey_type(const struct sshkey *k)
21036e94dc5SPeter Avalos {
211*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
21236e94dc5SPeter Avalos 
213*ba1276acSMatthew Dillon 	if ((impl = sshkey_impl_from_key(k)) == NULL)
21436e94dc5SPeter Avalos 		return "unknown";
215*ba1276acSMatthew Dillon 	return impl->shortname;
21636e94dc5SPeter Avalos }
21736e94dc5SPeter Avalos 
21836e94dc5SPeter Avalos static const char *
sshkey_ssh_name_from_type_nid(int type,int nid)21936e94dc5SPeter Avalos sshkey_ssh_name_from_type_nid(int type, int nid)
22036e94dc5SPeter Avalos {
221*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
22236e94dc5SPeter Avalos 
223*ba1276acSMatthew Dillon 	if ((impl = sshkey_impl_from_type_nid(type, nid)) == NULL)
22436e94dc5SPeter Avalos 		return "ssh-unknown";
225*ba1276acSMatthew Dillon 	return impl->name;
22636e94dc5SPeter Avalos }
22736e94dc5SPeter Avalos 
22836e94dc5SPeter Avalos int
sshkey_type_is_cert(int type)22936e94dc5SPeter Avalos sshkey_type_is_cert(int type)
23036e94dc5SPeter Avalos {
231*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
23236e94dc5SPeter Avalos 
233*ba1276acSMatthew Dillon 	if ((impl = sshkey_impl_from_type(type)) == NULL)
23436e94dc5SPeter Avalos 		return 0;
235*ba1276acSMatthew Dillon 	return impl->cert;
23636e94dc5SPeter Avalos }
23736e94dc5SPeter Avalos 
23836e94dc5SPeter Avalos const char *
sshkey_ssh_name(const struct sshkey * k)23936e94dc5SPeter Avalos sshkey_ssh_name(const struct sshkey *k)
24036e94dc5SPeter Avalos {
24136e94dc5SPeter Avalos 	return sshkey_ssh_name_from_type_nid(k->type, k->ecdsa_nid);
24236e94dc5SPeter Avalos }
24336e94dc5SPeter Avalos 
24436e94dc5SPeter Avalos const char *
sshkey_ssh_name_plain(const struct sshkey * k)24536e94dc5SPeter Avalos sshkey_ssh_name_plain(const struct sshkey *k)
24636e94dc5SPeter Avalos {
24736e94dc5SPeter Avalos 	return sshkey_ssh_name_from_type_nid(sshkey_type_plain(k->type),
24836e94dc5SPeter Avalos 	    k->ecdsa_nid);
24936e94dc5SPeter Avalos }
25036e94dc5SPeter Avalos 
25136e94dc5SPeter Avalos int
sshkey_type_from_name(const char * name)25236e94dc5SPeter Avalos sshkey_type_from_name(const char *name)
25336e94dc5SPeter Avalos {
254*ba1276acSMatthew Dillon 	int i;
255*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
25636e94dc5SPeter Avalos 
257*ba1276acSMatthew Dillon 	for (i = 0; keyimpls[i] != NULL; i++) {
258*ba1276acSMatthew Dillon 		impl = keyimpls[i];
25936e94dc5SPeter Avalos 		/* Only allow shortname matches for plain key types */
260*ba1276acSMatthew Dillon 		if ((impl->name != NULL && strcmp(name, impl->name) == 0) ||
261*ba1276acSMatthew Dillon 		    (!impl->cert && strcasecmp(impl->shortname, name) == 0))
262*ba1276acSMatthew Dillon 			return impl->type;
26336e94dc5SPeter Avalos 	}
26436e94dc5SPeter Avalos 	return KEY_UNSPEC;
26536e94dc5SPeter Avalos }
26636e94dc5SPeter Avalos 
2670cbfa66cSDaniel Fojt static int
key_type_is_ecdsa_variant(int type)2680cbfa66cSDaniel Fojt key_type_is_ecdsa_variant(int type)
2690cbfa66cSDaniel Fojt {
2700cbfa66cSDaniel Fojt 	switch (type) {
2710cbfa66cSDaniel Fojt 	case KEY_ECDSA:
2720cbfa66cSDaniel Fojt 	case KEY_ECDSA_CERT:
2730cbfa66cSDaniel Fojt 	case KEY_ECDSA_SK:
2740cbfa66cSDaniel Fojt 	case KEY_ECDSA_SK_CERT:
2750cbfa66cSDaniel Fojt 		return 1;
2760cbfa66cSDaniel Fojt 	}
2770cbfa66cSDaniel Fojt 	return 0;
2780cbfa66cSDaniel Fojt }
2790cbfa66cSDaniel Fojt 
28036e94dc5SPeter Avalos int
sshkey_ecdsa_nid_from_name(const char * name)28136e94dc5SPeter Avalos sshkey_ecdsa_nid_from_name(const char *name)
28236e94dc5SPeter Avalos {
283*ba1276acSMatthew Dillon 	int i;
28436e94dc5SPeter Avalos 
285*ba1276acSMatthew Dillon 	for (i = 0; keyimpls[i] != NULL; i++) {
286*ba1276acSMatthew Dillon 		if (!key_type_is_ecdsa_variant(keyimpls[i]->type))
28736e94dc5SPeter Avalos 			continue;
288*ba1276acSMatthew Dillon 		if (keyimpls[i]->name != NULL &&
289*ba1276acSMatthew Dillon 		    strcmp(name, keyimpls[i]->name) == 0)
290*ba1276acSMatthew Dillon 			return keyimpls[i]->nid;
29136e94dc5SPeter Avalos 	}
29236e94dc5SPeter Avalos 	return -1;
29336e94dc5SPeter Avalos }
29436e94dc5SPeter Avalos 
295ee116499SAntonio Huete Jimenez int
sshkey_match_keyname_to_sigalgs(const char * keyname,const char * sigalgs)296ee116499SAntonio Huete Jimenez sshkey_match_keyname_to_sigalgs(const char *keyname, const char *sigalgs)
297ee116499SAntonio Huete Jimenez {
298ee116499SAntonio Huete Jimenez 	int ktype;
299ee116499SAntonio Huete Jimenez 
300ee116499SAntonio Huete Jimenez 	if (sigalgs == NULL || *sigalgs == '\0' ||
301ee116499SAntonio Huete Jimenez 	    (ktype = sshkey_type_from_name(keyname)) == KEY_UNSPEC)
302ee116499SAntonio Huete Jimenez 		return 0;
303ee116499SAntonio Huete Jimenez 	else if (ktype == KEY_RSA) {
304ee116499SAntonio Huete Jimenez 		return match_pattern_list("ssh-rsa", sigalgs, 0) == 1 ||
305ee116499SAntonio Huete Jimenez 		    match_pattern_list("rsa-sha2-256", sigalgs, 0) == 1 ||
306ee116499SAntonio Huete Jimenez 		    match_pattern_list("rsa-sha2-512", sigalgs, 0) == 1;
307ee116499SAntonio Huete Jimenez 	} else if (ktype == KEY_RSA_CERT) {
308ee116499SAntonio Huete Jimenez 		return match_pattern_list("ssh-rsa-cert-v01@openssh.com",
309ee116499SAntonio Huete Jimenez 		    sigalgs, 0) == 1 ||
310ee116499SAntonio Huete Jimenez 		    match_pattern_list("rsa-sha2-256-cert-v01@openssh.com",
311ee116499SAntonio Huete Jimenez 		    sigalgs, 0) == 1 ||
312ee116499SAntonio Huete Jimenez 		    match_pattern_list("rsa-sha2-512-cert-v01@openssh.com",
313ee116499SAntonio Huete Jimenez 		    sigalgs, 0) == 1;
314ee116499SAntonio Huete Jimenez 	} else
315ee116499SAntonio Huete Jimenez 		return match_pattern_list(keyname, sigalgs, 0) == 1;
316ee116499SAntonio Huete Jimenez }
317ee116499SAntonio Huete Jimenez 
31836e94dc5SPeter Avalos char *
sshkey_alg_list(int certs_only,int plain_only,int include_sigonly,char sep)319ce74bacaSMatthew Dillon sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep)
32036e94dc5SPeter Avalos {
32136e94dc5SPeter Avalos 	char *tmp, *ret = NULL;
322*ba1276acSMatthew Dillon 	size_t i, nlen, rlen = 0;
323*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
32436e94dc5SPeter Avalos 
325*ba1276acSMatthew Dillon 	for (i = 0; keyimpls[i] != NULL; i++) {
326*ba1276acSMatthew Dillon 		impl = keyimpls[i];
327*ba1276acSMatthew Dillon 		if (impl->name == NULL)
328ce74bacaSMatthew Dillon 			continue;
329*ba1276acSMatthew Dillon 		if (!include_sigonly && impl->sigonly)
33036e94dc5SPeter Avalos 			continue;
331*ba1276acSMatthew Dillon 		if ((certs_only && !impl->cert) || (plain_only && impl->cert))
33236e94dc5SPeter Avalos 			continue;
33336e94dc5SPeter Avalos 		if (ret != NULL)
334ce74bacaSMatthew Dillon 			ret[rlen++] = sep;
335*ba1276acSMatthew Dillon 		nlen = strlen(impl->name);
33636e94dc5SPeter Avalos 		if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {
33736e94dc5SPeter Avalos 			free(ret);
33836e94dc5SPeter Avalos 			return NULL;
33936e94dc5SPeter Avalos 		}
34036e94dc5SPeter Avalos 		ret = tmp;
341*ba1276acSMatthew Dillon 		memcpy(ret + rlen, impl->name, nlen + 1);
34236e94dc5SPeter Avalos 		rlen += nlen;
34336e94dc5SPeter Avalos 	}
34436e94dc5SPeter Avalos 	return ret;
34536e94dc5SPeter Avalos }
34636e94dc5SPeter Avalos 
34736e94dc5SPeter Avalos int
sshkey_names_valid2(const char * names,int allow_wildcard,int plain_only)348*ba1276acSMatthew Dillon sshkey_names_valid2(const char *names, int allow_wildcard, int plain_only)
34936e94dc5SPeter Avalos {
35036e94dc5SPeter Avalos 	char *s, *cp, *p;
351*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
352*ba1276acSMatthew Dillon 	int i, type;
35336e94dc5SPeter Avalos 
35436e94dc5SPeter Avalos 	if (names == NULL || strcmp(names, "") == 0)
35536e94dc5SPeter Avalos 		return 0;
35636e94dc5SPeter Avalos 	if ((s = cp = strdup(names)) == NULL)
35736e94dc5SPeter Avalos 		return 0;
35836e94dc5SPeter Avalos 	for ((p = strsep(&cp, ",")); p && *p != '\0';
35936e94dc5SPeter Avalos 	    (p = strsep(&cp, ","))) {
360e9778795SPeter Avalos 		type = sshkey_type_from_name(p);
361e9778795SPeter Avalos 		if (type == KEY_UNSPEC) {
362e9778795SPeter Avalos 			if (allow_wildcard) {
363e9778795SPeter Avalos 				/*
364e9778795SPeter Avalos 				 * Try matching key types against the string.
365e9778795SPeter Avalos 				 * If any has a positive or negative match then
366e9778795SPeter Avalos 				 * the component is accepted.
367e9778795SPeter Avalos 				 */
368*ba1276acSMatthew Dillon 				impl = NULL;
369*ba1276acSMatthew Dillon 				for (i = 0; keyimpls[i] != NULL; i++) {
370*ba1276acSMatthew Dillon 					if (match_pattern_list(
371*ba1276acSMatthew Dillon 					    keyimpls[i]->name, p, 0) != 0) {
372*ba1276acSMatthew Dillon 						impl = keyimpls[i];
373e9778795SPeter Avalos 						break;
374e9778795SPeter Avalos 					}
375*ba1276acSMatthew Dillon 				}
376*ba1276acSMatthew Dillon 				if (impl != NULL)
377e9778795SPeter Avalos 					continue;
378e9778795SPeter Avalos 			}
37936e94dc5SPeter Avalos 			free(s);
38036e94dc5SPeter Avalos 			return 0;
381*ba1276acSMatthew Dillon 		} else if (plain_only && sshkey_type_is_cert(type)) {
382*ba1276acSMatthew Dillon 			free(s);
383*ba1276acSMatthew Dillon 			return 0;
38436e94dc5SPeter Avalos 		}
38536e94dc5SPeter Avalos 	}
38636e94dc5SPeter Avalos 	free(s);
38736e94dc5SPeter Avalos 	return 1;
38836e94dc5SPeter Avalos }
38936e94dc5SPeter Avalos 
39036e94dc5SPeter Avalos u_int
sshkey_size(const struct sshkey * k)39136e94dc5SPeter Avalos sshkey_size(const struct sshkey *k)
39236e94dc5SPeter Avalos {
393*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
394664f4763Szrj 
395*ba1276acSMatthew Dillon 	if ((impl = sshkey_impl_from_key(k)) == NULL)
396664f4763Szrj 		return 0;
397*ba1276acSMatthew Dillon 	if (impl->funcs->size != NULL)
398*ba1276acSMatthew Dillon 		return impl->funcs->size(k);
399*ba1276acSMatthew Dillon 	return impl->keybits;
40036e94dc5SPeter Avalos }
40136e94dc5SPeter Avalos 
40236e94dc5SPeter Avalos static int
sshkey_type_is_valid_ca(int type)40336e94dc5SPeter Avalos sshkey_type_is_valid_ca(int type)
40436e94dc5SPeter Avalos {
405*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
406*ba1276acSMatthew Dillon 
407*ba1276acSMatthew Dillon 	if ((impl = sshkey_impl_from_type(type)) == NULL)
40836e94dc5SPeter Avalos 		return 0;
409*ba1276acSMatthew Dillon 	/* All non-certificate types may act as CAs */
410*ba1276acSMatthew Dillon 	return !impl->cert;
41136e94dc5SPeter Avalos }
41236e94dc5SPeter Avalos 
41336e94dc5SPeter Avalos int
sshkey_is_cert(const struct sshkey * k)41436e94dc5SPeter Avalos sshkey_is_cert(const struct sshkey *k)
41536e94dc5SPeter Avalos {
41636e94dc5SPeter Avalos 	if (k == NULL)
41736e94dc5SPeter Avalos 		return 0;
41836e94dc5SPeter Avalos 	return sshkey_type_is_cert(k->type);
41936e94dc5SPeter Avalos }
42036e94dc5SPeter Avalos 
4210cbfa66cSDaniel Fojt int
sshkey_is_sk(const struct sshkey * k)4220cbfa66cSDaniel Fojt sshkey_is_sk(const struct sshkey *k)
4230cbfa66cSDaniel Fojt {
4240cbfa66cSDaniel Fojt 	if (k == NULL)
4250cbfa66cSDaniel Fojt 		return 0;
4260cbfa66cSDaniel Fojt 	switch (sshkey_type_plain(k->type)) {
4270cbfa66cSDaniel Fojt 	case KEY_ECDSA_SK:
4280cbfa66cSDaniel Fojt 	case KEY_ED25519_SK:
4290cbfa66cSDaniel Fojt 		return 1;
4300cbfa66cSDaniel Fojt 	default:
4310cbfa66cSDaniel Fojt 		return 0;
4320cbfa66cSDaniel Fojt 	}
4330cbfa66cSDaniel Fojt }
4340cbfa66cSDaniel Fojt 
43536e94dc5SPeter Avalos /* Return the cert-less equivalent to a certified key type */
43636e94dc5SPeter Avalos int
sshkey_type_plain(int type)43736e94dc5SPeter Avalos sshkey_type_plain(int type)
43836e94dc5SPeter Avalos {
43936e94dc5SPeter Avalos 	switch (type) {
44036e94dc5SPeter Avalos 	case KEY_RSA_CERT:
44136e94dc5SPeter Avalos 		return KEY_RSA;
44236e94dc5SPeter Avalos 	case KEY_DSA_CERT:
44336e94dc5SPeter Avalos 		return KEY_DSA;
44436e94dc5SPeter Avalos 	case KEY_ECDSA_CERT:
44536e94dc5SPeter Avalos 		return KEY_ECDSA;
4460cbfa66cSDaniel Fojt 	case KEY_ECDSA_SK_CERT:
4470cbfa66cSDaniel Fojt 		return KEY_ECDSA_SK;
44836e94dc5SPeter Avalos 	case KEY_ED25519_CERT:
44936e94dc5SPeter Avalos 		return KEY_ED25519;
4500cbfa66cSDaniel Fojt 	case KEY_ED25519_SK_CERT:
4510cbfa66cSDaniel Fojt 		return KEY_ED25519_SK;
452664f4763Szrj 	case KEY_XMSS_CERT:
453664f4763Szrj 		return KEY_XMSS;
45436e94dc5SPeter Avalos 	default:
45536e94dc5SPeter Avalos 		return type;
45636e94dc5SPeter Avalos 	}
45736e94dc5SPeter Avalos }
45836e94dc5SPeter Avalos 
459*ba1276acSMatthew Dillon /* Return the cert equivalent to a plain key type */
460*ba1276acSMatthew Dillon static int
sshkey_type_certified(int type)461*ba1276acSMatthew Dillon sshkey_type_certified(int type)
462*ba1276acSMatthew Dillon {
463*ba1276acSMatthew Dillon 	switch (type) {
464*ba1276acSMatthew Dillon 	case KEY_RSA:
465*ba1276acSMatthew Dillon 		return KEY_RSA_CERT;
466*ba1276acSMatthew Dillon 	case KEY_DSA:
467*ba1276acSMatthew Dillon 		return KEY_DSA_CERT;
468*ba1276acSMatthew Dillon 	case KEY_ECDSA:
469*ba1276acSMatthew Dillon 		return KEY_ECDSA_CERT;
470*ba1276acSMatthew Dillon 	case KEY_ECDSA_SK:
471*ba1276acSMatthew Dillon 		return KEY_ECDSA_SK_CERT;
472*ba1276acSMatthew Dillon 	case KEY_ED25519:
473*ba1276acSMatthew Dillon 		return KEY_ED25519_CERT;
474*ba1276acSMatthew Dillon 	case KEY_ED25519_SK:
475*ba1276acSMatthew Dillon 		return KEY_ED25519_SK_CERT;
476*ba1276acSMatthew Dillon 	case KEY_XMSS:
477*ba1276acSMatthew Dillon 		return KEY_XMSS_CERT;
478*ba1276acSMatthew Dillon 	default:
479*ba1276acSMatthew Dillon 		return -1;
480*ba1276acSMatthew Dillon 	}
481*ba1276acSMatthew Dillon }
482*ba1276acSMatthew Dillon 
48336e94dc5SPeter Avalos #ifdef WITH_OPENSSL
48436e94dc5SPeter Avalos /* XXX: these are really begging for a table-driven approach */
48536e94dc5SPeter Avalos int
sshkey_curve_name_to_nid(const char * name)48636e94dc5SPeter Avalos sshkey_curve_name_to_nid(const char *name)
48736e94dc5SPeter Avalos {
48836e94dc5SPeter Avalos 	if (strcmp(name, "nistp256") == 0)
48936e94dc5SPeter Avalos 		return NID_X9_62_prime256v1;
49036e94dc5SPeter Avalos 	else if (strcmp(name, "nistp384") == 0)
49136e94dc5SPeter Avalos 		return NID_secp384r1;
49236e94dc5SPeter Avalos # ifdef OPENSSL_HAS_NISTP521
49336e94dc5SPeter Avalos 	else if (strcmp(name, "nistp521") == 0)
49436e94dc5SPeter Avalos 		return NID_secp521r1;
49536e94dc5SPeter Avalos # endif /* OPENSSL_HAS_NISTP521 */
49636e94dc5SPeter Avalos 	else
49736e94dc5SPeter Avalos 		return -1;
49836e94dc5SPeter Avalos }
49936e94dc5SPeter Avalos 
50036e94dc5SPeter Avalos u_int
sshkey_curve_nid_to_bits(int nid)50136e94dc5SPeter Avalos sshkey_curve_nid_to_bits(int nid)
50236e94dc5SPeter Avalos {
50336e94dc5SPeter Avalos 	switch (nid) {
50436e94dc5SPeter Avalos 	case NID_X9_62_prime256v1:
50536e94dc5SPeter Avalos 		return 256;
50636e94dc5SPeter Avalos 	case NID_secp384r1:
50736e94dc5SPeter Avalos 		return 384;
50836e94dc5SPeter Avalos # ifdef OPENSSL_HAS_NISTP521
50936e94dc5SPeter Avalos 	case NID_secp521r1:
51036e94dc5SPeter Avalos 		return 521;
51136e94dc5SPeter Avalos # endif /* OPENSSL_HAS_NISTP521 */
51236e94dc5SPeter Avalos 	default:
51336e94dc5SPeter Avalos 		return 0;
51436e94dc5SPeter Avalos 	}
51536e94dc5SPeter Avalos }
51636e94dc5SPeter Avalos 
51736e94dc5SPeter Avalos int
sshkey_ecdsa_bits_to_nid(int bits)51836e94dc5SPeter Avalos sshkey_ecdsa_bits_to_nid(int bits)
51936e94dc5SPeter Avalos {
52036e94dc5SPeter Avalos 	switch (bits) {
52136e94dc5SPeter Avalos 	case 256:
52236e94dc5SPeter Avalos 		return NID_X9_62_prime256v1;
52336e94dc5SPeter Avalos 	case 384:
52436e94dc5SPeter Avalos 		return NID_secp384r1;
52536e94dc5SPeter Avalos # ifdef OPENSSL_HAS_NISTP521
52636e94dc5SPeter Avalos 	case 521:
52736e94dc5SPeter Avalos 		return NID_secp521r1;
52836e94dc5SPeter Avalos # endif /* OPENSSL_HAS_NISTP521 */
52936e94dc5SPeter Avalos 	default:
53036e94dc5SPeter Avalos 		return -1;
53136e94dc5SPeter Avalos 	}
53236e94dc5SPeter Avalos }
53336e94dc5SPeter Avalos 
53436e94dc5SPeter Avalos const char *
sshkey_curve_nid_to_name(int nid)53536e94dc5SPeter Avalos sshkey_curve_nid_to_name(int nid)
53636e94dc5SPeter Avalos {
53736e94dc5SPeter Avalos 	switch (nid) {
53836e94dc5SPeter Avalos 	case NID_X9_62_prime256v1:
53936e94dc5SPeter Avalos 		return "nistp256";
54036e94dc5SPeter Avalos 	case NID_secp384r1:
54136e94dc5SPeter Avalos 		return "nistp384";
54236e94dc5SPeter Avalos # ifdef OPENSSL_HAS_NISTP521
54336e94dc5SPeter Avalos 	case NID_secp521r1:
54436e94dc5SPeter Avalos 		return "nistp521";
54536e94dc5SPeter Avalos # endif /* OPENSSL_HAS_NISTP521 */
54636e94dc5SPeter Avalos 	default:
54736e94dc5SPeter Avalos 		return NULL;
54836e94dc5SPeter Avalos 	}
54936e94dc5SPeter Avalos }
55036e94dc5SPeter Avalos 
55136e94dc5SPeter Avalos int
sshkey_ec_nid_to_hash_alg(int nid)55236e94dc5SPeter Avalos sshkey_ec_nid_to_hash_alg(int nid)
55336e94dc5SPeter Avalos {
55436e94dc5SPeter Avalos 	int kbits = sshkey_curve_nid_to_bits(nid);
55536e94dc5SPeter Avalos 
55636e94dc5SPeter Avalos 	if (kbits <= 0)
55736e94dc5SPeter Avalos 		return -1;
55836e94dc5SPeter Avalos 
55936e94dc5SPeter Avalos 	/* RFC5656 section 6.2.1 */
56036e94dc5SPeter Avalos 	if (kbits <= 256)
56136e94dc5SPeter Avalos 		return SSH_DIGEST_SHA256;
56236e94dc5SPeter Avalos 	else if (kbits <= 384)
56336e94dc5SPeter Avalos 		return SSH_DIGEST_SHA384;
56436e94dc5SPeter Avalos 	else
56536e94dc5SPeter Avalos 		return SSH_DIGEST_SHA512;
56636e94dc5SPeter Avalos }
56736e94dc5SPeter Avalos #endif /* WITH_OPENSSL */
56836e94dc5SPeter Avalos 
56936e94dc5SPeter Avalos static void
cert_free(struct sshkey_cert * cert)57036e94dc5SPeter Avalos cert_free(struct sshkey_cert *cert)
57136e94dc5SPeter Avalos {
57236e94dc5SPeter Avalos 	u_int i;
57336e94dc5SPeter Avalos 
57436e94dc5SPeter Avalos 	if (cert == NULL)
57536e94dc5SPeter Avalos 		return;
57636e94dc5SPeter Avalos 	sshbuf_free(cert->certblob);
57736e94dc5SPeter Avalos 	sshbuf_free(cert->critical);
57836e94dc5SPeter Avalos 	sshbuf_free(cert->extensions);
57936e94dc5SPeter Avalos 	free(cert->key_id);
58036e94dc5SPeter Avalos 	for (i = 0; i < cert->nprincipals; i++)
58136e94dc5SPeter Avalos 		free(cert->principals[i]);
58236e94dc5SPeter Avalos 	free(cert->principals);
58336e94dc5SPeter Avalos 	sshkey_free(cert->signature_key);
584664f4763Szrj 	free(cert->signature_type);
585664f4763Szrj 	freezero(cert, sizeof(*cert));
58636e94dc5SPeter Avalos }
58736e94dc5SPeter Avalos 
58836e94dc5SPeter Avalos static struct sshkey_cert *
cert_new(void)58936e94dc5SPeter Avalos cert_new(void)
59036e94dc5SPeter Avalos {
59136e94dc5SPeter Avalos 	struct sshkey_cert *cert;
59236e94dc5SPeter Avalos 
59336e94dc5SPeter Avalos 	if ((cert = calloc(1, sizeof(*cert))) == NULL)
59436e94dc5SPeter Avalos 		return NULL;
59536e94dc5SPeter Avalos 	if ((cert->certblob = sshbuf_new()) == NULL ||
59636e94dc5SPeter Avalos 	    (cert->critical = sshbuf_new()) == NULL ||
59736e94dc5SPeter Avalos 	    (cert->extensions = sshbuf_new()) == NULL) {
59836e94dc5SPeter Avalos 		cert_free(cert);
59936e94dc5SPeter Avalos 		return NULL;
60036e94dc5SPeter Avalos 	}
60136e94dc5SPeter Avalos 	cert->key_id = NULL;
60236e94dc5SPeter Avalos 	cert->principals = NULL;
60336e94dc5SPeter Avalos 	cert->signature_key = NULL;
604664f4763Szrj 	cert->signature_type = NULL;
60536e94dc5SPeter Avalos 	return cert;
60636e94dc5SPeter Avalos }
60736e94dc5SPeter Avalos 
60836e94dc5SPeter Avalos struct sshkey *
sshkey_new(int type)60936e94dc5SPeter Avalos sshkey_new(int type)
61036e94dc5SPeter Avalos {
61136e94dc5SPeter Avalos 	struct sshkey *k;
612*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl = NULL;
61336e94dc5SPeter Avalos 
614*ba1276acSMatthew Dillon 	if (type != KEY_UNSPEC &&
615*ba1276acSMatthew Dillon 	    (impl = sshkey_impl_from_type(type)) == NULL)
616*ba1276acSMatthew Dillon 		return NULL;
617*ba1276acSMatthew Dillon 
618*ba1276acSMatthew Dillon 	/* All non-certificate types may act as CAs */
61936e94dc5SPeter Avalos 	if ((k = calloc(1, sizeof(*k))) == NULL)
62036e94dc5SPeter Avalos 		return NULL;
62136e94dc5SPeter Avalos 	k->type = type;
62236e94dc5SPeter Avalos 	k->ecdsa_nid = -1;
623*ba1276acSMatthew Dillon 	if (impl != NULL && impl->funcs->alloc != NULL) {
624*ba1276acSMatthew Dillon 		if (impl->funcs->alloc(k) != 0) {
62536e94dc5SPeter Avalos 			free(k);
62636e94dc5SPeter Avalos 			return NULL;
62736e94dc5SPeter Avalos 		}
62836e94dc5SPeter Avalos 	}
62936e94dc5SPeter Avalos 	if (sshkey_is_cert(k)) {
63036e94dc5SPeter Avalos 		if ((k->cert = cert_new()) == NULL) {
63136e94dc5SPeter Avalos 			sshkey_free(k);
63236e94dc5SPeter Avalos 			return NULL;
63336e94dc5SPeter Avalos 		}
63436e94dc5SPeter Avalos 	}
63536e94dc5SPeter Avalos 
63636e94dc5SPeter Avalos 	return k;
63736e94dc5SPeter Avalos }
63836e94dc5SPeter Avalos 
639*ba1276acSMatthew Dillon /* Frees common FIDO fields */
64036e94dc5SPeter Avalos void
sshkey_sk_cleanup(struct sshkey * k)641*ba1276acSMatthew Dillon sshkey_sk_cleanup(struct sshkey *k)
64236e94dc5SPeter Avalos {
643*ba1276acSMatthew Dillon 	free(k->sk_application);
644*ba1276acSMatthew Dillon 	sshbuf_free(k->sk_key_handle);
645*ba1276acSMatthew Dillon 	sshbuf_free(k->sk_reserved);
646*ba1276acSMatthew Dillon 	k->sk_application = NULL;
647*ba1276acSMatthew Dillon 	k->sk_key_handle = k->sk_reserved = NULL;
648*ba1276acSMatthew Dillon }
649*ba1276acSMatthew Dillon 
650*ba1276acSMatthew Dillon static void
sshkey_free_contents(struct sshkey * k)651*ba1276acSMatthew Dillon sshkey_free_contents(struct sshkey *k)
652*ba1276acSMatthew Dillon {
653*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
654*ba1276acSMatthew Dillon 
65536e94dc5SPeter Avalos 	if (k == NULL)
65636e94dc5SPeter Avalos 		return;
657*ba1276acSMatthew Dillon 	if ((impl = sshkey_impl_from_type(k->type)) != NULL &&
658*ba1276acSMatthew Dillon 	    impl->funcs->cleanup != NULL)
659*ba1276acSMatthew Dillon 		impl->funcs->cleanup(k);
66036e94dc5SPeter Avalos 	if (sshkey_is_cert(k))
66136e94dc5SPeter Avalos 		cert_free(k->cert);
6620cbfa66cSDaniel Fojt 	freezero(k->shielded_private, k->shielded_len);
6630cbfa66cSDaniel Fojt 	freezero(k->shield_prekey, k->shield_prekey_len);
664*ba1276acSMatthew Dillon }
665*ba1276acSMatthew Dillon 
666*ba1276acSMatthew Dillon void
sshkey_free(struct sshkey * k)667*ba1276acSMatthew Dillon sshkey_free(struct sshkey *k)
668*ba1276acSMatthew Dillon {
669*ba1276acSMatthew Dillon 	sshkey_free_contents(k);
670664f4763Szrj 	freezero(k, sizeof(*k));
67136e94dc5SPeter Avalos }
67236e94dc5SPeter Avalos 
67336e94dc5SPeter Avalos static int
cert_compare(struct sshkey_cert * a,struct sshkey_cert * b)67436e94dc5SPeter Avalos cert_compare(struct sshkey_cert *a, struct sshkey_cert *b)
67536e94dc5SPeter Avalos {
67636e94dc5SPeter Avalos 	if (a == NULL && b == NULL)
67736e94dc5SPeter Avalos 		return 1;
67836e94dc5SPeter Avalos 	if (a == NULL || b == NULL)
67936e94dc5SPeter Avalos 		return 0;
68036e94dc5SPeter Avalos 	if (sshbuf_len(a->certblob) != sshbuf_len(b->certblob))
68136e94dc5SPeter Avalos 		return 0;
68236e94dc5SPeter Avalos 	if (timingsafe_bcmp(sshbuf_ptr(a->certblob), sshbuf_ptr(b->certblob),
68336e94dc5SPeter Avalos 	    sshbuf_len(a->certblob)) != 0)
68436e94dc5SPeter Avalos 		return 0;
68536e94dc5SPeter Avalos 	return 1;
68636e94dc5SPeter Avalos }
68736e94dc5SPeter Avalos 
688*ba1276acSMatthew Dillon /* Compares FIDO-specific pubkey fields only */
689*ba1276acSMatthew Dillon int
sshkey_sk_fields_equal(const struct sshkey * a,const struct sshkey * b)690*ba1276acSMatthew Dillon sshkey_sk_fields_equal(const struct sshkey *a, const struct sshkey *b)
691*ba1276acSMatthew Dillon {
692*ba1276acSMatthew Dillon 	if (a->sk_application == NULL || b->sk_application == NULL)
693*ba1276acSMatthew Dillon 		return 0;
694*ba1276acSMatthew Dillon 	if (strcmp(a->sk_application, b->sk_application) != 0)
695*ba1276acSMatthew Dillon 		return 0;
696*ba1276acSMatthew Dillon 	return 1;
697*ba1276acSMatthew Dillon }
698*ba1276acSMatthew Dillon 
69936e94dc5SPeter Avalos /*
70036e94dc5SPeter Avalos  * Compare public portions of key only, allowing comparisons between
70136e94dc5SPeter Avalos  * certificates and plain keys too.
70236e94dc5SPeter Avalos  */
70336e94dc5SPeter Avalos int
sshkey_equal_public(const struct sshkey * a,const struct sshkey * b)70436e94dc5SPeter Avalos sshkey_equal_public(const struct sshkey *a, const struct sshkey *b)
70536e94dc5SPeter Avalos {
706*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
70736e94dc5SPeter Avalos 
70836e94dc5SPeter Avalos 	if (a == NULL || b == NULL ||
70936e94dc5SPeter Avalos 	    sshkey_type_plain(a->type) != sshkey_type_plain(b->type))
71036e94dc5SPeter Avalos 		return 0;
711*ba1276acSMatthew Dillon 	if ((impl = sshkey_impl_from_type(a->type)) == NULL)
712664f4763Szrj 		return 0;
713*ba1276acSMatthew Dillon 	return impl->funcs->equal(a, b);
71436e94dc5SPeter Avalos }
71536e94dc5SPeter Avalos 
71636e94dc5SPeter Avalos int
sshkey_equal(const struct sshkey * a,const struct sshkey * b)71736e94dc5SPeter Avalos sshkey_equal(const struct sshkey *a, const struct sshkey *b)
71836e94dc5SPeter Avalos {
71936e94dc5SPeter Avalos 	if (a == NULL || b == NULL || a->type != b->type)
72036e94dc5SPeter Avalos 		return 0;
72136e94dc5SPeter Avalos 	if (sshkey_is_cert(a)) {
72236e94dc5SPeter Avalos 		if (!cert_compare(a->cert, b->cert))
72336e94dc5SPeter Avalos 			return 0;
72436e94dc5SPeter Avalos 	}
72536e94dc5SPeter Avalos 	return sshkey_equal_public(a, b);
72636e94dc5SPeter Avalos }
72736e94dc5SPeter Avalos 
728*ba1276acSMatthew Dillon 
729*ba1276acSMatthew Dillon /* Serialise common FIDO key parts */
730*ba1276acSMatthew Dillon int
sshkey_serialize_sk(const struct sshkey * key,struct sshbuf * b)731*ba1276acSMatthew Dillon sshkey_serialize_sk(const struct sshkey *key, struct sshbuf *b)
732*ba1276acSMatthew Dillon {
733*ba1276acSMatthew Dillon 	int r;
734*ba1276acSMatthew Dillon 
735*ba1276acSMatthew Dillon 	if ((r = sshbuf_put_cstring(b, key->sk_application)) != 0)
736*ba1276acSMatthew Dillon 		return r;
737*ba1276acSMatthew Dillon 
738*ba1276acSMatthew Dillon 	return 0;
739*ba1276acSMatthew Dillon }
740*ba1276acSMatthew Dillon 
74136e94dc5SPeter Avalos static int
to_blob_buf(const struct sshkey * key,struct sshbuf * b,int force_plain,enum sshkey_serialize_rep opts)742664f4763Szrj to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain,
743664f4763Szrj   enum sshkey_serialize_rep opts)
74436e94dc5SPeter Avalos {
74536e94dc5SPeter Avalos 	int type, ret = SSH_ERR_INTERNAL_ERROR;
74636e94dc5SPeter Avalos 	const char *typename;
747*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
74836e94dc5SPeter Avalos 
74936e94dc5SPeter Avalos 	if (key == NULL)
75036e94dc5SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
75136e94dc5SPeter Avalos 
752*ba1276acSMatthew Dillon 	type = force_plain ? sshkey_type_plain(key->type) : key->type;
753*ba1276acSMatthew Dillon 
754*ba1276acSMatthew Dillon 	if (sshkey_type_is_cert(type)) {
755e9778795SPeter Avalos 		if (key->cert == NULL)
756e9778795SPeter Avalos 			return SSH_ERR_EXPECTED_CERT;
757e9778795SPeter Avalos 		if (sshbuf_len(key->cert->certblob) == 0)
758e9778795SPeter Avalos 			return SSH_ERR_KEY_LACKS_CERTBLOB;
75936e94dc5SPeter Avalos 		/* Use the existing blob */
76036e94dc5SPeter Avalos 		if ((ret = sshbuf_putb(b, key->cert->certblob)) != 0)
76136e94dc5SPeter Avalos 			return ret;
76236e94dc5SPeter Avalos 		return 0;
76336e94dc5SPeter Avalos 	}
764*ba1276acSMatthew Dillon 	if ((impl = sshkey_impl_from_type(type)) == NULL)
765*ba1276acSMatthew Dillon 		return SSH_ERR_KEY_TYPE_UNKNOWN;
766*ba1276acSMatthew Dillon 
767*ba1276acSMatthew Dillon 	typename = sshkey_ssh_name_from_type_nid(type, key->ecdsa_nid);
768*ba1276acSMatthew Dillon 	if ((ret = sshbuf_put_cstring(b, typename)) != 0)
769*ba1276acSMatthew Dillon 		return ret;
770*ba1276acSMatthew Dillon 	return impl->funcs->serialize_public(key, b, opts);
771*ba1276acSMatthew Dillon }
77236e94dc5SPeter Avalos 
77336e94dc5SPeter Avalos int
sshkey_putb(const struct sshkey * key,struct sshbuf * b)774e9778795SPeter Avalos sshkey_putb(const struct sshkey *key, struct sshbuf *b)
77536e94dc5SPeter Avalos {
776664f4763Szrj 	return to_blob_buf(key, b, 0, SSHKEY_SERIALIZE_DEFAULT);
77736e94dc5SPeter Avalos }
77836e94dc5SPeter Avalos 
77936e94dc5SPeter Avalos int
sshkey_puts_opts(const struct sshkey * key,struct sshbuf * b,enum sshkey_serialize_rep opts)780664f4763Szrj sshkey_puts_opts(const struct sshkey *key, struct sshbuf *b,
781664f4763Szrj     enum sshkey_serialize_rep opts)
782e9778795SPeter Avalos {
783e9778795SPeter Avalos 	struct sshbuf *tmp;
784e9778795SPeter Avalos 	int r;
785e9778795SPeter Avalos 
786e9778795SPeter Avalos 	if ((tmp = sshbuf_new()) == NULL)
787e9778795SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
788664f4763Szrj 	r = to_blob_buf(key, tmp, 0, opts);
789e9778795SPeter Avalos 	if (r == 0)
790e9778795SPeter Avalos 		r = sshbuf_put_stringb(b, tmp);
791e9778795SPeter Avalos 	sshbuf_free(tmp);
792e9778795SPeter Avalos 	return r;
793e9778795SPeter Avalos }
794e9778795SPeter Avalos 
795e9778795SPeter Avalos int
sshkey_puts(const struct sshkey * key,struct sshbuf * b)796664f4763Szrj sshkey_puts(const struct sshkey *key, struct sshbuf *b)
797664f4763Szrj {
798664f4763Szrj 	return sshkey_puts_opts(key, b, SSHKEY_SERIALIZE_DEFAULT);
799664f4763Szrj }
800664f4763Szrj 
801664f4763Szrj int
sshkey_putb_plain(const struct sshkey * key,struct sshbuf * b)802e9778795SPeter Avalos sshkey_putb_plain(const struct sshkey *key, struct sshbuf *b)
80336e94dc5SPeter Avalos {
804664f4763Szrj 	return to_blob_buf(key, b, 1, SSHKEY_SERIALIZE_DEFAULT);
80536e94dc5SPeter Avalos }
80636e94dc5SPeter Avalos 
80736e94dc5SPeter Avalos static int
to_blob(const struct sshkey * key,u_char ** blobp,size_t * lenp,int force_plain,enum sshkey_serialize_rep opts)808664f4763Szrj to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain,
809664f4763Szrj     enum sshkey_serialize_rep opts)
81036e94dc5SPeter Avalos {
81136e94dc5SPeter Avalos 	int ret = SSH_ERR_INTERNAL_ERROR;
81236e94dc5SPeter Avalos 	size_t len;
81336e94dc5SPeter Avalos 	struct sshbuf *b = NULL;
81436e94dc5SPeter Avalos 
81536e94dc5SPeter Avalos 	if (lenp != NULL)
81636e94dc5SPeter Avalos 		*lenp = 0;
81736e94dc5SPeter Avalos 	if (blobp != NULL)
81836e94dc5SPeter Avalos 		*blobp = NULL;
81936e94dc5SPeter Avalos 	if ((b = sshbuf_new()) == NULL)
82036e94dc5SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
821664f4763Szrj 	if ((ret = to_blob_buf(key, b, force_plain, opts)) != 0)
82236e94dc5SPeter Avalos 		goto out;
82336e94dc5SPeter Avalos 	len = sshbuf_len(b);
82436e94dc5SPeter Avalos 	if (lenp != NULL)
82536e94dc5SPeter Avalos 		*lenp = len;
82636e94dc5SPeter Avalos 	if (blobp != NULL) {
82736e94dc5SPeter Avalos 		if ((*blobp = malloc(len)) == NULL) {
82836e94dc5SPeter Avalos 			ret = SSH_ERR_ALLOC_FAIL;
82936e94dc5SPeter Avalos 			goto out;
83036e94dc5SPeter Avalos 		}
83136e94dc5SPeter Avalos 		memcpy(*blobp, sshbuf_ptr(b), len);
83236e94dc5SPeter Avalos 	}
83336e94dc5SPeter Avalos 	ret = 0;
83436e94dc5SPeter Avalos  out:
83536e94dc5SPeter Avalos 	sshbuf_free(b);
83636e94dc5SPeter Avalos 	return ret;
83736e94dc5SPeter Avalos }
83836e94dc5SPeter Avalos 
83936e94dc5SPeter Avalos int
sshkey_to_blob(const struct sshkey * key,u_char ** blobp,size_t * lenp)84036e94dc5SPeter Avalos sshkey_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
84136e94dc5SPeter Avalos {
842664f4763Szrj 	return to_blob(key, blobp, lenp, 0, SSHKEY_SERIALIZE_DEFAULT);
84336e94dc5SPeter Avalos }
84436e94dc5SPeter Avalos 
84536e94dc5SPeter Avalos int
sshkey_plain_to_blob(const struct sshkey * key,u_char ** blobp,size_t * lenp)84636e94dc5SPeter Avalos sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
84736e94dc5SPeter Avalos {
848664f4763Szrj 	return to_blob(key, blobp, lenp, 1, SSHKEY_SERIALIZE_DEFAULT);
84936e94dc5SPeter Avalos }
85036e94dc5SPeter Avalos 
85136e94dc5SPeter Avalos int
sshkey_fingerprint_raw(const struct sshkey * k,int dgst_alg,u_char ** retp,size_t * lenp)852e9778795SPeter Avalos sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg,
85336e94dc5SPeter Avalos     u_char **retp, size_t *lenp)
85436e94dc5SPeter Avalos {
85536e94dc5SPeter Avalos 	u_char *blob = NULL, *ret = NULL;
85636e94dc5SPeter Avalos 	size_t blob_len = 0;
857e9778795SPeter Avalos 	int r = SSH_ERR_INTERNAL_ERROR;
85836e94dc5SPeter Avalos 
85936e94dc5SPeter Avalos 	if (retp != NULL)
86036e94dc5SPeter Avalos 		*retp = NULL;
86136e94dc5SPeter Avalos 	if (lenp != NULL)
86236e94dc5SPeter Avalos 		*lenp = 0;
863e9778795SPeter Avalos 	if (ssh_digest_bytes(dgst_alg) == 0) {
86436e94dc5SPeter Avalos 		r = SSH_ERR_INVALID_ARGUMENT;
86536e94dc5SPeter Avalos 		goto out;
86636e94dc5SPeter Avalos 	}
867664f4763Szrj 	if ((r = to_blob(k, &blob, &blob_len, 1, SSHKEY_SERIALIZE_DEFAULT))
868664f4763Szrj 	    != 0)
86936e94dc5SPeter Avalos 		goto out;
87036e94dc5SPeter Avalos 	if ((ret = calloc(1, SSH_DIGEST_MAX_LENGTH)) == NULL) {
87136e94dc5SPeter Avalos 		r = SSH_ERR_ALLOC_FAIL;
87236e94dc5SPeter Avalos 		goto out;
87336e94dc5SPeter Avalos 	}
874e9778795SPeter Avalos 	if ((r = ssh_digest_memory(dgst_alg, blob, blob_len,
87536e94dc5SPeter Avalos 	    ret, SSH_DIGEST_MAX_LENGTH)) != 0)
87636e94dc5SPeter Avalos 		goto out;
87736e94dc5SPeter Avalos 	/* success */
87836e94dc5SPeter Avalos 	if (retp != NULL) {
87936e94dc5SPeter Avalos 		*retp = ret;
88036e94dc5SPeter Avalos 		ret = NULL;
88136e94dc5SPeter Avalos 	}
88236e94dc5SPeter Avalos 	if (lenp != NULL)
883e9778795SPeter Avalos 		*lenp = ssh_digest_bytes(dgst_alg);
88436e94dc5SPeter Avalos 	r = 0;
88536e94dc5SPeter Avalos  out:
88636e94dc5SPeter Avalos 	free(ret);
8870cbfa66cSDaniel Fojt 	if (blob != NULL)
8880cbfa66cSDaniel Fojt 		freezero(blob, blob_len);
88936e94dc5SPeter Avalos 	return r;
89036e94dc5SPeter Avalos }
89136e94dc5SPeter Avalos 
89236e94dc5SPeter Avalos static char *
fingerprint_b64(const char * alg,u_char * dgst_raw,size_t dgst_raw_len)893e9778795SPeter Avalos fingerprint_b64(const char *alg, u_char *dgst_raw, size_t dgst_raw_len)
89436e94dc5SPeter Avalos {
895e9778795SPeter Avalos 	char *ret;
896e9778795SPeter Avalos 	size_t plen = strlen(alg) + 1;
897e9778795SPeter Avalos 	size_t rlen = ((dgst_raw_len + 2) / 3) * 4 + plen + 1;
89836e94dc5SPeter Avalos 
899e9778795SPeter Avalos 	if (dgst_raw_len > 65536 || (ret = calloc(1, rlen)) == NULL)
90036e94dc5SPeter Avalos 		return NULL;
901e9778795SPeter Avalos 	strlcpy(ret, alg, rlen);
902e9778795SPeter Avalos 	strlcat(ret, ":", rlen);
903e9778795SPeter Avalos 	if (dgst_raw_len == 0)
904e9778795SPeter Avalos 		return ret;
9050cbfa66cSDaniel Fojt 	if (b64_ntop(dgst_raw, dgst_raw_len, ret + plen, rlen - plen) == -1) {
906664f4763Szrj 		freezero(ret, rlen);
907e9778795SPeter Avalos 		return NULL;
908e9778795SPeter Avalos 	}
909e9778795SPeter Avalos 	/* Trim padding characters from end */
910e9778795SPeter Avalos 	ret[strcspn(ret, "=")] = '\0';
911e9778795SPeter Avalos 	return ret;
91236e94dc5SPeter Avalos }
91336e94dc5SPeter Avalos 
914e9778795SPeter Avalos static char *
fingerprint_hex(const char * alg,u_char * dgst_raw,size_t dgst_raw_len)915e9778795SPeter Avalos fingerprint_hex(const char *alg, u_char *dgst_raw, size_t dgst_raw_len)
916e9778795SPeter Avalos {
917e9778795SPeter Avalos 	char *retval, hex[5];
918e9778795SPeter Avalos 	size_t i, rlen = dgst_raw_len * 3 + strlen(alg) + 2;
919e9778795SPeter Avalos 
920e9778795SPeter Avalos 	if (dgst_raw_len > 65536 || (retval = calloc(1, rlen)) == NULL)
921e9778795SPeter Avalos 		return NULL;
922e9778795SPeter Avalos 	strlcpy(retval, alg, rlen);
923e9778795SPeter Avalos 	strlcat(retval, ":", rlen);
924e9778795SPeter Avalos 	for (i = 0; i < dgst_raw_len; i++) {
925e9778795SPeter Avalos 		snprintf(hex, sizeof(hex), "%s%02x",
926e9778795SPeter Avalos 		    i > 0 ? ":" : "", dgst_raw[i]);
927e9778795SPeter Avalos 		strlcat(retval, hex, rlen);
928e9778795SPeter Avalos 	}
92936e94dc5SPeter Avalos 	return retval;
93036e94dc5SPeter Avalos }
93136e94dc5SPeter Avalos 
93236e94dc5SPeter Avalos static char *
fingerprint_bubblebabble(u_char * dgst_raw,size_t dgst_raw_len)93336e94dc5SPeter Avalos fingerprint_bubblebabble(u_char *dgst_raw, size_t dgst_raw_len)
93436e94dc5SPeter Avalos {
93536e94dc5SPeter Avalos 	char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' };
93636e94dc5SPeter Avalos 	char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm',
93736e94dc5SPeter Avalos 	    'n', 'p', 'r', 's', 't', 'v', 'z', 'x' };
93836e94dc5SPeter Avalos 	u_int i, j = 0, rounds, seed = 1;
93936e94dc5SPeter Avalos 	char *retval;
94036e94dc5SPeter Avalos 
94136e94dc5SPeter Avalos 	rounds = (dgst_raw_len / 2) + 1;
94236e94dc5SPeter Avalos 	if ((retval = calloc(rounds, 6)) == NULL)
94336e94dc5SPeter Avalos 		return NULL;
94436e94dc5SPeter Avalos 	retval[j++] = 'x';
94536e94dc5SPeter Avalos 	for (i = 0; i < rounds; i++) {
94636e94dc5SPeter Avalos 		u_int idx0, idx1, idx2, idx3, idx4;
94736e94dc5SPeter Avalos 		if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) {
94836e94dc5SPeter Avalos 			idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) +
94936e94dc5SPeter Avalos 			    seed) % 6;
95036e94dc5SPeter Avalos 			idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15;
95136e94dc5SPeter Avalos 			idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) +
95236e94dc5SPeter Avalos 			    (seed / 6)) % 6;
95336e94dc5SPeter Avalos 			retval[j++] = vowels[idx0];
95436e94dc5SPeter Avalos 			retval[j++] = consonants[idx1];
95536e94dc5SPeter Avalos 			retval[j++] = vowels[idx2];
95636e94dc5SPeter Avalos 			if ((i + 1) < rounds) {
95736e94dc5SPeter Avalos 				idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15;
95836e94dc5SPeter Avalos 				idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15;
95936e94dc5SPeter Avalos 				retval[j++] = consonants[idx3];
96036e94dc5SPeter Avalos 				retval[j++] = '-';
96136e94dc5SPeter Avalos 				retval[j++] = consonants[idx4];
96236e94dc5SPeter Avalos 				seed = ((seed * 5) +
96336e94dc5SPeter Avalos 				    ((((u_int)(dgst_raw[2 * i])) * 7) +
96436e94dc5SPeter Avalos 				    ((u_int)(dgst_raw[(2 * i) + 1])))) % 36;
96536e94dc5SPeter Avalos 			}
96636e94dc5SPeter Avalos 		} else {
96736e94dc5SPeter Avalos 			idx0 = seed % 6;
96836e94dc5SPeter Avalos 			idx1 = 16;
96936e94dc5SPeter Avalos 			idx2 = seed / 6;
97036e94dc5SPeter Avalos 			retval[j++] = vowels[idx0];
97136e94dc5SPeter Avalos 			retval[j++] = consonants[idx1];
97236e94dc5SPeter Avalos 			retval[j++] = vowels[idx2];
97336e94dc5SPeter Avalos 		}
97436e94dc5SPeter Avalos 	}
97536e94dc5SPeter Avalos 	retval[j++] = 'x';
97636e94dc5SPeter Avalos 	retval[j++] = '\0';
97736e94dc5SPeter Avalos 	return retval;
97836e94dc5SPeter Avalos }
97936e94dc5SPeter Avalos 
98036e94dc5SPeter Avalos /*
98136e94dc5SPeter Avalos  * Draw an ASCII-Art representing the fingerprint so human brain can
98236e94dc5SPeter Avalos  * profit from its built-in pattern recognition ability.
98336e94dc5SPeter Avalos  * This technique is called "random art" and can be found in some
98436e94dc5SPeter Avalos  * scientific publications like this original paper:
98536e94dc5SPeter Avalos  *
98636e94dc5SPeter Avalos  * "Hash Visualization: a New Technique to improve Real-World Security",
98736e94dc5SPeter Avalos  * Perrig A. and Song D., 1999, International Workshop on Cryptographic
98836e94dc5SPeter Avalos  * Techniques and E-Commerce (CrypTEC '99)
98936e94dc5SPeter Avalos  * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf
99036e94dc5SPeter Avalos  *
99136e94dc5SPeter Avalos  * The subject came up in a talk by Dan Kaminsky, too.
99236e94dc5SPeter Avalos  *
99336e94dc5SPeter Avalos  * If you see the picture is different, the key is different.
99436e94dc5SPeter Avalos  * If the picture looks the same, you still know nothing.
99536e94dc5SPeter Avalos  *
99636e94dc5SPeter Avalos  * The algorithm used here is a worm crawling over a discrete plane,
99736e94dc5SPeter Avalos  * leaving a trace (augmenting the field) everywhere it goes.
99836e94dc5SPeter Avalos  * Movement is taken from dgst_raw 2bit-wise.  Bumping into walls
99936e94dc5SPeter Avalos  * makes the respective movement vector be ignored for this turn.
100036e94dc5SPeter Avalos  * Graphs are not unambiguous, because circles in graphs can be
100136e94dc5SPeter Avalos  * walked in either direction.
100236e94dc5SPeter Avalos  */
100336e94dc5SPeter Avalos 
100436e94dc5SPeter Avalos /*
100536e94dc5SPeter Avalos  * Field sizes for the random art.  Have to be odd, so the starting point
100636e94dc5SPeter Avalos  * can be in the exact middle of the picture, and FLDBASE should be >=8 .
100736e94dc5SPeter Avalos  * Else pictures would be too dense, and drawing the frame would
100836e94dc5SPeter Avalos  * fail, too, because the key type would not fit in anymore.
100936e94dc5SPeter Avalos  */
101036e94dc5SPeter Avalos #define	FLDBASE		8
101136e94dc5SPeter Avalos #define	FLDSIZE_Y	(FLDBASE + 1)
101236e94dc5SPeter Avalos #define	FLDSIZE_X	(FLDBASE * 2 + 1)
101336e94dc5SPeter Avalos static char *
fingerprint_randomart(const char * alg,u_char * dgst_raw,size_t dgst_raw_len,const struct sshkey * k)1014e9778795SPeter Avalos fingerprint_randomart(const char *alg, u_char *dgst_raw, size_t dgst_raw_len,
101536e94dc5SPeter Avalos     const struct sshkey *k)
101636e94dc5SPeter Avalos {
101736e94dc5SPeter Avalos 	/*
101836e94dc5SPeter Avalos 	 * Chars to be used after each other every time the worm
101936e94dc5SPeter Avalos 	 * intersects with itself.  Matter of taste.
102036e94dc5SPeter Avalos 	 */
102136e94dc5SPeter Avalos 	char	*augmentation_string = " .o+=*BOX@%&#/^SE";
1022e9778795SPeter Avalos 	char	*retval, *p, title[FLDSIZE_X], hash[FLDSIZE_X];
102336e94dc5SPeter Avalos 	u_char	 field[FLDSIZE_X][FLDSIZE_Y];
1024e9778795SPeter Avalos 	size_t	 i, tlen, hlen;
102536e94dc5SPeter Avalos 	u_int	 b;
102636e94dc5SPeter Avalos 	int	 x, y, r;
102736e94dc5SPeter Avalos 	size_t	 len = strlen(augmentation_string) - 1;
102836e94dc5SPeter Avalos 
102936e94dc5SPeter Avalos 	if ((retval = calloc((FLDSIZE_X + 3), (FLDSIZE_Y + 2))) == NULL)
103036e94dc5SPeter Avalos 		return NULL;
103136e94dc5SPeter Avalos 
103236e94dc5SPeter Avalos 	/* initialize field */
103336e94dc5SPeter Avalos 	memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char));
103436e94dc5SPeter Avalos 	x = FLDSIZE_X / 2;
103536e94dc5SPeter Avalos 	y = FLDSIZE_Y / 2;
103636e94dc5SPeter Avalos 
103736e94dc5SPeter Avalos 	/* process raw key */
103836e94dc5SPeter Avalos 	for (i = 0; i < dgst_raw_len; i++) {
103936e94dc5SPeter Avalos 		int input;
104036e94dc5SPeter Avalos 		/* each byte conveys four 2-bit move commands */
104136e94dc5SPeter Avalos 		input = dgst_raw[i];
104236e94dc5SPeter Avalos 		for (b = 0; b < 4; b++) {
104336e94dc5SPeter Avalos 			/* evaluate 2 bit, rest is shifted later */
104436e94dc5SPeter Avalos 			x += (input & 0x1) ? 1 : -1;
104536e94dc5SPeter Avalos 			y += (input & 0x2) ? 1 : -1;
104636e94dc5SPeter Avalos 
104736e94dc5SPeter Avalos 			/* assure we are still in bounds */
1048ce74bacaSMatthew Dillon 			x = MAXIMUM(x, 0);
1049ce74bacaSMatthew Dillon 			y = MAXIMUM(y, 0);
1050ce74bacaSMatthew Dillon 			x = MINIMUM(x, FLDSIZE_X - 1);
1051ce74bacaSMatthew Dillon 			y = MINIMUM(y, FLDSIZE_Y - 1);
105236e94dc5SPeter Avalos 
105336e94dc5SPeter Avalos 			/* augment the field */
105436e94dc5SPeter Avalos 			if (field[x][y] < len - 2)
105536e94dc5SPeter Avalos 				field[x][y]++;
105636e94dc5SPeter Avalos 			input = input >> 2;
105736e94dc5SPeter Avalos 		}
105836e94dc5SPeter Avalos 	}
105936e94dc5SPeter Avalos 
106036e94dc5SPeter Avalos 	/* mark starting point and end point*/
106136e94dc5SPeter Avalos 	field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1;
106236e94dc5SPeter Avalos 	field[x][y] = len;
106336e94dc5SPeter Avalos 
106436e94dc5SPeter Avalos 	/* assemble title */
106536e94dc5SPeter Avalos 	r = snprintf(title, sizeof(title), "[%s %u]",
106636e94dc5SPeter Avalos 		sshkey_type(k), sshkey_size(k));
106736e94dc5SPeter Avalos 	/* If [type size] won't fit, then try [type]; fits "[ED25519-CERT]" */
106836e94dc5SPeter Avalos 	if (r < 0 || r > (int)sizeof(title))
1069e9778795SPeter Avalos 		r = snprintf(title, sizeof(title), "[%s]", sshkey_type(k));
1070e9778795SPeter Avalos 	tlen = (r <= 0) ? 0 : strlen(title);
1071e9778795SPeter Avalos 
1072e9778795SPeter Avalos 	/* assemble hash ID. */
1073e9778795SPeter Avalos 	r = snprintf(hash, sizeof(hash), "[%s]", alg);
1074e9778795SPeter Avalos 	hlen = (r <= 0) ? 0 : strlen(hash);
107536e94dc5SPeter Avalos 
107636e94dc5SPeter Avalos 	/* output upper border */
107736e94dc5SPeter Avalos 	p = retval;
107836e94dc5SPeter Avalos 	*p++ = '+';
107936e94dc5SPeter Avalos 	for (i = 0; i < (FLDSIZE_X - tlen) / 2; i++)
108036e94dc5SPeter Avalos 		*p++ = '-';
108136e94dc5SPeter Avalos 	memcpy(p, title, tlen);
108236e94dc5SPeter Avalos 	p += tlen;
1083e9778795SPeter Avalos 	for (i += tlen; i < FLDSIZE_X; i++)
108436e94dc5SPeter Avalos 		*p++ = '-';
108536e94dc5SPeter Avalos 	*p++ = '+';
108636e94dc5SPeter Avalos 	*p++ = '\n';
108736e94dc5SPeter Avalos 
108836e94dc5SPeter Avalos 	/* output content */
108936e94dc5SPeter Avalos 	for (y = 0; y < FLDSIZE_Y; y++) {
109036e94dc5SPeter Avalos 		*p++ = '|';
109136e94dc5SPeter Avalos 		for (x = 0; x < FLDSIZE_X; x++)
1092ce74bacaSMatthew Dillon 			*p++ = augmentation_string[MINIMUM(field[x][y], len)];
109336e94dc5SPeter Avalos 		*p++ = '|';
109436e94dc5SPeter Avalos 		*p++ = '\n';
109536e94dc5SPeter Avalos 	}
109636e94dc5SPeter Avalos 
109736e94dc5SPeter Avalos 	/* output lower border */
109836e94dc5SPeter Avalos 	*p++ = '+';
1099e9778795SPeter Avalos 	for (i = 0; i < (FLDSIZE_X - hlen) / 2; i++)
1100e9778795SPeter Avalos 		*p++ = '-';
1101e9778795SPeter Avalos 	memcpy(p, hash, hlen);
1102e9778795SPeter Avalos 	p += hlen;
1103e9778795SPeter Avalos 	for (i += hlen; i < FLDSIZE_X; i++)
110436e94dc5SPeter Avalos 		*p++ = '-';
110536e94dc5SPeter Avalos 	*p++ = '+';
110636e94dc5SPeter Avalos 
110736e94dc5SPeter Avalos 	return retval;
110836e94dc5SPeter Avalos }
110936e94dc5SPeter Avalos 
111036e94dc5SPeter Avalos char *
sshkey_fingerprint(const struct sshkey * k,int dgst_alg,enum sshkey_fp_rep dgst_rep)1111e9778795SPeter Avalos sshkey_fingerprint(const struct sshkey *k, int dgst_alg,
111236e94dc5SPeter Avalos     enum sshkey_fp_rep dgst_rep)
111336e94dc5SPeter Avalos {
111436e94dc5SPeter Avalos 	char *retval = NULL;
111536e94dc5SPeter Avalos 	u_char *dgst_raw;
111636e94dc5SPeter Avalos 	size_t dgst_raw_len;
111736e94dc5SPeter Avalos 
1118e9778795SPeter Avalos 	if (sshkey_fingerprint_raw(k, dgst_alg, &dgst_raw, &dgst_raw_len) != 0)
111936e94dc5SPeter Avalos 		return NULL;
112036e94dc5SPeter Avalos 	switch (dgst_rep) {
1121e9778795SPeter Avalos 	case SSH_FP_DEFAULT:
1122e9778795SPeter Avalos 		if (dgst_alg == SSH_DIGEST_MD5) {
1123e9778795SPeter Avalos 			retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg),
1124e9778795SPeter Avalos 			    dgst_raw, dgst_raw_len);
1125e9778795SPeter Avalos 		} else {
1126e9778795SPeter Avalos 			retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg),
1127e9778795SPeter Avalos 			    dgst_raw, dgst_raw_len);
1128e9778795SPeter Avalos 		}
1129e9778795SPeter Avalos 		break;
113036e94dc5SPeter Avalos 	case SSH_FP_HEX:
1131e9778795SPeter Avalos 		retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg),
1132e9778795SPeter Avalos 		    dgst_raw, dgst_raw_len);
1133e9778795SPeter Avalos 		break;
1134e9778795SPeter Avalos 	case SSH_FP_BASE64:
1135e9778795SPeter Avalos 		retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg),
1136e9778795SPeter Avalos 		    dgst_raw, dgst_raw_len);
113736e94dc5SPeter Avalos 		break;
113836e94dc5SPeter Avalos 	case SSH_FP_BUBBLEBABBLE:
113936e94dc5SPeter Avalos 		retval = fingerprint_bubblebabble(dgst_raw, dgst_raw_len);
114036e94dc5SPeter Avalos 		break;
114136e94dc5SPeter Avalos 	case SSH_FP_RANDOMART:
1142e9778795SPeter Avalos 		retval = fingerprint_randomart(ssh_digest_alg_name(dgst_alg),
1143e9778795SPeter Avalos 		    dgst_raw, dgst_raw_len, k);
114436e94dc5SPeter Avalos 		break;
114536e94dc5SPeter Avalos 	default:
11460cbfa66cSDaniel Fojt 		freezero(dgst_raw, dgst_raw_len);
114736e94dc5SPeter Avalos 		return NULL;
114836e94dc5SPeter Avalos 	}
11490cbfa66cSDaniel Fojt 	freezero(dgst_raw, dgst_raw_len);
115036e94dc5SPeter Avalos 	return retval;
115136e94dc5SPeter Avalos }
115236e94dc5SPeter Avalos 
1153664f4763Szrj static int
peek_type_nid(const char * s,size_t l,int * nid)1154664f4763Szrj peek_type_nid(const char *s, size_t l, int *nid)
1155664f4763Szrj {
1156*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
1157*ba1276acSMatthew Dillon 	int i;
115836e94dc5SPeter Avalos 
1159*ba1276acSMatthew Dillon 	for (i = 0; keyimpls[i] != NULL; i++) {
1160*ba1276acSMatthew Dillon 		impl = keyimpls[i];
1161*ba1276acSMatthew Dillon 		if (impl->name == NULL || strlen(impl->name) != l)
1162664f4763Szrj 			continue;
1163*ba1276acSMatthew Dillon 		if (memcmp(s, impl->name, l) == 0) {
1164664f4763Szrj 			*nid = -1;
1165*ba1276acSMatthew Dillon 			if (key_type_is_ecdsa_variant(impl->type))
1166*ba1276acSMatthew Dillon 				*nid = impl->nid;
1167*ba1276acSMatthew Dillon 			return impl->type;
1168664f4763Szrj 		}
1169664f4763Szrj 	}
1170664f4763Szrj 	return KEY_UNSPEC;
1171664f4763Szrj }
1172664f4763Szrj 
1173664f4763Szrj /* XXX this can now be made const char * */
117436e94dc5SPeter Avalos int
sshkey_read(struct sshkey * ret,char ** cpp)117536e94dc5SPeter Avalos sshkey_read(struct sshkey *ret, char **cpp)
117636e94dc5SPeter Avalos {
117736e94dc5SPeter Avalos 	struct sshkey *k;
1178664f4763Szrj 	char *cp, *blobcopy;
1179664f4763Szrj 	size_t space;
118036e94dc5SPeter Avalos 	int r, type, curve_nid = -1;
118136e94dc5SPeter Avalos 	struct sshbuf *blob;
1182ce74bacaSMatthew Dillon 
1183ce74bacaSMatthew Dillon 	if (ret == NULL)
1184ce74bacaSMatthew Dillon 		return SSH_ERR_INVALID_ARGUMENT;
1185*ba1276acSMatthew Dillon 	if (ret->type != KEY_UNSPEC && sshkey_impl_from_type(ret->type) == NULL)
1186664f4763Szrj 		return SSH_ERR_INVALID_ARGUMENT;
1187664f4763Szrj 
1188664f4763Szrj 	/* Decode type */
1189664f4763Szrj 	cp = *cpp;
1190664f4763Szrj 	space = strcspn(cp, " \t");
1191664f4763Szrj 	if (space == strlen(cp))
119236e94dc5SPeter Avalos 		return SSH_ERR_INVALID_FORMAT;
1193664f4763Szrj 	if ((type = peek_type_nid(cp, space, &curve_nid)) == KEY_UNSPEC)
119436e94dc5SPeter Avalos 		return SSH_ERR_INVALID_FORMAT;
1195664f4763Szrj 
1196664f4763Szrj 	/* skip whitespace */
1197664f4763Szrj 	for (cp += space; *cp == ' ' || *cp == '\t'; cp++)
1198664f4763Szrj 		;
119936e94dc5SPeter Avalos 	if (*cp == '\0')
120036e94dc5SPeter Avalos 		return SSH_ERR_INVALID_FORMAT;
1201e9778795SPeter Avalos 	if (ret->type != KEY_UNSPEC && ret->type != type)
120236e94dc5SPeter Avalos 		return SSH_ERR_KEY_TYPE_MISMATCH;
120336e94dc5SPeter Avalos 	if ((blob = sshbuf_new()) == NULL)
120436e94dc5SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
1205664f4763Szrj 
1206664f4763Szrj 	/* find end of keyblob and decode */
1207664f4763Szrj 	space = strcspn(cp, " \t");
1208664f4763Szrj 	if ((blobcopy = strndup(cp, space)) == NULL) {
1209664f4763Szrj 		sshbuf_free(blob);
1210664f4763Szrj 		return SSH_ERR_ALLOC_FAIL;
1211664f4763Szrj 	}
1212664f4763Szrj 	if ((r = sshbuf_b64tod(blob, blobcopy)) != 0) {
1213664f4763Szrj 		free(blobcopy);
121436e94dc5SPeter Avalos 		sshbuf_free(blob);
121536e94dc5SPeter Avalos 		return r;
121636e94dc5SPeter Avalos 	}
1217664f4763Szrj 	free(blobcopy);
1218664f4763Szrj 	if ((r = sshkey_fromb(blob, &k)) != 0) {
121936e94dc5SPeter Avalos 		sshbuf_free(blob);
122036e94dc5SPeter Avalos 		return r;
122136e94dc5SPeter Avalos 	}
122236e94dc5SPeter Avalos 	sshbuf_free(blob);
1223664f4763Szrj 
1224664f4763Szrj 	/* skip whitespace and leave cp at start of comment */
1225664f4763Szrj 	for (cp += space; *cp == ' ' || *cp == '\t'; cp++)
1226664f4763Szrj 		;
1227664f4763Szrj 
1228664f4763Szrj 	/* ensure type of blob matches type at start of line */
122936e94dc5SPeter Avalos 	if (k->type != type) {
123036e94dc5SPeter Avalos 		sshkey_free(k);
123136e94dc5SPeter Avalos 		return SSH_ERR_KEY_TYPE_MISMATCH;
123236e94dc5SPeter Avalos 	}
12330cbfa66cSDaniel Fojt 	if (key_type_is_ecdsa_variant(type) && curve_nid != k->ecdsa_nid) {
123436e94dc5SPeter Avalos 		sshkey_free(k);
123536e94dc5SPeter Avalos 		return SSH_ERR_EC_CURVE_MISMATCH;
123636e94dc5SPeter Avalos 	}
1237664f4763Szrj 
1238664f4763Szrj 	/* Fill in ret from parsed key */
1239*ba1276acSMatthew Dillon 	sshkey_free_contents(ret);
1240*ba1276acSMatthew Dillon 	*ret = *k;
1241*ba1276acSMatthew Dillon 	freezero(k, sizeof(*k));
1242664f4763Szrj 
1243664f4763Szrj 	/* success */
1244664f4763Szrj 	*cpp = cp;
1245664f4763Szrj 	return 0;
124636e94dc5SPeter Avalos }
124736e94dc5SPeter Avalos 
124836e94dc5SPeter Avalos int
sshkey_to_base64(const struct sshkey * key,char ** b64p)1249e9778795SPeter Avalos sshkey_to_base64(const struct sshkey *key, char **b64p)
125036e94dc5SPeter Avalos {
1251e9778795SPeter Avalos 	int r = SSH_ERR_INTERNAL_ERROR;
1252e9778795SPeter Avalos 	struct sshbuf *b = NULL;
125336e94dc5SPeter Avalos 	char *uu = NULL;
1254e9778795SPeter Avalos 
1255e9778795SPeter Avalos 	if (b64p != NULL)
1256e9778795SPeter Avalos 		*b64p = NULL;
1257e9778795SPeter Avalos 	if ((b = sshbuf_new()) == NULL)
1258e9778795SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
1259e9778795SPeter Avalos 	if ((r = sshkey_putb(key, b)) != 0)
1260e9778795SPeter Avalos 		goto out;
12610cbfa66cSDaniel Fojt 	if ((uu = sshbuf_dtob64_string(b, 0)) == NULL) {
1262e9778795SPeter Avalos 		r = SSH_ERR_ALLOC_FAIL;
1263e9778795SPeter Avalos 		goto out;
1264e9778795SPeter Avalos 	}
1265e9778795SPeter Avalos 	/* Success */
1266e9778795SPeter Avalos 	if (b64p != NULL) {
1267e9778795SPeter Avalos 		*b64p = uu;
1268e9778795SPeter Avalos 		uu = NULL;
1269e9778795SPeter Avalos 	}
1270e9778795SPeter Avalos 	r = 0;
1271e9778795SPeter Avalos  out:
1272e9778795SPeter Avalos 	sshbuf_free(b);
1273e9778795SPeter Avalos 	free(uu);
1274e9778795SPeter Avalos 	return r;
1275e9778795SPeter Avalos }
1276e9778795SPeter Avalos 
1277ce74bacaSMatthew Dillon int
sshkey_format_text(const struct sshkey * key,struct sshbuf * b)1278e9778795SPeter Avalos sshkey_format_text(const struct sshkey *key, struct sshbuf *b)
1279e9778795SPeter Avalos {
1280e9778795SPeter Avalos 	int r = SSH_ERR_INTERNAL_ERROR;
1281e9778795SPeter Avalos 	char *uu = NULL;
1282e9778795SPeter Avalos 
1283e9778795SPeter Avalos 	if ((r = sshkey_to_base64(key, &uu)) != 0)
1284e9778795SPeter Avalos 		goto out;
1285e9778795SPeter Avalos 	if ((r = sshbuf_putf(b, "%s %s",
1286e9778795SPeter Avalos 	    sshkey_ssh_name(key), uu)) != 0)
1287e9778795SPeter Avalos 		goto out;
1288e9778795SPeter Avalos 	r = 0;
1289e9778795SPeter Avalos  out:
1290e9778795SPeter Avalos 	free(uu);
1291e9778795SPeter Avalos 	return r;
1292e9778795SPeter Avalos }
1293e9778795SPeter Avalos 
1294e9778795SPeter Avalos int
sshkey_write(const struct sshkey * key,FILE * f)1295e9778795SPeter Avalos sshkey_write(const struct sshkey *key, FILE *f)
1296e9778795SPeter Avalos {
1297e9778795SPeter Avalos 	struct sshbuf *b = NULL;
1298e9778795SPeter Avalos 	int r = SSH_ERR_INTERNAL_ERROR;
1299e9778795SPeter Avalos 
1300e9778795SPeter Avalos 	if ((b = sshbuf_new()) == NULL)
1301e9778795SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
1302e9778795SPeter Avalos 	if ((r = sshkey_format_text(key, b)) != 0)
1303e9778795SPeter Avalos 		goto out;
1304e9778795SPeter Avalos 	if (fwrite(sshbuf_ptr(b), sshbuf_len(b), 1, f) != 1) {
1305e9778795SPeter Avalos 		if (feof(f))
1306e9778795SPeter Avalos 			errno = EPIPE;
1307e9778795SPeter Avalos 		r = SSH_ERR_SYSTEM_ERROR;
1308e9778795SPeter Avalos 		goto out;
1309e9778795SPeter Avalos 	}
1310e9778795SPeter Avalos 	/* Success */
1311e9778795SPeter Avalos 	r = 0;
1312e9778795SPeter Avalos  out:
1313e9778795SPeter Avalos 	sshbuf_free(b);
1314e9778795SPeter Avalos 	return r;
131536e94dc5SPeter Avalos }
131636e94dc5SPeter Avalos 
131736e94dc5SPeter Avalos const char *
sshkey_cert_type(const struct sshkey * k)131836e94dc5SPeter Avalos sshkey_cert_type(const struct sshkey *k)
131936e94dc5SPeter Avalos {
132036e94dc5SPeter Avalos 	switch (k->cert->type) {
132136e94dc5SPeter Avalos 	case SSH2_CERT_TYPE_USER:
132236e94dc5SPeter Avalos 		return "user";
132336e94dc5SPeter Avalos 	case SSH2_CERT_TYPE_HOST:
132436e94dc5SPeter Avalos 		return "host";
132536e94dc5SPeter Avalos 	default:
132636e94dc5SPeter Avalos 		return "unknown";
132736e94dc5SPeter Avalos 	}
132836e94dc5SPeter Avalos }
132936e94dc5SPeter Avalos 
1330*ba1276acSMatthew Dillon int
sshkey_check_rsa_length(const struct sshkey * k,int min_size)1331*ba1276acSMatthew Dillon sshkey_check_rsa_length(const struct sshkey *k, int min_size)
1332*ba1276acSMatthew Dillon {
133336e94dc5SPeter Avalos #ifdef WITH_OPENSSL
1334*ba1276acSMatthew Dillon 	const BIGNUM *rsa_n;
1335*ba1276acSMatthew Dillon 	int nbits;
133636e94dc5SPeter Avalos 
1337*ba1276acSMatthew Dillon 	if (k == NULL || k->rsa == NULL ||
1338*ba1276acSMatthew Dillon 	    (k->type != KEY_RSA && k->type != KEY_RSA_CERT))
1339*ba1276acSMatthew Dillon 		return 0;
1340*ba1276acSMatthew Dillon 	RSA_get0_key(k->rsa, &rsa_n, NULL, NULL);
1341*ba1276acSMatthew Dillon 	nbits = BN_num_bits(rsa_n);
1342*ba1276acSMatthew Dillon 	if (nbits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
1343*ba1276acSMatthew Dillon 	    (min_size > 0 && nbits < min_size))
1344ce74bacaSMatthew Dillon 		return SSH_ERR_KEY_LENGTH;
1345*ba1276acSMatthew Dillon #endif /* WITH_OPENSSL */
1346*ba1276acSMatthew Dillon 	return 0;
134736e94dc5SPeter Avalos }
134836e94dc5SPeter Avalos 
1349*ba1276acSMatthew Dillon #ifdef WITH_OPENSSL
135036e94dc5SPeter Avalos # ifdef OPENSSL_HAS_ECC
135136e94dc5SPeter Avalos int
sshkey_ecdsa_key_to_nid(EC_KEY * k)135236e94dc5SPeter Avalos sshkey_ecdsa_key_to_nid(EC_KEY *k)
135336e94dc5SPeter Avalos {
135436e94dc5SPeter Avalos 	EC_GROUP *eg;
135536e94dc5SPeter Avalos 	int nids[] = {
135636e94dc5SPeter Avalos 		NID_X9_62_prime256v1,
135736e94dc5SPeter Avalos 		NID_secp384r1,
135836e94dc5SPeter Avalos #  ifdef OPENSSL_HAS_NISTP521
135936e94dc5SPeter Avalos 		NID_secp521r1,
136036e94dc5SPeter Avalos #  endif /* OPENSSL_HAS_NISTP521 */
136136e94dc5SPeter Avalos 		-1
136236e94dc5SPeter Avalos 	};
136336e94dc5SPeter Avalos 	int nid;
136436e94dc5SPeter Avalos 	u_int i;
136536e94dc5SPeter Avalos 	const EC_GROUP *g = EC_KEY_get0_group(k);
136636e94dc5SPeter Avalos 
136736e94dc5SPeter Avalos 	/*
136836e94dc5SPeter Avalos 	 * The group may be stored in a ASN.1 encoded private key in one of two
136936e94dc5SPeter Avalos 	 * ways: as a "named group", which is reconstituted by ASN.1 object ID
137036e94dc5SPeter Avalos 	 * or explicit group parameters encoded into the key blob. Only the
137136e94dc5SPeter Avalos 	 * "named group" case sets the group NID for us, but we can figure
137236e94dc5SPeter Avalos 	 * it out for the other case by comparing against all the groups that
137336e94dc5SPeter Avalos 	 * are supported.
137436e94dc5SPeter Avalos 	 */
137536e94dc5SPeter Avalos 	if ((nid = EC_GROUP_get_curve_name(g)) > 0)
137636e94dc5SPeter Avalos 		return nid;
137736e94dc5SPeter Avalos 	for (i = 0; nids[i] != -1; i++) {
13780cbfa66cSDaniel Fojt 		if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL)
137936e94dc5SPeter Avalos 			return -1;
13800cbfa66cSDaniel Fojt 		if (EC_GROUP_cmp(g, eg, NULL) == 0)
138136e94dc5SPeter Avalos 			break;
138236e94dc5SPeter Avalos 		EC_GROUP_free(eg);
138336e94dc5SPeter Avalos 	}
138436e94dc5SPeter Avalos 	if (nids[i] != -1) {
138536e94dc5SPeter Avalos 		/* Use the group with the NID attached */
138636e94dc5SPeter Avalos 		EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE);
138736e94dc5SPeter Avalos 		if (EC_KEY_set_group(k, eg) != 1) {
138836e94dc5SPeter Avalos 			EC_GROUP_free(eg);
138936e94dc5SPeter Avalos 			return -1;
139036e94dc5SPeter Avalos 		}
139136e94dc5SPeter Avalos 	}
139236e94dc5SPeter Avalos 	return nids[i];
139336e94dc5SPeter Avalos }
139436e94dc5SPeter Avalos # endif /* OPENSSL_HAS_ECC */
139536e94dc5SPeter Avalos #endif /* WITH_OPENSSL */
139636e94dc5SPeter Avalos 
139736e94dc5SPeter Avalos int
sshkey_generate(int type,u_int bits,struct sshkey ** keyp)139836e94dc5SPeter Avalos sshkey_generate(int type, u_int bits, struct sshkey **keyp)
139936e94dc5SPeter Avalos {
140036e94dc5SPeter Avalos 	struct sshkey *k;
140136e94dc5SPeter Avalos 	int ret = SSH_ERR_INTERNAL_ERROR;
1402*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
140336e94dc5SPeter Avalos 
1404*ba1276acSMatthew Dillon 	if (keyp == NULL || sshkey_type_is_cert(type))
140536e94dc5SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
140636e94dc5SPeter Avalos 	*keyp = NULL;
1407*ba1276acSMatthew Dillon 	if ((impl = sshkey_impl_from_type(type)) == NULL)
1408*ba1276acSMatthew Dillon 		return SSH_ERR_KEY_TYPE_UNKNOWN;
1409*ba1276acSMatthew Dillon 	if (impl->funcs->generate == NULL)
1410*ba1276acSMatthew Dillon 		return SSH_ERR_FEATURE_UNSUPPORTED;
141136e94dc5SPeter Avalos 	if ((k = sshkey_new(KEY_UNSPEC)) == NULL)
141236e94dc5SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
141336e94dc5SPeter Avalos 	k->type = type;
1414*ba1276acSMatthew Dillon 	if ((ret = impl->funcs->generate(k, bits)) != 0) {
141536e94dc5SPeter Avalos 		sshkey_free(k);
141636e94dc5SPeter Avalos 		return ret;
141736e94dc5SPeter Avalos 	}
1418*ba1276acSMatthew Dillon 	/* success */
1419*ba1276acSMatthew Dillon 	*keyp = k;
1420*ba1276acSMatthew Dillon 	return 0;
1421*ba1276acSMatthew Dillon }
142236e94dc5SPeter Avalos 
142336e94dc5SPeter Avalos int
sshkey_cert_copy(const struct sshkey * from_key,struct sshkey * to_key)142436e94dc5SPeter Avalos sshkey_cert_copy(const struct sshkey *from_key, struct sshkey *to_key)
142536e94dc5SPeter Avalos {
142636e94dc5SPeter Avalos 	u_int i;
142736e94dc5SPeter Avalos 	const struct sshkey_cert *from;
142836e94dc5SPeter Avalos 	struct sshkey_cert *to;
1429664f4763Szrj 	int r = SSH_ERR_INTERNAL_ERROR;
143036e94dc5SPeter Avalos 
1431664f4763Szrj 	if (to_key == NULL || (from = from_key->cert) == NULL)
143236e94dc5SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
143336e94dc5SPeter Avalos 
1434664f4763Szrj 	if ((to = cert_new()) == NULL)
143536e94dc5SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
143636e94dc5SPeter Avalos 
1437664f4763Szrj 	if ((r = sshbuf_putb(to->certblob, from->certblob)) != 0 ||
1438664f4763Szrj 	    (r = sshbuf_putb(to->critical, from->critical)) != 0 ||
1439664f4763Szrj 	    (r = sshbuf_putb(to->extensions, from->extensions)) != 0)
1440664f4763Szrj 		goto out;
144136e94dc5SPeter Avalos 
144236e94dc5SPeter Avalos 	to->serial = from->serial;
144336e94dc5SPeter Avalos 	to->type = from->type;
144436e94dc5SPeter Avalos 	if (from->key_id == NULL)
144536e94dc5SPeter Avalos 		to->key_id = NULL;
1446664f4763Szrj 	else if ((to->key_id = strdup(from->key_id)) == NULL) {
1447664f4763Szrj 		r = SSH_ERR_ALLOC_FAIL;
1448664f4763Szrj 		goto out;
1449664f4763Szrj 	}
145036e94dc5SPeter Avalos 	to->valid_after = from->valid_after;
145136e94dc5SPeter Avalos 	to->valid_before = from->valid_before;
145236e94dc5SPeter Avalos 	if (from->signature_key == NULL)
145336e94dc5SPeter Avalos 		to->signature_key = NULL;
1454664f4763Szrj 	else if ((r = sshkey_from_private(from->signature_key,
145536e94dc5SPeter Avalos 	    &to->signature_key)) != 0)
1456664f4763Szrj 		goto out;
1457664f4763Szrj 	if (from->signature_type != NULL &&
1458664f4763Szrj 	    (to->signature_type = strdup(from->signature_type)) == NULL) {
1459664f4763Szrj 		r = SSH_ERR_ALLOC_FAIL;
1460664f4763Szrj 		goto out;
1461664f4763Szrj 	}
1462664f4763Szrj 	if (from->nprincipals > SSHKEY_CERT_MAX_PRINCIPALS) {
1463664f4763Szrj 		r = SSH_ERR_INVALID_ARGUMENT;
1464664f4763Szrj 		goto out;
1465664f4763Szrj 	}
146636e94dc5SPeter Avalos 	if (from->nprincipals > 0) {
146736e94dc5SPeter Avalos 		if ((to->principals = calloc(from->nprincipals,
1468664f4763Szrj 		    sizeof(*to->principals))) == NULL) {
1469664f4763Szrj 			r = SSH_ERR_ALLOC_FAIL;
1470664f4763Szrj 			goto out;
1471664f4763Szrj 		}
147236e94dc5SPeter Avalos 		for (i = 0; i < from->nprincipals; i++) {
147336e94dc5SPeter Avalos 			to->principals[i] = strdup(from->principals[i]);
147436e94dc5SPeter Avalos 			if (to->principals[i] == NULL) {
147536e94dc5SPeter Avalos 				to->nprincipals = i;
1476664f4763Szrj 				r = SSH_ERR_ALLOC_FAIL;
1477664f4763Szrj 				goto out;
147836e94dc5SPeter Avalos 			}
147936e94dc5SPeter Avalos 		}
148036e94dc5SPeter Avalos 	}
148136e94dc5SPeter Avalos 	to->nprincipals = from->nprincipals;
1482664f4763Szrj 
1483664f4763Szrj 	/* success */
1484664f4763Szrj 	cert_free(to_key->cert);
1485664f4763Szrj 	to_key->cert = to;
1486664f4763Szrj 	to = NULL;
1487664f4763Szrj 	r = 0;
1488664f4763Szrj  out:
1489664f4763Szrj 	cert_free(to);
1490664f4763Szrj 	return r;
149136e94dc5SPeter Avalos }
149236e94dc5SPeter Avalos 
149336e94dc5SPeter Avalos int
sshkey_copy_public_sk(const struct sshkey * from,struct sshkey * to)1494*ba1276acSMatthew Dillon sshkey_copy_public_sk(const struct sshkey *from, struct sshkey *to)
1495*ba1276acSMatthew Dillon {
1496*ba1276acSMatthew Dillon 	/* Append security-key application string */
1497*ba1276acSMatthew Dillon 	if ((to->sk_application = strdup(from->sk_application)) == NULL)
1498*ba1276acSMatthew Dillon 		return SSH_ERR_ALLOC_FAIL;
1499*ba1276acSMatthew Dillon 	return 0;
1500*ba1276acSMatthew Dillon }
1501*ba1276acSMatthew Dillon 
1502*ba1276acSMatthew Dillon int
sshkey_from_private(const struct sshkey * k,struct sshkey ** pkp)150336e94dc5SPeter Avalos sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
150436e94dc5SPeter Avalos {
150536e94dc5SPeter Avalos 	struct sshkey *n = NULL;
1506664f4763Szrj 	int r = SSH_ERR_INTERNAL_ERROR;
1507*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
150836e94dc5SPeter Avalos 
150936e94dc5SPeter Avalos 	*pkp = NULL;
1510*ba1276acSMatthew Dillon 	if ((impl = sshkey_impl_from_key(k)) == NULL)
1511*ba1276acSMatthew Dillon 		return SSH_ERR_KEY_TYPE_UNKNOWN;
1512664f4763Szrj 	if ((n = sshkey_new(k->type)) == NULL) {
1513664f4763Szrj 		r = SSH_ERR_ALLOC_FAIL;
1514664f4763Szrj 		goto out;
151536e94dc5SPeter Avalos 	}
1516*ba1276acSMatthew Dillon 	if ((r = impl->funcs->copy_public(k, n)) != 0)
1517664f4763Szrj 		goto out;
1518664f4763Szrj 	if (sshkey_is_cert(k) && (r = sshkey_cert_copy(k, n)) != 0)
1519664f4763Szrj 		goto out;
1520664f4763Szrj 	/* success */
152136e94dc5SPeter Avalos 	*pkp = n;
1522664f4763Szrj 	n = NULL;
1523664f4763Szrj 	r = 0;
1524664f4763Szrj  out:
1525664f4763Szrj 	sshkey_free(n);
1526664f4763Szrj 	return r;
152736e94dc5SPeter Avalos }
152836e94dc5SPeter Avalos 
15290cbfa66cSDaniel Fojt int
sshkey_is_shielded(struct sshkey * k)15300cbfa66cSDaniel Fojt sshkey_is_shielded(struct sshkey *k)
15310cbfa66cSDaniel Fojt {
15320cbfa66cSDaniel Fojt 	return k != NULL && k->shielded_private != NULL;
15330cbfa66cSDaniel Fojt }
15340cbfa66cSDaniel Fojt 
15350cbfa66cSDaniel Fojt int
sshkey_shield_private(struct sshkey * k)15360cbfa66cSDaniel Fojt sshkey_shield_private(struct sshkey *k)
15370cbfa66cSDaniel Fojt {
15380cbfa66cSDaniel Fojt 	struct sshbuf *prvbuf = NULL;
15390cbfa66cSDaniel Fojt 	u_char *prekey = NULL, *enc = NULL, keyiv[SSH_DIGEST_MAX_LENGTH];
15400cbfa66cSDaniel Fojt 	struct sshcipher_ctx *cctx = NULL;
15410cbfa66cSDaniel Fojt 	const struct sshcipher *cipher;
15420cbfa66cSDaniel Fojt 	size_t i, enclen = 0;
15430cbfa66cSDaniel Fojt 	struct sshkey *kswap = NULL, tmp;
15440cbfa66cSDaniel Fojt 	int r = SSH_ERR_INTERNAL_ERROR;
15450cbfa66cSDaniel Fojt 
15460cbfa66cSDaniel Fojt #ifdef DEBUG_PK
15470cbfa66cSDaniel Fojt 	fprintf(stderr, "%s: entering for %s\n", __func__, sshkey_ssh_name(k));
15480cbfa66cSDaniel Fojt #endif
15490cbfa66cSDaniel Fojt 	if ((cipher = cipher_by_name(SSHKEY_SHIELD_CIPHER)) == NULL) {
15500cbfa66cSDaniel Fojt 		r = SSH_ERR_INVALID_ARGUMENT;
15510cbfa66cSDaniel Fojt 		goto out;
15520cbfa66cSDaniel Fojt 	}
15530cbfa66cSDaniel Fojt 	if (cipher_keylen(cipher) + cipher_ivlen(cipher) >
15540cbfa66cSDaniel Fojt 	    ssh_digest_bytes(SSHKEY_SHIELD_PREKEY_HASH)) {
15550cbfa66cSDaniel Fojt 		r = SSH_ERR_INTERNAL_ERROR;
15560cbfa66cSDaniel Fojt 		goto out;
15570cbfa66cSDaniel Fojt 	}
15580cbfa66cSDaniel Fojt 
15590cbfa66cSDaniel Fojt 	/* Prepare a random pre-key, and from it an ephemeral key */
15600cbfa66cSDaniel Fojt 	if ((prekey = malloc(SSHKEY_SHIELD_PREKEY_LEN)) == NULL) {
15610cbfa66cSDaniel Fojt 		r = SSH_ERR_ALLOC_FAIL;
15620cbfa66cSDaniel Fojt 		goto out;
15630cbfa66cSDaniel Fojt 	}
15640cbfa66cSDaniel Fojt 	arc4random_buf(prekey, SSHKEY_SHIELD_PREKEY_LEN);
15650cbfa66cSDaniel Fojt 	if ((r = ssh_digest_memory(SSHKEY_SHIELD_PREKEY_HASH,
15660cbfa66cSDaniel Fojt 	    prekey, SSHKEY_SHIELD_PREKEY_LEN,
15670cbfa66cSDaniel Fojt 	    keyiv, SSH_DIGEST_MAX_LENGTH)) != 0)
15680cbfa66cSDaniel Fojt 		goto out;
15690cbfa66cSDaniel Fojt #ifdef DEBUG_PK
15700cbfa66cSDaniel Fojt 	fprintf(stderr, "%s: key+iv\n", __func__);
15710cbfa66cSDaniel Fojt 	sshbuf_dump_data(keyiv, ssh_digest_bytes(SSHKEY_SHIELD_PREKEY_HASH),
15720cbfa66cSDaniel Fojt 	    stderr);
15730cbfa66cSDaniel Fojt #endif
15740cbfa66cSDaniel Fojt 	if ((r = cipher_init(&cctx, cipher, keyiv, cipher_keylen(cipher),
15750cbfa66cSDaniel Fojt 	    keyiv + cipher_keylen(cipher), cipher_ivlen(cipher), 1)) != 0)
15760cbfa66cSDaniel Fojt 		goto out;
15770cbfa66cSDaniel Fojt 
15780cbfa66cSDaniel Fojt 	/* Serialise and encrypt the private key using the ephemeral key */
15790cbfa66cSDaniel Fojt 	if ((prvbuf = sshbuf_new()) == NULL) {
15800cbfa66cSDaniel Fojt 		r = SSH_ERR_ALLOC_FAIL;
15810cbfa66cSDaniel Fojt 		goto out;
15820cbfa66cSDaniel Fojt 	}
15830cbfa66cSDaniel Fojt 	if (sshkey_is_shielded(k) && (r = sshkey_unshield_private(k)) != 0)
15840cbfa66cSDaniel Fojt 		goto out;
15850cbfa66cSDaniel Fojt 	if ((r = sshkey_private_serialize_opt(k, prvbuf,
15860cbfa66cSDaniel Fojt 	    SSHKEY_SERIALIZE_SHIELD)) != 0)
15870cbfa66cSDaniel Fojt 		goto out;
15880cbfa66cSDaniel Fojt 	/* pad to cipher blocksize */
15890cbfa66cSDaniel Fojt 	i = 0;
15900cbfa66cSDaniel Fojt 	while (sshbuf_len(prvbuf) % cipher_blocksize(cipher)) {
15910cbfa66cSDaniel Fojt 		if ((r = sshbuf_put_u8(prvbuf, ++i & 0xff)) != 0)
15920cbfa66cSDaniel Fojt 			goto out;
15930cbfa66cSDaniel Fojt 	}
15940cbfa66cSDaniel Fojt #ifdef DEBUG_PK
15950cbfa66cSDaniel Fojt 	fprintf(stderr, "%s: serialised\n", __func__);
15960cbfa66cSDaniel Fojt 	sshbuf_dump(prvbuf, stderr);
15970cbfa66cSDaniel Fojt #endif
15980cbfa66cSDaniel Fojt 	/* encrypt */
15990cbfa66cSDaniel Fojt 	enclen = sshbuf_len(prvbuf);
16000cbfa66cSDaniel Fojt 	if ((enc = malloc(enclen)) == NULL) {
16010cbfa66cSDaniel Fojt 		r = SSH_ERR_ALLOC_FAIL;
16020cbfa66cSDaniel Fojt 		goto out;
16030cbfa66cSDaniel Fojt 	}
16040cbfa66cSDaniel Fojt 	if ((r = cipher_crypt(cctx, 0, enc,
16050cbfa66cSDaniel Fojt 	    sshbuf_ptr(prvbuf), sshbuf_len(prvbuf), 0, 0)) != 0)
16060cbfa66cSDaniel Fojt 		goto out;
16070cbfa66cSDaniel Fojt #ifdef DEBUG_PK
16080cbfa66cSDaniel Fojt 	fprintf(stderr, "%s: encrypted\n", __func__);
16090cbfa66cSDaniel Fojt 	sshbuf_dump_data(enc, enclen, stderr);
16100cbfa66cSDaniel Fojt #endif
16110cbfa66cSDaniel Fojt 
16120cbfa66cSDaniel Fojt 	/* Make a scrubbed, public-only copy of our private key argument */
16130cbfa66cSDaniel Fojt 	if ((r = sshkey_from_private(k, &kswap)) != 0)
16140cbfa66cSDaniel Fojt 		goto out;
16150cbfa66cSDaniel Fojt 
16160cbfa66cSDaniel Fojt 	/* Swap the private key out (it will be destroyed below) */
16170cbfa66cSDaniel Fojt 	tmp = *kswap;
16180cbfa66cSDaniel Fojt 	*kswap = *k;
16190cbfa66cSDaniel Fojt 	*k = tmp;
16200cbfa66cSDaniel Fojt 
16210cbfa66cSDaniel Fojt 	/* Insert the shielded key into our argument */
16220cbfa66cSDaniel Fojt 	k->shielded_private = enc;
16230cbfa66cSDaniel Fojt 	k->shielded_len = enclen;
16240cbfa66cSDaniel Fojt 	k->shield_prekey = prekey;
16250cbfa66cSDaniel Fojt 	k->shield_prekey_len = SSHKEY_SHIELD_PREKEY_LEN;
16260cbfa66cSDaniel Fojt 	enc = prekey = NULL; /* transferred */
16270cbfa66cSDaniel Fojt 	enclen = 0;
16280cbfa66cSDaniel Fojt 
16290cbfa66cSDaniel Fojt 	/* preserve key fields that are required for correct operation */
16300cbfa66cSDaniel Fojt 	k->sk_flags = kswap->sk_flags;
16310cbfa66cSDaniel Fojt 
16320cbfa66cSDaniel Fojt 	/* success */
16330cbfa66cSDaniel Fojt 	r = 0;
16340cbfa66cSDaniel Fojt 
16350cbfa66cSDaniel Fojt  out:
16360cbfa66cSDaniel Fojt 	/* XXX behaviour on error - invalidate original private key? */
16370cbfa66cSDaniel Fojt 	cipher_free(cctx);
16380cbfa66cSDaniel Fojt 	explicit_bzero(keyiv, sizeof(keyiv));
16390cbfa66cSDaniel Fojt 	explicit_bzero(&tmp, sizeof(tmp));
16400cbfa66cSDaniel Fojt 	freezero(enc, enclen);
16410cbfa66cSDaniel Fojt 	freezero(prekey, SSHKEY_SHIELD_PREKEY_LEN);
16420cbfa66cSDaniel Fojt 	sshkey_free(kswap);
16430cbfa66cSDaniel Fojt 	sshbuf_free(prvbuf);
16440cbfa66cSDaniel Fojt 	return r;
16450cbfa66cSDaniel Fojt }
16460cbfa66cSDaniel Fojt 
1647ee116499SAntonio Huete Jimenez /* Check deterministic padding after private key */
1648ee116499SAntonio Huete Jimenez static int
private2_check_padding(struct sshbuf * decrypted)1649ee116499SAntonio Huete Jimenez private2_check_padding(struct sshbuf *decrypted)
1650ee116499SAntonio Huete Jimenez {
1651ee116499SAntonio Huete Jimenez 	u_char pad;
1652ee116499SAntonio Huete Jimenez 	size_t i;
1653ee116499SAntonio Huete Jimenez 	int r;
1654ee116499SAntonio Huete Jimenez 
1655ee116499SAntonio Huete Jimenez 	i = 0;
1656ee116499SAntonio Huete Jimenez 	while (sshbuf_len(decrypted)) {
1657ee116499SAntonio Huete Jimenez 		if ((r = sshbuf_get_u8(decrypted, &pad)) != 0)
1658ee116499SAntonio Huete Jimenez 			goto out;
1659ee116499SAntonio Huete Jimenez 		if (pad != (++i & 0xff)) {
1660ee116499SAntonio Huete Jimenez 			r = SSH_ERR_INVALID_FORMAT;
1661ee116499SAntonio Huete Jimenez 			goto out;
1662ee116499SAntonio Huete Jimenez 		}
1663ee116499SAntonio Huete Jimenez 	}
1664ee116499SAntonio Huete Jimenez 	/* success */
1665ee116499SAntonio Huete Jimenez 	r = 0;
1666ee116499SAntonio Huete Jimenez  out:
1667ee116499SAntonio Huete Jimenez 	explicit_bzero(&pad, sizeof(pad));
1668ee116499SAntonio Huete Jimenez 	explicit_bzero(&i, sizeof(i));
1669ee116499SAntonio Huete Jimenez 	return r;
1670ee116499SAntonio Huete Jimenez }
1671ee116499SAntonio Huete Jimenez 
16720cbfa66cSDaniel Fojt int
sshkey_unshield_private(struct sshkey * k)16730cbfa66cSDaniel Fojt sshkey_unshield_private(struct sshkey *k)
16740cbfa66cSDaniel Fojt {
16750cbfa66cSDaniel Fojt 	struct sshbuf *prvbuf = NULL;
1676ee116499SAntonio Huete Jimenez 	u_char *cp, keyiv[SSH_DIGEST_MAX_LENGTH];
16770cbfa66cSDaniel Fojt 	struct sshcipher_ctx *cctx = NULL;
16780cbfa66cSDaniel Fojt 	const struct sshcipher *cipher;
16790cbfa66cSDaniel Fojt 	struct sshkey *kswap = NULL, tmp;
16800cbfa66cSDaniel Fojt 	int r = SSH_ERR_INTERNAL_ERROR;
16810cbfa66cSDaniel Fojt 
16820cbfa66cSDaniel Fojt #ifdef DEBUG_PK
16830cbfa66cSDaniel Fojt 	fprintf(stderr, "%s: entering for %s\n", __func__, sshkey_ssh_name(k));
16840cbfa66cSDaniel Fojt #endif
16850cbfa66cSDaniel Fojt 	if (!sshkey_is_shielded(k))
16860cbfa66cSDaniel Fojt 		return 0; /* nothing to do */
16870cbfa66cSDaniel Fojt 
16880cbfa66cSDaniel Fojt 	if ((cipher = cipher_by_name(SSHKEY_SHIELD_CIPHER)) == NULL) {
16890cbfa66cSDaniel Fojt 		r = SSH_ERR_INVALID_ARGUMENT;
16900cbfa66cSDaniel Fojt 		goto out;
16910cbfa66cSDaniel Fojt 	}
16920cbfa66cSDaniel Fojt 	if (cipher_keylen(cipher) + cipher_ivlen(cipher) >
16930cbfa66cSDaniel Fojt 	    ssh_digest_bytes(SSHKEY_SHIELD_PREKEY_HASH)) {
16940cbfa66cSDaniel Fojt 		r = SSH_ERR_INTERNAL_ERROR;
16950cbfa66cSDaniel Fojt 		goto out;
16960cbfa66cSDaniel Fojt 	}
16970cbfa66cSDaniel Fojt 	/* check size of shielded key blob */
16980cbfa66cSDaniel Fojt 	if (k->shielded_len < cipher_blocksize(cipher) ||
16990cbfa66cSDaniel Fojt 	    (k->shielded_len % cipher_blocksize(cipher)) != 0) {
17000cbfa66cSDaniel Fojt 		r = SSH_ERR_INVALID_FORMAT;
17010cbfa66cSDaniel Fojt 		goto out;
17020cbfa66cSDaniel Fojt 	}
17030cbfa66cSDaniel Fojt 
17040cbfa66cSDaniel Fojt 	/* Calculate the ephemeral key from the prekey */
17050cbfa66cSDaniel Fojt 	if ((r = ssh_digest_memory(SSHKEY_SHIELD_PREKEY_HASH,
17060cbfa66cSDaniel Fojt 	    k->shield_prekey, k->shield_prekey_len,
17070cbfa66cSDaniel Fojt 	    keyiv, SSH_DIGEST_MAX_LENGTH)) != 0)
17080cbfa66cSDaniel Fojt 		goto out;
17090cbfa66cSDaniel Fojt 	if ((r = cipher_init(&cctx, cipher, keyiv, cipher_keylen(cipher),
17100cbfa66cSDaniel Fojt 	    keyiv + cipher_keylen(cipher), cipher_ivlen(cipher), 0)) != 0)
17110cbfa66cSDaniel Fojt 		goto out;
17120cbfa66cSDaniel Fojt #ifdef DEBUG_PK
17130cbfa66cSDaniel Fojt 	fprintf(stderr, "%s: key+iv\n", __func__);
17140cbfa66cSDaniel Fojt 	sshbuf_dump_data(keyiv, ssh_digest_bytes(SSHKEY_SHIELD_PREKEY_HASH),
17150cbfa66cSDaniel Fojt 	    stderr);
17160cbfa66cSDaniel Fojt #endif
17170cbfa66cSDaniel Fojt 
17180cbfa66cSDaniel Fojt 	/* Decrypt and parse the shielded private key using the ephemeral key */
17190cbfa66cSDaniel Fojt 	if ((prvbuf = sshbuf_new()) == NULL) {
17200cbfa66cSDaniel Fojt 		r = SSH_ERR_ALLOC_FAIL;
17210cbfa66cSDaniel Fojt 		goto out;
17220cbfa66cSDaniel Fojt 	}
17230cbfa66cSDaniel Fojt 	if ((r = sshbuf_reserve(prvbuf, k->shielded_len, &cp)) != 0)
17240cbfa66cSDaniel Fojt 		goto out;
17250cbfa66cSDaniel Fojt 	/* decrypt */
17260cbfa66cSDaniel Fojt #ifdef DEBUG_PK
17270cbfa66cSDaniel Fojt 	fprintf(stderr, "%s: encrypted\n", __func__);
17280cbfa66cSDaniel Fojt 	sshbuf_dump_data(k->shielded_private, k->shielded_len, stderr);
17290cbfa66cSDaniel Fojt #endif
17300cbfa66cSDaniel Fojt 	if ((r = cipher_crypt(cctx, 0, cp,
17310cbfa66cSDaniel Fojt 	    k->shielded_private, k->shielded_len, 0, 0)) != 0)
17320cbfa66cSDaniel Fojt 		goto out;
17330cbfa66cSDaniel Fojt #ifdef DEBUG_PK
17340cbfa66cSDaniel Fojt 	fprintf(stderr, "%s: serialised\n", __func__);
17350cbfa66cSDaniel Fojt 	sshbuf_dump(prvbuf, stderr);
17360cbfa66cSDaniel Fojt #endif
17370cbfa66cSDaniel Fojt 	/* Parse private key */
17380cbfa66cSDaniel Fojt 	if ((r = sshkey_private_deserialize(prvbuf, &kswap)) != 0)
17390cbfa66cSDaniel Fojt 		goto out;
1740ee116499SAntonio Huete Jimenez 
1741ee116499SAntonio Huete Jimenez 	if ((r = private2_check_padding(prvbuf)) != 0)
17420cbfa66cSDaniel Fojt 		goto out;
17430cbfa66cSDaniel Fojt 
17440cbfa66cSDaniel Fojt 	/* Swap the parsed key back into place */
17450cbfa66cSDaniel Fojt 	tmp = *kswap;
17460cbfa66cSDaniel Fojt 	*kswap = *k;
17470cbfa66cSDaniel Fojt 	*k = tmp;
17480cbfa66cSDaniel Fojt 
17490cbfa66cSDaniel Fojt 	/* success */
17500cbfa66cSDaniel Fojt 	r = 0;
17510cbfa66cSDaniel Fojt 
17520cbfa66cSDaniel Fojt  out:
17530cbfa66cSDaniel Fojt 	cipher_free(cctx);
17540cbfa66cSDaniel Fojt 	explicit_bzero(keyiv, sizeof(keyiv));
17550cbfa66cSDaniel Fojt 	explicit_bzero(&tmp, sizeof(tmp));
17560cbfa66cSDaniel Fojt 	sshkey_free(kswap);
17570cbfa66cSDaniel Fojt 	sshbuf_free(prvbuf);
17580cbfa66cSDaniel Fojt 	return r;
17590cbfa66cSDaniel Fojt }
17600cbfa66cSDaniel Fojt 
176136e94dc5SPeter Avalos static int
cert_parse(struct sshbuf * b,struct sshkey * key,struct sshbuf * certbuf)1762e9778795SPeter Avalos cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf)
176336e94dc5SPeter Avalos {
1764e9778795SPeter Avalos 	struct sshbuf *principals = NULL, *crit = NULL;
1765e9778795SPeter Avalos 	struct sshbuf *exts = NULL, *ca = NULL;
1766e9778795SPeter Avalos 	u_char *sig = NULL;
1767e9778795SPeter Avalos 	size_t signed_len = 0, slen = 0, kidlen = 0;
176836e94dc5SPeter Avalos 	int ret = SSH_ERR_INTERNAL_ERROR;
176936e94dc5SPeter Avalos 
177036e94dc5SPeter Avalos 	/* Copy the entire key blob for verification and later serialisation */
1771e9778795SPeter Avalos 	if ((ret = sshbuf_putb(key->cert->certblob, certbuf)) != 0)
177236e94dc5SPeter Avalos 		return ret;
177336e94dc5SPeter Avalos 
1774e9778795SPeter Avalos 	/* Parse body of certificate up to signature */
1775e9778795SPeter Avalos 	if ((ret = sshbuf_get_u64(b, &key->cert->serial)) != 0 ||
177636e94dc5SPeter Avalos 	    (ret = sshbuf_get_u32(b, &key->cert->type)) != 0 ||
177736e94dc5SPeter Avalos 	    (ret = sshbuf_get_cstring(b, &key->cert->key_id, &kidlen)) != 0 ||
1778e9778795SPeter Avalos 	    (ret = sshbuf_froms(b, &principals)) != 0 ||
177936e94dc5SPeter Avalos 	    (ret = sshbuf_get_u64(b, &key->cert->valid_after)) != 0 ||
178036e94dc5SPeter Avalos 	    (ret = sshbuf_get_u64(b, &key->cert->valid_before)) != 0 ||
1781e9778795SPeter Avalos 	    (ret = sshbuf_froms(b, &crit)) != 0 ||
1782e9778795SPeter Avalos 	    (ret = sshbuf_froms(b, &exts)) != 0 ||
178336e94dc5SPeter Avalos 	    (ret = sshbuf_get_string_direct(b, NULL, NULL)) != 0 ||
1784e9778795SPeter Avalos 	    (ret = sshbuf_froms(b, &ca)) != 0) {
178536e94dc5SPeter Avalos 		/* XXX debug print error for ret */
178636e94dc5SPeter Avalos 		ret = SSH_ERR_INVALID_FORMAT;
178736e94dc5SPeter Avalos 		goto out;
178836e94dc5SPeter Avalos 	}
178936e94dc5SPeter Avalos 
179036e94dc5SPeter Avalos 	/* Signature is left in the buffer so we can calculate this length */
179136e94dc5SPeter Avalos 	signed_len = sshbuf_len(key->cert->certblob) - sshbuf_len(b);
179236e94dc5SPeter Avalos 
179336e94dc5SPeter Avalos 	if ((ret = sshbuf_get_string(b, &sig, &slen)) != 0) {
179436e94dc5SPeter Avalos 		ret = SSH_ERR_INVALID_FORMAT;
179536e94dc5SPeter Avalos 		goto out;
179636e94dc5SPeter Avalos 	}
179736e94dc5SPeter Avalos 
179836e94dc5SPeter Avalos 	if (key->cert->type != SSH2_CERT_TYPE_USER &&
179936e94dc5SPeter Avalos 	    key->cert->type != SSH2_CERT_TYPE_HOST) {
180036e94dc5SPeter Avalos 		ret = SSH_ERR_KEY_CERT_UNKNOWN_TYPE;
180136e94dc5SPeter Avalos 		goto out;
180236e94dc5SPeter Avalos 	}
180336e94dc5SPeter Avalos 
1804e9778795SPeter Avalos 	/* Parse principals section */
1805e9778795SPeter Avalos 	while (sshbuf_len(principals) > 0) {
1806e9778795SPeter Avalos 		char *principal = NULL;
1807e9778795SPeter Avalos 		char **oprincipals = NULL;
1808e9778795SPeter Avalos 
180936e94dc5SPeter Avalos 		if (key->cert->nprincipals >= SSHKEY_CERT_MAX_PRINCIPALS) {
181036e94dc5SPeter Avalos 			ret = SSH_ERR_INVALID_FORMAT;
181136e94dc5SPeter Avalos 			goto out;
181236e94dc5SPeter Avalos 		}
1813e9778795SPeter Avalos 		if ((ret = sshbuf_get_cstring(principals, &principal,
1814e9778795SPeter Avalos 		    NULL)) != 0) {
181536e94dc5SPeter Avalos 			ret = SSH_ERR_INVALID_FORMAT;
181636e94dc5SPeter Avalos 			goto out;
181736e94dc5SPeter Avalos 		}
181836e94dc5SPeter Avalos 		oprincipals = key->cert->principals;
1819ce74bacaSMatthew Dillon 		key->cert->principals = recallocarray(key->cert->principals,
1820ce74bacaSMatthew Dillon 		    key->cert->nprincipals, key->cert->nprincipals + 1,
1821ce74bacaSMatthew Dillon 		    sizeof(*key->cert->principals));
182236e94dc5SPeter Avalos 		if (key->cert->principals == NULL) {
182336e94dc5SPeter Avalos 			free(principal);
182436e94dc5SPeter Avalos 			key->cert->principals = oprincipals;
182536e94dc5SPeter Avalos 			ret = SSH_ERR_ALLOC_FAIL;
182636e94dc5SPeter Avalos 			goto out;
182736e94dc5SPeter Avalos 		}
182836e94dc5SPeter Avalos 		key->cert->principals[key->cert->nprincipals++] = principal;
182936e94dc5SPeter Avalos 	}
183036e94dc5SPeter Avalos 
1831e9778795SPeter Avalos 	/*
1832e9778795SPeter Avalos 	 * Stash a copies of the critical options and extensions sections
1833e9778795SPeter Avalos 	 * for later use.
1834e9778795SPeter Avalos 	 */
1835e9778795SPeter Avalos 	if ((ret = sshbuf_putb(key->cert->critical, crit)) != 0 ||
1836e9778795SPeter Avalos 	    (exts != NULL &&
1837e9778795SPeter Avalos 	    (ret = sshbuf_putb(key->cert->extensions, exts)) != 0))
183836e94dc5SPeter Avalos 		goto out;
183936e94dc5SPeter Avalos 
1840e9778795SPeter Avalos 	/*
1841e9778795SPeter Avalos 	 * Validate critical options and extensions sections format.
1842e9778795SPeter Avalos 	 */
1843e9778795SPeter Avalos 	while (sshbuf_len(crit) != 0) {
1844e9778795SPeter Avalos 		if ((ret = sshbuf_get_string_direct(crit, NULL, NULL)) != 0 ||
1845e9778795SPeter Avalos 		    (ret = sshbuf_get_string_direct(crit, NULL, NULL)) != 0) {
1846e9778795SPeter Avalos 			sshbuf_reset(key->cert->critical);
184736e94dc5SPeter Avalos 			ret = SSH_ERR_INVALID_FORMAT;
184836e94dc5SPeter Avalos 			goto out;
184936e94dc5SPeter Avalos 		}
185036e94dc5SPeter Avalos 	}
1851e9778795SPeter Avalos 	while (exts != NULL && sshbuf_len(exts) != 0) {
1852e9778795SPeter Avalos 		if ((ret = sshbuf_get_string_direct(exts, NULL, NULL)) != 0 ||
1853e9778795SPeter Avalos 		    (ret = sshbuf_get_string_direct(exts, NULL, NULL)) != 0) {
1854e9778795SPeter Avalos 			sshbuf_reset(key->cert->extensions);
185536e94dc5SPeter Avalos 			ret = SSH_ERR_INVALID_FORMAT;
185636e94dc5SPeter Avalos 			goto out;
185736e94dc5SPeter Avalos 		}
185836e94dc5SPeter Avalos 	}
185936e94dc5SPeter Avalos 
1860e9778795SPeter Avalos 	/* Parse CA key and check signature */
1861e9778795SPeter Avalos 	if (sshkey_from_blob_internal(ca, &key->cert->signature_key, 0) != 0) {
186236e94dc5SPeter Avalos 		ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
186336e94dc5SPeter Avalos 		goto out;
186436e94dc5SPeter Avalos 	}
186536e94dc5SPeter Avalos 	if (!sshkey_type_is_valid_ca(key->cert->signature_key->type)) {
186636e94dc5SPeter Avalos 		ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
186736e94dc5SPeter Avalos 		goto out;
186836e94dc5SPeter Avalos 	}
186936e94dc5SPeter Avalos 	if ((ret = sshkey_verify(key->cert->signature_key, sig, slen,
18700cbfa66cSDaniel Fojt 	    sshbuf_ptr(key->cert->certblob), signed_len, NULL, 0, NULL)) != 0)
1871664f4763Szrj 		goto out;
18720cbfa66cSDaniel Fojt 	if ((ret = sshkey_get_sigtype(sig, slen,
18730cbfa66cSDaniel Fojt 	    &key->cert->signature_type)) != 0)
187436e94dc5SPeter Avalos 		goto out;
187536e94dc5SPeter Avalos 
1876e9778795SPeter Avalos 	/* Success */
1877e9778795SPeter Avalos 	ret = 0;
187836e94dc5SPeter Avalos  out:
1879e9778795SPeter Avalos 	sshbuf_free(ca);
1880e9778795SPeter Avalos 	sshbuf_free(crit);
1881e9778795SPeter Avalos 	sshbuf_free(exts);
1882e9778795SPeter Avalos 	sshbuf_free(principals);
188336e94dc5SPeter Avalos 	free(sig);
188436e94dc5SPeter Avalos 	return ret;
188536e94dc5SPeter Avalos }
188636e94dc5SPeter Avalos 
1887ee116499SAntonio Huete Jimenez int
sshkey_deserialize_sk(struct sshbuf * b,struct sshkey * key)1888*ba1276acSMatthew Dillon sshkey_deserialize_sk(struct sshbuf *b, struct sshkey *key)
1889664f4763Szrj {
1890*ba1276acSMatthew Dillon 	/* Parse additional security-key application string */
1891*ba1276acSMatthew Dillon 	if (sshbuf_get_cstring(b, &key->sk_application, NULL) != 0)
1892*ba1276acSMatthew Dillon 		return SSH_ERR_INVALID_FORMAT;
1893664f4763Szrj 	return 0;
1894664f4763Szrj }
1895664f4763Szrj 
189636e94dc5SPeter Avalos static int
sshkey_from_blob_internal(struct sshbuf * b,struct sshkey ** keyp,int allow_cert)1897e9778795SPeter Avalos sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
1898e9778795SPeter Avalos     int allow_cert)
189936e94dc5SPeter Avalos {
1900e9778795SPeter Avalos 	int type, ret = SSH_ERR_INTERNAL_ERROR;
1901*ba1276acSMatthew Dillon 	char *ktype = NULL;
190236e94dc5SPeter Avalos 	struct sshkey *key = NULL;
1903e9778795SPeter Avalos 	struct sshbuf *copy;
1904*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
190536e94dc5SPeter Avalos 
190636e94dc5SPeter Avalos #ifdef DEBUG_PK /* XXX */
1907e9778795SPeter Avalos 	sshbuf_dump(b, stderr);
190836e94dc5SPeter Avalos #endif
1909e9778795SPeter Avalos 	if (keyp != NULL)
191036e94dc5SPeter Avalos 		*keyp = NULL;
1911e9778795SPeter Avalos 	if ((copy = sshbuf_fromb(b)) == NULL) {
1912e9778795SPeter Avalos 		ret = SSH_ERR_ALLOC_FAIL;
1913e9778795SPeter Avalos 		goto out;
1914e9778795SPeter Avalos 	}
191536e94dc5SPeter Avalos 	if (sshbuf_get_cstring(b, &ktype, NULL) != 0) {
191636e94dc5SPeter Avalos 		ret = SSH_ERR_INVALID_FORMAT;
191736e94dc5SPeter Avalos 		goto out;
191836e94dc5SPeter Avalos 	}
191936e94dc5SPeter Avalos 
192036e94dc5SPeter Avalos 	type = sshkey_type_from_name(ktype);
192136e94dc5SPeter Avalos 	if (!allow_cert && sshkey_type_is_cert(type)) {
192236e94dc5SPeter Avalos 		ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
192336e94dc5SPeter Avalos 		goto out;
192436e94dc5SPeter Avalos 	}
1925*ba1276acSMatthew Dillon 	if ((impl = sshkey_impl_from_type(type)) == NULL) {
192636e94dc5SPeter Avalos 		ret = SSH_ERR_KEY_TYPE_UNKNOWN;
192736e94dc5SPeter Avalos 		goto out;
192836e94dc5SPeter Avalos 	}
1929*ba1276acSMatthew Dillon 	if ((key = sshkey_new(type)) == NULL) {
1930*ba1276acSMatthew Dillon 		ret = SSH_ERR_ALLOC_FAIL;
1931*ba1276acSMatthew Dillon 		goto out;
1932*ba1276acSMatthew Dillon 	}
1933*ba1276acSMatthew Dillon 	if (sshkey_type_is_cert(type)) {
1934*ba1276acSMatthew Dillon 		/* Skip nonce that precedes all certificates */
1935*ba1276acSMatthew Dillon 		if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
1936*ba1276acSMatthew Dillon 			ret = SSH_ERR_INVALID_FORMAT;
1937*ba1276acSMatthew Dillon 			goto out;
1938*ba1276acSMatthew Dillon 		}
1939*ba1276acSMatthew Dillon 	}
1940*ba1276acSMatthew Dillon 	if ((ret = impl->funcs->deserialize_public(ktype, b, key)) != 0)
1941*ba1276acSMatthew Dillon 		goto out;
194236e94dc5SPeter Avalos 
194336e94dc5SPeter Avalos 	/* Parse certificate potion */
1944e9778795SPeter Avalos 	if (sshkey_is_cert(key) && (ret = cert_parse(b, key, copy)) != 0)
194536e94dc5SPeter Avalos 		goto out;
194636e94dc5SPeter Avalos 
194736e94dc5SPeter Avalos 	if (key != NULL && sshbuf_len(b) != 0) {
194836e94dc5SPeter Avalos 		ret = SSH_ERR_INVALID_FORMAT;
194936e94dc5SPeter Avalos 		goto out;
195036e94dc5SPeter Avalos 	}
195136e94dc5SPeter Avalos 	ret = 0;
1952e9778795SPeter Avalos 	if (keyp != NULL) {
195336e94dc5SPeter Avalos 		*keyp = key;
195436e94dc5SPeter Avalos 		key = NULL;
1955e9778795SPeter Avalos 	}
195636e94dc5SPeter Avalos  out:
1957e9778795SPeter Avalos 	sshbuf_free(copy);
195836e94dc5SPeter Avalos 	sshkey_free(key);
195936e94dc5SPeter Avalos 	free(ktype);
196036e94dc5SPeter Avalos 	return ret;
196136e94dc5SPeter Avalos }
196236e94dc5SPeter Avalos 
196336e94dc5SPeter Avalos int
sshkey_from_blob(const u_char * blob,size_t blen,struct sshkey ** keyp)196436e94dc5SPeter Avalos sshkey_from_blob(const u_char *blob, size_t blen, struct sshkey **keyp)
196536e94dc5SPeter Avalos {
1966e9778795SPeter Avalos 	struct sshbuf *b;
1967e9778795SPeter Avalos 	int r;
1968e9778795SPeter Avalos 
1969e9778795SPeter Avalos 	if ((b = sshbuf_from(blob, blen)) == NULL)
1970e9778795SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
1971e9778795SPeter Avalos 	r = sshkey_from_blob_internal(b, keyp, 1);
1972e9778795SPeter Avalos 	sshbuf_free(b);
1973e9778795SPeter Avalos 	return r;
1974e9778795SPeter Avalos }
1975e9778795SPeter Avalos 
1976e9778795SPeter Avalos int
sshkey_fromb(struct sshbuf * b,struct sshkey ** keyp)1977e9778795SPeter Avalos sshkey_fromb(struct sshbuf *b, struct sshkey **keyp)
1978e9778795SPeter Avalos {
1979e9778795SPeter Avalos 	return sshkey_from_blob_internal(b, keyp, 1);
1980e9778795SPeter Avalos }
1981e9778795SPeter Avalos 
1982e9778795SPeter Avalos int
sshkey_froms(struct sshbuf * buf,struct sshkey ** keyp)1983e9778795SPeter Avalos sshkey_froms(struct sshbuf *buf, struct sshkey **keyp)
1984e9778795SPeter Avalos {
1985e9778795SPeter Avalos 	struct sshbuf *b;
1986e9778795SPeter Avalos 	int r;
1987e9778795SPeter Avalos 
1988e9778795SPeter Avalos 	if ((r = sshbuf_froms(buf, &b)) != 0)
1989e9778795SPeter Avalos 		return r;
1990e9778795SPeter Avalos 	r = sshkey_from_blob_internal(b, keyp, 1);
1991e9778795SPeter Avalos 	sshbuf_free(b);
1992e9778795SPeter Avalos 	return r;
199336e94dc5SPeter Avalos }
199436e94dc5SPeter Avalos 
19950cbfa66cSDaniel Fojt int
sshkey_get_sigtype(const u_char * sig,size_t siglen,char ** sigtypep)19960cbfa66cSDaniel Fojt sshkey_get_sigtype(const u_char *sig, size_t siglen, char **sigtypep)
1997664f4763Szrj {
1998664f4763Szrj 	int r;
1999664f4763Szrj 	struct sshbuf *b = NULL;
2000664f4763Szrj 	char *sigtype = NULL;
2001664f4763Szrj 
2002664f4763Szrj 	if (sigtypep != NULL)
2003664f4763Szrj 		*sigtypep = NULL;
2004664f4763Szrj 	if ((b = sshbuf_from(sig, siglen)) == NULL)
2005664f4763Szrj 		return SSH_ERR_ALLOC_FAIL;
2006664f4763Szrj 	if ((r = sshbuf_get_cstring(b, &sigtype, NULL)) != 0)
2007664f4763Szrj 		goto out;
2008664f4763Szrj 	/* success */
2009664f4763Szrj 	if (sigtypep != NULL) {
2010664f4763Szrj 		*sigtypep = sigtype;
2011664f4763Szrj 		sigtype = NULL;
2012664f4763Szrj 	}
2013664f4763Szrj 	r = 0;
2014664f4763Szrj  out:
2015664f4763Szrj 	free(sigtype);
2016664f4763Szrj 	sshbuf_free(b);
2017664f4763Szrj 	return r;
2018664f4763Szrj }
2019664f4763Szrj 
2020664f4763Szrj /*
2021664f4763Szrj  *
2022664f4763Szrj  * Checks whether a certificate's signature type is allowed.
2023664f4763Szrj  * Returns 0 (success) if the certificate signature type appears in the
2024664f4763Szrj  * "allowed" pattern-list, or the key is not a certificate to begin with.
2025664f4763Szrj  * Otherwise returns a ssherr.h code.
2026664f4763Szrj  */
2027664f4763Szrj int
sshkey_check_cert_sigtype(const struct sshkey * key,const char * allowed)2028664f4763Szrj sshkey_check_cert_sigtype(const struct sshkey *key, const char *allowed)
2029664f4763Szrj {
2030664f4763Szrj 	if (key == NULL || allowed == NULL)
2031664f4763Szrj 		return SSH_ERR_INVALID_ARGUMENT;
2032664f4763Szrj 	if (!sshkey_type_is_cert(key->type))
2033664f4763Szrj 		return 0;
2034664f4763Szrj 	if (key->cert == NULL || key->cert->signature_type == NULL)
2035664f4763Szrj 		return SSH_ERR_INVALID_ARGUMENT;
2036664f4763Szrj 	if (match_pattern_list(key->cert->signature_type, allowed, 0) != 1)
2037664f4763Szrj 		return SSH_ERR_SIGN_ALG_UNSUPPORTED;
2038664f4763Szrj 	return 0;
2039664f4763Szrj }
2040664f4763Szrj 
2041664f4763Szrj /*
2042664f4763Szrj  * Returns the expected signature algorithm for a given public key algorithm.
2043664f4763Szrj  */
2044664f4763Szrj const char *
sshkey_sigalg_by_name(const char * name)2045664f4763Szrj sshkey_sigalg_by_name(const char *name)
2046664f4763Szrj {
2047*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
2048*ba1276acSMatthew Dillon 	int i;
2049664f4763Szrj 
2050*ba1276acSMatthew Dillon 	for (i = 0; keyimpls[i] != NULL; i++) {
2051*ba1276acSMatthew Dillon 		impl = keyimpls[i];
2052*ba1276acSMatthew Dillon 		if (strcmp(impl->name, name) != 0)
2053664f4763Szrj 			continue;
2054*ba1276acSMatthew Dillon 		if (impl->sigalg != NULL)
2055*ba1276acSMatthew Dillon 			return impl->sigalg;
2056*ba1276acSMatthew Dillon 		if (!impl->cert)
2057*ba1276acSMatthew Dillon 			return impl->name;
2058664f4763Szrj 		return sshkey_ssh_name_from_type_nid(
2059*ba1276acSMatthew Dillon 		    sshkey_type_plain(impl->type), impl->nid);
2060664f4763Szrj 	}
2061664f4763Szrj 	return NULL;
2062664f4763Szrj }
2063664f4763Szrj 
2064664f4763Szrj /*
2065664f4763Szrj  * Verifies that the signature algorithm appearing inside the signature blob
2066664f4763Szrj  * matches that which was requested.
2067664f4763Szrj  */
2068664f4763Szrj int
sshkey_check_sigtype(const u_char * sig,size_t siglen,const char * requested_alg)2069664f4763Szrj sshkey_check_sigtype(const u_char *sig, size_t siglen,
2070664f4763Szrj     const char *requested_alg)
2071664f4763Szrj {
2072664f4763Szrj 	const char *expected_alg;
2073664f4763Szrj 	char *sigtype = NULL;
2074664f4763Szrj 	int r;
2075664f4763Szrj 
2076664f4763Szrj 	if (requested_alg == NULL)
2077664f4763Szrj 		return 0;
2078664f4763Szrj 	if ((expected_alg = sshkey_sigalg_by_name(requested_alg)) == NULL)
2079664f4763Szrj 		return SSH_ERR_INVALID_ARGUMENT;
20800cbfa66cSDaniel Fojt 	if ((r = sshkey_get_sigtype(sig, siglen, &sigtype)) != 0)
2081664f4763Szrj 		return r;
2082664f4763Szrj 	r = strcmp(expected_alg, sigtype) == 0;
2083664f4763Szrj 	free(sigtype);
2084664f4763Szrj 	return r ? 0 : SSH_ERR_SIGN_ALG_UNSUPPORTED;
2085664f4763Szrj }
2086664f4763Szrj 
208736e94dc5SPeter Avalos int
sshkey_sign(struct sshkey * key,u_char ** sigp,size_t * lenp,const u_char * data,size_t datalen,const char * alg,const char * sk_provider,const char * sk_pin,u_int compat)20880cbfa66cSDaniel Fojt sshkey_sign(struct sshkey *key,
208936e94dc5SPeter Avalos     u_char **sigp, size_t *lenp,
20900cbfa66cSDaniel Fojt     const u_char *data, size_t datalen,
209150a69bb5SSascha Wildner     const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
209236e94dc5SPeter Avalos {
20930cbfa66cSDaniel Fojt 	int was_shielded = sshkey_is_shielded(key);
20940cbfa66cSDaniel Fojt 	int r2, r = SSH_ERR_INTERNAL_ERROR;
2095*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
20960cbfa66cSDaniel Fojt 
209736e94dc5SPeter Avalos 	if (sigp != NULL)
209836e94dc5SPeter Avalos 		*sigp = NULL;
209936e94dc5SPeter Avalos 	if (lenp != NULL)
210036e94dc5SPeter Avalos 		*lenp = 0;
210136e94dc5SPeter Avalos 	if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE)
210236e94dc5SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
2103*ba1276acSMatthew Dillon 	if ((impl = sshkey_impl_from_key(key)) == NULL)
2104*ba1276acSMatthew Dillon 		return SSH_ERR_KEY_TYPE_UNKNOWN;
21050cbfa66cSDaniel Fojt 	if ((r = sshkey_unshield_private(key)) != 0)
21060cbfa66cSDaniel Fojt 		return r;
2107*ba1276acSMatthew Dillon 	if (sshkey_is_sk(key)) {
21080cbfa66cSDaniel Fojt 		r = sshsk_sign(sk_provider, key, sigp, lenp, data,
210950a69bb5SSascha Wildner 		    datalen, compat, sk_pin);
2110*ba1276acSMatthew Dillon 	} else {
2111*ba1276acSMatthew Dillon 		if (impl->funcs->sign == NULL)
2112*ba1276acSMatthew Dillon 			r = SSH_ERR_SIGN_ALG_UNSUPPORTED;
2113*ba1276acSMatthew Dillon 		else {
2114*ba1276acSMatthew Dillon 			r = impl->funcs->sign(key, sigp, lenp, data, datalen,
2115*ba1276acSMatthew Dillon 			    alg, sk_provider, sk_pin, compat);
2116*ba1276acSMatthew Dillon 		 }
211736e94dc5SPeter Avalos 	}
21180cbfa66cSDaniel Fojt 	if (was_shielded && (r2 = sshkey_shield_private(key)) != 0)
21190cbfa66cSDaniel Fojt 		return r2;
21200cbfa66cSDaniel Fojt 	return r;
212136e94dc5SPeter Avalos }
212236e94dc5SPeter Avalos 
212336e94dc5SPeter Avalos /*
212436e94dc5SPeter Avalos  * ssh_key_verify returns 0 for a correct signature  and < 0 on error.
2125664f4763Szrj  * If "alg" specified, then the signature must use that algorithm.
212636e94dc5SPeter Avalos  */
212736e94dc5SPeter Avalos int
sshkey_verify(const struct sshkey * key,const u_char * sig,size_t siglen,const u_char * data,size_t dlen,const char * alg,u_int compat,struct sshkey_sig_details ** detailsp)212836e94dc5SPeter Avalos sshkey_verify(const struct sshkey *key,
212936e94dc5SPeter Avalos     const u_char *sig, size_t siglen,
21300cbfa66cSDaniel Fojt     const u_char *data, size_t dlen, const char *alg, u_int compat,
21310cbfa66cSDaniel Fojt     struct sshkey_sig_details **detailsp)
213236e94dc5SPeter Avalos {
2133*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
2134*ba1276acSMatthew Dillon 
21350cbfa66cSDaniel Fojt 	if (detailsp != NULL)
21360cbfa66cSDaniel Fojt 		*detailsp = NULL;
2137e9778795SPeter Avalos 	if (siglen == 0 || dlen > SSH_KEY_MAX_SIGN_DATA_SIZE)
213836e94dc5SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
2139*ba1276acSMatthew Dillon 	if ((impl = sshkey_impl_from_key(key)) == NULL)
214036e94dc5SPeter Avalos 		return SSH_ERR_KEY_TYPE_UNKNOWN;
2141*ba1276acSMatthew Dillon 	return impl->funcs->verify(key, sig, siglen, data, dlen,
2142*ba1276acSMatthew Dillon 	    alg, compat, detailsp);
214336e94dc5SPeter Avalos }
214436e94dc5SPeter Avalos 
214536e94dc5SPeter Avalos /* Convert a plain key to their _CERT equivalent */
214636e94dc5SPeter Avalos int
sshkey_to_certified(struct sshkey * k)2147e9778795SPeter Avalos sshkey_to_certified(struct sshkey *k)
214836e94dc5SPeter Avalos {
214936e94dc5SPeter Avalos 	int newtype;
215036e94dc5SPeter Avalos 
2151*ba1276acSMatthew Dillon 	if ((newtype = sshkey_type_certified(k->type)) == -1)
215236e94dc5SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
215336e94dc5SPeter Avalos 	if ((k->cert = cert_new()) == NULL)
215436e94dc5SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
215536e94dc5SPeter Avalos 	k->type = newtype;
215636e94dc5SPeter Avalos 	return 0;
215736e94dc5SPeter Avalos }
215836e94dc5SPeter Avalos 
215936e94dc5SPeter Avalos /* Convert a certificate to its raw key equivalent */
216036e94dc5SPeter Avalos int
sshkey_drop_cert(struct sshkey * k)216136e94dc5SPeter Avalos sshkey_drop_cert(struct sshkey *k)
216236e94dc5SPeter Avalos {
216336e94dc5SPeter Avalos 	if (!sshkey_type_is_cert(k->type))
216436e94dc5SPeter Avalos 		return SSH_ERR_KEY_TYPE_UNKNOWN;
216536e94dc5SPeter Avalos 	cert_free(k->cert);
216636e94dc5SPeter Avalos 	k->cert = NULL;
216736e94dc5SPeter Avalos 	k->type = sshkey_type_plain(k->type);
216836e94dc5SPeter Avalos 	return 0;
216936e94dc5SPeter Avalos }
217036e94dc5SPeter Avalos 
217136e94dc5SPeter Avalos /* Sign a certified key, (re-)generating the signed certblob. */
217236e94dc5SPeter Avalos int
sshkey_certify_custom(struct sshkey * k,struct sshkey * ca,const char * alg,const char * sk_provider,const char * sk_pin,sshkey_certify_signer * signer,void * signer_ctx)2173ce74bacaSMatthew Dillon sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg,
217450a69bb5SSascha Wildner     const char *sk_provider, const char *sk_pin,
217550a69bb5SSascha Wildner     sshkey_certify_signer *signer, void *signer_ctx)
217636e94dc5SPeter Avalos {
2177*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
217836e94dc5SPeter Avalos 	struct sshbuf *principals = NULL;
217936e94dc5SPeter Avalos 	u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32];
218036e94dc5SPeter Avalos 	size_t i, ca_len, sig_len;
218136e94dc5SPeter Avalos 	int ret = SSH_ERR_INTERNAL_ERROR;
2182664f4763Szrj 	struct sshbuf *cert = NULL;
2183664f4763Szrj 	char *sigtype = NULL;
218436e94dc5SPeter Avalos 
218536e94dc5SPeter Avalos 	if (k == NULL || k->cert == NULL ||
218636e94dc5SPeter Avalos 	    k->cert->certblob == NULL || ca == NULL)
218736e94dc5SPeter Avalos 		return SSH_ERR_INVALID_ARGUMENT;
218836e94dc5SPeter Avalos 	if (!sshkey_is_cert(k))
218936e94dc5SPeter Avalos 		return SSH_ERR_KEY_TYPE_UNKNOWN;
219036e94dc5SPeter Avalos 	if (!sshkey_type_is_valid_ca(ca->type))
219136e94dc5SPeter Avalos 		return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
2192*ba1276acSMatthew Dillon 	if ((impl = sshkey_impl_from_key(k)) == NULL)
2193*ba1276acSMatthew Dillon 		return SSH_ERR_INTERNAL_ERROR;
219436e94dc5SPeter Avalos 
2195664f4763Szrj 	/*
2196664f4763Szrj 	 * If no alg specified as argument but a signature_type was set,
2197664f4763Szrj 	 * then prefer that. If both were specified, then they must match.
2198664f4763Szrj 	 */
2199664f4763Szrj 	if (alg == NULL)
2200664f4763Szrj 		alg = k->cert->signature_type;
2201664f4763Szrj 	else if (k->cert->signature_type != NULL &&
2202664f4763Szrj 	    strcmp(alg, k->cert->signature_type) != 0)
2203664f4763Szrj 		return SSH_ERR_INVALID_ARGUMENT;
2204664f4763Szrj 
22050cbfa66cSDaniel Fojt 	/*
22060cbfa66cSDaniel Fojt 	 * If no signing algorithm or signature_type was specified and we're
22070cbfa66cSDaniel Fojt 	 * using a RSA key, then default to a good signature algorithm.
22080cbfa66cSDaniel Fojt 	 */
22090cbfa66cSDaniel Fojt 	if (alg == NULL && ca->type == KEY_RSA)
22100cbfa66cSDaniel Fojt 		alg = "rsa-sha2-512";
22110cbfa66cSDaniel Fojt 
221236e94dc5SPeter Avalos 	if ((ret = sshkey_to_blob(ca, &ca_blob, &ca_len)) != 0)
221336e94dc5SPeter Avalos 		return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
221436e94dc5SPeter Avalos 
221536e94dc5SPeter Avalos 	cert = k->cert->certblob; /* for readability */
221636e94dc5SPeter Avalos 	sshbuf_reset(cert);
221736e94dc5SPeter Avalos 	if ((ret = sshbuf_put_cstring(cert, sshkey_ssh_name(k))) != 0)
221836e94dc5SPeter Avalos 		goto out;
221936e94dc5SPeter Avalos 
222036e94dc5SPeter Avalos 	/* -v01 certs put nonce first */
222136e94dc5SPeter Avalos 	arc4random_buf(&nonce, sizeof(nonce));
222236e94dc5SPeter Avalos 	if ((ret = sshbuf_put_string(cert, nonce, sizeof(nonce))) != 0)
222336e94dc5SPeter Avalos 		goto out;
222436e94dc5SPeter Avalos 
2225*ba1276acSMatthew Dillon 	/* Public key next */
2226*ba1276acSMatthew Dillon 	if ((ret = impl->funcs->serialize_public(k, cert,
2227*ba1276acSMatthew Dillon 	    SSHKEY_SERIALIZE_DEFAULT)) != 0)
222836e94dc5SPeter Avalos 		goto out;
222936e94dc5SPeter Avalos 
2230*ba1276acSMatthew Dillon 	/* Then remaining cert fields */
2231e9778795SPeter Avalos 	if ((ret = sshbuf_put_u64(cert, k->cert->serial)) != 0 ||
2232e9778795SPeter Avalos 	    (ret = sshbuf_put_u32(cert, k->cert->type)) != 0 ||
223336e94dc5SPeter Avalos 	    (ret = sshbuf_put_cstring(cert, k->cert->key_id)) != 0)
223436e94dc5SPeter Avalos 		goto out;
223536e94dc5SPeter Avalos 
223636e94dc5SPeter Avalos 	if ((principals = sshbuf_new()) == NULL) {
223736e94dc5SPeter Avalos 		ret = SSH_ERR_ALLOC_FAIL;
223836e94dc5SPeter Avalos 		goto out;
223936e94dc5SPeter Avalos 	}
224036e94dc5SPeter Avalos 	for (i = 0; i < k->cert->nprincipals; i++) {
224136e94dc5SPeter Avalos 		if ((ret = sshbuf_put_cstring(principals,
224236e94dc5SPeter Avalos 		    k->cert->principals[i])) != 0)
224336e94dc5SPeter Avalos 			goto out;
224436e94dc5SPeter Avalos 	}
224536e94dc5SPeter Avalos 	if ((ret = sshbuf_put_stringb(cert, principals)) != 0 ||
224636e94dc5SPeter Avalos 	    (ret = sshbuf_put_u64(cert, k->cert->valid_after)) != 0 ||
224736e94dc5SPeter Avalos 	    (ret = sshbuf_put_u64(cert, k->cert->valid_before)) != 0 ||
2248e9778795SPeter Avalos 	    (ret = sshbuf_put_stringb(cert, k->cert->critical)) != 0 ||
2249e9778795SPeter Avalos 	    (ret = sshbuf_put_stringb(cert, k->cert->extensions)) != 0 ||
2250e9778795SPeter Avalos 	    (ret = sshbuf_put_string(cert, NULL, 0)) != 0 || /* Reserved */
225136e94dc5SPeter Avalos 	    (ret = sshbuf_put_string(cert, ca_blob, ca_len)) != 0)
225236e94dc5SPeter Avalos 		goto out;
225336e94dc5SPeter Avalos 
225436e94dc5SPeter Avalos 	/* Sign the whole mess */
2255ce74bacaSMatthew Dillon 	if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert),
225650a69bb5SSascha Wildner 	    sshbuf_len(cert), alg, sk_provider, sk_pin, 0, signer_ctx)) != 0)
225736e94dc5SPeter Avalos 		goto out;
2258664f4763Szrj 	/* Check and update signature_type against what was actually used */
22590cbfa66cSDaniel Fojt 	if ((ret = sshkey_get_sigtype(sig_blob, sig_len, &sigtype)) != 0)
2260664f4763Szrj 		goto out;
2261664f4763Szrj 	if (alg != NULL && strcmp(alg, sigtype) != 0) {
2262664f4763Szrj 		ret = SSH_ERR_SIGN_ALG_UNSUPPORTED;
2263664f4763Szrj 		goto out;
2264664f4763Szrj 	}
2265664f4763Szrj 	if (k->cert->signature_type == NULL) {
2266664f4763Szrj 		k->cert->signature_type = sigtype;
2267664f4763Szrj 		sigtype = NULL;
2268664f4763Szrj 	}
226936e94dc5SPeter Avalos 	/* Append signature and we are done */
227036e94dc5SPeter Avalos 	if ((ret = sshbuf_put_string(cert, sig_blob, sig_len)) != 0)
227136e94dc5SPeter Avalos 		goto out;
227236e94dc5SPeter Avalos 	ret = 0;
227336e94dc5SPeter Avalos  out:
227436e94dc5SPeter Avalos 	if (ret != 0)
227536e94dc5SPeter Avalos 		sshbuf_reset(cert);
227636e94dc5SPeter Avalos 	free(sig_blob);
227736e94dc5SPeter Avalos 	free(ca_blob);
2278664f4763Szrj 	free(sigtype);
227936e94dc5SPeter Avalos 	sshbuf_free(principals);
228036e94dc5SPeter Avalos 	return ret;
228136e94dc5SPeter Avalos }
228236e94dc5SPeter Avalos 
2283ce74bacaSMatthew Dillon static int
default_key_sign(struct sshkey * key,u_char ** sigp,size_t * lenp,const u_char * data,size_t datalen,const char * alg,const char * sk_provider,const char * sk_pin,u_int compat,void * ctx)22840cbfa66cSDaniel Fojt default_key_sign(struct sshkey *key, u_char **sigp, size_t *lenp,
2285ce74bacaSMatthew Dillon     const u_char *data, size_t datalen,
228650a69bb5SSascha Wildner     const char *alg, const char *sk_provider, const char *sk_pin,
228750a69bb5SSascha Wildner     u_int compat, void *ctx)
2288ce74bacaSMatthew Dillon {
2289ce74bacaSMatthew Dillon 	if (ctx != NULL)
2290ce74bacaSMatthew Dillon 		return SSH_ERR_INVALID_ARGUMENT;
22910cbfa66cSDaniel Fojt 	return sshkey_sign(key, sigp, lenp, data, datalen, alg,
229250a69bb5SSascha Wildner 	    sk_provider, sk_pin, compat);
2293ce74bacaSMatthew Dillon }
2294ce74bacaSMatthew Dillon 
2295ce74bacaSMatthew Dillon int
sshkey_certify(struct sshkey * k,struct sshkey * ca,const char * alg,const char * sk_provider,const char * sk_pin)22960cbfa66cSDaniel Fojt sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg,
229750a69bb5SSascha Wildner     const char *sk_provider, const char *sk_pin)
2298ce74bacaSMatthew Dillon {
229950a69bb5SSascha Wildner 	return sshkey_certify_custom(k, ca, alg, sk_provider, sk_pin,
23000cbfa66cSDaniel Fojt 	    default_key_sign, NULL);
2301ce74bacaSMatthew Dillon }
2302ce74bacaSMatthew Dillon 
230336e94dc5SPeter Avalos int
sshkey_cert_check_authority(const struct sshkey * k,int want_host,int require_principal,int wildcard_pattern,uint64_t verify_time,const char * name,const char ** reason)230436e94dc5SPeter Avalos sshkey_cert_check_authority(const struct sshkey *k,
230550a69bb5SSascha Wildner     int want_host, int require_principal, int wildcard_pattern,
230650a69bb5SSascha Wildner     uint64_t verify_time, const char *name, const char **reason)
230736e94dc5SPeter Avalos {
230836e94dc5SPeter Avalos 	u_int i, principal_matches;
230936e94dc5SPeter Avalos 
23100cbfa66cSDaniel Fojt 	if (reason == NULL)
23110cbfa66cSDaniel Fojt 		return SSH_ERR_INVALID_ARGUMENT;
231250a69bb5SSascha Wildner 	if (!sshkey_is_cert(k)) {
231350a69bb5SSascha Wildner 		*reason = "Key is not a certificate";
231450a69bb5SSascha Wildner 		return SSH_ERR_KEY_CERT_INVALID;
231550a69bb5SSascha Wildner 	}
231636e94dc5SPeter Avalos 	if (want_host) {
231736e94dc5SPeter Avalos 		if (k->cert->type != SSH2_CERT_TYPE_HOST) {
231836e94dc5SPeter Avalos 			*reason = "Certificate invalid: not a host certificate";
231936e94dc5SPeter Avalos 			return SSH_ERR_KEY_CERT_INVALID;
232036e94dc5SPeter Avalos 		}
232136e94dc5SPeter Avalos 	} else {
232236e94dc5SPeter Avalos 		if (k->cert->type != SSH2_CERT_TYPE_USER) {
232336e94dc5SPeter Avalos 			*reason = "Certificate invalid: not a user certificate";
232436e94dc5SPeter Avalos 			return SSH_ERR_KEY_CERT_INVALID;
232536e94dc5SPeter Avalos 		}
232636e94dc5SPeter Avalos 	}
232750a69bb5SSascha Wildner 	if (verify_time < k->cert->valid_after) {
232836e94dc5SPeter Avalos 		*reason = "Certificate invalid: not yet valid";
232936e94dc5SPeter Avalos 		return SSH_ERR_KEY_CERT_INVALID;
233036e94dc5SPeter Avalos 	}
233150a69bb5SSascha Wildner 	if (verify_time >= k->cert->valid_before) {
233236e94dc5SPeter Avalos 		*reason = "Certificate invalid: expired";
233336e94dc5SPeter Avalos 		return SSH_ERR_KEY_CERT_INVALID;
233436e94dc5SPeter Avalos 	}
233536e94dc5SPeter Avalos 	if (k->cert->nprincipals == 0) {
233636e94dc5SPeter Avalos 		if (require_principal) {
233736e94dc5SPeter Avalos 			*reason = "Certificate lacks principal list";
233836e94dc5SPeter Avalos 			return SSH_ERR_KEY_CERT_INVALID;
233936e94dc5SPeter Avalos 		}
234036e94dc5SPeter Avalos 	} else if (name != NULL) {
234136e94dc5SPeter Avalos 		principal_matches = 0;
234236e94dc5SPeter Avalos 		for (i = 0; i < k->cert->nprincipals; i++) {
234350a69bb5SSascha Wildner 			if (wildcard_pattern) {
234450a69bb5SSascha Wildner 				if (match_pattern(k->cert->principals[i],
234550a69bb5SSascha Wildner 				    name)) {
234650a69bb5SSascha Wildner 					principal_matches = 1;
234750a69bb5SSascha Wildner 					break;
234850a69bb5SSascha Wildner 				}
234950a69bb5SSascha Wildner 			} else if (strcmp(name, k->cert->principals[i]) == 0) {
235036e94dc5SPeter Avalos 				principal_matches = 1;
235136e94dc5SPeter Avalos 				break;
235236e94dc5SPeter Avalos 			}
235336e94dc5SPeter Avalos 		}
235436e94dc5SPeter Avalos 		if (!principal_matches) {
235536e94dc5SPeter Avalos 			*reason = "Certificate invalid: name is not a listed "
235636e94dc5SPeter Avalos 			    "principal";
235736e94dc5SPeter Avalos 			return SSH_ERR_KEY_CERT_INVALID;
235836e94dc5SPeter Avalos 		}
235936e94dc5SPeter Avalos 	}
236036e94dc5SPeter Avalos 	return 0;
236136e94dc5SPeter Avalos }
236236e94dc5SPeter Avalos 
236350a69bb5SSascha Wildner int
sshkey_cert_check_authority_now(const struct sshkey * k,int want_host,int require_principal,int wildcard_pattern,const char * name,const char ** reason)236450a69bb5SSascha Wildner sshkey_cert_check_authority_now(const struct sshkey *k,
236550a69bb5SSascha Wildner     int want_host, int require_principal, int wildcard_pattern,
236650a69bb5SSascha Wildner     const char *name, const char **reason)
236750a69bb5SSascha Wildner {
236850a69bb5SSascha Wildner 	time_t now;
236950a69bb5SSascha Wildner 
237050a69bb5SSascha Wildner 	if ((now = time(NULL)) < 0) {
237150a69bb5SSascha Wildner 		/* yikes - system clock before epoch! */
237250a69bb5SSascha Wildner 		*reason = "Certificate invalid: not yet valid";
237350a69bb5SSascha Wildner 		return SSH_ERR_KEY_CERT_INVALID;
237450a69bb5SSascha Wildner 	}
237550a69bb5SSascha Wildner 	return sshkey_cert_check_authority(k, want_host, require_principal,
237650a69bb5SSascha Wildner 	    wildcard_pattern, (uint64_t)now, name, reason);
237750a69bb5SSascha Wildner }
237850a69bb5SSascha Wildner 
237950a69bb5SSascha Wildner int
sshkey_cert_check_host(const struct sshkey * key,const char * host,int wildcard_principals,const char * ca_sign_algorithms,const char ** reason)238050a69bb5SSascha Wildner sshkey_cert_check_host(const struct sshkey *key, const char *host,
238150a69bb5SSascha Wildner     int wildcard_principals, const char *ca_sign_algorithms,
238250a69bb5SSascha Wildner     const char **reason)
238350a69bb5SSascha Wildner {
238450a69bb5SSascha Wildner 	int r;
238550a69bb5SSascha Wildner 
238650a69bb5SSascha Wildner 	if ((r = sshkey_cert_check_authority_now(key, 1, 0, wildcard_principals,
238750a69bb5SSascha Wildner 	    host, reason)) != 0)
238850a69bb5SSascha Wildner 		return r;
238950a69bb5SSascha Wildner 	if (sshbuf_len(key->cert->critical) != 0) {
239050a69bb5SSascha Wildner 		*reason = "Certificate contains unsupported critical options";
239150a69bb5SSascha Wildner 		return SSH_ERR_KEY_CERT_INVALID;
239250a69bb5SSascha Wildner 	}
239350a69bb5SSascha Wildner 	if (ca_sign_algorithms != NULL &&
239450a69bb5SSascha Wildner 	    (r = sshkey_check_cert_sigtype(key, ca_sign_algorithms)) != 0) {
239550a69bb5SSascha Wildner 		*reason = "Certificate signed with disallowed algorithm";
239650a69bb5SSascha Wildner 		return SSH_ERR_KEY_CERT_INVALID;
239750a69bb5SSascha Wildner 	}
239850a69bb5SSascha Wildner 	return 0;
239950a69bb5SSascha Wildner }
240050a69bb5SSascha Wildner 
2401e9778795SPeter Avalos size_t
sshkey_format_cert_validity(const struct sshkey_cert * cert,char * s,size_t l)2402e9778795SPeter Avalos sshkey_format_cert_validity(const struct sshkey_cert *cert, char *s, size_t l)
2403e9778795SPeter Avalos {
240450a69bb5SSascha Wildner 	char from[32], to[32], ret[128];
2405e9778795SPeter Avalos 
2406e9778795SPeter Avalos 	*from = *to = '\0';
2407e9778795SPeter Avalos 	if (cert->valid_after == 0 &&
2408e9778795SPeter Avalos 	    cert->valid_before == 0xffffffffffffffffULL)
2409e9778795SPeter Avalos 		return strlcpy(s, "forever", l);
2410e9778795SPeter Avalos 
241150a69bb5SSascha Wildner 	if (cert->valid_after != 0)
241250a69bb5SSascha Wildner 		format_absolute_time(cert->valid_after, from, sizeof(from));
241350a69bb5SSascha Wildner 	if (cert->valid_before != 0xffffffffffffffffULL)
241450a69bb5SSascha Wildner 		format_absolute_time(cert->valid_before, to, sizeof(to));
2415e9778795SPeter Avalos 
2416e9778795SPeter Avalos 	if (cert->valid_after == 0)
2417e9778795SPeter Avalos 		snprintf(ret, sizeof(ret), "before %s", to);
2418e9778795SPeter Avalos 	else if (cert->valid_before == 0xffffffffffffffffULL)
2419e9778795SPeter Avalos 		snprintf(ret, sizeof(ret), "after %s", from);
2420e9778795SPeter Avalos 	else
2421e9778795SPeter Avalos 		snprintf(ret, sizeof(ret), "from %s to %s", from, to);
2422e9778795SPeter Avalos 
2423e9778795SPeter Avalos 	return strlcpy(s, ret, l);
2424e9778795SPeter Avalos }
2425e9778795SPeter Avalos 
2426*ba1276acSMatthew Dillon /* Common serialization for FIDO private keys */
2427*ba1276acSMatthew Dillon int
sshkey_serialize_private_sk(const struct sshkey * key,struct sshbuf * b)2428*ba1276acSMatthew Dillon sshkey_serialize_private_sk(const struct sshkey *key, struct sshbuf *b)
2429*ba1276acSMatthew Dillon {
2430*ba1276acSMatthew Dillon 	int r;
2431*ba1276acSMatthew Dillon 
2432*ba1276acSMatthew Dillon 	if ((r = sshbuf_put_cstring(b, key->sk_application)) != 0 ||
2433*ba1276acSMatthew Dillon 	    (r = sshbuf_put_u8(b, key->sk_flags)) != 0 ||
2434*ba1276acSMatthew Dillon 	    (r = sshbuf_put_stringb(b, key->sk_key_handle)) != 0 ||
2435*ba1276acSMatthew Dillon 	    (r = sshbuf_put_stringb(b, key->sk_reserved)) != 0)
2436*ba1276acSMatthew Dillon 		return r;
2437*ba1276acSMatthew Dillon 
2438*ba1276acSMatthew Dillon 	return 0;
2439*ba1276acSMatthew Dillon }
2440*ba1276acSMatthew Dillon 
244136e94dc5SPeter Avalos int
sshkey_private_serialize_opt(struct sshkey * key,struct sshbuf * buf,enum sshkey_serialize_rep opts)24420cbfa66cSDaniel Fojt sshkey_private_serialize_opt(struct sshkey *key, struct sshbuf *buf,
2443664f4763Szrj     enum sshkey_serialize_rep opts)
244436e94dc5SPeter Avalos {
244536e94dc5SPeter Avalos 	int r = SSH_ERR_INTERNAL_ERROR;
24460cbfa66cSDaniel Fojt 	int was_shielded = sshkey_is_shielded(key);
24470cbfa66cSDaniel Fojt 	struct sshbuf *b = NULL;
2448*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
244936e94dc5SPeter Avalos 
2450*ba1276acSMatthew Dillon 	if ((impl = sshkey_impl_from_key(key)) == NULL)
2451*ba1276acSMatthew Dillon 		return SSH_ERR_INTERNAL_ERROR;
24520cbfa66cSDaniel Fojt 	if ((r = sshkey_unshield_private(key)) != 0)
24530cbfa66cSDaniel Fojt 		return r;
24540cbfa66cSDaniel Fojt 	if ((b = sshbuf_new()) == NULL)
24550cbfa66cSDaniel Fojt 		return SSH_ERR_ALLOC_FAIL;
245636e94dc5SPeter Avalos 	if ((r = sshbuf_put_cstring(b, sshkey_ssh_name(key))) != 0)
245736e94dc5SPeter Avalos 		goto out;
2458*ba1276acSMatthew Dillon 	if (sshkey_is_cert(key)) {
2459*ba1276acSMatthew Dillon 		if (key->cert == NULL ||
2460*ba1276acSMatthew Dillon 		    sshbuf_len(key->cert->certblob) == 0) {
246136e94dc5SPeter Avalos 			r = SSH_ERR_INVALID_ARGUMENT;
246236e94dc5SPeter Avalos 			goto out;
246336e94dc5SPeter Avalos 		}
2464*ba1276acSMatthew Dillon 		if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0)
246536e94dc5SPeter Avalos 			goto out;
246636e94dc5SPeter Avalos 	}
2467*ba1276acSMatthew Dillon 	if ((r = impl->funcs->serialize_private(key, b, opts)) != 0)
246836e94dc5SPeter Avalos 		goto out;
2469*ba1276acSMatthew Dillon 
24700cbfa66cSDaniel Fojt 	/*
24710cbfa66cSDaniel Fojt 	 * success (but we still need to append the output to buf after
24720cbfa66cSDaniel Fojt 	 * possibly re-shielding the private key)
24730cbfa66cSDaniel Fojt 	 */
247436e94dc5SPeter Avalos 	r = 0;
247536e94dc5SPeter Avalos  out:
24760cbfa66cSDaniel Fojt 	if (was_shielded)
24770cbfa66cSDaniel Fojt 		r = sshkey_shield_private(key);
24780cbfa66cSDaniel Fojt 	if (r == 0)
24790cbfa66cSDaniel Fojt 		r = sshbuf_putb(buf, b);
24800cbfa66cSDaniel Fojt 	sshbuf_free(b);
24810cbfa66cSDaniel Fojt 
248236e94dc5SPeter Avalos 	return r;
248336e94dc5SPeter Avalos }
248436e94dc5SPeter Avalos 
248536e94dc5SPeter Avalos int
sshkey_private_serialize(struct sshkey * key,struct sshbuf * b)24860cbfa66cSDaniel Fojt sshkey_private_serialize(struct sshkey *key, struct sshbuf *b)
2487664f4763Szrj {
2488664f4763Szrj 	return sshkey_private_serialize_opt(key, b,
2489664f4763Szrj 	    SSHKEY_SERIALIZE_DEFAULT);
2490664f4763Szrj }
2491664f4763Szrj 
2492*ba1276acSMatthew Dillon /* Shared deserialization of FIDO private key components */
2493*ba1276acSMatthew Dillon int
sshkey_private_deserialize_sk(struct sshbuf * buf,struct sshkey * k)2494*ba1276acSMatthew Dillon sshkey_private_deserialize_sk(struct sshbuf *buf, struct sshkey *k)
2495*ba1276acSMatthew Dillon {
2496*ba1276acSMatthew Dillon 	int r;
2497*ba1276acSMatthew Dillon 
2498*ba1276acSMatthew Dillon 	if ((k->sk_key_handle = sshbuf_new()) == NULL ||
2499*ba1276acSMatthew Dillon 	    (k->sk_reserved = sshbuf_new()) == NULL)
2500*ba1276acSMatthew Dillon 		return SSH_ERR_ALLOC_FAIL;
2501*ba1276acSMatthew Dillon 	if ((r = sshbuf_get_cstring(buf, &k->sk_application, NULL)) != 0 ||
2502*ba1276acSMatthew Dillon 	    (r = sshbuf_get_u8(buf, &k->sk_flags)) != 0 ||
2503*ba1276acSMatthew Dillon 	    (r = sshbuf_get_stringb(buf, k->sk_key_handle)) != 0 ||
2504*ba1276acSMatthew Dillon 	    (r = sshbuf_get_stringb(buf, k->sk_reserved)) != 0)
2505*ba1276acSMatthew Dillon 		return r;
2506*ba1276acSMatthew Dillon 
2507*ba1276acSMatthew Dillon 	return 0;
2508*ba1276acSMatthew Dillon }
2509*ba1276acSMatthew Dillon 
2510664f4763Szrj int
sshkey_private_deserialize(struct sshbuf * buf,struct sshkey ** kp)251136e94dc5SPeter Avalos sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
251236e94dc5SPeter Avalos {
2513*ba1276acSMatthew Dillon 	const struct sshkey_impl *impl;
2514*ba1276acSMatthew Dillon 	char *tname = NULL;
251550a69bb5SSascha Wildner 	char *expect_sk_application = NULL;
251650a69bb5SSascha Wildner 	u_char *expect_ed25519_pk = NULL;
2517*ba1276acSMatthew Dillon 	struct sshkey *k = NULL;
2518*ba1276acSMatthew Dillon 	int type, r = SSH_ERR_INTERNAL_ERROR;
251936e94dc5SPeter Avalos 
252036e94dc5SPeter Avalos 	if (kp != NULL)
252136e94dc5SPeter Avalos 		*kp = NULL;
252236e94dc5SPeter Avalos 	if ((r = sshbuf_get_cstring(buf, &tname, NULL)) != 0)
252336e94dc5SPeter Avalos 		goto out;
252436e94dc5SPeter Avalos 	type = sshkey_type_from_name(tname);
25250cbfa66cSDaniel Fojt 	if (sshkey_type_is_cert(type)) {
25260cbfa66cSDaniel Fojt 		/*
25270cbfa66cSDaniel Fojt 		 * Certificate key private keys begin with the certificate
25280cbfa66cSDaniel Fojt 		 * itself. Make sure this matches the type of the enclosing
25290cbfa66cSDaniel Fojt 		 * private key.
25300cbfa66cSDaniel Fojt 		 */
25310cbfa66cSDaniel Fojt 		if ((r = sshkey_froms(buf, &k)) != 0)
25320cbfa66cSDaniel Fojt 			goto out;
25330cbfa66cSDaniel Fojt 		if (k->type != type) {
25340cbfa66cSDaniel Fojt 			r = SSH_ERR_KEY_CERT_MISMATCH;
25350cbfa66cSDaniel Fojt 			goto out;
25360cbfa66cSDaniel Fojt 		}
25370cbfa66cSDaniel Fojt 		/* For ECDSA keys, the group must match too */
25380cbfa66cSDaniel Fojt 		if (k->type == KEY_ECDSA &&
25390cbfa66cSDaniel Fojt 		    k->ecdsa_nid != sshkey_ecdsa_nid_from_name(tname)) {
25400cbfa66cSDaniel Fojt 			r = SSH_ERR_KEY_CERT_MISMATCH;
25410cbfa66cSDaniel Fojt 			goto out;
25420cbfa66cSDaniel Fojt 		}
254350a69bb5SSascha Wildner 		/*
254450a69bb5SSascha Wildner 		 * Several fields are redundant between certificate and
254550a69bb5SSascha Wildner 		 * private key body, we require these to match.
254650a69bb5SSascha Wildner 		 */
254750a69bb5SSascha Wildner 		expect_sk_application = k->sk_application;
254850a69bb5SSascha Wildner 		expect_ed25519_pk = k->ed25519_pk;
254950a69bb5SSascha Wildner 		k->sk_application = NULL;
255050a69bb5SSascha Wildner 		k->ed25519_pk = NULL;
2551*ba1276acSMatthew Dillon 		/* XXX xmss too or refactor */
25520cbfa66cSDaniel Fojt 	} else {
2553664f4763Szrj 		if ((k = sshkey_new(type)) == NULL) {
255436e94dc5SPeter Avalos 			r = SSH_ERR_ALLOC_FAIL;
255536e94dc5SPeter Avalos 			goto out;
255636e94dc5SPeter Avalos 		}
25570cbfa66cSDaniel Fojt 	}
2558*ba1276acSMatthew Dillon 	if ((impl = sshkey_impl_from_type(type)) == NULL) {
2559*ba1276acSMatthew Dillon 		r = SSH_ERR_INTERNAL_ERROR;
2560664f4763Szrj 		goto out;
2561664f4763Szrj 	}
2562*ba1276acSMatthew Dillon 	if ((r = impl->funcs->deserialize_private(tname, buf, k)) != 0)
2563664f4763Szrj 		goto out;
2564*ba1276acSMatthew Dillon 
2565*ba1276acSMatthew Dillon 	/* XXX xmss too or refactor */
256650a69bb5SSascha Wildner 	if ((expect_sk_application != NULL && (k->sk_application == NULL ||
256750a69bb5SSascha Wildner 	    strcmp(expect_sk_application, k->sk_application) != 0)) ||
256850a69bb5SSascha Wildner 	    (expect_ed25519_pk != NULL && (k->ed25519_pk == NULL ||
256950a69bb5SSascha Wildner 	    memcmp(expect_ed25519_pk, k->ed25519_pk, ED25519_PK_SZ) != 0))) {
257050a69bb5SSascha Wildner 		r = SSH_ERR_KEY_CERT_MISMATCH;
257150a69bb5SSascha Wildner 		goto out;
257250a69bb5SSascha Wildner 	}
257336e94dc5SPeter Avalos 	/* success */
257436e94dc5SPeter Avalos 	r = 0;
257536e94dc5SPeter Avalos 	if (kp != NULL) {
257636e94dc5SPeter Avalos 		*kp = k;
257736e94dc5SPeter Avalos 		k = NULL;
257836e94dc5SPeter Avalos 	}
257936e94dc5SPeter Avalos  out:
258036e94dc5SPeter Avalos 	free(tname);
258136e94dc5SPeter Avalos 	sshkey_free(k);
258250a69bb5SSascha Wildner 	free(expect_sk_application);
258350a69bb5SSascha Wildner 	free(expect_ed25519_pk);
258436e94dc5SPeter Avalos 	return r;
258536e94dc5SPeter Avalos }
258636e94dc5SPeter Avalos 
258736e94dc5SPeter Avalos #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
258836e94dc5SPeter Avalos int
sshkey_ec_validate_public(const EC_GROUP * group,const EC_POINT * public)258936e94dc5SPeter Avalos sshkey_ec_validate_public(const EC_GROUP *group, const EC_POINT *public)
259036e94dc5SPeter Avalos {
259136e94dc5SPeter Avalos 	EC_POINT *nq = NULL;
25920cbfa66cSDaniel Fojt 	BIGNUM *order = NULL, *x = NULL, *y = NULL, *tmp = NULL;
259336e94dc5SPeter Avalos 	int ret = SSH_ERR_KEY_INVALID_EC_VALUE;
259436e94dc5SPeter Avalos 
2595ce74bacaSMatthew Dillon 	/*
2596ce74bacaSMatthew Dillon 	 * NB. This assumes OpenSSL has already verified that the public
2597ce74bacaSMatthew Dillon 	 * point lies on the curve. This is done by EC_POINT_oct2point()
2598ce74bacaSMatthew Dillon 	 * implicitly calling EC_POINT_is_on_curve(). If this code is ever
2599ce74bacaSMatthew Dillon 	 * reachable with public points not unmarshalled using
2600ce74bacaSMatthew Dillon 	 * EC_POINT_oct2point then the caller will need to explicitly check.
2601ce74bacaSMatthew Dillon 	 */
2602ce74bacaSMatthew Dillon 
260336e94dc5SPeter Avalos 	/*
260436e94dc5SPeter Avalos 	 * We shouldn't ever hit this case because bignum_get_ecpoint()
260536e94dc5SPeter Avalos 	 * refuses to load GF2m points.
260636e94dc5SPeter Avalos 	 */
260736e94dc5SPeter Avalos 	if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
260836e94dc5SPeter Avalos 	    NID_X9_62_prime_field)
260936e94dc5SPeter Avalos 		goto out;
261036e94dc5SPeter Avalos 
261136e94dc5SPeter Avalos 	/* Q != infinity */
261236e94dc5SPeter Avalos 	if (EC_POINT_is_at_infinity(group, public))
261336e94dc5SPeter Avalos 		goto out;
261436e94dc5SPeter Avalos 
26150cbfa66cSDaniel Fojt 	if ((x = BN_new()) == NULL ||
26160cbfa66cSDaniel Fojt 	    (y = BN_new()) == NULL ||
26170cbfa66cSDaniel Fojt 	    (order = BN_new()) == NULL ||
26180cbfa66cSDaniel Fojt 	    (tmp = BN_new()) == NULL) {
261936e94dc5SPeter Avalos 		ret = SSH_ERR_ALLOC_FAIL;
262036e94dc5SPeter Avalos 		goto out;
262136e94dc5SPeter Avalos 	}
262236e94dc5SPeter Avalos 
262336e94dc5SPeter Avalos 	/* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */
26240cbfa66cSDaniel Fojt 	if (EC_GROUP_get_order(group, order, NULL) != 1 ||
262536e94dc5SPeter Avalos 	    EC_POINT_get_affine_coordinates_GFp(group, public,
26260cbfa66cSDaniel Fojt 	    x, y, NULL) != 1) {
262736e94dc5SPeter Avalos 		ret = SSH_ERR_LIBCRYPTO_ERROR;
262836e94dc5SPeter Avalos 		goto out;
262936e94dc5SPeter Avalos 	}
263036e94dc5SPeter Avalos 	if (BN_num_bits(x) <= BN_num_bits(order) / 2 ||
263136e94dc5SPeter Avalos 	    BN_num_bits(y) <= BN_num_bits(order) / 2)
263236e94dc5SPeter Avalos 		goto out;
263336e94dc5SPeter Avalos 
263436e94dc5SPeter Avalos 	/* nQ == infinity (n == order of subgroup) */
263536e94dc5SPeter Avalos 	if ((nq = EC_POINT_new(group)) == NULL) {
263636e94dc5SPeter Avalos 		ret = SSH_ERR_ALLOC_FAIL;
263736e94dc5SPeter Avalos 		goto out;
263836e94dc5SPeter Avalos 	}
26390cbfa66cSDaniel Fojt 	if (EC_POINT_mul(group, nq, NULL, public, order, NULL) != 1) {
264036e94dc5SPeter Avalos 		ret = SSH_ERR_LIBCRYPTO_ERROR;
264136e94dc5SPeter Avalos 		goto out;
264236e94dc5SPeter Avalos 	}
264336e94dc5SPeter Avalos 	if (EC_POINT_is_at_infinity(group, nq) != 1)
264436e94dc5SPeter Avalos 		goto out;
264536e94dc5SPeter Avalos 
264636e94dc5SPeter Avalos 	/* x < order - 1, y < order - 1 */
264736e94dc5SPeter Avalos 	if (!BN_sub(tmp, order, BN_value_one())) {
264836e94dc5SPeter Avalos 		ret = SSH_ERR_LIBCRYPTO_ERROR;
264936e94dc5SPeter Avalos 		goto out;
265036e94dc5SPeter Avalos 	}
265136e94dc5SPeter Avalos 	if (BN_cmp(x, tmp) >= 0 || BN_cmp(y, tmp) >= 0)
265236e94dc5SPeter Avalos 		goto out;
265336e94dc5SPeter Avalos 	ret = 0;
265436e94dc5SPeter Avalos  out:
26550cbfa66cSDaniel Fojt 	BN_clear_free(x);
26560cbfa66cSDaniel Fojt 	BN_clear_free(y);
26570cbfa66cSDaniel Fojt 	BN_clear_free(order);
26580cbfa66cSDaniel Fojt 	BN_clear_free(tmp);
265936e94dc5SPeter Avalos 	EC_POINT_free(nq);
266036e94dc5SPeter Avalos 	return ret;
266136e94dc5SPeter Avalos }
266236e94dc5SPeter Avalos 
266336e94dc5SPeter Avalos int
sshkey_ec_validate_private(const EC_KEY * key)266436e94dc5SPeter Avalos sshkey_ec_validate_private(const EC_KEY *key)
266536e94dc5SPeter Avalos {
26660cbfa66cSDaniel Fojt 	BIGNUM *order = NULL, *tmp = NULL;
266736e94dc5SPeter Avalos 	int ret = SSH_ERR_KEY_INVALID_EC_VALUE;
266836e94dc5SPeter Avalos 
26690cbfa66cSDaniel Fojt 	if ((order = BN_new()) == NULL || (tmp = BN_new()) == NULL) {
267036e94dc5SPeter Avalos 		ret = SSH_ERR_ALLOC_FAIL;
267136e94dc5SPeter Avalos 		goto out;
267236e94dc5SPeter Avalos 	}
267336e94dc5SPeter Avalos 
267436e94dc5SPeter Avalos 	/* log2(private) > log2(order)/2 */
26750cbfa66cSDaniel Fojt 	if (EC_GROUP_get_order(EC_KEY_get0_group(key), order, NULL) != 1) {
267636e94dc5SPeter Avalos 		ret = SSH_ERR_LIBCRYPTO_ERROR;
267736e94dc5SPeter Avalos 		goto out;
267836e94dc5SPeter Avalos 	}
267936e94dc5SPeter Avalos 	if (BN_num_bits(EC_KEY_get0_private_key(key)) <=
268036e94dc5SPeter Avalos 	    BN_num_bits(order) / 2)
268136e94dc5SPeter Avalos 		goto out;
268236e94dc5SPeter Avalos 
268336e94dc5SPeter Avalos 	/* private < order - 1 */
268436e94dc5SPeter Avalos 	if (!BN_sub(tmp, order, BN_value_one())) {
268536e94dc5SPeter Avalos 		ret = SSH_ERR_LIBCRYPTO_ERROR;
268636e94dc5SPeter Avalos 		goto out;
268736e94dc5SPeter Avalos 	}
268836e94dc5SPeter Avalos 	if (BN_cmp(EC_KEY_get0_private_key(key), tmp) >= 0)
268936e94dc5SPeter Avalos 		goto out;
269036e94dc5SPeter Avalos 	ret = 0;
269136e94dc5SPeter Avalos  out:
26920cbfa66cSDaniel Fojt 	BN_clear_free(order);
26930cbfa66cSDaniel Fojt 	BN_clear_free(tmp);
269436e94dc5SPeter Avalos 	return ret;
269536e94dc5SPeter Avalos }
269636e94dc5SPeter Avalos 
269736e94dc5SPeter Avalos void
sshkey_dump_ec_point(const EC_GROUP * group,const EC_POINT * point)269836e94dc5SPeter Avalos sshkey_dump_ec_point(const EC_GROUP *group, const EC_POINT *point)
269936e94dc5SPeter Avalos {
27000cbfa66cSDaniel Fojt 	BIGNUM *x = NULL, *y = NULL;
270136e94dc5SPeter Avalos 
270236e94dc5SPeter Avalos 	if (point == NULL) {
270336e94dc5SPeter Avalos 		fputs("point=(NULL)\n", stderr);
270436e94dc5SPeter Avalos 		return;
270536e94dc5SPeter Avalos 	}
27060cbfa66cSDaniel Fojt 	if ((x = BN_new()) == NULL || (y = BN_new()) == NULL) {
27070cbfa66cSDaniel Fojt 		fprintf(stderr, "%s: BN_new failed\n", __func__);
27080cbfa66cSDaniel Fojt 		goto out;
270936e94dc5SPeter Avalos 	}
271036e94dc5SPeter Avalos 	if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) !=
271136e94dc5SPeter Avalos 	    NID_X9_62_prime_field) {
271236e94dc5SPeter Avalos 		fprintf(stderr, "%s: group is not a prime field\n", __func__);
27130cbfa66cSDaniel Fojt 		goto out;
271436e94dc5SPeter Avalos 	}
27150cbfa66cSDaniel Fojt 	if (EC_POINT_get_affine_coordinates_GFp(group, point,
27160cbfa66cSDaniel Fojt 	    x, y, NULL) != 1) {
271736e94dc5SPeter Avalos 		fprintf(stderr, "%s: EC_POINT_get_affine_coordinates_GFp\n",
271836e94dc5SPeter Avalos 		    __func__);
27190cbfa66cSDaniel Fojt 		goto out;
272036e94dc5SPeter Avalos 	}
272136e94dc5SPeter Avalos 	fputs("x=", stderr);
272236e94dc5SPeter Avalos 	BN_print_fp(stderr, x);
272336e94dc5SPeter Avalos 	fputs("\ny=", stderr);
272436e94dc5SPeter Avalos 	BN_print_fp(stderr, y);
272536e94dc5SPeter Avalos 	fputs("\n", stderr);
27260cbfa66cSDaniel Fojt  out:
27270cbfa66cSDaniel Fojt 	BN_clear_free(x);
27280cbfa66cSDaniel Fojt 	BN_clear_free(y);
272936e94dc5SPeter Avalos }
273036e94dc5SPeter Avalos 
273136e94dc5SPeter Avalos void
sshkey_dump_ec_key(const EC_KEY * key)273236e94dc5SPeter Avalos sshkey_dump_ec_key(const EC_KEY *key)
273336e94dc5SPeter Avalos {
273436e94dc5SPeter Avalos 	const BIGNUM *exponent;
273536e94dc5SPeter Avalos 
273636e94dc5SPeter Avalos 	sshkey_dump_ec_point(EC_KEY_get0_group(key),
273736e94dc5SPeter Avalos 	    EC_KEY_get0_public_key(key));
273836e94dc5SPeter Avalos 	fputs("exponent=", stderr);
273936e94dc5SPeter Avalos 	if ((exponent = EC_KEY_get0_private_key(key)) == NULL)
274036e94dc5SPeter Avalos 		fputs("(NULL)", stderr);
274136e94dc5SPeter Avalos 	else
274236e94dc5SPeter Avalos 		BN_print_fp(stderr, EC_KEY_get0_private_key(key));
274336e94dc5SPeter Avalos 	fputs("\n", stderr);
274436e94dc5SPeter Avalos }
274536e94dc5SPeter Avalos #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */
274636e94dc5SPeter Avalos 
274736e94dc5SPeter Avalos static int
sshkey_private_to_blob2(struct sshkey * prv,struct sshbuf * blob,const char * passphrase,const char * comment,const char * ciphername,int rounds)27480cbfa66cSDaniel Fojt sshkey_private_to_blob2(struct sshkey *prv, struct sshbuf *blob,
274936e94dc5SPeter Avalos     const char *passphrase, const char *comment, const char *ciphername,
275036e94dc5SPeter Avalos     int rounds)
275136e94dc5SPeter Avalos {
2752e9778795SPeter Avalos 	u_char *cp, *key = NULL, *pubkeyblob = NULL;
275336e94dc5SPeter Avalos 	u_char salt[SALT_LEN];
275436e94dc5SPeter Avalos 	size_t i, pubkeylen, keylen, ivlen, blocksize, authlen;
275536e94dc5SPeter Avalos 	u_int check;
275636e94dc5SPeter Avalos 	int r = SSH_ERR_INTERNAL_ERROR;
2757ce74bacaSMatthew Dillon 	struct sshcipher_ctx *ciphercontext = NULL;
275836e94dc5SPeter Avalos 	const struct sshcipher *cipher;
275936e94dc5SPeter Avalos 	const char *kdfname = KDFNAME;
276036e94dc5SPeter Avalos 	struct sshbuf *encoded = NULL, *encrypted = NULL, *kdf = NULL;
276136e94dc5SPeter Avalos 
276236e94dc5SPeter Avalos 	if (rounds <= 0)
276336e94dc5SPeter Avalos 		rounds = DEFAULT_ROUNDS;
276436e94dc5SPeter Avalos 	if (passphrase == NULL || !strlen(passphrase)) {
276536e94dc5SPeter Avalos 		ciphername = "none";
276636e94dc5SPeter Avalos 		kdfname = "none";
276736e94dc5SPeter Avalos 	} else if (ciphername == NULL)
276836e94dc5SPeter Avalos 		ciphername = DEFAULT_CIPHERNAME;
276936e94dc5SPeter Avalos 	if ((cipher = cipher_by_name(ciphername)) == NULL) {
2770ce74bacaSMatthew Dillon 		r = SSH_ERR_INVALID_ARGUMENT;
277136e94dc5SPeter Avalos 		goto out;
277236e94dc5SPeter Avalos 	}
277336e94dc5SPeter Avalos 
277436e94dc5SPeter Avalos 	if ((kdf = sshbuf_new()) == NULL ||
277536e94dc5SPeter Avalos 	    (encoded = sshbuf_new()) == NULL ||
277636e94dc5SPeter Avalos 	    (encrypted = sshbuf_new()) == NULL) {
277736e94dc5SPeter Avalos 		r = SSH_ERR_ALLOC_FAIL;
277836e94dc5SPeter Avalos 		goto out;
277936e94dc5SPeter Avalos 	}
278036e94dc5SPeter Avalos 	blocksize = cipher_blocksize(cipher);
278136e94dc5SPeter Avalos 	keylen = cipher_keylen(cipher);
278236e94dc5SPeter Avalos 	ivlen = cipher_ivlen(cipher);
278336e94dc5SPeter Avalos 	authlen = cipher_authlen(cipher);
278436e94dc5SPeter Avalos 	if ((key = calloc(1, keylen + ivlen)) == NULL) {
278536e94dc5SPeter Avalos 		r = SSH_ERR_ALLOC_FAIL;
278636e94dc5SPeter Avalos 		goto out;
278736e94dc5SPeter Avalos 	}
278836e94dc5SPeter Avalos 	if (strcmp(kdfname, "bcrypt") == 0) {
278936e94dc5SPeter Avalos 		arc4random_buf(salt, SALT_LEN);
279036e94dc5SPeter Avalos 		if (bcrypt_pbkdf(passphrase, strlen(passphrase),
279136e94dc5SPeter Avalos 		    salt, SALT_LEN, key, keylen + ivlen, rounds) < 0) {
279236e94dc5SPeter Avalos 			r = SSH_ERR_INVALID_ARGUMENT;
279336e94dc5SPeter Avalos 			goto out;
279436e94dc5SPeter Avalos 		}
279536e94dc5SPeter Avalos 		if ((r = sshbuf_put_string(kdf, salt, SALT_LEN)) != 0 ||
279636e94dc5SPeter Avalos 		    (r = sshbuf_put_u32(kdf, rounds)) != 0)
279736e94dc5SPeter Avalos 			goto out;
279836e94dc5SPeter Avalos 	} else if (strcmp(kdfname, "none") != 0) {
279936e94dc5SPeter Avalos 		/* Unsupported KDF type */
280036e94dc5SPeter Avalos 		r = SSH_ERR_KEY_UNKNOWN_CIPHER;
280136e94dc5SPeter Avalos 		goto out;
280236e94dc5SPeter Avalos 	}
280336e94dc5SPeter Avalos 	if ((r = cipher_init(&ciphercontext, cipher, key, keylen,
280436e94dc5SPeter Avalos 	    key + keylen, ivlen, 1)) != 0)
280536e94dc5SPeter Avalos 		goto out;
280636e94dc5SPeter Avalos 
280736e94dc5SPeter Avalos 	if ((r = sshbuf_put(encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC))) != 0 ||
280836e94dc5SPeter Avalos 	    (r = sshbuf_put_cstring(encoded, ciphername)) != 0 ||
280936e94dc5SPeter Avalos 	    (r = sshbuf_put_cstring(encoded, kdfname)) != 0 ||
281036e94dc5SPeter Avalos 	    (r = sshbuf_put_stringb(encoded, kdf)) != 0 ||
281136e94dc5SPeter Avalos 	    (r = sshbuf_put_u32(encoded, 1)) != 0 ||	/* number of keys */
281236e94dc5SPeter Avalos 	    (r = sshkey_to_blob(prv, &pubkeyblob, &pubkeylen)) != 0 ||
281336e94dc5SPeter Avalos 	    (r = sshbuf_put_string(encoded, pubkeyblob, pubkeylen)) != 0)
281436e94dc5SPeter Avalos 		goto out;
281536e94dc5SPeter Avalos 
281636e94dc5SPeter Avalos 	/* set up the buffer that will be encrypted */
281736e94dc5SPeter Avalos 
281836e94dc5SPeter Avalos 	/* Random check bytes */
281936e94dc5SPeter Avalos 	check = arc4random();
282036e94dc5SPeter Avalos 	if ((r = sshbuf_put_u32(encrypted, check)) != 0 ||
282136e94dc5SPeter Avalos 	    (r = sshbuf_put_u32(encrypted, check)) != 0)
282236e94dc5SPeter Avalos 		goto out;
282336e94dc5SPeter Avalos 
282436e94dc5SPeter Avalos 	/* append private key and comment*/
2825664f4763Szrj 	if ((r = sshkey_private_serialize_opt(prv, encrypted,
2826664f4763Szrj 	    SSHKEY_SERIALIZE_FULL)) != 0 ||
282736e94dc5SPeter Avalos 	    (r = sshbuf_put_cstring(encrypted, comment)) != 0)
282836e94dc5SPeter Avalos 		goto out;
282936e94dc5SPeter Avalos 
283036e94dc5SPeter Avalos 	/* padding */
283136e94dc5SPeter Avalos 	i = 0;
283236e94dc5SPeter Avalos 	while (sshbuf_len(encrypted) % blocksize) {
283336e94dc5SPeter Avalos 		if ((r = sshbuf_put_u8(encrypted, ++i & 0xff)) != 0)
283436e94dc5SPeter Avalos 			goto out;
283536e94dc5SPeter Avalos 	}
283636e94dc5SPeter Avalos 
283736e94dc5SPeter Avalos 	/* length in destination buffer */
283836e94dc5SPeter Avalos 	if ((r = sshbuf_put_u32(encoded, sshbuf_len(encrypted))) != 0)
283936e94dc5SPeter Avalos 		goto out;
284036e94dc5SPeter Avalos 
284136e94dc5SPeter Avalos 	/* encrypt */
284236e94dc5SPeter Avalos 	if ((r = sshbuf_reserve(encoded,
284336e94dc5SPeter Avalos 	    sshbuf_len(encrypted) + authlen, &cp)) != 0)
284436e94dc5SPeter Avalos 		goto out;
2845ce74bacaSMatthew Dillon 	if ((r = cipher_crypt(ciphercontext, 0, cp,
284636e94dc5SPeter Avalos 	    sshbuf_ptr(encrypted), sshbuf_len(encrypted), 0, authlen)) != 0)
284736e94dc5SPeter Avalos 		goto out;
284836e94dc5SPeter Avalos 
284936e94dc5SPeter Avalos 	sshbuf_reset(blob);
28500cbfa66cSDaniel Fojt 
28510cbfa66cSDaniel Fojt 	/* assemble uuencoded key */
28520cbfa66cSDaniel Fojt 	if ((r = sshbuf_put(blob, MARK_BEGIN, MARK_BEGIN_LEN)) != 0 ||
28530cbfa66cSDaniel Fojt 	    (r = sshbuf_dtob64(encoded, blob, 1)) != 0 ||
28540cbfa66cSDaniel Fojt 	    (r = sshbuf_put(blob, MARK_END, MARK_END_LEN)) != 0)
285536e94dc5SPeter Avalos 		goto out;
285636e94dc5SPeter Avalos 
285736e94dc5SPeter Avalos 	/* success */
285836e94dc5SPeter Avalos 	r = 0;
285936e94dc5SPeter Avalos 
286036e94dc5SPeter Avalos  out:
286136e94dc5SPeter Avalos 	sshbuf_free(kdf);
286236e94dc5SPeter Avalos 	sshbuf_free(encoded);
286336e94dc5SPeter Avalos 	sshbuf_free(encrypted);
2864ce74bacaSMatthew Dillon 	cipher_free(ciphercontext);
286536e94dc5SPeter Avalos 	explicit_bzero(salt, sizeof(salt));
28660cbfa66cSDaniel Fojt 	if (key != NULL)
28670cbfa66cSDaniel Fojt 		freezero(key, keylen + ivlen);
28680cbfa66cSDaniel Fojt 	if (pubkeyblob != NULL)
28690cbfa66cSDaniel Fojt 		freezero(pubkeyblob, pubkeylen);
287036e94dc5SPeter Avalos 	return r;
287136e94dc5SPeter Avalos }
287236e94dc5SPeter Avalos 
287336e94dc5SPeter Avalos static int
private2_uudecode(struct sshbuf * blob,struct sshbuf ** decodedp)28740cbfa66cSDaniel Fojt private2_uudecode(struct sshbuf *blob, struct sshbuf **decodedp)
287536e94dc5SPeter Avalos {
287636e94dc5SPeter Avalos 	const u_char *cp;
287736e94dc5SPeter Avalos 	size_t encoded_len;
28780cbfa66cSDaniel Fojt 	int r;
28790cbfa66cSDaniel Fojt 	u_char last;
288036e94dc5SPeter Avalos 	struct sshbuf *encoded = NULL, *decoded = NULL;
288136e94dc5SPeter Avalos 
28820cbfa66cSDaniel Fojt 	if (blob == NULL || decodedp == NULL)
28830cbfa66cSDaniel Fojt 		return SSH_ERR_INVALID_ARGUMENT;
28840cbfa66cSDaniel Fojt 
28850cbfa66cSDaniel Fojt 	*decodedp = NULL;
288636e94dc5SPeter Avalos 
288736e94dc5SPeter Avalos 	if ((encoded = sshbuf_new()) == NULL ||
28880cbfa66cSDaniel Fojt 	    (decoded = sshbuf_new()) == NULL) {
288936e94dc5SPeter Avalos 		r = SSH_ERR_ALLOC_FAIL;
289036e94dc5SPeter Avalos 		goto out;
289136e94dc5SPeter Avalos 	}
289236e94dc5SPeter Avalos 
289336e94dc5SPeter Avalos 	/* check preamble */
289436e94dc5SPeter Avalos 	cp = sshbuf_ptr(blob);
289536e94dc5SPeter Avalos 	encoded_len = sshbuf_len(blob);
289636e94dc5SPeter Avalos 	if (encoded_len < (MARK_BEGIN_LEN + MARK_END_LEN) ||
289736e94dc5SPeter Avalos 	    memcmp(cp, MARK_BEGIN, MARK_BEGIN_LEN) != 0) {
289836e94dc5SPeter Avalos 		r = SSH_ERR_INVALID_FORMAT;
289936e94dc5SPeter Avalos 		goto out;
290036e94dc5SPeter Avalos 	}
290136e94dc5SPeter Avalos 	cp += MARK_BEGIN_LEN;
290236e94dc5SPeter Avalos 	encoded_len -= MARK_BEGIN_LEN;
290336e94dc5SPeter Avalos 
290436e94dc5SPeter Avalos 	/* Look for end marker, removing whitespace as we go */
290536e94dc5SPeter Avalos 	while (encoded_len > 0) {
290636e94dc5SPeter Avalos 		if (*cp != '\n' && *cp != '\r') {
290736e94dc5SPeter Avalos 			if ((r = sshbuf_put_u8(encoded, *cp)) != 0)
290836e94dc5SPeter Avalos 				goto out;
290936e94dc5SPeter Avalos 		}
291036e94dc5SPeter Avalos 		last = *cp;
291136e94dc5SPeter Avalos 		encoded_len--;
291236e94dc5SPeter Avalos 		cp++;
291336e94dc5SPeter Avalos 		if (last == '\n') {
291436e94dc5SPeter Avalos 			if (encoded_len >= MARK_END_LEN &&
291536e94dc5SPeter Avalos 			    memcmp(cp, MARK_END, MARK_END_LEN) == 0) {
291636e94dc5SPeter Avalos 				/* \0 terminate */
291736e94dc5SPeter Avalos 				if ((r = sshbuf_put_u8(encoded, 0)) != 0)
291836e94dc5SPeter Avalos 					goto out;
291936e94dc5SPeter Avalos 				break;
292036e94dc5SPeter Avalos 			}
292136e94dc5SPeter Avalos 		}
292236e94dc5SPeter Avalos 	}
292336e94dc5SPeter Avalos 	if (encoded_len == 0) {
292436e94dc5SPeter Avalos 		r = SSH_ERR_INVALID_FORMAT;
292536e94dc5SPeter Avalos 		goto out;
292636e94dc5SPeter Avalos 	}
292736e94dc5SPeter Avalos 
292836e94dc5SPeter Avalos 	/* decode base64 */
2929e9778795SPeter Avalos 	if ((r = sshbuf_b64tod(decoded, (char *)sshbuf_ptr(encoded))) != 0)
293036e94dc5SPeter Avalos 		goto out;
293136e94dc5SPeter Avalos 
293236e94dc5SPeter Avalos 	/* check magic */
293336e94dc5SPeter Avalos 	if (sshbuf_len(decoded) < sizeof(AUTH_MAGIC) ||
293436e94dc5SPeter Avalos 	    memcmp(sshbuf_ptr(decoded), AUTH_MAGIC, sizeof(AUTH_MAGIC))) {
293536e94dc5SPeter Avalos 		r = SSH_ERR_INVALID_FORMAT;
293636e94dc5SPeter Avalos 		goto out;
293736e94dc5SPeter Avalos 	}
29380cbfa66cSDaniel Fojt 	/* success */
29390cbfa66cSDaniel Fojt 	*decodedp = decoded;
29400cbfa66cSDaniel Fojt 	decoded = NULL;
29410cbfa66cSDaniel Fojt 	r = 0;
29420cbfa66cSDaniel Fojt  out:
29430cbfa66cSDaniel Fojt 	sshbuf_free(encoded);
29440cbfa66cSDaniel Fojt 	sshbuf_free(decoded);
29450cbfa66cSDaniel Fojt 	return r;
29460cbfa66cSDaniel Fojt }
29470cbfa66cSDaniel Fojt 
29480cbfa66cSDaniel Fojt static int
private2_decrypt(struct sshbuf * decoded,const char * passphrase,struct sshbuf ** decryptedp,struct sshkey ** pubkeyp)29490cbfa66cSDaniel Fojt private2_decrypt(struct sshbuf *decoded, const char *passphrase,
29500cbfa66cSDaniel Fojt     struct sshbuf **decryptedp, struct sshkey **pubkeyp)
29510cbfa66cSDaniel Fojt {
29520cbfa66cSDaniel Fojt 	char *ciphername = NULL, *kdfname = NULL;
29530cbfa66cSDaniel Fojt 	const struct sshcipher *cipher = NULL;
29540cbfa66cSDaniel Fojt 	int r = SSH_ERR_INTERNAL_ERROR;
29550cbfa66cSDaniel Fojt 	size_t keylen = 0, ivlen = 0, authlen = 0, slen = 0;
29560cbfa66cSDaniel Fojt 	struct sshbuf *kdf = NULL, *decrypted = NULL;
29570cbfa66cSDaniel Fojt 	struct sshcipher_ctx *ciphercontext = NULL;
29580cbfa66cSDaniel Fojt 	struct sshkey *pubkey = NULL;
29590cbfa66cSDaniel Fojt 	u_char *key = NULL, *salt = NULL, *dp;
29600cbfa66cSDaniel Fojt 	u_int blocksize, rounds, nkeys, encrypted_len, check1, check2;
29610cbfa66cSDaniel Fojt 
29620cbfa66cSDaniel Fojt 	if (decoded == NULL || decryptedp == NULL || pubkeyp == NULL)
29630cbfa66cSDaniel Fojt 		return SSH_ERR_INVALID_ARGUMENT;
29640cbfa66cSDaniel Fojt 
29650cbfa66cSDaniel Fojt 	*decryptedp = NULL;
29660cbfa66cSDaniel Fojt 	*pubkeyp = NULL;
29670cbfa66cSDaniel Fojt 
29680cbfa66cSDaniel Fojt 	if ((decrypted = sshbuf_new()) == NULL) {
29690cbfa66cSDaniel Fojt 		r = SSH_ERR_ALLOC_FAIL;
29700cbfa66cSDaniel Fojt 		goto out;
29710cbfa66cSDaniel Fojt 	}
29720cbfa66cSDaniel Fojt 
297336e94dc5SPeter Avalos 	/* parse public portion of key */
297436e94dc5SPeter Avalos 	if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 ||
297536e94dc5SPeter Avalos 	    (r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 ||
297636e94dc5SPeter Avalos 	    (r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 ||
297736e94dc5SPeter Avalos 	    (r = sshbuf_froms(decoded, &kdf)) != 0 ||
29780cbfa66cSDaniel Fojt 	    (r = sshbuf_get_u32(decoded, &nkeys)) != 0)
29790cbfa66cSDaniel Fojt 		goto out;
29800cbfa66cSDaniel Fojt 
29810cbfa66cSDaniel Fojt 	if (nkeys != 1) {
29820cbfa66cSDaniel Fojt 		/* XXX only one key supported at present */
29830cbfa66cSDaniel Fojt 		r = SSH_ERR_INVALID_FORMAT;
29840cbfa66cSDaniel Fojt 		goto out;
29850cbfa66cSDaniel Fojt 	}
29860cbfa66cSDaniel Fojt 
29870cbfa66cSDaniel Fojt 	if ((r = sshkey_froms(decoded, &pubkey)) != 0 ||
298836e94dc5SPeter Avalos 	    (r = sshbuf_get_u32(decoded, &encrypted_len)) != 0)
298936e94dc5SPeter Avalos 		goto out;
299036e94dc5SPeter Avalos 
299136e94dc5SPeter Avalos 	if ((cipher = cipher_by_name(ciphername)) == NULL) {
299236e94dc5SPeter Avalos 		r = SSH_ERR_KEY_UNKNOWN_CIPHER;
299336e94dc5SPeter Avalos 		goto out;
299436e94dc5SPeter Avalos 	}
299536e94dc5SPeter Avalos 	if (strcmp(kdfname, "none") != 0 && strcmp(kdfname, "bcrypt") != 0) {
299636e94dc5SPeter Avalos 		r = SSH_ERR_KEY_UNKNOWN_CIPHER;
299736e94dc5SPeter Avalos 		goto out;
299836e94dc5SPeter Avalos 	}
29990cbfa66cSDaniel Fojt 	if (strcmp(kdfname, "none") == 0 && strcmp(ciphername, "none") != 0) {
300036e94dc5SPeter Avalos 		r = SSH_ERR_INVALID_FORMAT;
300136e94dc5SPeter Avalos 		goto out;
300236e94dc5SPeter Avalos 	}
30030cbfa66cSDaniel Fojt 	if ((passphrase == NULL || strlen(passphrase) == 0) &&
30040cbfa66cSDaniel Fojt 	    strcmp(kdfname, "none") != 0) {
30050cbfa66cSDaniel Fojt 		/* passphrase required */
30060cbfa66cSDaniel Fojt 		r = SSH_ERR_KEY_WRONG_PASSPHRASE;
300736e94dc5SPeter Avalos 		goto out;
300836e94dc5SPeter Avalos 	}
300936e94dc5SPeter Avalos 
301036e94dc5SPeter Avalos 	/* check size of encrypted key blob */
301136e94dc5SPeter Avalos 	blocksize = cipher_blocksize(cipher);
301236e94dc5SPeter Avalos 	if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) {
301336e94dc5SPeter Avalos 		r = SSH_ERR_INVALID_FORMAT;
301436e94dc5SPeter Avalos 		goto out;
301536e94dc5SPeter Avalos 	}
301636e94dc5SPeter Avalos 
301736e94dc5SPeter Avalos 	/* setup key */
301836e94dc5SPeter Avalos 	keylen = cipher_keylen(cipher);
301936e94dc5SPeter Avalos 	ivlen = cipher_ivlen(cipher);
3020e9778795SPeter Avalos 	authlen = cipher_authlen(cipher);
302136e94dc5SPeter Avalos 	if ((key = calloc(1, keylen + ivlen)) == NULL) {
302236e94dc5SPeter Avalos 		r = SSH_ERR_ALLOC_FAIL;
302336e94dc5SPeter Avalos 		goto out;
302436e94dc5SPeter Avalos 	}
302536e94dc5SPeter Avalos 	if (strcmp(kdfname, "bcrypt") == 0) {
302636e94dc5SPeter Avalos 		if ((r = sshbuf_get_string(kdf, &salt, &slen)) != 0 ||
302736e94dc5SPeter Avalos 		    (r = sshbuf_get_u32(kdf, &rounds)) != 0)
302836e94dc5SPeter Avalos 			goto out;
302936e94dc5SPeter Avalos 		if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen,
303036e94dc5SPeter Avalos 		    key, keylen + ivlen, rounds) < 0) {
303136e94dc5SPeter Avalos 			r = SSH_ERR_INVALID_FORMAT;
303236e94dc5SPeter Avalos 			goto out;
303336e94dc5SPeter Avalos 		}
303436e94dc5SPeter Avalos 	}
303536e94dc5SPeter Avalos 
3036e9778795SPeter Avalos 	/* check that an appropriate amount of auth data is present */
30370cbfa66cSDaniel Fojt 	if (sshbuf_len(decoded) < authlen ||
30380cbfa66cSDaniel Fojt 	    sshbuf_len(decoded) - authlen < encrypted_len) {
3039e9778795SPeter Avalos 		r = SSH_ERR_INVALID_FORMAT;
3040e9778795SPeter Avalos 		goto out;
3041e9778795SPeter Avalos 	}
3042e9778795SPeter Avalos 
304336e94dc5SPeter Avalos 	/* decrypt private portion of key */
304436e94dc5SPeter Avalos 	if ((r = sshbuf_reserve(decrypted, encrypted_len, &dp)) != 0 ||
304536e94dc5SPeter Avalos 	    (r = cipher_init(&ciphercontext, cipher, key, keylen,
304636e94dc5SPeter Avalos 	    key + keylen, ivlen, 0)) != 0)
304736e94dc5SPeter Avalos 		goto out;
3048ce74bacaSMatthew Dillon 	if ((r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(decoded),
3049e9778795SPeter Avalos 	    encrypted_len, 0, authlen)) != 0) {
305036e94dc5SPeter Avalos 		/* an integrity error here indicates an incorrect passphrase */
305136e94dc5SPeter Avalos 		if (r == SSH_ERR_MAC_INVALID)
305236e94dc5SPeter Avalos 			r = SSH_ERR_KEY_WRONG_PASSPHRASE;
305336e94dc5SPeter Avalos 		goto out;
305436e94dc5SPeter Avalos 	}
3055e9778795SPeter Avalos 	if ((r = sshbuf_consume(decoded, encrypted_len + authlen)) != 0)
305636e94dc5SPeter Avalos 		goto out;
305736e94dc5SPeter Avalos 	/* there should be no trailing data */
305836e94dc5SPeter Avalos 	if (sshbuf_len(decoded) != 0) {
305936e94dc5SPeter Avalos 		r = SSH_ERR_INVALID_FORMAT;
306036e94dc5SPeter Avalos 		goto out;
306136e94dc5SPeter Avalos 	}
306236e94dc5SPeter Avalos 
306336e94dc5SPeter Avalos 	/* check check bytes */
306436e94dc5SPeter Avalos 	if ((r = sshbuf_get_u32(decrypted, &check1)) != 0 ||
306536e94dc5SPeter Avalos 	    (r = sshbuf_get_u32(decrypted, &check2)) != 0)
306636e94dc5SPeter Avalos 		goto out;
306736e94dc5SPeter Avalos 	if (check1 != check2) {
306836e94dc5SPeter Avalos 		r = SSH_ERR_KEY_WRONG_PASSPHRASE;
306936e94dc5SPeter Avalos 		goto out;
307036e94dc5SPeter Avalos 	}
30710cbfa66cSDaniel Fojt 	/* success */
30720cbfa66cSDaniel Fojt 	*decryptedp = decrypted;
30730cbfa66cSDaniel Fojt 	decrypted = NULL;
30740cbfa66cSDaniel Fojt 	*pubkeyp = pubkey;
30750cbfa66cSDaniel Fojt 	pubkey = NULL;
30760cbfa66cSDaniel Fojt 	r = 0;
30770cbfa66cSDaniel Fojt  out:
30780cbfa66cSDaniel Fojt 	cipher_free(ciphercontext);
30790cbfa66cSDaniel Fojt 	free(ciphername);
30800cbfa66cSDaniel Fojt 	free(kdfname);
30810cbfa66cSDaniel Fojt 	sshkey_free(pubkey);
30820cbfa66cSDaniel Fojt 	if (salt != NULL) {
30830cbfa66cSDaniel Fojt 		explicit_bzero(salt, slen);
30840cbfa66cSDaniel Fojt 		free(salt);
30850cbfa66cSDaniel Fojt 	}
30860cbfa66cSDaniel Fojt 	if (key != NULL) {
30870cbfa66cSDaniel Fojt 		explicit_bzero(key, keylen + ivlen);
30880cbfa66cSDaniel Fojt 		free(key);
30890cbfa66cSDaniel Fojt 	}
30900cbfa66cSDaniel Fojt 	sshbuf_free(kdf);
30910cbfa66cSDaniel Fojt 	sshbuf_free(decrypted);
30920cbfa66cSDaniel Fojt 	return r;
30930cbfa66cSDaniel Fojt }
309436e94dc5SPeter Avalos 
30950cbfa66cSDaniel Fojt static int
sshkey_parse_private2(struct sshbuf * blob,int type,const char * passphrase,struct sshkey ** keyp,char ** commentp)30960cbfa66cSDaniel Fojt sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase,
30970cbfa66cSDaniel Fojt     struct sshkey **keyp, char **commentp)
30980cbfa66cSDaniel Fojt {
30990cbfa66cSDaniel Fojt 	char *comment = NULL;
31000cbfa66cSDaniel Fojt 	int r = SSH_ERR_INTERNAL_ERROR;
31010cbfa66cSDaniel Fojt 	struct sshbuf *decoded = NULL, *decrypted = NULL;
31020cbfa66cSDaniel Fojt 	struct sshkey *k = NULL, *pubkey = NULL;
31030cbfa66cSDaniel Fojt 
31040cbfa66cSDaniel Fojt 	if (keyp != NULL)
31050cbfa66cSDaniel Fojt 		*keyp = NULL;
31060cbfa66cSDaniel Fojt 	if (commentp != NULL)
31070cbfa66cSDaniel Fojt 		*commentp = NULL;
31080cbfa66cSDaniel Fojt 
31090cbfa66cSDaniel Fojt 	/* Undo base64 encoding and decrypt the private section */
31100cbfa66cSDaniel Fojt 	if ((r = private2_uudecode(blob, &decoded)) != 0 ||
31110cbfa66cSDaniel Fojt 	    (r = private2_decrypt(decoded, passphrase,
31120cbfa66cSDaniel Fojt 	    &decrypted, &pubkey)) != 0)
31130cbfa66cSDaniel Fojt 		goto out;
31140cbfa66cSDaniel Fojt 
31150cbfa66cSDaniel Fojt 	if (type != KEY_UNSPEC &&
31160cbfa66cSDaniel Fojt 	    sshkey_type_plain(type) != sshkey_type_plain(pubkey->type)) {
31170cbfa66cSDaniel Fojt 		r = SSH_ERR_KEY_TYPE_MISMATCH;
31180cbfa66cSDaniel Fojt 		goto out;
31190cbfa66cSDaniel Fojt 	}
31200cbfa66cSDaniel Fojt 
31210cbfa66cSDaniel Fojt 	/* Load the private key and comment */
31220cbfa66cSDaniel Fojt 	if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 ||
31230cbfa66cSDaniel Fojt 	    (r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0)
31240cbfa66cSDaniel Fojt 		goto out;
31250cbfa66cSDaniel Fojt 
31260cbfa66cSDaniel Fojt 	/* Check deterministic padding after private section */
31270cbfa66cSDaniel Fojt 	if ((r = private2_check_padding(decrypted)) != 0)
31280cbfa66cSDaniel Fojt 		goto out;
31290cbfa66cSDaniel Fojt 
31300cbfa66cSDaniel Fojt 	/* Check that the public key in the envelope matches the private key */
31310cbfa66cSDaniel Fojt 	if (!sshkey_equal(pubkey, k)) {
31320cbfa66cSDaniel Fojt 		r = SSH_ERR_INVALID_FORMAT;
31330cbfa66cSDaniel Fojt 		goto out;
31340cbfa66cSDaniel Fojt 	}
313536e94dc5SPeter Avalos 
313636e94dc5SPeter Avalos 	/* success */
313736e94dc5SPeter Avalos 	r = 0;
313836e94dc5SPeter Avalos 	if (keyp != NULL) {
313936e94dc5SPeter Avalos 		*keyp = k;
314036e94dc5SPeter Avalos 		k = NULL;
314136e94dc5SPeter Avalos 	}
314236e94dc5SPeter Avalos 	if (commentp != NULL) {
314336e94dc5SPeter Avalos 		*commentp = comment;
314436e94dc5SPeter Avalos 		comment = NULL;
314536e94dc5SPeter Avalos 	}
314636e94dc5SPeter Avalos  out:
314736e94dc5SPeter Avalos 	free(comment);
314836e94dc5SPeter Avalos 	sshbuf_free(decoded);
314936e94dc5SPeter Avalos 	sshbuf_free(decrypted);
315036e94dc5SPeter Avalos 	sshkey_free(k);
31510cbfa66cSDaniel Fojt 	sshkey_free(pubkey);
315236e94dc5SPeter Avalos 	return r;
315336e94dc5SPeter Avalos }
315436e94dc5SPeter Avalos 
31550cbfa66cSDaniel Fojt static int
sshkey_parse_private2_pubkey(struct sshbuf * blob,int type,struct sshkey ** keyp)31560cbfa66cSDaniel Fojt sshkey_parse_private2_pubkey(struct sshbuf *blob, int type,
31570cbfa66cSDaniel Fojt     struct sshkey **keyp)
31580cbfa66cSDaniel Fojt {
31590cbfa66cSDaniel Fojt 	int r = SSH_ERR_INTERNAL_ERROR;
31600cbfa66cSDaniel Fojt 	struct sshbuf *decoded = NULL;
31610cbfa66cSDaniel Fojt 	struct sshkey *pubkey = NULL;
31620cbfa66cSDaniel Fojt 	u_int nkeys = 0;
31630cbfa66cSDaniel Fojt 
31640cbfa66cSDaniel Fojt 	if (keyp != NULL)
31650cbfa66cSDaniel Fojt 		*keyp = NULL;
31660cbfa66cSDaniel Fojt 
31670cbfa66cSDaniel Fojt 	if ((r = private2_uudecode(blob, &decoded)) != 0)
31680cbfa66cSDaniel Fojt 		goto out;
31690cbfa66cSDaniel Fojt 	/* parse public key from unencrypted envelope */
31700cbfa66cSDaniel Fojt 	if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 ||
31710cbfa66cSDaniel Fojt 	    (r = sshbuf_skip_string(decoded)) != 0 || /* cipher */
31720cbfa66cSDaniel Fojt 	    (r = sshbuf_skip_string(decoded)) != 0 || /* KDF alg */
31730cbfa66cSDaniel Fojt 	    (r = sshbuf_skip_string(decoded)) != 0 || /* KDF hint */
31740cbfa66cSDaniel Fojt 	    (r = sshbuf_get_u32(decoded, &nkeys)) != 0)
31750cbfa66cSDaniel Fojt 		goto out;
31760cbfa66cSDaniel Fojt 
31770cbfa66cSDaniel Fojt 	if (nkeys != 1) {
31780cbfa66cSDaniel Fojt 		/* XXX only one key supported at present */
31790cbfa66cSDaniel Fojt 		r = SSH_ERR_INVALID_FORMAT;
31800cbfa66cSDaniel Fojt 		goto out;
31810cbfa66cSDaniel Fojt 	}
31820cbfa66cSDaniel Fojt 
31830cbfa66cSDaniel Fojt 	/* Parse the public key */
31840cbfa66cSDaniel Fojt 	if ((r = sshkey_froms(decoded, &pubkey)) != 0)
31850cbfa66cSDaniel Fojt 		goto out;
31860cbfa66cSDaniel Fojt 
31870cbfa66cSDaniel Fojt 	if (type != KEY_UNSPEC &&
31880cbfa66cSDaniel Fojt 	    sshkey_type_plain(type) != sshkey_type_plain(pubkey->type)) {
31890cbfa66cSDaniel Fojt 		r = SSH_ERR_KEY_TYPE_MISMATCH;
31900cbfa66cSDaniel Fojt 		goto out;
31910cbfa66cSDaniel Fojt 	}
31920cbfa66cSDaniel Fojt 
31930cbfa66cSDaniel Fojt 	/* success */
31940cbfa66cSDaniel Fojt 	r = 0;
31950cbfa66cSDaniel Fojt 	if (keyp != NULL) {
31960cbfa66cSDaniel Fojt 		*keyp = pubkey;
31970cbfa66cSDaniel Fojt 		pubkey = NULL;
31980cbfa66cSDaniel Fojt 	}
31990cbfa66cSDaniel Fojt  out:
32000cbfa66cSDaniel Fojt 	sshbuf_free(decoded);
32010cbfa66cSDaniel Fojt 	sshkey_free(pubkey);
32020cbfa66cSDaniel Fojt 	return r;
32030cbfa66cSDaniel Fojt }
320436e94dc5SPeter Avalos 
320536e94dc5SPeter Avalos #ifdef WITH_OPENSSL
32060cbfa66cSDaniel Fojt /* convert SSH v2 key to PEM or PKCS#8 format */
320736e94dc5SPeter Avalos static int
sshkey_private_to_blob_pem_pkcs8(struct sshkey * key,struct sshbuf * buf,int format,const char * _passphrase,const char * comment)32080cbfa66cSDaniel Fojt sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf,
32090cbfa66cSDaniel Fojt     int format, const char *_passphrase, const char *comment)
321036e94dc5SPeter Avalos {
32110cbfa66cSDaniel Fojt 	int was_shielded = sshkey_is_shielded(key);
321236e94dc5SPeter Avalos 	int success, r;
321336e94dc5SPeter Avalos 	int blen, len = strlen(_passphrase);
321436e94dc5SPeter Avalos 	u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
321536e94dc5SPeter Avalos 	const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL;
3216664f4763Szrj 	char *bptr;
321736e94dc5SPeter Avalos 	BIO *bio = NULL;
32180cbfa66cSDaniel Fojt 	struct sshbuf *blob;
32190cbfa66cSDaniel Fojt 	EVP_PKEY *pkey = NULL;
322036e94dc5SPeter Avalos 
322136e94dc5SPeter Avalos 	if (len > 0 && len <= 4)
322236e94dc5SPeter Avalos 		return SSH_ERR_PASSPHRASE_TOO_SHORT;
32230cbfa66cSDaniel Fojt 	if ((blob = sshbuf_new()) == NULL)
322436e94dc5SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
32250cbfa66cSDaniel Fojt 	if ((bio = BIO_new(BIO_s_mem())) == NULL) {
32260cbfa66cSDaniel Fojt 		r = SSH_ERR_ALLOC_FAIL;
32270cbfa66cSDaniel Fojt 		goto out;
32280cbfa66cSDaniel Fojt 	}
32290cbfa66cSDaniel Fojt 	if (format == SSHKEY_PRIVATE_PKCS8 && (pkey = EVP_PKEY_new()) == NULL) {
32300cbfa66cSDaniel Fojt 		r = SSH_ERR_ALLOC_FAIL;
32310cbfa66cSDaniel Fojt 		goto out;
32320cbfa66cSDaniel Fojt 	}
32330cbfa66cSDaniel Fojt 	if ((r = sshkey_unshield_private(key)) != 0)
32340cbfa66cSDaniel Fojt 		goto out;
323536e94dc5SPeter Avalos 
323636e94dc5SPeter Avalos 	switch (key->type) {
3237*ba1276acSMatthew Dillon #ifdef WITH_DSA
323836e94dc5SPeter Avalos 	case KEY_DSA:
32390cbfa66cSDaniel Fojt 		if (format == SSHKEY_PRIVATE_PEM) {
324036e94dc5SPeter Avalos 			success = PEM_write_bio_DSAPrivateKey(bio, key->dsa,
324136e94dc5SPeter Avalos 			    cipher, passphrase, len, NULL, NULL);
32420cbfa66cSDaniel Fojt 		} else {
32430cbfa66cSDaniel Fojt 			success = EVP_PKEY_set1_DSA(pkey, key->dsa);
32440cbfa66cSDaniel Fojt 		}
324536e94dc5SPeter Avalos 		break;
3246*ba1276acSMatthew Dillon #endif
324736e94dc5SPeter Avalos #ifdef OPENSSL_HAS_ECC
324836e94dc5SPeter Avalos 	case KEY_ECDSA:
32490cbfa66cSDaniel Fojt 		if (format == SSHKEY_PRIVATE_PEM) {
325036e94dc5SPeter Avalos 			success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa,
325136e94dc5SPeter Avalos 			    cipher, passphrase, len, NULL, NULL);
32520cbfa66cSDaniel Fojt 		} else {
32530cbfa66cSDaniel Fojt 			success = EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa);
32540cbfa66cSDaniel Fojt 		}
325536e94dc5SPeter Avalos 		break;
325636e94dc5SPeter Avalos #endif
325736e94dc5SPeter Avalos 	case KEY_RSA:
32580cbfa66cSDaniel Fojt 		if (format == SSHKEY_PRIVATE_PEM) {
325936e94dc5SPeter Avalos 			success = PEM_write_bio_RSAPrivateKey(bio, key->rsa,
326036e94dc5SPeter Avalos 			    cipher, passphrase, len, NULL, NULL);
32610cbfa66cSDaniel Fojt 		} else {
32620cbfa66cSDaniel Fojt 			success = EVP_PKEY_set1_RSA(pkey, key->rsa);
32630cbfa66cSDaniel Fojt 		}
326436e94dc5SPeter Avalos 		break;
326536e94dc5SPeter Avalos 	default:
326636e94dc5SPeter Avalos 		success = 0;
326736e94dc5SPeter Avalos 		break;
326836e94dc5SPeter Avalos 	}
326936e94dc5SPeter Avalos 	if (success == 0) {
327036e94dc5SPeter Avalos 		r = SSH_ERR_LIBCRYPTO_ERROR;
327136e94dc5SPeter Avalos 		goto out;
327236e94dc5SPeter Avalos 	}
32730cbfa66cSDaniel Fojt 	if (format == SSHKEY_PRIVATE_PKCS8) {
32740cbfa66cSDaniel Fojt 		if ((success = PEM_write_bio_PrivateKey(bio, pkey, cipher,
32750cbfa66cSDaniel Fojt 		    passphrase, len, NULL, NULL)) == 0) {
32760cbfa66cSDaniel Fojt 			r = SSH_ERR_LIBCRYPTO_ERROR;
32770cbfa66cSDaniel Fojt 			goto out;
32780cbfa66cSDaniel Fojt 		}
32790cbfa66cSDaniel Fojt 	}
328036e94dc5SPeter Avalos 	if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) {
328136e94dc5SPeter Avalos 		r = SSH_ERR_INTERNAL_ERROR;
328236e94dc5SPeter Avalos 		goto out;
328336e94dc5SPeter Avalos 	}
328436e94dc5SPeter Avalos 	if ((r = sshbuf_put(blob, bptr, blen)) != 0)
328536e94dc5SPeter Avalos 		goto out;
328636e94dc5SPeter Avalos 	r = 0;
328736e94dc5SPeter Avalos  out:
32880cbfa66cSDaniel Fojt 	if (was_shielded)
32890cbfa66cSDaniel Fojt 		r = sshkey_shield_private(key);
32900cbfa66cSDaniel Fojt 	if (r == 0)
32910cbfa66cSDaniel Fojt 		r = sshbuf_putb(buf, blob);
32920cbfa66cSDaniel Fojt 
32930cbfa66cSDaniel Fojt 	EVP_PKEY_free(pkey);
32940cbfa66cSDaniel Fojt 	sshbuf_free(blob);
329536e94dc5SPeter Avalos 	BIO_free(bio);
329636e94dc5SPeter Avalos 	return r;
329736e94dc5SPeter Avalos }
329836e94dc5SPeter Avalos #endif /* WITH_OPENSSL */
329936e94dc5SPeter Avalos 
330036e94dc5SPeter Avalos /* Serialise "key" to buffer "blob" */
330136e94dc5SPeter Avalos int
sshkey_private_to_fileblob(struct sshkey * key,struct sshbuf * blob,const char * passphrase,const char * comment,int format,const char * openssh_format_cipher,int openssh_format_rounds)330236e94dc5SPeter Avalos sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob,
330336e94dc5SPeter Avalos     const char *passphrase, const char *comment,
33040cbfa66cSDaniel Fojt     int format, const char *openssh_format_cipher, int openssh_format_rounds)
330536e94dc5SPeter Avalos {
330636e94dc5SPeter Avalos 	switch (key->type) {
3307e9778795SPeter Avalos #ifdef WITH_OPENSSL
330836e94dc5SPeter Avalos 	case KEY_DSA:
330936e94dc5SPeter Avalos 	case KEY_ECDSA:
331036e94dc5SPeter Avalos 	case KEY_RSA:
33110cbfa66cSDaniel Fojt 		break; /* see below */
331236e94dc5SPeter Avalos #endif /* WITH_OPENSSL */
331336e94dc5SPeter Avalos 	case KEY_ED25519:
33140cbfa66cSDaniel Fojt 	case KEY_ED25519_SK:
3315664f4763Szrj #ifdef WITH_XMSS
3316664f4763Szrj 	case KEY_XMSS:
3317664f4763Szrj #endif /* WITH_XMSS */
33180cbfa66cSDaniel Fojt #ifdef WITH_OPENSSL
33190cbfa66cSDaniel Fojt 	case KEY_ECDSA_SK:
33200cbfa66cSDaniel Fojt #endif /* WITH_OPENSSL */
332136e94dc5SPeter Avalos 		return sshkey_private_to_blob2(key, blob, passphrase,
33220cbfa66cSDaniel Fojt 		    comment, openssh_format_cipher, openssh_format_rounds);
332336e94dc5SPeter Avalos 	default:
332436e94dc5SPeter Avalos 		return SSH_ERR_KEY_TYPE_UNKNOWN;
332536e94dc5SPeter Avalos 	}
332636e94dc5SPeter Avalos 
33270cbfa66cSDaniel Fojt #ifdef WITH_OPENSSL
33280cbfa66cSDaniel Fojt 	switch (format) {
33290cbfa66cSDaniel Fojt 	case SSHKEY_PRIVATE_OPENSSH:
33300cbfa66cSDaniel Fojt 		return sshkey_private_to_blob2(key, blob, passphrase,
33310cbfa66cSDaniel Fojt 		    comment, openssh_format_cipher, openssh_format_rounds);
33320cbfa66cSDaniel Fojt 	case SSHKEY_PRIVATE_PEM:
33330cbfa66cSDaniel Fojt 	case SSHKEY_PRIVATE_PKCS8:
33340cbfa66cSDaniel Fojt 		return sshkey_private_to_blob_pem_pkcs8(key, blob,
33350cbfa66cSDaniel Fojt 		    format, passphrase, comment);
33360cbfa66cSDaniel Fojt 	default:
33370cbfa66cSDaniel Fojt 		return SSH_ERR_INVALID_ARGUMENT;
33380cbfa66cSDaniel Fojt 	}
33390cbfa66cSDaniel Fojt #endif /* WITH_OPENSSL */
33400cbfa66cSDaniel Fojt }
334136e94dc5SPeter Avalos 
334236e94dc5SPeter Avalos #ifdef WITH_OPENSSL
3343e9778795SPeter Avalos static int
translate_libcrypto_error(unsigned long pem_err)3344ce74bacaSMatthew Dillon translate_libcrypto_error(unsigned long pem_err)
3345ce74bacaSMatthew Dillon {
3346ce74bacaSMatthew Dillon 	int pem_reason = ERR_GET_REASON(pem_err);
3347ce74bacaSMatthew Dillon 
3348ce74bacaSMatthew Dillon 	switch (ERR_GET_LIB(pem_err)) {
3349ce74bacaSMatthew Dillon 	case ERR_LIB_PEM:
3350ce74bacaSMatthew Dillon 		switch (pem_reason) {
3351ce74bacaSMatthew Dillon 		case PEM_R_BAD_PASSWORD_READ:
3352*ba1276acSMatthew Dillon #ifdef PEM_R_PROBLEMS_GETTING_PASSWORD
3353ce74bacaSMatthew Dillon 		case PEM_R_PROBLEMS_GETTING_PASSWORD:
3354*ba1276acSMatthew Dillon #endif
3355*ba1276acSMatthew Dillon #ifdef PEM_R_BAD_DECRYPT
3356ce74bacaSMatthew Dillon 		case PEM_R_BAD_DECRYPT:
3357*ba1276acSMatthew Dillon #endif
3358ce74bacaSMatthew Dillon 			return SSH_ERR_KEY_WRONG_PASSPHRASE;
3359ce74bacaSMatthew Dillon 		default:
3360ce74bacaSMatthew Dillon 			return SSH_ERR_INVALID_FORMAT;
3361ce74bacaSMatthew Dillon 		}
3362ce74bacaSMatthew Dillon 	case ERR_LIB_EVP:
3363ce74bacaSMatthew Dillon 		switch (pem_reason) {
3364*ba1276acSMatthew Dillon #ifdef EVP_R_BAD_DECRYPT
3365ce74bacaSMatthew Dillon 		case EVP_R_BAD_DECRYPT:
3366ce74bacaSMatthew Dillon 			return SSH_ERR_KEY_WRONG_PASSPHRASE;
3367*ba1276acSMatthew Dillon #endif
3368664f4763Szrj #ifdef EVP_R_BN_DECODE_ERROR
3369ce74bacaSMatthew Dillon 		case EVP_R_BN_DECODE_ERROR:
3370664f4763Szrj #endif
3371ce74bacaSMatthew Dillon 		case EVP_R_DECODE_ERROR:
3372ce74bacaSMatthew Dillon #ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR
3373ce74bacaSMatthew Dillon 		case EVP_R_PRIVATE_KEY_DECODE_ERROR:
3374ce74bacaSMatthew Dillon #endif
3375ce74bacaSMatthew Dillon 			return SSH_ERR_INVALID_FORMAT;
3376ce74bacaSMatthew Dillon 		default:
3377ce74bacaSMatthew Dillon 			return SSH_ERR_LIBCRYPTO_ERROR;
3378ce74bacaSMatthew Dillon 		}
3379ce74bacaSMatthew Dillon 	case ERR_LIB_ASN1:
3380ce74bacaSMatthew Dillon 		return SSH_ERR_INVALID_FORMAT;
3381ce74bacaSMatthew Dillon 	}
3382ce74bacaSMatthew Dillon 	return SSH_ERR_LIBCRYPTO_ERROR;
3383ce74bacaSMatthew Dillon }
3384ce74bacaSMatthew Dillon 
3385ce74bacaSMatthew Dillon static void
clear_libcrypto_errors(void)3386ce74bacaSMatthew Dillon clear_libcrypto_errors(void)
3387ce74bacaSMatthew Dillon {
3388ce74bacaSMatthew Dillon 	while (ERR_get_error() != 0)
3389ce74bacaSMatthew Dillon 		;
3390ce74bacaSMatthew Dillon }
3391ce74bacaSMatthew Dillon 
3392ce74bacaSMatthew Dillon /*
3393ce74bacaSMatthew Dillon  * Translate OpenSSL error codes to determine whether
3394ce74bacaSMatthew Dillon  * passphrase is required/incorrect.
3395ce74bacaSMatthew Dillon  */
3396ce74bacaSMatthew Dillon static int
convert_libcrypto_error(void)3397ce74bacaSMatthew Dillon convert_libcrypto_error(void)
3398ce74bacaSMatthew Dillon {
3399ce74bacaSMatthew Dillon 	/*
3400ce74bacaSMatthew Dillon 	 * Some password errors are reported at the beginning
3401ce74bacaSMatthew Dillon 	 * of the error queue.
3402ce74bacaSMatthew Dillon 	 */
3403ce74bacaSMatthew Dillon 	if (translate_libcrypto_error(ERR_peek_error()) ==
3404ce74bacaSMatthew Dillon 	    SSH_ERR_KEY_WRONG_PASSPHRASE)
3405ce74bacaSMatthew Dillon 		return SSH_ERR_KEY_WRONG_PASSPHRASE;
3406ce74bacaSMatthew Dillon 	return translate_libcrypto_error(ERR_peek_last_error());
3407ce74bacaSMatthew Dillon }
3408ce74bacaSMatthew Dillon 
3409ce74bacaSMatthew Dillon static int
pem_passphrase_cb(char * buf,int size,int rwflag,void * u)3410664f4763Szrj pem_passphrase_cb(char *buf, int size, int rwflag, void *u)
3411664f4763Szrj {
3412664f4763Szrj 	char *p = (char *)u;
3413664f4763Szrj 	size_t len;
3414664f4763Szrj 
3415664f4763Szrj 	if (p == NULL || (len = strlen(p)) == 0)
3416664f4763Szrj 		return -1;
3417664f4763Szrj 	if (size < 0 || len > (size_t)size)
3418664f4763Szrj 		return -1;
3419664f4763Szrj 	memcpy(buf, p, len);
3420664f4763Szrj 	return (int)len;
3421664f4763Szrj }
3422664f4763Szrj 
3423664f4763Szrj static int
sshkey_parse_private_pem_fileblob(struct sshbuf * blob,int type,const char * passphrase,struct sshkey ** keyp)342436e94dc5SPeter Avalos sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
3425e9778795SPeter Avalos     const char *passphrase, struct sshkey **keyp)
342636e94dc5SPeter Avalos {
342736e94dc5SPeter Avalos 	EVP_PKEY *pk = NULL;
342836e94dc5SPeter Avalos 	struct sshkey *prv = NULL;
342936e94dc5SPeter Avalos 	BIO *bio = NULL;
343036e94dc5SPeter Avalos 	int r;
343136e94dc5SPeter Avalos 
3432e9778795SPeter Avalos 	if (keyp != NULL)
343336e94dc5SPeter Avalos 		*keyp = NULL;
343436e94dc5SPeter Avalos 
343536e94dc5SPeter Avalos 	if ((bio = BIO_new(BIO_s_mem())) == NULL || sshbuf_len(blob) > INT_MAX)
343636e94dc5SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
343736e94dc5SPeter Avalos 	if (BIO_write(bio, sshbuf_ptr(blob), sshbuf_len(blob)) !=
343836e94dc5SPeter Avalos 	    (int)sshbuf_len(blob)) {
343936e94dc5SPeter Avalos 		r = SSH_ERR_ALLOC_FAIL;
344036e94dc5SPeter Avalos 		goto out;
344136e94dc5SPeter Avalos 	}
344236e94dc5SPeter Avalos 
3443ce74bacaSMatthew Dillon 	clear_libcrypto_errors();
3444664f4763Szrj 	if ((pk = PEM_read_bio_PrivateKey(bio, NULL, pem_passphrase_cb,
344536e94dc5SPeter Avalos 	    (char *)passphrase)) == NULL) {
3446664f4763Szrj 		/*
3447664f4763Szrj 		 * libcrypto may return various ASN.1 errors when attempting
3448664f4763Szrj 		 * to parse a key with an incorrect passphrase.
3449664f4763Szrj 		 * Treat all format errors as "incorrect passphrase" if a
3450664f4763Szrj 		 * passphrase was supplied.
3451664f4763Szrj 		 */
3452664f4763Szrj 		if (passphrase != NULL && *passphrase != '\0')
3453664f4763Szrj 			r = SSH_ERR_KEY_WRONG_PASSPHRASE;
3454664f4763Szrj 		else
3455ce74bacaSMatthew Dillon 			r = convert_libcrypto_error();
345636e94dc5SPeter Avalos 		goto out;
345736e94dc5SPeter Avalos 	}
3458664f4763Szrj 	if (EVP_PKEY_base_id(pk) == EVP_PKEY_RSA &&
345936e94dc5SPeter Avalos 	    (type == KEY_UNSPEC || type == KEY_RSA)) {
346036e94dc5SPeter Avalos 		if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
346136e94dc5SPeter Avalos 			r = SSH_ERR_ALLOC_FAIL;
346236e94dc5SPeter Avalos 			goto out;
346336e94dc5SPeter Avalos 		}
346436e94dc5SPeter Avalos 		prv->rsa = EVP_PKEY_get1_RSA(pk);
346536e94dc5SPeter Avalos 		prv->type = KEY_RSA;
346636e94dc5SPeter Avalos #ifdef DEBUG_PK
346736e94dc5SPeter Avalos 		RSA_print_fp(stderr, prv->rsa, 8);
346836e94dc5SPeter Avalos #endif
346936e94dc5SPeter Avalos 		if (RSA_blinding_on(prv->rsa, NULL) != 1) {
347036e94dc5SPeter Avalos 			r = SSH_ERR_LIBCRYPTO_ERROR;
347136e94dc5SPeter Avalos 			goto out;
347236e94dc5SPeter Avalos 		}
3473ee116499SAntonio Huete Jimenez 		if ((r = sshkey_check_rsa_length(prv, 0)) != 0)
3474ce74bacaSMatthew Dillon 			goto out;
3475*ba1276acSMatthew Dillon #ifdef WITH_DSA
3476664f4763Szrj 	} else if (EVP_PKEY_base_id(pk) == EVP_PKEY_DSA &&
347736e94dc5SPeter Avalos 	    (type == KEY_UNSPEC || type == KEY_DSA)) {
347836e94dc5SPeter Avalos 		if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
347936e94dc5SPeter Avalos 			r = SSH_ERR_ALLOC_FAIL;
348036e94dc5SPeter Avalos 			goto out;
348136e94dc5SPeter Avalos 		}
348236e94dc5SPeter Avalos 		prv->dsa = EVP_PKEY_get1_DSA(pk);
348336e94dc5SPeter Avalos 		prv->type = KEY_DSA;
348436e94dc5SPeter Avalos #ifdef DEBUG_PK
348536e94dc5SPeter Avalos 		DSA_print_fp(stderr, prv->dsa, 8);
348636e94dc5SPeter Avalos #endif
3487*ba1276acSMatthew Dillon #endif
348836e94dc5SPeter Avalos #ifdef OPENSSL_HAS_ECC
3489664f4763Szrj 	} else if (EVP_PKEY_base_id(pk) == EVP_PKEY_EC &&
349036e94dc5SPeter Avalos 	    (type == KEY_UNSPEC || type == KEY_ECDSA)) {
349136e94dc5SPeter Avalos 		if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
349236e94dc5SPeter Avalos 			r = SSH_ERR_ALLOC_FAIL;
349336e94dc5SPeter Avalos 			goto out;
349436e94dc5SPeter Avalos 		}
349536e94dc5SPeter Avalos 		prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk);
349636e94dc5SPeter Avalos 		prv->type = KEY_ECDSA;
349736e94dc5SPeter Avalos 		prv->ecdsa_nid = sshkey_ecdsa_key_to_nid(prv->ecdsa);
349836e94dc5SPeter Avalos 		if (prv->ecdsa_nid == -1 ||
349936e94dc5SPeter Avalos 		    sshkey_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
350036e94dc5SPeter Avalos 		    sshkey_ec_validate_public(EC_KEY_get0_group(prv->ecdsa),
350136e94dc5SPeter Avalos 		    EC_KEY_get0_public_key(prv->ecdsa)) != 0 ||
350236e94dc5SPeter Avalos 		    sshkey_ec_validate_private(prv->ecdsa) != 0) {
350336e94dc5SPeter Avalos 			r = SSH_ERR_INVALID_FORMAT;
350436e94dc5SPeter Avalos 			goto out;
350536e94dc5SPeter Avalos 		}
350636e94dc5SPeter Avalos # ifdef DEBUG_PK
350736e94dc5SPeter Avalos 		if (prv != NULL && prv->ecdsa != NULL)
350836e94dc5SPeter Avalos 			sshkey_dump_ec_key(prv->ecdsa);
350936e94dc5SPeter Avalos # endif
351036e94dc5SPeter Avalos #endif /* OPENSSL_HAS_ECC */
3511*ba1276acSMatthew Dillon #ifdef OPENSSL_HAS_ED25519
3512*ba1276acSMatthew Dillon 	} else if (EVP_PKEY_base_id(pk) == EVP_PKEY_ED25519 &&
3513*ba1276acSMatthew Dillon 	    (type == KEY_UNSPEC || type == KEY_ED25519)) {
3514*ba1276acSMatthew Dillon 		size_t len;
3515*ba1276acSMatthew Dillon 
3516*ba1276acSMatthew Dillon 		if ((prv = sshkey_new(KEY_UNSPEC)) == NULL ||
3517*ba1276acSMatthew Dillon 		    (prv->ed25519_sk = calloc(1, ED25519_SK_SZ)) == NULL ||
3518*ba1276acSMatthew Dillon 		    (prv->ed25519_pk = calloc(1, ED25519_PK_SZ)) == NULL) {
3519*ba1276acSMatthew Dillon 			r = SSH_ERR_ALLOC_FAIL;
3520*ba1276acSMatthew Dillon 			goto out;
3521*ba1276acSMatthew Dillon 		}
3522*ba1276acSMatthew Dillon 		prv->type = KEY_ED25519;
3523*ba1276acSMatthew Dillon 		len = ED25519_PK_SZ;
3524*ba1276acSMatthew Dillon 		if (!EVP_PKEY_get_raw_public_key(pk, prv->ed25519_pk, &len)) {
3525*ba1276acSMatthew Dillon 			r = SSH_ERR_LIBCRYPTO_ERROR;
3526*ba1276acSMatthew Dillon 			goto out;
3527*ba1276acSMatthew Dillon 		}
3528*ba1276acSMatthew Dillon 		if (len != ED25519_PK_SZ) {
3529*ba1276acSMatthew Dillon 			r = SSH_ERR_INVALID_FORMAT;
3530*ba1276acSMatthew Dillon 			goto out;
3531*ba1276acSMatthew Dillon 		}
3532*ba1276acSMatthew Dillon 		len = ED25519_SK_SZ - ED25519_PK_SZ;
3533*ba1276acSMatthew Dillon 		if (!EVP_PKEY_get_raw_private_key(pk, prv->ed25519_sk, &len)) {
3534*ba1276acSMatthew Dillon 			r = SSH_ERR_LIBCRYPTO_ERROR;
3535*ba1276acSMatthew Dillon 			goto out;
3536*ba1276acSMatthew Dillon 		}
3537*ba1276acSMatthew Dillon 		if (len != ED25519_SK_SZ - ED25519_PK_SZ) {
3538*ba1276acSMatthew Dillon 			r = SSH_ERR_INVALID_FORMAT;
3539*ba1276acSMatthew Dillon 			goto out;
3540*ba1276acSMatthew Dillon 		}
3541*ba1276acSMatthew Dillon 		/* Append the public key to our private key */
3542*ba1276acSMatthew Dillon 		memcpy(prv->ed25519_sk + (ED25519_SK_SZ - ED25519_PK_SZ),
3543*ba1276acSMatthew Dillon 		    prv->ed25519_pk, ED25519_PK_SZ);
3544*ba1276acSMatthew Dillon # ifdef DEBUG_PK
3545*ba1276acSMatthew Dillon 		sshbuf_dump_data(prv->ed25519_sk, ED25519_SK_SZ, stderr);
3546*ba1276acSMatthew Dillon # endif
3547*ba1276acSMatthew Dillon #endif /* OPENSSL_HAS_ED25519 */
354836e94dc5SPeter Avalos 	} else {
354936e94dc5SPeter Avalos 		r = SSH_ERR_INVALID_FORMAT;
355036e94dc5SPeter Avalos 		goto out;
355136e94dc5SPeter Avalos 	}
355236e94dc5SPeter Avalos 	r = 0;
3553e9778795SPeter Avalos 	if (keyp != NULL) {
355436e94dc5SPeter Avalos 		*keyp = prv;
355536e94dc5SPeter Avalos 		prv = NULL;
3556e9778795SPeter Avalos 	}
355736e94dc5SPeter Avalos  out:
355836e94dc5SPeter Avalos 	BIO_free(bio);
355936e94dc5SPeter Avalos 	EVP_PKEY_free(pk);
356036e94dc5SPeter Avalos 	sshkey_free(prv);
356136e94dc5SPeter Avalos 	return r;
356236e94dc5SPeter Avalos }
356336e94dc5SPeter Avalos #endif /* WITH_OPENSSL */
356436e94dc5SPeter Avalos 
356536e94dc5SPeter Avalos int
sshkey_parse_private_fileblob_type(struct sshbuf * blob,int type,const char * passphrase,struct sshkey ** keyp,char ** commentp)356636e94dc5SPeter Avalos sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
356736e94dc5SPeter Avalos     const char *passphrase, struct sshkey **keyp, char **commentp)
356836e94dc5SPeter Avalos {
3569ce74bacaSMatthew Dillon 	int r = SSH_ERR_INTERNAL_ERROR;
3570ce74bacaSMatthew Dillon 
3571e9778795SPeter Avalos 	if (keyp != NULL)
357236e94dc5SPeter Avalos 		*keyp = NULL;
357336e94dc5SPeter Avalos 	if (commentp != NULL)
357436e94dc5SPeter Avalos 		*commentp = NULL;
357536e94dc5SPeter Avalos 
357636e94dc5SPeter Avalos 	switch (type) {
3577664f4763Szrj 	case KEY_XMSS:
35780cbfa66cSDaniel Fojt 		/* No fallback for new-format-only keys */
357936e94dc5SPeter Avalos 		return sshkey_parse_private2(blob, type, passphrase,
358036e94dc5SPeter Avalos 		    keyp, commentp);
35810cbfa66cSDaniel Fojt 	default:
3582ce74bacaSMatthew Dillon 		r = sshkey_parse_private2(blob, type, passphrase, keyp,
3583ce74bacaSMatthew Dillon 		    commentp);
35840cbfa66cSDaniel Fojt 		/* Only fallback to PEM parser if a format error occurred. */
35850cbfa66cSDaniel Fojt 		if (r != SSH_ERR_INVALID_FORMAT)
3586ce74bacaSMatthew Dillon 			return r;
358736e94dc5SPeter Avalos #ifdef WITH_OPENSSL
3588e9778795SPeter Avalos 		return sshkey_parse_private_pem_fileblob(blob, type,
3589e9778795SPeter Avalos 		    passphrase, keyp);
359036e94dc5SPeter Avalos #else
359136e94dc5SPeter Avalos 		return SSH_ERR_INVALID_FORMAT;
359236e94dc5SPeter Avalos #endif /* WITH_OPENSSL */
359336e94dc5SPeter Avalos 	}
359436e94dc5SPeter Avalos }
359536e94dc5SPeter Avalos 
359636e94dc5SPeter Avalos int
sshkey_parse_private_fileblob(struct sshbuf * buffer,const char * passphrase,struct sshkey ** keyp,char ** commentp)359736e94dc5SPeter Avalos sshkey_parse_private_fileblob(struct sshbuf *buffer, const char *passphrase,
3598e9778795SPeter Avalos     struct sshkey **keyp, char **commentp)
359936e94dc5SPeter Avalos {
360036e94dc5SPeter Avalos 	if (keyp != NULL)
360136e94dc5SPeter Avalos 		*keyp = NULL;
360236e94dc5SPeter Avalos 	if (commentp != NULL)
360336e94dc5SPeter Avalos 		*commentp = NULL;
360436e94dc5SPeter Avalos 
3605e9778795SPeter Avalos 	return sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC,
3606e9778795SPeter Avalos 	    passphrase, keyp, commentp);
360736e94dc5SPeter Avalos }
3608664f4763Szrj 
36090cbfa66cSDaniel Fojt void
sshkey_sig_details_free(struct sshkey_sig_details * details)36100cbfa66cSDaniel Fojt sshkey_sig_details_free(struct sshkey_sig_details *details)
36110cbfa66cSDaniel Fojt {
36120cbfa66cSDaniel Fojt 	freezero(details, sizeof(*details));
36130cbfa66cSDaniel Fojt }
36140cbfa66cSDaniel Fojt 
36150cbfa66cSDaniel Fojt int
sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf * blob,int type,struct sshkey ** pubkeyp)36160cbfa66cSDaniel Fojt sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob, int type,
36170cbfa66cSDaniel Fojt     struct sshkey **pubkeyp)
36180cbfa66cSDaniel Fojt {
36190cbfa66cSDaniel Fojt 	int r = SSH_ERR_INTERNAL_ERROR;
36200cbfa66cSDaniel Fojt 
36210cbfa66cSDaniel Fojt 	if (pubkeyp != NULL)
36220cbfa66cSDaniel Fojt 		*pubkeyp = NULL;
36230cbfa66cSDaniel Fojt 	/* only new-format private keys bundle a public key inside */
36240cbfa66cSDaniel Fojt 	if ((r = sshkey_parse_private2_pubkey(blob, type, pubkeyp)) != 0)
36250cbfa66cSDaniel Fojt 		return r;
36260cbfa66cSDaniel Fojt 	return 0;
36270cbfa66cSDaniel Fojt }
36280cbfa66cSDaniel Fojt 
3629664f4763Szrj #ifdef WITH_XMSS
3630664f4763Szrj /*
3631664f4763Szrj  * serialize the key with the current state and forward the state
3632664f4763Szrj  * maxsign times.
3633664f4763Szrj  */
3634664f4763Szrj int
sshkey_private_serialize_maxsign(struct sshkey * k,struct sshbuf * b,u_int32_t maxsign,int printerror)36350cbfa66cSDaniel Fojt sshkey_private_serialize_maxsign(struct sshkey *k, struct sshbuf *b,
363650a69bb5SSascha Wildner     u_int32_t maxsign, int printerror)
3637664f4763Szrj {
3638664f4763Szrj 	int r, rupdate;
3639664f4763Szrj 
3640664f4763Szrj 	if (maxsign == 0 ||
3641664f4763Szrj 	    sshkey_type_plain(k->type) != KEY_XMSS)
3642664f4763Szrj 		return sshkey_private_serialize_opt(k, b,
3643664f4763Szrj 		    SSHKEY_SERIALIZE_DEFAULT);
364450a69bb5SSascha Wildner 	if ((r = sshkey_xmss_get_state(k, printerror)) != 0 ||
3645664f4763Szrj 	    (r = sshkey_private_serialize_opt(k, b,
3646664f4763Szrj 	    SSHKEY_SERIALIZE_STATE)) != 0 ||
3647664f4763Szrj 	    (r = sshkey_xmss_forward_state(k, maxsign)) != 0)
3648664f4763Szrj 		goto out;
3649664f4763Szrj 	r = 0;
3650664f4763Szrj out:
365150a69bb5SSascha Wildner 	if ((rupdate = sshkey_xmss_update_state(k, printerror)) != 0) {
3652664f4763Szrj 		if (r == 0)
3653664f4763Szrj 			r = rupdate;
3654664f4763Szrj 	}
3655664f4763Szrj 	return r;
3656664f4763Szrj }
3657664f4763Szrj 
3658664f4763Szrj u_int32_t
sshkey_signatures_left(const struct sshkey * k)3659664f4763Szrj sshkey_signatures_left(const struct sshkey *k)
3660664f4763Szrj {
3661664f4763Szrj 	if (sshkey_type_plain(k->type) == KEY_XMSS)
3662664f4763Szrj 		return sshkey_xmss_signatures_left(k);
3663664f4763Szrj 	return 0;
3664664f4763Szrj }
3665664f4763Szrj 
3666664f4763Szrj int
sshkey_enable_maxsign(struct sshkey * k,u_int32_t maxsign)3667664f4763Szrj sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign)
3668664f4763Szrj {
3669664f4763Szrj 	if (sshkey_type_plain(k->type) != KEY_XMSS)
3670664f4763Szrj 		return SSH_ERR_INVALID_ARGUMENT;
3671664f4763Szrj 	return sshkey_xmss_enable_maxsign(k, maxsign);
3672664f4763Szrj }
3673664f4763Szrj 
3674664f4763Szrj int
sshkey_set_filename(struct sshkey * k,const char * filename)3675664f4763Szrj sshkey_set_filename(struct sshkey *k, const char *filename)
3676664f4763Szrj {
3677664f4763Szrj 	if (k == NULL)
3678664f4763Szrj 		return SSH_ERR_INVALID_ARGUMENT;
3679664f4763Szrj 	if (sshkey_type_plain(k->type) != KEY_XMSS)
3680664f4763Szrj 		return 0;
3681664f4763Szrj 	if (filename == NULL)
3682664f4763Szrj 		return SSH_ERR_INVALID_ARGUMENT;
3683664f4763Szrj 	if ((k->xmss_filename = strdup(filename)) == NULL)
3684664f4763Szrj 		return SSH_ERR_ALLOC_FAIL;
3685664f4763Szrj 	return 0;
3686664f4763Szrj }
3687664f4763Szrj #else
3688664f4763Szrj int
sshkey_private_serialize_maxsign(struct sshkey * k,struct sshbuf * b,u_int32_t maxsign,int printerror)36890cbfa66cSDaniel Fojt sshkey_private_serialize_maxsign(struct sshkey *k, struct sshbuf *b,
369050a69bb5SSascha Wildner     u_int32_t maxsign, int printerror)
3691664f4763Szrj {
3692664f4763Szrj 	return sshkey_private_serialize_opt(k, b, SSHKEY_SERIALIZE_DEFAULT);
3693664f4763Szrj }
3694664f4763Szrj 
3695664f4763Szrj u_int32_t
sshkey_signatures_left(const struct sshkey * k)3696664f4763Szrj sshkey_signatures_left(const struct sshkey *k)
3697664f4763Szrj {
3698664f4763Szrj 	return 0;
3699664f4763Szrj }
3700664f4763Szrj 
3701664f4763Szrj int
sshkey_enable_maxsign(struct sshkey * k,u_int32_t maxsign)3702664f4763Szrj sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign)
3703664f4763Szrj {
3704664f4763Szrj 	return SSH_ERR_INVALID_ARGUMENT;
3705664f4763Szrj }
3706664f4763Szrj 
3707664f4763Szrj int
sshkey_set_filename(struct sshkey * k,const char * filename)3708664f4763Szrj sshkey_set_filename(struct sshkey *k, const char *filename)
3709664f4763Szrj {
3710664f4763Szrj 	if (k == NULL)
3711664f4763Szrj 		return SSH_ERR_INVALID_ARGUMENT;
3712664f4763Szrj 	return 0;
3713664f4763Szrj }
3714664f4763Szrj #endif /* WITH_XMSS */
3715