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