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