1296853Sdes/* $OpenBSD: sshkey.c,v 1.31 2015/12/11 04:21:12 mmcc Exp $ */ 2276707Sdes/* 3276707Sdes * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 4276707Sdes * Copyright (c) 2008 Alexander von Gernler. All rights reserved. 5276707Sdes * Copyright (c) 2010,2011 Damien Miller. All rights reserved. 6276707Sdes * 7276707Sdes * Redistribution and use in source and binary forms, with or without 8276707Sdes * modification, are permitted provided that the following conditions 9276707Sdes * are met: 10276707Sdes * 1. Redistributions of source code must retain the above copyright 11276707Sdes * notice, this list of conditions and the following disclaimer. 12276707Sdes * 2. Redistributions in binary form must reproduce the above copyright 13276707Sdes * notice, this list of conditions and the following disclaimer in the 14276707Sdes * documentation and/or other materials provided with the distribution. 15276707Sdes * 16276707Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17276707Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18276707Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19276707Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20276707Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21276707Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22276707Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23276707Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24276707Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25276707Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26276707Sdes */ 27276707Sdes 28276707Sdes#include "includes.h" 29276707Sdes 30295367Sdes#include <sys/param.h> /* MIN MAX */ 31276707Sdes#include <sys/types.h> 32295367Sdes#include <netinet/in.h> 33276707Sdes 34295367Sdes#ifdef WITH_OPENSSL 35276707Sdes#include <openssl/evp.h> 36276707Sdes#include <openssl/err.h> 37276707Sdes#include <openssl/pem.h> 38295367Sdes#endif 39276707Sdes 40276707Sdes#include "crypto_api.h" 41276707Sdes 42276707Sdes#include <errno.h> 43295367Sdes#include <limits.h> 44276707Sdes#include <stdio.h> 45276707Sdes#include <string.h> 46295367Sdes#include <resolv.h> 47276707Sdes#ifdef HAVE_UTIL_H 48276707Sdes#include <util.h> 49276707Sdes#endif /* HAVE_UTIL_H */ 50276707Sdes 51276707Sdes#include "ssh2.h" 52276707Sdes#include "ssherr.h" 53276707Sdes#include "misc.h" 54276707Sdes#include "sshbuf.h" 55276707Sdes#include "rsa.h" 56276707Sdes#include "cipher.h" 57276707Sdes#include "digest.h" 58276707Sdes#define SSHKEY_INTERNAL 59276707Sdes#include "sshkey.h" 60295367Sdes#include "match.h" 61276707Sdes 62276707Sdes/* openssh private key file format */ 63276707Sdes#define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n" 64276707Sdes#define MARK_END "-----END OPENSSH PRIVATE KEY-----\n" 65276707Sdes#define MARK_BEGIN_LEN (sizeof(MARK_BEGIN) - 1) 66276707Sdes#define MARK_END_LEN (sizeof(MARK_END) - 1) 67276707Sdes#define KDFNAME "bcrypt" 68276707Sdes#define AUTH_MAGIC "openssh-key-v1" 69276707Sdes#define SALT_LEN 16 70276707Sdes#define DEFAULT_CIPHERNAME "aes256-cbc" 71276707Sdes#define DEFAULT_ROUNDS 16 72276707Sdes 73276707Sdes/* Version identification string for SSH v1 identity files. */ 74276707Sdes#define LEGACY_BEGIN "SSH PRIVATE KEY FILE FORMAT 1.1\n" 75276707Sdes 76295367Sdesstatic int sshkey_from_blob_internal(struct sshbuf *buf, 77276707Sdes struct sshkey **keyp, int allow_cert); 78276707Sdes 79276707Sdes/* Supported key types */ 80276707Sdesstruct keytype { 81276707Sdes const char *name; 82276707Sdes const char *shortname; 83276707Sdes int type; 84276707Sdes int nid; 85276707Sdes int cert; 86296853Sdes int sigonly; 87276707Sdes}; 88276707Sdesstatic const struct keytype keytypes[] = { 89296853Sdes { "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0, 0 }, 90276707Sdes { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT", 91296853Sdes KEY_ED25519_CERT, 0, 1, 0 }, 92276707Sdes#ifdef WITH_OPENSSL 93296853Sdes { NULL, "RSA1", KEY_RSA1, 0, 0, 0 }, 94296853Sdes { "ssh-rsa", "RSA", KEY_RSA, 0, 0, 0 }, 95296853Sdes { "rsa-sha2-256", "RSA", KEY_RSA, 0, 0, 1 }, 96296853Sdes { "rsa-sha2-512", "RSA", KEY_RSA, 0, 0, 1 }, 97296853Sdes { "ssh-dss", "DSA", KEY_DSA, 0, 0, 0 }, 98276707Sdes# ifdef OPENSSL_HAS_ECC 99296853Sdes { "ecdsa-sha2-nistp256", "ECDSA", KEY_ECDSA, NID_X9_62_prime256v1, 0, 0 }, 100296853Sdes { "ecdsa-sha2-nistp384", "ECDSA", KEY_ECDSA, NID_secp384r1, 0, 0 }, 101276707Sdes# ifdef OPENSSL_HAS_NISTP521 102296853Sdes { "ecdsa-sha2-nistp521", "ECDSA", KEY_ECDSA, NID_secp521r1, 0, 0 }, 103276707Sdes# endif /* OPENSSL_HAS_NISTP521 */ 104276707Sdes# endif /* OPENSSL_HAS_ECC */ 105296853Sdes { "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", KEY_RSA_CERT, 0, 1, 0 }, 106296853Sdes { "ssh-dss-cert-v01@openssh.com", "DSA-CERT", KEY_DSA_CERT, 0, 1, 0 }, 107276707Sdes# ifdef OPENSSL_HAS_ECC 108276707Sdes { "ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-CERT", 109296853Sdes KEY_ECDSA_CERT, NID_X9_62_prime256v1, 1, 0 }, 110276707Sdes { "ecdsa-sha2-nistp384-cert-v01@openssh.com", "ECDSA-CERT", 111296853Sdes KEY_ECDSA_CERT, NID_secp384r1, 1, 0 }, 112276707Sdes# ifdef OPENSSL_HAS_NISTP521 113276707Sdes { "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT", 114296853Sdes KEY_ECDSA_CERT, NID_secp521r1, 1, 0 }, 115276707Sdes# endif /* OPENSSL_HAS_NISTP521 */ 116276707Sdes# endif /* OPENSSL_HAS_ECC */ 117276707Sdes#endif /* WITH_OPENSSL */ 118296853Sdes { NULL, NULL, -1, -1, 0, 0 } 119276707Sdes}; 120276707Sdes 121276707Sdesconst char * 122276707Sdessshkey_type(const struct sshkey *k) 123276707Sdes{ 124276707Sdes const struct keytype *kt; 125276707Sdes 126276707Sdes for (kt = keytypes; kt->type != -1; kt++) { 127276707Sdes if (kt->type == k->type) 128276707Sdes return kt->shortname; 129276707Sdes } 130276707Sdes return "unknown"; 131276707Sdes} 132276707Sdes 133276707Sdesstatic const char * 134276707Sdessshkey_ssh_name_from_type_nid(int type, int nid) 135276707Sdes{ 136276707Sdes const struct keytype *kt; 137276707Sdes 138276707Sdes for (kt = keytypes; kt->type != -1; kt++) { 139276707Sdes if (kt->type == type && (kt->nid == 0 || kt->nid == nid)) 140276707Sdes return kt->name; 141276707Sdes } 142276707Sdes return "ssh-unknown"; 143276707Sdes} 144276707Sdes 145276707Sdesint 146276707Sdessshkey_type_is_cert(int type) 147276707Sdes{ 148276707Sdes const struct keytype *kt; 149276707Sdes 150276707Sdes for (kt = keytypes; kt->type != -1; kt++) { 151276707Sdes if (kt->type == type) 152276707Sdes return kt->cert; 153276707Sdes } 154276707Sdes return 0; 155276707Sdes} 156276707Sdes 157276707Sdesconst char * 158276707Sdessshkey_ssh_name(const struct sshkey *k) 159276707Sdes{ 160276707Sdes return sshkey_ssh_name_from_type_nid(k->type, k->ecdsa_nid); 161276707Sdes} 162276707Sdes 163276707Sdesconst char * 164276707Sdessshkey_ssh_name_plain(const struct sshkey *k) 165276707Sdes{ 166276707Sdes return sshkey_ssh_name_from_type_nid(sshkey_type_plain(k->type), 167276707Sdes k->ecdsa_nid); 168276707Sdes} 169276707Sdes 170276707Sdesint 171276707Sdessshkey_type_from_name(const char *name) 172276707Sdes{ 173276707Sdes const struct keytype *kt; 174276707Sdes 175276707Sdes for (kt = keytypes; kt->type != -1; kt++) { 176276707Sdes /* Only allow shortname matches for plain key types */ 177276707Sdes if ((kt->name != NULL && strcmp(name, kt->name) == 0) || 178276707Sdes (!kt->cert && strcasecmp(kt->shortname, name) == 0)) 179276707Sdes return kt->type; 180276707Sdes } 181276707Sdes return KEY_UNSPEC; 182276707Sdes} 183276707Sdes 184276707Sdesint 185276707Sdessshkey_ecdsa_nid_from_name(const char *name) 186276707Sdes{ 187276707Sdes const struct keytype *kt; 188276707Sdes 189295367Sdes for (kt = keytypes; kt->type != -1; kt++) { 190295367Sdes if (kt->type != KEY_ECDSA && kt->type != KEY_ECDSA_CERT) 191295367Sdes continue; 192295367Sdes if (kt->name != NULL && strcmp(name, kt->name) == 0) 193295367Sdes return kt->nid; 194295367Sdes } 195276707Sdes return -1; 196276707Sdes} 197276707Sdes 198276707Sdeschar * 199276707Sdeskey_alg_list(int certs_only, int plain_only) 200276707Sdes{ 201276707Sdes char *tmp, *ret = NULL; 202276707Sdes size_t nlen, rlen = 0; 203276707Sdes const struct keytype *kt; 204276707Sdes 205276707Sdes for (kt = keytypes; kt->type != -1; kt++) { 206296853Sdes if (kt->name == NULL || kt->sigonly) 207276707Sdes continue; 208276707Sdes if ((certs_only && !kt->cert) || (plain_only && kt->cert)) 209276707Sdes continue; 210276707Sdes if (ret != NULL) 211276707Sdes ret[rlen++] = '\n'; 212276707Sdes nlen = strlen(kt->name); 213276707Sdes if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { 214276707Sdes free(ret); 215276707Sdes return NULL; 216276707Sdes } 217276707Sdes ret = tmp; 218276707Sdes memcpy(ret + rlen, kt->name, nlen + 1); 219276707Sdes rlen += nlen; 220276707Sdes } 221276707Sdes return ret; 222276707Sdes} 223276707Sdes 224276707Sdesint 225295367Sdessshkey_names_valid2(const char *names, int allow_wildcard) 226276707Sdes{ 227276707Sdes char *s, *cp, *p; 228295367Sdes const struct keytype *kt; 229295367Sdes int type; 230276707Sdes 231276707Sdes if (names == NULL || strcmp(names, "") == 0) 232276707Sdes return 0; 233276707Sdes if ((s = cp = strdup(names)) == NULL) 234276707Sdes return 0; 235276707Sdes for ((p = strsep(&cp, ",")); p && *p != '\0'; 236276707Sdes (p = strsep(&cp, ","))) { 237295367Sdes type = sshkey_type_from_name(p); 238295367Sdes if (type == KEY_RSA1) { 239276707Sdes free(s); 240276707Sdes return 0; 241276707Sdes } 242295367Sdes if (type == KEY_UNSPEC) { 243295367Sdes if (allow_wildcard) { 244295367Sdes /* 245295367Sdes * Try matching key types against the string. 246295367Sdes * If any has a positive or negative match then 247295367Sdes * the component is accepted. 248295367Sdes */ 249295367Sdes for (kt = keytypes; kt->type != -1; kt++) { 250295367Sdes if (kt->type == KEY_RSA1) 251295367Sdes continue; 252295367Sdes if (match_pattern_list(kt->name, 253295367Sdes p, 0) != 0) 254295367Sdes break; 255295367Sdes } 256295367Sdes if (kt->type != -1) 257295367Sdes continue; 258295367Sdes } 259295367Sdes free(s); 260295367Sdes return 0; 261295367Sdes } 262276707Sdes } 263276707Sdes free(s); 264276707Sdes return 1; 265276707Sdes} 266276707Sdes 267276707Sdesu_int 268276707Sdessshkey_size(const struct sshkey *k) 269276707Sdes{ 270276707Sdes switch (k->type) { 271276707Sdes#ifdef WITH_OPENSSL 272276707Sdes case KEY_RSA1: 273276707Sdes case KEY_RSA: 274276707Sdes case KEY_RSA_CERT: 275276707Sdes return BN_num_bits(k->rsa->n); 276276707Sdes case KEY_DSA: 277276707Sdes case KEY_DSA_CERT: 278276707Sdes return BN_num_bits(k->dsa->p); 279276707Sdes case KEY_ECDSA: 280276707Sdes case KEY_ECDSA_CERT: 281276707Sdes return sshkey_curve_nid_to_bits(k->ecdsa_nid); 282276707Sdes#endif /* WITH_OPENSSL */ 283276707Sdes case KEY_ED25519: 284276707Sdes case KEY_ED25519_CERT: 285276707Sdes return 256; /* XXX */ 286276707Sdes } 287276707Sdes return 0; 288276707Sdes} 289276707Sdes 290276707Sdesstatic int 291276707Sdessshkey_type_is_valid_ca(int type) 292276707Sdes{ 293276707Sdes switch (type) { 294276707Sdes case KEY_RSA: 295276707Sdes case KEY_DSA: 296276707Sdes case KEY_ECDSA: 297276707Sdes case KEY_ED25519: 298276707Sdes return 1; 299276707Sdes default: 300276707Sdes return 0; 301276707Sdes } 302276707Sdes} 303276707Sdes 304276707Sdesint 305276707Sdessshkey_is_cert(const struct sshkey *k) 306276707Sdes{ 307276707Sdes if (k == NULL) 308276707Sdes return 0; 309276707Sdes return sshkey_type_is_cert(k->type); 310276707Sdes} 311276707Sdes 312276707Sdes/* Return the cert-less equivalent to a certified key type */ 313276707Sdesint 314276707Sdessshkey_type_plain(int type) 315276707Sdes{ 316276707Sdes switch (type) { 317276707Sdes case KEY_RSA_CERT: 318276707Sdes return KEY_RSA; 319276707Sdes case KEY_DSA_CERT: 320276707Sdes return KEY_DSA; 321276707Sdes case KEY_ECDSA_CERT: 322276707Sdes return KEY_ECDSA; 323276707Sdes case KEY_ED25519_CERT: 324276707Sdes return KEY_ED25519; 325276707Sdes default: 326276707Sdes return type; 327276707Sdes } 328276707Sdes} 329276707Sdes 330276707Sdes#ifdef WITH_OPENSSL 331276707Sdes/* XXX: these are really begging for a table-driven approach */ 332276707Sdesint 333276707Sdessshkey_curve_name_to_nid(const char *name) 334276707Sdes{ 335276707Sdes if (strcmp(name, "nistp256") == 0) 336276707Sdes return NID_X9_62_prime256v1; 337276707Sdes else if (strcmp(name, "nistp384") == 0) 338276707Sdes return NID_secp384r1; 339276707Sdes# ifdef OPENSSL_HAS_NISTP521 340276707Sdes else if (strcmp(name, "nistp521") == 0) 341276707Sdes return NID_secp521r1; 342276707Sdes# endif /* OPENSSL_HAS_NISTP521 */ 343276707Sdes else 344276707Sdes return -1; 345276707Sdes} 346276707Sdes 347276707Sdesu_int 348276707Sdessshkey_curve_nid_to_bits(int nid) 349276707Sdes{ 350276707Sdes switch (nid) { 351276707Sdes case NID_X9_62_prime256v1: 352276707Sdes return 256; 353276707Sdes case NID_secp384r1: 354276707Sdes return 384; 355276707Sdes# ifdef OPENSSL_HAS_NISTP521 356276707Sdes case NID_secp521r1: 357276707Sdes return 521; 358276707Sdes# endif /* OPENSSL_HAS_NISTP521 */ 359276707Sdes default: 360276707Sdes return 0; 361276707Sdes } 362276707Sdes} 363276707Sdes 364276707Sdesint 365276707Sdessshkey_ecdsa_bits_to_nid(int bits) 366276707Sdes{ 367276707Sdes switch (bits) { 368276707Sdes case 256: 369276707Sdes return NID_X9_62_prime256v1; 370276707Sdes case 384: 371276707Sdes return NID_secp384r1; 372276707Sdes# ifdef OPENSSL_HAS_NISTP521 373276707Sdes case 521: 374276707Sdes return NID_secp521r1; 375276707Sdes# endif /* OPENSSL_HAS_NISTP521 */ 376276707Sdes default: 377276707Sdes return -1; 378276707Sdes } 379276707Sdes} 380276707Sdes 381276707Sdesconst char * 382276707Sdessshkey_curve_nid_to_name(int nid) 383276707Sdes{ 384276707Sdes switch (nid) { 385276707Sdes case NID_X9_62_prime256v1: 386276707Sdes return "nistp256"; 387276707Sdes case NID_secp384r1: 388276707Sdes return "nistp384"; 389276707Sdes# ifdef OPENSSL_HAS_NISTP521 390276707Sdes case NID_secp521r1: 391276707Sdes return "nistp521"; 392276707Sdes# endif /* OPENSSL_HAS_NISTP521 */ 393276707Sdes default: 394276707Sdes return NULL; 395276707Sdes } 396276707Sdes} 397276707Sdes 398276707Sdesint 399276707Sdessshkey_ec_nid_to_hash_alg(int nid) 400276707Sdes{ 401276707Sdes int kbits = sshkey_curve_nid_to_bits(nid); 402276707Sdes 403276707Sdes if (kbits <= 0) 404276707Sdes return -1; 405276707Sdes 406276707Sdes /* RFC5656 section 6.2.1 */ 407276707Sdes if (kbits <= 256) 408276707Sdes return SSH_DIGEST_SHA256; 409276707Sdes else if (kbits <= 384) 410276707Sdes return SSH_DIGEST_SHA384; 411276707Sdes else 412276707Sdes return SSH_DIGEST_SHA512; 413276707Sdes} 414276707Sdes#endif /* WITH_OPENSSL */ 415276707Sdes 416276707Sdesstatic void 417276707Sdescert_free(struct sshkey_cert *cert) 418276707Sdes{ 419276707Sdes u_int i; 420276707Sdes 421276707Sdes if (cert == NULL) 422276707Sdes return; 423296853Sdes sshbuf_free(cert->certblob); 424296853Sdes sshbuf_free(cert->critical); 425296853Sdes sshbuf_free(cert->extensions); 426296853Sdes free(cert->key_id); 427276707Sdes for (i = 0; i < cert->nprincipals; i++) 428276707Sdes free(cert->principals[i]); 429296853Sdes free(cert->principals); 430296853Sdes sshkey_free(cert->signature_key); 431276707Sdes explicit_bzero(cert, sizeof(*cert)); 432276707Sdes free(cert); 433276707Sdes} 434276707Sdes 435276707Sdesstatic struct sshkey_cert * 436276707Sdescert_new(void) 437276707Sdes{ 438276707Sdes struct sshkey_cert *cert; 439276707Sdes 440276707Sdes if ((cert = calloc(1, sizeof(*cert))) == NULL) 441276707Sdes return NULL; 442276707Sdes if ((cert->certblob = sshbuf_new()) == NULL || 443276707Sdes (cert->critical = sshbuf_new()) == NULL || 444276707Sdes (cert->extensions = sshbuf_new()) == NULL) { 445276707Sdes cert_free(cert); 446276707Sdes return NULL; 447276707Sdes } 448276707Sdes cert->key_id = NULL; 449276707Sdes cert->principals = NULL; 450276707Sdes cert->signature_key = NULL; 451276707Sdes return cert; 452276707Sdes} 453276707Sdes 454276707Sdesstruct sshkey * 455276707Sdessshkey_new(int type) 456276707Sdes{ 457276707Sdes struct sshkey *k; 458276707Sdes#ifdef WITH_OPENSSL 459276707Sdes RSA *rsa; 460276707Sdes DSA *dsa; 461276707Sdes#endif /* WITH_OPENSSL */ 462276707Sdes 463276707Sdes if ((k = calloc(1, sizeof(*k))) == NULL) 464276707Sdes return NULL; 465276707Sdes k->type = type; 466276707Sdes k->ecdsa = NULL; 467276707Sdes k->ecdsa_nid = -1; 468276707Sdes k->dsa = NULL; 469276707Sdes k->rsa = NULL; 470276707Sdes k->cert = NULL; 471276707Sdes k->ed25519_sk = NULL; 472276707Sdes k->ed25519_pk = NULL; 473276707Sdes switch (k->type) { 474276707Sdes#ifdef WITH_OPENSSL 475276707Sdes case KEY_RSA1: 476276707Sdes case KEY_RSA: 477276707Sdes case KEY_RSA_CERT: 478276707Sdes if ((rsa = RSA_new()) == NULL || 479276707Sdes (rsa->n = BN_new()) == NULL || 480276707Sdes (rsa->e = BN_new()) == NULL) { 481276707Sdes if (rsa != NULL) 482276707Sdes RSA_free(rsa); 483276707Sdes free(k); 484276707Sdes return NULL; 485276707Sdes } 486276707Sdes k->rsa = rsa; 487276707Sdes break; 488276707Sdes case KEY_DSA: 489276707Sdes case KEY_DSA_CERT: 490276707Sdes if ((dsa = DSA_new()) == NULL || 491276707Sdes (dsa->p = BN_new()) == NULL || 492276707Sdes (dsa->q = BN_new()) == NULL || 493276707Sdes (dsa->g = BN_new()) == NULL || 494276707Sdes (dsa->pub_key = BN_new()) == NULL) { 495276707Sdes if (dsa != NULL) 496276707Sdes DSA_free(dsa); 497276707Sdes free(k); 498276707Sdes return NULL; 499276707Sdes } 500276707Sdes k->dsa = dsa; 501276707Sdes break; 502276707Sdes case KEY_ECDSA: 503276707Sdes case KEY_ECDSA_CERT: 504276707Sdes /* Cannot do anything until we know the group */ 505276707Sdes break; 506276707Sdes#endif /* WITH_OPENSSL */ 507276707Sdes case KEY_ED25519: 508276707Sdes case KEY_ED25519_CERT: 509276707Sdes /* no need to prealloc */ 510276707Sdes break; 511276707Sdes case KEY_UNSPEC: 512276707Sdes break; 513276707Sdes default: 514276707Sdes free(k); 515276707Sdes return NULL; 516276707Sdes break; 517276707Sdes } 518276707Sdes 519276707Sdes if (sshkey_is_cert(k)) { 520276707Sdes if ((k->cert = cert_new()) == NULL) { 521276707Sdes sshkey_free(k); 522276707Sdes return NULL; 523276707Sdes } 524276707Sdes } 525276707Sdes 526276707Sdes return k; 527276707Sdes} 528276707Sdes 529276707Sdesint 530276707Sdessshkey_add_private(struct sshkey *k) 531276707Sdes{ 532276707Sdes switch (k->type) { 533276707Sdes#ifdef WITH_OPENSSL 534276707Sdes case KEY_RSA1: 535276707Sdes case KEY_RSA: 536276707Sdes case KEY_RSA_CERT: 537276707Sdes#define bn_maybe_alloc_failed(p) (p == NULL && (p = BN_new()) == NULL) 538276707Sdes if (bn_maybe_alloc_failed(k->rsa->d) || 539276707Sdes bn_maybe_alloc_failed(k->rsa->iqmp) || 540276707Sdes bn_maybe_alloc_failed(k->rsa->q) || 541276707Sdes bn_maybe_alloc_failed(k->rsa->p) || 542276707Sdes bn_maybe_alloc_failed(k->rsa->dmq1) || 543276707Sdes bn_maybe_alloc_failed(k->rsa->dmp1)) 544276707Sdes return SSH_ERR_ALLOC_FAIL; 545276707Sdes break; 546276707Sdes case KEY_DSA: 547276707Sdes case KEY_DSA_CERT: 548276707Sdes if (bn_maybe_alloc_failed(k->dsa->priv_key)) 549276707Sdes return SSH_ERR_ALLOC_FAIL; 550276707Sdes break; 551276707Sdes#undef bn_maybe_alloc_failed 552276707Sdes case KEY_ECDSA: 553276707Sdes case KEY_ECDSA_CERT: 554276707Sdes /* Cannot do anything until we know the group */ 555276707Sdes break; 556276707Sdes#endif /* WITH_OPENSSL */ 557276707Sdes case KEY_ED25519: 558276707Sdes case KEY_ED25519_CERT: 559276707Sdes /* no need to prealloc */ 560276707Sdes break; 561276707Sdes case KEY_UNSPEC: 562276707Sdes break; 563276707Sdes default: 564276707Sdes return SSH_ERR_INVALID_ARGUMENT; 565276707Sdes } 566276707Sdes return 0; 567276707Sdes} 568276707Sdes 569276707Sdesstruct sshkey * 570276707Sdessshkey_new_private(int type) 571276707Sdes{ 572276707Sdes struct sshkey *k = sshkey_new(type); 573276707Sdes 574276707Sdes if (k == NULL) 575276707Sdes return NULL; 576276707Sdes if (sshkey_add_private(k) != 0) { 577276707Sdes sshkey_free(k); 578276707Sdes return NULL; 579276707Sdes } 580276707Sdes return k; 581276707Sdes} 582276707Sdes 583276707Sdesvoid 584276707Sdessshkey_free(struct sshkey *k) 585276707Sdes{ 586276707Sdes if (k == NULL) 587276707Sdes return; 588276707Sdes switch (k->type) { 589276707Sdes#ifdef WITH_OPENSSL 590276707Sdes case KEY_RSA1: 591276707Sdes case KEY_RSA: 592276707Sdes case KEY_RSA_CERT: 593276707Sdes if (k->rsa != NULL) 594276707Sdes RSA_free(k->rsa); 595276707Sdes k->rsa = NULL; 596276707Sdes break; 597276707Sdes case KEY_DSA: 598276707Sdes case KEY_DSA_CERT: 599276707Sdes if (k->dsa != NULL) 600276707Sdes DSA_free(k->dsa); 601276707Sdes k->dsa = NULL; 602276707Sdes break; 603276707Sdes# ifdef OPENSSL_HAS_ECC 604276707Sdes case KEY_ECDSA: 605276707Sdes case KEY_ECDSA_CERT: 606276707Sdes if (k->ecdsa != NULL) 607276707Sdes EC_KEY_free(k->ecdsa); 608276707Sdes k->ecdsa = NULL; 609276707Sdes break; 610276707Sdes# endif /* OPENSSL_HAS_ECC */ 611276707Sdes#endif /* WITH_OPENSSL */ 612276707Sdes case KEY_ED25519: 613276707Sdes case KEY_ED25519_CERT: 614276707Sdes if (k->ed25519_pk) { 615276707Sdes explicit_bzero(k->ed25519_pk, ED25519_PK_SZ); 616276707Sdes free(k->ed25519_pk); 617276707Sdes k->ed25519_pk = NULL; 618276707Sdes } 619276707Sdes if (k->ed25519_sk) { 620276707Sdes explicit_bzero(k->ed25519_sk, ED25519_SK_SZ); 621276707Sdes free(k->ed25519_sk); 622276707Sdes k->ed25519_sk = NULL; 623276707Sdes } 624276707Sdes break; 625276707Sdes case KEY_UNSPEC: 626276707Sdes break; 627276707Sdes default: 628276707Sdes break; 629276707Sdes } 630276707Sdes if (sshkey_is_cert(k)) 631276707Sdes cert_free(k->cert); 632276707Sdes explicit_bzero(k, sizeof(*k)); 633276707Sdes free(k); 634276707Sdes} 635276707Sdes 636276707Sdesstatic int 637276707Sdescert_compare(struct sshkey_cert *a, struct sshkey_cert *b) 638276707Sdes{ 639276707Sdes if (a == NULL && b == NULL) 640276707Sdes return 1; 641276707Sdes if (a == NULL || b == NULL) 642276707Sdes return 0; 643276707Sdes if (sshbuf_len(a->certblob) != sshbuf_len(b->certblob)) 644276707Sdes return 0; 645276707Sdes if (timingsafe_bcmp(sshbuf_ptr(a->certblob), sshbuf_ptr(b->certblob), 646276707Sdes sshbuf_len(a->certblob)) != 0) 647276707Sdes return 0; 648276707Sdes return 1; 649276707Sdes} 650276707Sdes 651276707Sdes/* 652276707Sdes * Compare public portions of key only, allowing comparisons between 653276707Sdes * certificates and plain keys too. 654276707Sdes */ 655276707Sdesint 656276707Sdessshkey_equal_public(const struct sshkey *a, const struct sshkey *b) 657276707Sdes{ 658276707Sdes#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) 659276707Sdes BN_CTX *bnctx; 660276707Sdes#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ 661276707Sdes 662276707Sdes if (a == NULL || b == NULL || 663276707Sdes sshkey_type_plain(a->type) != sshkey_type_plain(b->type)) 664276707Sdes return 0; 665276707Sdes 666276707Sdes switch (a->type) { 667276707Sdes#ifdef WITH_OPENSSL 668276707Sdes case KEY_RSA1: 669276707Sdes case KEY_RSA_CERT: 670276707Sdes case KEY_RSA: 671276707Sdes return a->rsa != NULL && b->rsa != NULL && 672276707Sdes BN_cmp(a->rsa->e, b->rsa->e) == 0 && 673276707Sdes BN_cmp(a->rsa->n, b->rsa->n) == 0; 674276707Sdes case KEY_DSA_CERT: 675276707Sdes case KEY_DSA: 676276707Sdes return a->dsa != NULL && b->dsa != NULL && 677276707Sdes BN_cmp(a->dsa->p, b->dsa->p) == 0 && 678276707Sdes BN_cmp(a->dsa->q, b->dsa->q) == 0 && 679276707Sdes BN_cmp(a->dsa->g, b->dsa->g) == 0 && 680276707Sdes BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0; 681276707Sdes# ifdef OPENSSL_HAS_ECC 682276707Sdes case KEY_ECDSA_CERT: 683276707Sdes case KEY_ECDSA: 684276707Sdes if (a->ecdsa == NULL || b->ecdsa == NULL || 685276707Sdes EC_KEY_get0_public_key(a->ecdsa) == NULL || 686276707Sdes EC_KEY_get0_public_key(b->ecdsa) == NULL) 687276707Sdes return 0; 688276707Sdes if ((bnctx = BN_CTX_new()) == NULL) 689276707Sdes return 0; 690276707Sdes if (EC_GROUP_cmp(EC_KEY_get0_group(a->ecdsa), 691276707Sdes EC_KEY_get0_group(b->ecdsa), bnctx) != 0 || 692276707Sdes EC_POINT_cmp(EC_KEY_get0_group(a->ecdsa), 693276707Sdes EC_KEY_get0_public_key(a->ecdsa), 694276707Sdes EC_KEY_get0_public_key(b->ecdsa), bnctx) != 0) { 695276707Sdes BN_CTX_free(bnctx); 696276707Sdes return 0; 697276707Sdes } 698276707Sdes BN_CTX_free(bnctx); 699276707Sdes return 1; 700276707Sdes# endif /* OPENSSL_HAS_ECC */ 701276707Sdes#endif /* WITH_OPENSSL */ 702276707Sdes case KEY_ED25519: 703276707Sdes case KEY_ED25519_CERT: 704276707Sdes return a->ed25519_pk != NULL && b->ed25519_pk != NULL && 705276707Sdes memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0; 706276707Sdes default: 707276707Sdes return 0; 708276707Sdes } 709276707Sdes /* NOTREACHED */ 710276707Sdes} 711276707Sdes 712276707Sdesint 713276707Sdessshkey_equal(const struct sshkey *a, const struct sshkey *b) 714276707Sdes{ 715276707Sdes if (a == NULL || b == NULL || a->type != b->type) 716276707Sdes return 0; 717276707Sdes if (sshkey_is_cert(a)) { 718276707Sdes if (!cert_compare(a->cert, b->cert)) 719276707Sdes return 0; 720276707Sdes } 721276707Sdes return sshkey_equal_public(a, b); 722276707Sdes} 723276707Sdes 724276707Sdesstatic int 725276707Sdesto_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain) 726276707Sdes{ 727276707Sdes int type, ret = SSH_ERR_INTERNAL_ERROR; 728276707Sdes const char *typename; 729276707Sdes 730276707Sdes if (key == NULL) 731276707Sdes return SSH_ERR_INVALID_ARGUMENT; 732276707Sdes 733295367Sdes if (sshkey_is_cert(key)) { 734295367Sdes if (key->cert == NULL) 735295367Sdes return SSH_ERR_EXPECTED_CERT; 736295367Sdes if (sshbuf_len(key->cert->certblob) == 0) 737295367Sdes return SSH_ERR_KEY_LACKS_CERTBLOB; 738295367Sdes } 739276707Sdes type = force_plain ? sshkey_type_plain(key->type) : key->type; 740276707Sdes typename = sshkey_ssh_name_from_type_nid(type, key->ecdsa_nid); 741276707Sdes 742276707Sdes switch (type) { 743276707Sdes#ifdef WITH_OPENSSL 744276707Sdes case KEY_DSA_CERT: 745276707Sdes case KEY_ECDSA_CERT: 746276707Sdes case KEY_RSA_CERT: 747276707Sdes#endif /* WITH_OPENSSL */ 748276707Sdes case KEY_ED25519_CERT: 749276707Sdes /* Use the existing blob */ 750276707Sdes /* XXX modified flag? */ 751276707Sdes if ((ret = sshbuf_putb(b, key->cert->certblob)) != 0) 752276707Sdes return ret; 753276707Sdes break; 754276707Sdes#ifdef WITH_OPENSSL 755276707Sdes case KEY_DSA: 756276707Sdes if (key->dsa == NULL) 757276707Sdes return SSH_ERR_INVALID_ARGUMENT; 758276707Sdes if ((ret = sshbuf_put_cstring(b, typename)) != 0 || 759276707Sdes (ret = sshbuf_put_bignum2(b, key->dsa->p)) != 0 || 760276707Sdes (ret = sshbuf_put_bignum2(b, key->dsa->q)) != 0 || 761276707Sdes (ret = sshbuf_put_bignum2(b, key->dsa->g)) != 0 || 762276707Sdes (ret = sshbuf_put_bignum2(b, key->dsa->pub_key)) != 0) 763276707Sdes return ret; 764276707Sdes break; 765276707Sdes# ifdef OPENSSL_HAS_ECC 766276707Sdes case KEY_ECDSA: 767276707Sdes if (key->ecdsa == NULL) 768276707Sdes return SSH_ERR_INVALID_ARGUMENT; 769276707Sdes if ((ret = sshbuf_put_cstring(b, typename)) != 0 || 770276707Sdes (ret = sshbuf_put_cstring(b, 771276707Sdes sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 || 772276707Sdes (ret = sshbuf_put_eckey(b, key->ecdsa)) != 0) 773276707Sdes return ret; 774276707Sdes break; 775276707Sdes# endif 776276707Sdes case KEY_RSA: 777276707Sdes if (key->rsa == NULL) 778276707Sdes return SSH_ERR_INVALID_ARGUMENT; 779276707Sdes if ((ret = sshbuf_put_cstring(b, typename)) != 0 || 780276707Sdes (ret = sshbuf_put_bignum2(b, key->rsa->e)) != 0 || 781276707Sdes (ret = sshbuf_put_bignum2(b, key->rsa->n)) != 0) 782276707Sdes return ret; 783276707Sdes break; 784276707Sdes#endif /* WITH_OPENSSL */ 785276707Sdes case KEY_ED25519: 786276707Sdes if (key->ed25519_pk == NULL) 787276707Sdes return SSH_ERR_INVALID_ARGUMENT; 788276707Sdes if ((ret = sshbuf_put_cstring(b, typename)) != 0 || 789276707Sdes (ret = sshbuf_put_string(b, 790276707Sdes key->ed25519_pk, ED25519_PK_SZ)) != 0) 791276707Sdes return ret; 792276707Sdes break; 793276707Sdes default: 794276707Sdes return SSH_ERR_KEY_TYPE_UNKNOWN; 795276707Sdes } 796276707Sdes return 0; 797276707Sdes} 798276707Sdes 799276707Sdesint 800295367Sdessshkey_putb(const struct sshkey *key, struct sshbuf *b) 801276707Sdes{ 802276707Sdes return to_blob_buf(key, b, 0); 803276707Sdes} 804276707Sdes 805276707Sdesint 806295367Sdessshkey_puts(const struct sshkey *key, struct sshbuf *b) 807276707Sdes{ 808295367Sdes struct sshbuf *tmp; 809295367Sdes int r; 810295367Sdes 811295367Sdes if ((tmp = sshbuf_new()) == NULL) 812295367Sdes return SSH_ERR_ALLOC_FAIL; 813295367Sdes r = to_blob_buf(key, tmp, 0); 814295367Sdes if (r == 0) 815295367Sdes r = sshbuf_put_stringb(b, tmp); 816295367Sdes sshbuf_free(tmp); 817295367Sdes return r; 818295367Sdes} 819295367Sdes 820295367Sdesint 821295367Sdessshkey_putb_plain(const struct sshkey *key, struct sshbuf *b) 822295367Sdes{ 823276707Sdes return to_blob_buf(key, b, 1); 824276707Sdes} 825276707Sdes 826276707Sdesstatic int 827276707Sdesto_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain) 828276707Sdes{ 829276707Sdes int ret = SSH_ERR_INTERNAL_ERROR; 830276707Sdes size_t len; 831276707Sdes struct sshbuf *b = NULL; 832276707Sdes 833276707Sdes if (lenp != NULL) 834276707Sdes *lenp = 0; 835276707Sdes if (blobp != NULL) 836276707Sdes *blobp = NULL; 837276707Sdes if ((b = sshbuf_new()) == NULL) 838276707Sdes return SSH_ERR_ALLOC_FAIL; 839276707Sdes if ((ret = to_blob_buf(key, b, force_plain)) != 0) 840276707Sdes goto out; 841276707Sdes len = sshbuf_len(b); 842276707Sdes if (lenp != NULL) 843276707Sdes *lenp = len; 844276707Sdes if (blobp != NULL) { 845276707Sdes if ((*blobp = malloc(len)) == NULL) { 846276707Sdes ret = SSH_ERR_ALLOC_FAIL; 847276707Sdes goto out; 848276707Sdes } 849276707Sdes memcpy(*blobp, sshbuf_ptr(b), len); 850276707Sdes } 851276707Sdes ret = 0; 852276707Sdes out: 853276707Sdes sshbuf_free(b); 854276707Sdes return ret; 855276707Sdes} 856276707Sdes 857276707Sdesint 858276707Sdessshkey_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp) 859276707Sdes{ 860276707Sdes return to_blob(key, blobp, lenp, 0); 861276707Sdes} 862276707Sdes 863276707Sdesint 864276707Sdessshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp) 865276707Sdes{ 866276707Sdes return to_blob(key, blobp, lenp, 1); 867276707Sdes} 868276707Sdes 869276707Sdesint 870295367Sdessshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg, 871276707Sdes u_char **retp, size_t *lenp) 872276707Sdes{ 873276707Sdes u_char *blob = NULL, *ret = NULL; 874276707Sdes size_t blob_len = 0; 875295367Sdes int r = SSH_ERR_INTERNAL_ERROR; 876276707Sdes 877276707Sdes if (retp != NULL) 878276707Sdes *retp = NULL; 879276707Sdes if (lenp != NULL) 880276707Sdes *lenp = 0; 881295367Sdes if (ssh_digest_bytes(dgst_alg) == 0) { 882276707Sdes r = SSH_ERR_INVALID_ARGUMENT; 883276707Sdes goto out; 884276707Sdes } 885276707Sdes 886276707Sdes if (k->type == KEY_RSA1) { 887276707Sdes#ifdef WITH_OPENSSL 888276707Sdes int nlen = BN_num_bytes(k->rsa->n); 889276707Sdes int elen = BN_num_bytes(k->rsa->e); 890276707Sdes 891276707Sdes blob_len = nlen + elen; 892276707Sdes if (nlen >= INT_MAX - elen || 893276707Sdes (blob = malloc(blob_len)) == NULL) { 894276707Sdes r = SSH_ERR_ALLOC_FAIL; 895276707Sdes goto out; 896276707Sdes } 897276707Sdes BN_bn2bin(k->rsa->n, blob); 898276707Sdes BN_bn2bin(k->rsa->e, blob + nlen); 899276707Sdes#endif /* WITH_OPENSSL */ 900276707Sdes } else if ((r = to_blob(k, &blob, &blob_len, 1)) != 0) 901276707Sdes goto out; 902276707Sdes if ((ret = calloc(1, SSH_DIGEST_MAX_LENGTH)) == NULL) { 903276707Sdes r = SSH_ERR_ALLOC_FAIL; 904276707Sdes goto out; 905276707Sdes } 906295367Sdes if ((r = ssh_digest_memory(dgst_alg, blob, blob_len, 907276707Sdes ret, SSH_DIGEST_MAX_LENGTH)) != 0) 908276707Sdes goto out; 909276707Sdes /* success */ 910276707Sdes if (retp != NULL) { 911276707Sdes *retp = ret; 912276707Sdes ret = NULL; 913276707Sdes } 914276707Sdes if (lenp != NULL) 915295367Sdes *lenp = ssh_digest_bytes(dgst_alg); 916276707Sdes r = 0; 917276707Sdes out: 918276707Sdes free(ret); 919276707Sdes if (blob != NULL) { 920276707Sdes explicit_bzero(blob, blob_len); 921276707Sdes free(blob); 922276707Sdes } 923276707Sdes return r; 924276707Sdes} 925276707Sdes 926276707Sdesstatic char * 927295367Sdesfingerprint_b64(const char *alg, u_char *dgst_raw, size_t dgst_raw_len) 928276707Sdes{ 929295367Sdes char *ret; 930295367Sdes size_t plen = strlen(alg) + 1; 931295367Sdes size_t rlen = ((dgst_raw_len + 2) / 3) * 4 + plen + 1; 932295367Sdes int r; 933276707Sdes 934295367Sdes if (dgst_raw_len > 65536 || (ret = calloc(1, rlen)) == NULL) 935276707Sdes return NULL; 936295367Sdes strlcpy(ret, alg, rlen); 937295367Sdes strlcat(ret, ":", rlen); 938295367Sdes if (dgst_raw_len == 0) 939295367Sdes return ret; 940295367Sdes if ((r = b64_ntop(dgst_raw, dgst_raw_len, 941295367Sdes ret + plen, rlen - plen)) == -1) { 942295367Sdes explicit_bzero(ret, rlen); 943295367Sdes free(ret); 944295367Sdes return NULL; 945295367Sdes } 946295367Sdes /* Trim padding characters from end */ 947295367Sdes ret[strcspn(ret, "=")] = '\0'; 948295367Sdes return ret; 949295367Sdes} 950295367Sdes 951295367Sdesstatic char * 952295367Sdesfingerprint_hex(const char *alg, u_char *dgst_raw, size_t dgst_raw_len) 953295367Sdes{ 954295367Sdes char *retval, hex[5]; 955295367Sdes size_t i, rlen = dgst_raw_len * 3 + strlen(alg) + 2; 956295367Sdes 957295367Sdes if (dgst_raw_len > 65536 || (retval = calloc(1, rlen)) == NULL) 958295367Sdes return NULL; 959295367Sdes strlcpy(retval, alg, rlen); 960295367Sdes strlcat(retval, ":", rlen); 961276707Sdes for (i = 0; i < dgst_raw_len; i++) { 962295367Sdes snprintf(hex, sizeof(hex), "%s%02x", 963295367Sdes i > 0 ? ":" : "", dgst_raw[i]); 964295367Sdes strlcat(retval, hex, rlen); 965276707Sdes } 966276707Sdes return retval; 967276707Sdes} 968276707Sdes 969276707Sdesstatic char * 970276707Sdesfingerprint_bubblebabble(u_char *dgst_raw, size_t dgst_raw_len) 971276707Sdes{ 972276707Sdes char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' }; 973276707Sdes char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', 974276707Sdes 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' }; 975276707Sdes u_int i, j = 0, rounds, seed = 1; 976276707Sdes char *retval; 977276707Sdes 978276707Sdes rounds = (dgst_raw_len / 2) + 1; 979276707Sdes if ((retval = calloc(rounds, 6)) == NULL) 980276707Sdes return NULL; 981276707Sdes retval[j++] = 'x'; 982276707Sdes for (i = 0; i < rounds; i++) { 983276707Sdes u_int idx0, idx1, idx2, idx3, idx4; 984276707Sdes if ((i + 1 < rounds) || (dgst_raw_len % 2 != 0)) { 985276707Sdes idx0 = (((((u_int)(dgst_raw[2 * i])) >> 6) & 3) + 986276707Sdes seed) % 6; 987276707Sdes idx1 = (((u_int)(dgst_raw[2 * i])) >> 2) & 15; 988276707Sdes idx2 = ((((u_int)(dgst_raw[2 * i])) & 3) + 989276707Sdes (seed / 6)) % 6; 990276707Sdes retval[j++] = vowels[idx0]; 991276707Sdes retval[j++] = consonants[idx1]; 992276707Sdes retval[j++] = vowels[idx2]; 993276707Sdes if ((i + 1) < rounds) { 994276707Sdes idx3 = (((u_int)(dgst_raw[(2 * i) + 1])) >> 4) & 15; 995276707Sdes idx4 = (((u_int)(dgst_raw[(2 * i) + 1]))) & 15; 996276707Sdes retval[j++] = consonants[idx3]; 997276707Sdes retval[j++] = '-'; 998276707Sdes retval[j++] = consonants[idx4]; 999276707Sdes seed = ((seed * 5) + 1000276707Sdes ((((u_int)(dgst_raw[2 * i])) * 7) + 1001276707Sdes ((u_int)(dgst_raw[(2 * i) + 1])))) % 36; 1002276707Sdes } 1003276707Sdes } else { 1004276707Sdes idx0 = seed % 6; 1005276707Sdes idx1 = 16; 1006276707Sdes idx2 = seed / 6; 1007276707Sdes retval[j++] = vowels[idx0]; 1008276707Sdes retval[j++] = consonants[idx1]; 1009276707Sdes retval[j++] = vowels[idx2]; 1010276707Sdes } 1011276707Sdes } 1012276707Sdes retval[j++] = 'x'; 1013276707Sdes retval[j++] = '\0'; 1014276707Sdes return retval; 1015276707Sdes} 1016276707Sdes 1017276707Sdes/* 1018276707Sdes * Draw an ASCII-Art representing the fingerprint so human brain can 1019276707Sdes * profit from its built-in pattern recognition ability. 1020276707Sdes * This technique is called "random art" and can be found in some 1021276707Sdes * scientific publications like this original paper: 1022276707Sdes * 1023276707Sdes * "Hash Visualization: a New Technique to improve Real-World Security", 1024276707Sdes * Perrig A. and Song D., 1999, International Workshop on Cryptographic 1025276707Sdes * Techniques and E-Commerce (CrypTEC '99) 1026276707Sdes * sparrow.ece.cmu.edu/~adrian/projects/validation/validation.pdf 1027276707Sdes * 1028276707Sdes * The subject came up in a talk by Dan Kaminsky, too. 1029276707Sdes * 1030276707Sdes * If you see the picture is different, the key is different. 1031276707Sdes * If the picture looks the same, you still know nothing. 1032276707Sdes * 1033276707Sdes * The algorithm used here is a worm crawling over a discrete plane, 1034276707Sdes * leaving a trace (augmenting the field) everywhere it goes. 1035276707Sdes * Movement is taken from dgst_raw 2bit-wise. Bumping into walls 1036276707Sdes * makes the respective movement vector be ignored for this turn. 1037276707Sdes * Graphs are not unambiguous, because circles in graphs can be 1038276707Sdes * walked in either direction. 1039276707Sdes */ 1040276707Sdes 1041276707Sdes/* 1042276707Sdes * Field sizes for the random art. Have to be odd, so the starting point 1043276707Sdes * can be in the exact middle of the picture, and FLDBASE should be >=8 . 1044276707Sdes * Else pictures would be too dense, and drawing the frame would 1045276707Sdes * fail, too, because the key type would not fit in anymore. 1046276707Sdes */ 1047276707Sdes#define FLDBASE 8 1048276707Sdes#define FLDSIZE_Y (FLDBASE + 1) 1049276707Sdes#define FLDSIZE_X (FLDBASE * 2 + 1) 1050276707Sdesstatic char * 1051295367Sdesfingerprint_randomart(const char *alg, u_char *dgst_raw, size_t dgst_raw_len, 1052276707Sdes const struct sshkey *k) 1053276707Sdes{ 1054276707Sdes /* 1055276707Sdes * Chars to be used after each other every time the worm 1056276707Sdes * intersects with itself. Matter of taste. 1057276707Sdes */ 1058276707Sdes char *augmentation_string = " .o+=*BOX@%&#/^SE"; 1059295367Sdes char *retval, *p, title[FLDSIZE_X], hash[FLDSIZE_X]; 1060276707Sdes u_char field[FLDSIZE_X][FLDSIZE_Y]; 1061295367Sdes size_t i, tlen, hlen; 1062276707Sdes u_int b; 1063276707Sdes int x, y, r; 1064276707Sdes size_t len = strlen(augmentation_string) - 1; 1065276707Sdes 1066276707Sdes if ((retval = calloc((FLDSIZE_X + 3), (FLDSIZE_Y + 2))) == NULL) 1067276707Sdes return NULL; 1068276707Sdes 1069276707Sdes /* initialize field */ 1070276707Sdes memset(field, 0, FLDSIZE_X * FLDSIZE_Y * sizeof(char)); 1071276707Sdes x = FLDSIZE_X / 2; 1072276707Sdes y = FLDSIZE_Y / 2; 1073276707Sdes 1074276707Sdes /* process raw key */ 1075276707Sdes for (i = 0; i < dgst_raw_len; i++) { 1076276707Sdes int input; 1077276707Sdes /* each byte conveys four 2-bit move commands */ 1078276707Sdes input = dgst_raw[i]; 1079276707Sdes for (b = 0; b < 4; b++) { 1080276707Sdes /* evaluate 2 bit, rest is shifted later */ 1081276707Sdes x += (input & 0x1) ? 1 : -1; 1082276707Sdes y += (input & 0x2) ? 1 : -1; 1083276707Sdes 1084276707Sdes /* assure we are still in bounds */ 1085276707Sdes x = MAX(x, 0); 1086276707Sdes y = MAX(y, 0); 1087276707Sdes x = MIN(x, FLDSIZE_X - 1); 1088276707Sdes y = MIN(y, FLDSIZE_Y - 1); 1089276707Sdes 1090276707Sdes /* augment the field */ 1091276707Sdes if (field[x][y] < len - 2) 1092276707Sdes field[x][y]++; 1093276707Sdes input = input >> 2; 1094276707Sdes } 1095276707Sdes } 1096276707Sdes 1097276707Sdes /* mark starting point and end point*/ 1098276707Sdes field[FLDSIZE_X / 2][FLDSIZE_Y / 2] = len - 1; 1099276707Sdes field[x][y] = len; 1100276707Sdes 1101276707Sdes /* assemble title */ 1102276707Sdes r = snprintf(title, sizeof(title), "[%s %u]", 1103276707Sdes sshkey_type(k), sshkey_size(k)); 1104276707Sdes /* If [type size] won't fit, then try [type]; fits "[ED25519-CERT]" */ 1105276707Sdes if (r < 0 || r > (int)sizeof(title)) 1106295367Sdes r = snprintf(title, sizeof(title), "[%s]", sshkey_type(k)); 1107295367Sdes tlen = (r <= 0) ? 0 : strlen(title); 1108276707Sdes 1109295367Sdes /* assemble hash ID. */ 1110295367Sdes r = snprintf(hash, sizeof(hash), "[%s]", alg); 1111295367Sdes hlen = (r <= 0) ? 0 : strlen(hash); 1112295367Sdes 1113276707Sdes /* output upper border */ 1114276707Sdes p = retval; 1115276707Sdes *p++ = '+'; 1116276707Sdes for (i = 0; i < (FLDSIZE_X - tlen) / 2; i++) 1117276707Sdes *p++ = '-'; 1118276707Sdes memcpy(p, title, tlen); 1119276707Sdes p += tlen; 1120295367Sdes for (i += tlen; i < FLDSIZE_X; i++) 1121276707Sdes *p++ = '-'; 1122276707Sdes *p++ = '+'; 1123276707Sdes *p++ = '\n'; 1124276707Sdes 1125276707Sdes /* output content */ 1126276707Sdes for (y = 0; y < FLDSIZE_Y; y++) { 1127276707Sdes *p++ = '|'; 1128276707Sdes for (x = 0; x < FLDSIZE_X; x++) 1129276707Sdes *p++ = augmentation_string[MIN(field[x][y], len)]; 1130276707Sdes *p++ = '|'; 1131276707Sdes *p++ = '\n'; 1132276707Sdes } 1133276707Sdes 1134276707Sdes /* output lower border */ 1135276707Sdes *p++ = '+'; 1136295367Sdes for (i = 0; i < (FLDSIZE_X - hlen) / 2; i++) 1137276707Sdes *p++ = '-'; 1138295367Sdes memcpy(p, hash, hlen); 1139295367Sdes p += hlen; 1140295367Sdes for (i += hlen; i < FLDSIZE_X; i++) 1141295367Sdes *p++ = '-'; 1142276707Sdes *p++ = '+'; 1143276707Sdes 1144276707Sdes return retval; 1145276707Sdes} 1146276707Sdes 1147276707Sdeschar * 1148295367Sdessshkey_fingerprint(const struct sshkey *k, int dgst_alg, 1149276707Sdes enum sshkey_fp_rep dgst_rep) 1150276707Sdes{ 1151276707Sdes char *retval = NULL; 1152276707Sdes u_char *dgst_raw; 1153276707Sdes size_t dgst_raw_len; 1154276707Sdes 1155295367Sdes if (sshkey_fingerprint_raw(k, dgst_alg, &dgst_raw, &dgst_raw_len) != 0) 1156276707Sdes return NULL; 1157276707Sdes switch (dgst_rep) { 1158295367Sdes case SSH_FP_DEFAULT: 1159295367Sdes if (dgst_alg == SSH_DIGEST_MD5) { 1160295367Sdes retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg), 1161295367Sdes dgst_raw, dgst_raw_len); 1162295367Sdes } else { 1163295367Sdes retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg), 1164295367Sdes dgst_raw, dgst_raw_len); 1165295367Sdes } 1166295367Sdes break; 1167276707Sdes case SSH_FP_HEX: 1168295367Sdes retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg), 1169295367Sdes dgst_raw, dgst_raw_len); 1170276707Sdes break; 1171295367Sdes case SSH_FP_BASE64: 1172295367Sdes retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg), 1173295367Sdes dgst_raw, dgst_raw_len); 1174295367Sdes break; 1175276707Sdes case SSH_FP_BUBBLEBABBLE: 1176276707Sdes retval = fingerprint_bubblebabble(dgst_raw, dgst_raw_len); 1177276707Sdes break; 1178276707Sdes case SSH_FP_RANDOMART: 1179295367Sdes retval = fingerprint_randomart(ssh_digest_alg_name(dgst_alg), 1180295367Sdes dgst_raw, dgst_raw_len, k); 1181276707Sdes break; 1182276707Sdes default: 1183276707Sdes explicit_bzero(dgst_raw, dgst_raw_len); 1184276707Sdes free(dgst_raw); 1185276707Sdes return NULL; 1186276707Sdes } 1187276707Sdes explicit_bzero(dgst_raw, dgst_raw_len); 1188276707Sdes free(dgst_raw); 1189276707Sdes return retval; 1190276707Sdes} 1191276707Sdes 1192276707Sdes#ifdef WITH_SSH1 1193276707Sdes/* 1194276707Sdes * Reads a multiple-precision integer in decimal from the buffer, and advances 1195276707Sdes * the pointer. The integer must already be initialized. This function is 1196276707Sdes * permitted to modify the buffer. This leaves *cpp to point just beyond the 1197276707Sdes * last processed character. 1198276707Sdes */ 1199276707Sdesstatic int 1200276707Sdesread_decimal_bignum(char **cpp, BIGNUM *v) 1201276707Sdes{ 1202276707Sdes char *cp; 1203276707Sdes size_t e; 1204276707Sdes int skip = 1; /* skip white space */ 1205276707Sdes 1206276707Sdes cp = *cpp; 1207276707Sdes while (*cp == ' ' || *cp == '\t') 1208276707Sdes cp++; 1209276707Sdes e = strspn(cp, "0123456789"); 1210276707Sdes if (e == 0) 1211276707Sdes return SSH_ERR_INVALID_FORMAT; 1212276707Sdes if (e > SSHBUF_MAX_BIGNUM * 3) 1213276707Sdes return SSH_ERR_BIGNUM_TOO_LARGE; 1214276707Sdes if (cp[e] == '\0') 1215276707Sdes skip = 0; 1216296853Sdes else if (strchr(" \t\r\n", cp[e]) == NULL) 1217276707Sdes return SSH_ERR_INVALID_FORMAT; 1218276707Sdes cp[e] = '\0'; 1219276707Sdes if (BN_dec2bn(&v, cp) <= 0) 1220276707Sdes return SSH_ERR_INVALID_FORMAT; 1221276707Sdes *cpp = cp + e + skip; 1222276707Sdes return 0; 1223276707Sdes} 1224276707Sdes#endif /* WITH_SSH1 */ 1225276707Sdes 1226276707Sdes/* returns 0 ok, and < 0 error */ 1227276707Sdesint 1228276707Sdessshkey_read(struct sshkey *ret, char **cpp) 1229276707Sdes{ 1230276707Sdes struct sshkey *k; 1231276707Sdes int retval = SSH_ERR_INVALID_FORMAT; 1232296853Sdes char *ep, *cp, *space; 1233276707Sdes int r, type, curve_nid = -1; 1234276707Sdes struct sshbuf *blob; 1235276707Sdes#ifdef WITH_SSH1 1236276707Sdes u_long bits; 1237276707Sdes#endif /* WITH_SSH1 */ 1238276707Sdes 1239276707Sdes cp = *cpp; 1240276707Sdes 1241276707Sdes switch (ret->type) { 1242276707Sdes case KEY_RSA1: 1243276707Sdes#ifdef WITH_SSH1 1244276707Sdes /* Get number of bits. */ 1245276707Sdes bits = strtoul(cp, &ep, 10); 1246296853Sdes if (*cp == '\0' || strchr(" \t\r\n", *ep) == NULL || 1247276707Sdes bits == 0 || bits > SSHBUF_MAX_BIGNUM * 8) 1248276707Sdes return SSH_ERR_INVALID_FORMAT; /* Bad bit count... */ 1249276707Sdes /* Get public exponent, public modulus. */ 1250276707Sdes if ((r = read_decimal_bignum(&ep, ret->rsa->e)) < 0) 1251276707Sdes return r; 1252276707Sdes if ((r = read_decimal_bignum(&ep, ret->rsa->n)) < 0) 1253276707Sdes return r; 1254276707Sdes /* validate the claimed number of bits */ 1255276707Sdes if (BN_num_bits(ret->rsa->n) != (int)bits) 1256276707Sdes return SSH_ERR_KEY_BITS_MISMATCH; 1257296853Sdes *cpp = ep; 1258276707Sdes retval = 0; 1259276707Sdes#endif /* WITH_SSH1 */ 1260276707Sdes break; 1261276707Sdes case KEY_UNSPEC: 1262276707Sdes case KEY_RSA: 1263276707Sdes case KEY_DSA: 1264276707Sdes case KEY_ECDSA: 1265276707Sdes case KEY_ED25519: 1266276707Sdes case KEY_DSA_CERT: 1267276707Sdes case KEY_ECDSA_CERT: 1268276707Sdes case KEY_RSA_CERT: 1269276707Sdes case KEY_ED25519_CERT: 1270276707Sdes space = strchr(cp, ' '); 1271276707Sdes if (space == NULL) 1272276707Sdes return SSH_ERR_INVALID_FORMAT; 1273276707Sdes *space = '\0'; 1274276707Sdes type = sshkey_type_from_name(cp); 1275276707Sdes if (sshkey_type_plain(type) == KEY_ECDSA && 1276276707Sdes (curve_nid = sshkey_ecdsa_nid_from_name(cp)) == -1) 1277276707Sdes return SSH_ERR_EC_CURVE_INVALID; 1278276707Sdes *space = ' '; 1279276707Sdes if (type == KEY_UNSPEC) 1280276707Sdes return SSH_ERR_INVALID_FORMAT; 1281276707Sdes cp = space+1; 1282276707Sdes if (*cp == '\0') 1283276707Sdes return SSH_ERR_INVALID_FORMAT; 1284295367Sdes if (ret->type != KEY_UNSPEC && ret->type != type) 1285276707Sdes return SSH_ERR_KEY_TYPE_MISMATCH; 1286276707Sdes if ((blob = sshbuf_new()) == NULL) 1287276707Sdes return SSH_ERR_ALLOC_FAIL; 1288276707Sdes /* trim comment */ 1289276707Sdes space = strchr(cp, ' '); 1290295367Sdes if (space) { 1291295367Sdes /* advance 'space': skip whitespace */ 1292295367Sdes *space++ = '\0'; 1293295367Sdes while (*space == ' ' || *space == '\t') 1294295367Sdes space++; 1295296853Sdes ep = space; 1296295367Sdes } else 1297296853Sdes ep = cp + strlen(cp); 1298276707Sdes if ((r = sshbuf_b64tod(blob, cp)) != 0) { 1299276707Sdes sshbuf_free(blob); 1300276707Sdes return r; 1301276707Sdes } 1302276707Sdes if ((r = sshkey_from_blob(sshbuf_ptr(blob), 1303276707Sdes sshbuf_len(blob), &k)) != 0) { 1304276707Sdes sshbuf_free(blob); 1305276707Sdes return r; 1306276707Sdes } 1307276707Sdes sshbuf_free(blob); 1308276707Sdes if (k->type != type) { 1309276707Sdes sshkey_free(k); 1310276707Sdes return SSH_ERR_KEY_TYPE_MISMATCH; 1311276707Sdes } 1312276707Sdes if (sshkey_type_plain(type) == KEY_ECDSA && 1313276707Sdes curve_nid != k->ecdsa_nid) { 1314276707Sdes sshkey_free(k); 1315276707Sdes return SSH_ERR_EC_CURVE_MISMATCH; 1316276707Sdes } 1317295367Sdes ret->type = type; 1318276707Sdes if (sshkey_is_cert(ret)) { 1319276707Sdes if (!sshkey_is_cert(k)) { 1320276707Sdes sshkey_free(k); 1321276707Sdes return SSH_ERR_EXPECTED_CERT; 1322276707Sdes } 1323276707Sdes if (ret->cert != NULL) 1324276707Sdes cert_free(ret->cert); 1325276707Sdes ret->cert = k->cert; 1326276707Sdes k->cert = NULL; 1327276707Sdes } 1328296853Sdes switch (sshkey_type_plain(ret->type)) { 1329276707Sdes#ifdef WITH_OPENSSL 1330296853Sdes case KEY_RSA: 1331276707Sdes if (ret->rsa != NULL) 1332276707Sdes RSA_free(ret->rsa); 1333276707Sdes ret->rsa = k->rsa; 1334276707Sdes k->rsa = NULL; 1335276707Sdes#ifdef DEBUG_PK 1336276707Sdes RSA_print_fp(stderr, ret->rsa, 8); 1337276707Sdes#endif 1338296853Sdes break; 1339296853Sdes case KEY_DSA: 1340276707Sdes if (ret->dsa != NULL) 1341276707Sdes DSA_free(ret->dsa); 1342276707Sdes ret->dsa = k->dsa; 1343276707Sdes k->dsa = NULL; 1344276707Sdes#ifdef DEBUG_PK 1345276707Sdes DSA_print_fp(stderr, ret->dsa, 8); 1346276707Sdes#endif 1347296853Sdes break; 1348276707Sdes# ifdef OPENSSL_HAS_ECC 1349296853Sdes case KEY_ECDSA: 1350276707Sdes if (ret->ecdsa != NULL) 1351276707Sdes EC_KEY_free(ret->ecdsa); 1352276707Sdes ret->ecdsa = k->ecdsa; 1353276707Sdes ret->ecdsa_nid = k->ecdsa_nid; 1354276707Sdes k->ecdsa = NULL; 1355276707Sdes k->ecdsa_nid = -1; 1356276707Sdes#ifdef DEBUG_PK 1357276707Sdes sshkey_dump_ec_key(ret->ecdsa); 1358276707Sdes#endif 1359296853Sdes break; 1360276707Sdes# endif /* OPENSSL_HAS_ECC */ 1361276707Sdes#endif /* WITH_OPENSSL */ 1362296853Sdes case KEY_ED25519: 1363276707Sdes free(ret->ed25519_pk); 1364276707Sdes ret->ed25519_pk = k->ed25519_pk; 1365276707Sdes k->ed25519_pk = NULL; 1366276707Sdes#ifdef DEBUG_PK 1367276707Sdes /* XXX */ 1368276707Sdes#endif 1369296853Sdes break; 1370276707Sdes } 1371296853Sdes *cpp = ep; 1372276707Sdes retval = 0; 1373276707Sdes/*XXXX*/ 1374276707Sdes sshkey_free(k); 1375276707Sdes if (retval != 0) 1376276707Sdes break; 1377276707Sdes break; 1378276707Sdes default: 1379276707Sdes return SSH_ERR_INVALID_ARGUMENT; 1380276707Sdes } 1381276707Sdes return retval; 1382276707Sdes} 1383276707Sdes 1384276707Sdesint 1385295367Sdessshkey_to_base64(const struct sshkey *key, char **b64p) 1386276707Sdes{ 1387295367Sdes int r = SSH_ERR_INTERNAL_ERROR; 1388295367Sdes struct sshbuf *b = NULL; 1389276707Sdes char *uu = NULL; 1390295367Sdes 1391295367Sdes if (b64p != NULL) 1392295367Sdes *b64p = NULL; 1393295367Sdes if ((b = sshbuf_new()) == NULL) 1394295367Sdes return SSH_ERR_ALLOC_FAIL; 1395295367Sdes if ((r = sshkey_putb(key, b)) != 0) 1396295367Sdes goto out; 1397295367Sdes if ((uu = sshbuf_dtob64(b)) == NULL) { 1398295367Sdes r = SSH_ERR_ALLOC_FAIL; 1399295367Sdes goto out; 1400295367Sdes } 1401295367Sdes /* Success */ 1402295367Sdes if (b64p != NULL) { 1403295367Sdes *b64p = uu; 1404295367Sdes uu = NULL; 1405295367Sdes } 1406295367Sdes r = 0; 1407295367Sdes out: 1408295367Sdes sshbuf_free(b); 1409295367Sdes free(uu); 1410295367Sdes return r; 1411295367Sdes} 1412295367Sdes 1413295367Sdesstatic int 1414295367Sdessshkey_format_rsa1(const struct sshkey *key, struct sshbuf *b) 1415295367Sdes{ 1416295367Sdes int r = SSH_ERR_INTERNAL_ERROR; 1417276707Sdes#ifdef WITH_SSH1 1418276707Sdes u_int bits = 0; 1419276707Sdes char *dec_e = NULL, *dec_n = NULL; 1420276707Sdes 1421295367Sdes if (key->rsa == NULL || key->rsa->e == NULL || 1422295367Sdes key->rsa->n == NULL) { 1423295367Sdes r = SSH_ERR_INVALID_ARGUMENT; 1424295367Sdes goto out; 1425276707Sdes } 1426295367Sdes if ((dec_e = BN_bn2dec(key->rsa->e)) == NULL || 1427295367Sdes (dec_n = BN_bn2dec(key->rsa->n)) == NULL) { 1428295367Sdes r = SSH_ERR_ALLOC_FAIL; 1429295367Sdes goto out; 1430295367Sdes } 1431295367Sdes /* size of modulus 'n' */ 1432295367Sdes if ((bits = BN_num_bits(key->rsa->n)) <= 0) { 1433295367Sdes r = SSH_ERR_INVALID_ARGUMENT; 1434295367Sdes goto out; 1435295367Sdes } 1436295367Sdes if ((r = sshbuf_putf(b, "%u %s %s", bits, dec_e, dec_n)) != 0) 1437295367Sdes goto out; 1438295367Sdes 1439295367Sdes /* Success */ 1440295367Sdes r = 0; 1441295367Sdes out: 1442295367Sdes if (dec_e != NULL) 1443295367Sdes OPENSSL_free(dec_e); 1444295367Sdes if (dec_n != NULL) 1445295367Sdes OPENSSL_free(dec_n); 1446276707Sdes#endif /* WITH_SSH1 */ 1447295367Sdes 1448295367Sdes return r; 1449295367Sdes} 1450295367Sdes 1451295367Sdesstatic int 1452295367Sdessshkey_format_text(const struct sshkey *key, struct sshbuf *b) 1453295367Sdes{ 1454295367Sdes int r = SSH_ERR_INTERNAL_ERROR; 1455295367Sdes char *uu = NULL; 1456295367Sdes 1457295367Sdes if (key->type == KEY_RSA1) { 1458295367Sdes if ((r = sshkey_format_rsa1(key, b)) != 0) 1459276707Sdes goto out; 1460295367Sdes } else { 1461295367Sdes /* Unsupported key types handled in sshkey_to_base64() */ 1462295367Sdes if ((r = sshkey_to_base64(key, &uu)) != 0) 1463276707Sdes goto out; 1464295367Sdes if ((r = sshbuf_putf(b, "%s %s", 1465295367Sdes sshkey_ssh_name(key), uu)) != 0) 1466276707Sdes goto out; 1467295367Sdes } 1468295367Sdes r = 0; 1469295367Sdes out: 1470295367Sdes free(uu); 1471295367Sdes return r; 1472295367Sdes} 1473295367Sdes 1474295367Sdesint 1475295367Sdessshkey_write(const struct sshkey *key, FILE *f) 1476295367Sdes{ 1477295367Sdes struct sshbuf *b = NULL; 1478295367Sdes int r = SSH_ERR_INTERNAL_ERROR; 1479295367Sdes 1480295367Sdes if ((b = sshbuf_new()) == NULL) 1481295367Sdes return SSH_ERR_ALLOC_FAIL; 1482295367Sdes if ((r = sshkey_format_text(key, b)) != 0) 1483276707Sdes goto out; 1484276707Sdes if (fwrite(sshbuf_ptr(b), sshbuf_len(b), 1, f) != 1) { 1485276707Sdes if (feof(f)) 1486276707Sdes errno = EPIPE; 1487295367Sdes r = SSH_ERR_SYSTEM_ERROR; 1488276707Sdes goto out; 1489276707Sdes } 1490295367Sdes /* Success */ 1491295367Sdes r = 0; 1492276707Sdes out: 1493295367Sdes sshbuf_free(b); 1494295367Sdes return r; 1495276707Sdes} 1496276707Sdes 1497276707Sdesconst char * 1498276707Sdessshkey_cert_type(const struct sshkey *k) 1499276707Sdes{ 1500276707Sdes switch (k->cert->type) { 1501276707Sdes case SSH2_CERT_TYPE_USER: 1502276707Sdes return "user"; 1503276707Sdes case SSH2_CERT_TYPE_HOST: 1504276707Sdes return "host"; 1505276707Sdes default: 1506276707Sdes return "unknown"; 1507276707Sdes } 1508276707Sdes} 1509276707Sdes 1510276707Sdes#ifdef WITH_OPENSSL 1511276707Sdesstatic int 1512276707Sdesrsa_generate_private_key(u_int bits, RSA **rsap) 1513276707Sdes{ 1514276707Sdes RSA *private = NULL; 1515276707Sdes BIGNUM *f4 = NULL; 1516276707Sdes int ret = SSH_ERR_INTERNAL_ERROR; 1517276707Sdes 1518276707Sdes if (rsap == NULL || 1519276707Sdes bits < SSH_RSA_MINIMUM_MODULUS_SIZE || 1520276707Sdes bits > SSHBUF_MAX_BIGNUM * 8) 1521276707Sdes return SSH_ERR_INVALID_ARGUMENT; 1522276707Sdes *rsap = NULL; 1523276707Sdes if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) { 1524276707Sdes ret = SSH_ERR_ALLOC_FAIL; 1525276707Sdes goto out; 1526276707Sdes } 1527276707Sdes if (!BN_set_word(f4, RSA_F4) || 1528276707Sdes !RSA_generate_key_ex(private, bits, f4, NULL)) { 1529276707Sdes ret = SSH_ERR_LIBCRYPTO_ERROR; 1530276707Sdes goto out; 1531276707Sdes } 1532276707Sdes *rsap = private; 1533276707Sdes private = NULL; 1534276707Sdes ret = 0; 1535276707Sdes out: 1536276707Sdes if (private != NULL) 1537276707Sdes RSA_free(private); 1538276707Sdes if (f4 != NULL) 1539276707Sdes BN_free(f4); 1540276707Sdes return ret; 1541276707Sdes} 1542276707Sdes 1543276707Sdesstatic int 1544276707Sdesdsa_generate_private_key(u_int bits, DSA **dsap) 1545276707Sdes{ 1546276707Sdes DSA *private; 1547276707Sdes int ret = SSH_ERR_INTERNAL_ERROR; 1548276707Sdes 1549276707Sdes if (dsap == NULL || bits != 1024) 1550276707Sdes return SSH_ERR_INVALID_ARGUMENT; 1551276707Sdes if ((private = DSA_new()) == NULL) { 1552276707Sdes ret = SSH_ERR_ALLOC_FAIL; 1553276707Sdes goto out; 1554276707Sdes } 1555276707Sdes *dsap = NULL; 1556276707Sdes if (!DSA_generate_parameters_ex(private, bits, NULL, 0, NULL, 1557276707Sdes NULL, NULL) || !DSA_generate_key(private)) { 1558276707Sdes ret = SSH_ERR_LIBCRYPTO_ERROR; 1559276707Sdes goto out; 1560276707Sdes } 1561276707Sdes *dsap = private; 1562276707Sdes private = NULL; 1563276707Sdes ret = 0; 1564276707Sdes out: 1565276707Sdes if (private != NULL) 1566276707Sdes DSA_free(private); 1567276707Sdes return ret; 1568276707Sdes} 1569276707Sdes 1570276707Sdes# ifdef OPENSSL_HAS_ECC 1571276707Sdesint 1572276707Sdessshkey_ecdsa_key_to_nid(EC_KEY *k) 1573276707Sdes{ 1574276707Sdes EC_GROUP *eg; 1575276707Sdes int nids[] = { 1576276707Sdes NID_X9_62_prime256v1, 1577276707Sdes NID_secp384r1, 1578276707Sdes# ifdef OPENSSL_HAS_NISTP521 1579276707Sdes NID_secp521r1, 1580276707Sdes# endif /* OPENSSL_HAS_NISTP521 */ 1581276707Sdes -1 1582276707Sdes }; 1583276707Sdes int nid; 1584276707Sdes u_int i; 1585276707Sdes BN_CTX *bnctx; 1586276707Sdes const EC_GROUP *g = EC_KEY_get0_group(k); 1587276707Sdes 1588276707Sdes /* 1589276707Sdes * The group may be stored in a ASN.1 encoded private key in one of two 1590276707Sdes * ways: as a "named group", which is reconstituted by ASN.1 object ID 1591276707Sdes * or explicit group parameters encoded into the key blob. Only the 1592276707Sdes * "named group" case sets the group NID for us, but we can figure 1593276707Sdes * it out for the other case by comparing against all the groups that 1594276707Sdes * are supported. 1595276707Sdes */ 1596276707Sdes if ((nid = EC_GROUP_get_curve_name(g)) > 0) 1597276707Sdes return nid; 1598276707Sdes if ((bnctx = BN_CTX_new()) == NULL) 1599276707Sdes return -1; 1600276707Sdes for (i = 0; nids[i] != -1; i++) { 1601276707Sdes if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL) { 1602276707Sdes BN_CTX_free(bnctx); 1603276707Sdes return -1; 1604276707Sdes } 1605276707Sdes if (EC_GROUP_cmp(g, eg, bnctx) == 0) 1606276707Sdes break; 1607276707Sdes EC_GROUP_free(eg); 1608276707Sdes } 1609276707Sdes BN_CTX_free(bnctx); 1610276707Sdes if (nids[i] != -1) { 1611276707Sdes /* Use the group with the NID attached */ 1612276707Sdes EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE); 1613276707Sdes if (EC_KEY_set_group(k, eg) != 1) { 1614276707Sdes EC_GROUP_free(eg); 1615276707Sdes return -1; 1616276707Sdes } 1617276707Sdes } 1618276707Sdes return nids[i]; 1619276707Sdes} 1620276707Sdes 1621276707Sdesstatic int 1622276707Sdesecdsa_generate_private_key(u_int bits, int *nid, EC_KEY **ecdsap) 1623276707Sdes{ 1624276707Sdes EC_KEY *private; 1625276707Sdes int ret = SSH_ERR_INTERNAL_ERROR; 1626276707Sdes 1627276707Sdes if (nid == NULL || ecdsap == NULL || 1628276707Sdes (*nid = sshkey_ecdsa_bits_to_nid(bits)) == -1) 1629276707Sdes return SSH_ERR_INVALID_ARGUMENT; 1630276707Sdes *ecdsap = NULL; 1631276707Sdes if ((private = EC_KEY_new_by_curve_name(*nid)) == NULL) { 1632276707Sdes ret = SSH_ERR_ALLOC_FAIL; 1633276707Sdes goto out; 1634276707Sdes } 1635276707Sdes if (EC_KEY_generate_key(private) != 1) { 1636276707Sdes ret = SSH_ERR_LIBCRYPTO_ERROR; 1637276707Sdes goto out; 1638276707Sdes } 1639276707Sdes EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE); 1640276707Sdes *ecdsap = private; 1641276707Sdes private = NULL; 1642276707Sdes ret = 0; 1643276707Sdes out: 1644276707Sdes if (private != NULL) 1645276707Sdes EC_KEY_free(private); 1646276707Sdes return ret; 1647276707Sdes} 1648276707Sdes# endif /* OPENSSL_HAS_ECC */ 1649276707Sdes#endif /* WITH_OPENSSL */ 1650276707Sdes 1651276707Sdesint 1652276707Sdessshkey_generate(int type, u_int bits, struct sshkey **keyp) 1653276707Sdes{ 1654276707Sdes struct sshkey *k; 1655276707Sdes int ret = SSH_ERR_INTERNAL_ERROR; 1656276707Sdes 1657276707Sdes if (keyp == NULL) 1658276707Sdes return SSH_ERR_INVALID_ARGUMENT; 1659276707Sdes *keyp = NULL; 1660276707Sdes if ((k = sshkey_new(KEY_UNSPEC)) == NULL) 1661276707Sdes return SSH_ERR_ALLOC_FAIL; 1662276707Sdes switch (type) { 1663276707Sdes case KEY_ED25519: 1664276707Sdes if ((k->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL || 1665276707Sdes (k->ed25519_sk = malloc(ED25519_SK_SZ)) == NULL) { 1666276707Sdes ret = SSH_ERR_ALLOC_FAIL; 1667276707Sdes break; 1668276707Sdes } 1669276707Sdes crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk); 1670276707Sdes ret = 0; 1671276707Sdes break; 1672276707Sdes#ifdef WITH_OPENSSL 1673276707Sdes case KEY_DSA: 1674276707Sdes ret = dsa_generate_private_key(bits, &k->dsa); 1675276707Sdes break; 1676276707Sdes# ifdef OPENSSL_HAS_ECC 1677276707Sdes case KEY_ECDSA: 1678276707Sdes ret = ecdsa_generate_private_key(bits, &k->ecdsa_nid, 1679276707Sdes &k->ecdsa); 1680276707Sdes break; 1681276707Sdes# endif /* OPENSSL_HAS_ECC */ 1682276707Sdes case KEY_RSA: 1683276707Sdes case KEY_RSA1: 1684276707Sdes ret = rsa_generate_private_key(bits, &k->rsa); 1685276707Sdes break; 1686276707Sdes#endif /* WITH_OPENSSL */ 1687276707Sdes default: 1688276707Sdes ret = SSH_ERR_INVALID_ARGUMENT; 1689276707Sdes } 1690276707Sdes if (ret == 0) { 1691276707Sdes k->type = type; 1692276707Sdes *keyp = k; 1693276707Sdes } else 1694276707Sdes sshkey_free(k); 1695276707Sdes return ret; 1696276707Sdes} 1697276707Sdes 1698276707Sdesint 1699276707Sdessshkey_cert_copy(const struct sshkey *from_key, struct sshkey *to_key) 1700276707Sdes{ 1701276707Sdes u_int i; 1702276707Sdes const struct sshkey_cert *from; 1703276707Sdes struct sshkey_cert *to; 1704276707Sdes int ret = SSH_ERR_INTERNAL_ERROR; 1705276707Sdes 1706276707Sdes if (to_key->cert != NULL) { 1707276707Sdes cert_free(to_key->cert); 1708276707Sdes to_key->cert = NULL; 1709276707Sdes } 1710276707Sdes 1711276707Sdes if ((from = from_key->cert) == NULL) 1712276707Sdes return SSH_ERR_INVALID_ARGUMENT; 1713276707Sdes 1714276707Sdes if ((to = to_key->cert = cert_new()) == NULL) 1715276707Sdes return SSH_ERR_ALLOC_FAIL; 1716276707Sdes 1717276707Sdes if ((ret = sshbuf_putb(to->certblob, from->certblob)) != 0 || 1718276707Sdes (ret = sshbuf_putb(to->critical, from->critical)) != 0 || 1719296853Sdes (ret = sshbuf_putb(to->extensions, from->extensions)) != 0) 1720276707Sdes return ret; 1721276707Sdes 1722276707Sdes to->serial = from->serial; 1723276707Sdes to->type = from->type; 1724276707Sdes if (from->key_id == NULL) 1725276707Sdes to->key_id = NULL; 1726276707Sdes else if ((to->key_id = strdup(from->key_id)) == NULL) 1727276707Sdes return SSH_ERR_ALLOC_FAIL; 1728276707Sdes to->valid_after = from->valid_after; 1729276707Sdes to->valid_before = from->valid_before; 1730276707Sdes if (from->signature_key == NULL) 1731276707Sdes to->signature_key = NULL; 1732276707Sdes else if ((ret = sshkey_from_private(from->signature_key, 1733276707Sdes &to->signature_key)) != 0) 1734276707Sdes return ret; 1735276707Sdes 1736276707Sdes if (from->nprincipals > SSHKEY_CERT_MAX_PRINCIPALS) 1737276707Sdes return SSH_ERR_INVALID_ARGUMENT; 1738276707Sdes if (from->nprincipals > 0) { 1739276707Sdes if ((to->principals = calloc(from->nprincipals, 1740276707Sdes sizeof(*to->principals))) == NULL) 1741276707Sdes return SSH_ERR_ALLOC_FAIL; 1742276707Sdes for (i = 0; i < from->nprincipals; i++) { 1743276707Sdes to->principals[i] = strdup(from->principals[i]); 1744276707Sdes if (to->principals[i] == NULL) { 1745276707Sdes to->nprincipals = i; 1746276707Sdes return SSH_ERR_ALLOC_FAIL; 1747276707Sdes } 1748276707Sdes } 1749276707Sdes } 1750276707Sdes to->nprincipals = from->nprincipals; 1751276707Sdes return 0; 1752276707Sdes} 1753276707Sdes 1754276707Sdesint 1755276707Sdessshkey_from_private(const struct sshkey *k, struct sshkey **pkp) 1756276707Sdes{ 1757276707Sdes struct sshkey *n = NULL; 1758276707Sdes int ret = SSH_ERR_INTERNAL_ERROR; 1759276707Sdes 1760296853Sdes *pkp = NULL; 1761276707Sdes switch (k->type) { 1762276707Sdes#ifdef WITH_OPENSSL 1763276707Sdes case KEY_DSA: 1764276707Sdes case KEY_DSA_CERT: 1765276707Sdes if ((n = sshkey_new(k->type)) == NULL) 1766276707Sdes return SSH_ERR_ALLOC_FAIL; 1767276707Sdes if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) || 1768276707Sdes (BN_copy(n->dsa->q, k->dsa->q) == NULL) || 1769276707Sdes (BN_copy(n->dsa->g, k->dsa->g) == NULL) || 1770276707Sdes (BN_copy(n->dsa->pub_key, k->dsa->pub_key) == NULL)) { 1771276707Sdes sshkey_free(n); 1772276707Sdes return SSH_ERR_ALLOC_FAIL; 1773276707Sdes } 1774276707Sdes break; 1775276707Sdes# ifdef OPENSSL_HAS_ECC 1776276707Sdes case KEY_ECDSA: 1777276707Sdes case KEY_ECDSA_CERT: 1778276707Sdes if ((n = sshkey_new(k->type)) == NULL) 1779276707Sdes return SSH_ERR_ALLOC_FAIL; 1780276707Sdes n->ecdsa_nid = k->ecdsa_nid; 1781276707Sdes n->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid); 1782276707Sdes if (n->ecdsa == NULL) { 1783276707Sdes sshkey_free(n); 1784276707Sdes return SSH_ERR_ALLOC_FAIL; 1785276707Sdes } 1786276707Sdes if (EC_KEY_set_public_key(n->ecdsa, 1787276707Sdes EC_KEY_get0_public_key(k->ecdsa)) != 1) { 1788276707Sdes sshkey_free(n); 1789276707Sdes return SSH_ERR_LIBCRYPTO_ERROR; 1790276707Sdes } 1791276707Sdes break; 1792276707Sdes# endif /* OPENSSL_HAS_ECC */ 1793276707Sdes case KEY_RSA: 1794276707Sdes case KEY_RSA1: 1795276707Sdes case KEY_RSA_CERT: 1796276707Sdes if ((n = sshkey_new(k->type)) == NULL) 1797276707Sdes return SSH_ERR_ALLOC_FAIL; 1798276707Sdes if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) || 1799276707Sdes (BN_copy(n->rsa->e, k->rsa->e) == NULL)) { 1800276707Sdes sshkey_free(n); 1801276707Sdes return SSH_ERR_ALLOC_FAIL; 1802276707Sdes } 1803276707Sdes break; 1804276707Sdes#endif /* WITH_OPENSSL */ 1805276707Sdes case KEY_ED25519: 1806276707Sdes case KEY_ED25519_CERT: 1807276707Sdes if ((n = sshkey_new(k->type)) == NULL) 1808276707Sdes return SSH_ERR_ALLOC_FAIL; 1809276707Sdes if (k->ed25519_pk != NULL) { 1810276707Sdes if ((n->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) { 1811276707Sdes sshkey_free(n); 1812276707Sdes return SSH_ERR_ALLOC_FAIL; 1813276707Sdes } 1814276707Sdes memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ); 1815276707Sdes } 1816276707Sdes break; 1817276707Sdes default: 1818276707Sdes return SSH_ERR_KEY_TYPE_UNKNOWN; 1819276707Sdes } 1820276707Sdes if (sshkey_is_cert(k)) { 1821276707Sdes if ((ret = sshkey_cert_copy(k, n)) != 0) { 1822276707Sdes sshkey_free(n); 1823276707Sdes return ret; 1824276707Sdes } 1825276707Sdes } 1826276707Sdes *pkp = n; 1827276707Sdes return 0; 1828276707Sdes} 1829276707Sdes 1830276707Sdesstatic int 1831295367Sdescert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf) 1832276707Sdes{ 1833295367Sdes struct sshbuf *principals = NULL, *crit = NULL; 1834295367Sdes struct sshbuf *exts = NULL, *ca = NULL; 1835295367Sdes u_char *sig = NULL; 1836295367Sdes size_t signed_len = 0, slen = 0, kidlen = 0; 1837276707Sdes int ret = SSH_ERR_INTERNAL_ERROR; 1838276707Sdes 1839276707Sdes /* Copy the entire key blob for verification and later serialisation */ 1840295367Sdes if ((ret = sshbuf_putb(key->cert->certblob, certbuf)) != 0) 1841276707Sdes return ret; 1842276707Sdes 1843295367Sdes /* Parse body of certificate up to signature */ 1844295367Sdes if ((ret = sshbuf_get_u64(b, &key->cert->serial)) != 0 || 1845276707Sdes (ret = sshbuf_get_u32(b, &key->cert->type)) != 0 || 1846276707Sdes (ret = sshbuf_get_cstring(b, &key->cert->key_id, &kidlen)) != 0 || 1847295367Sdes (ret = sshbuf_froms(b, &principals)) != 0 || 1848276707Sdes (ret = sshbuf_get_u64(b, &key->cert->valid_after)) != 0 || 1849276707Sdes (ret = sshbuf_get_u64(b, &key->cert->valid_before)) != 0 || 1850295367Sdes (ret = sshbuf_froms(b, &crit)) != 0 || 1851295367Sdes (ret = sshbuf_froms(b, &exts)) != 0 || 1852276707Sdes (ret = sshbuf_get_string_direct(b, NULL, NULL)) != 0 || 1853295367Sdes (ret = sshbuf_froms(b, &ca)) != 0) { 1854276707Sdes /* XXX debug print error for ret */ 1855276707Sdes ret = SSH_ERR_INVALID_FORMAT; 1856276707Sdes goto out; 1857276707Sdes } 1858276707Sdes 1859276707Sdes /* Signature is left in the buffer so we can calculate this length */ 1860276707Sdes signed_len = sshbuf_len(key->cert->certblob) - sshbuf_len(b); 1861276707Sdes 1862276707Sdes if ((ret = sshbuf_get_string(b, &sig, &slen)) != 0) { 1863276707Sdes ret = SSH_ERR_INVALID_FORMAT; 1864276707Sdes goto out; 1865276707Sdes } 1866276707Sdes 1867276707Sdes if (key->cert->type != SSH2_CERT_TYPE_USER && 1868276707Sdes key->cert->type != SSH2_CERT_TYPE_HOST) { 1869276707Sdes ret = SSH_ERR_KEY_CERT_UNKNOWN_TYPE; 1870276707Sdes goto out; 1871276707Sdes } 1872276707Sdes 1873295367Sdes /* Parse principals section */ 1874295367Sdes while (sshbuf_len(principals) > 0) { 1875295367Sdes char *principal = NULL; 1876295367Sdes char **oprincipals = NULL; 1877295367Sdes 1878276707Sdes if (key->cert->nprincipals >= SSHKEY_CERT_MAX_PRINCIPALS) { 1879276707Sdes ret = SSH_ERR_INVALID_FORMAT; 1880276707Sdes goto out; 1881276707Sdes } 1882295367Sdes if ((ret = sshbuf_get_cstring(principals, &principal, 1883295367Sdes NULL)) != 0) { 1884276707Sdes ret = SSH_ERR_INVALID_FORMAT; 1885276707Sdes goto out; 1886276707Sdes } 1887276707Sdes oprincipals = key->cert->principals; 1888295367Sdes key->cert->principals = reallocarray(key->cert->principals, 1889295367Sdes key->cert->nprincipals + 1, sizeof(*key->cert->principals)); 1890276707Sdes if (key->cert->principals == NULL) { 1891276707Sdes free(principal); 1892276707Sdes key->cert->principals = oprincipals; 1893276707Sdes ret = SSH_ERR_ALLOC_FAIL; 1894276707Sdes goto out; 1895276707Sdes } 1896276707Sdes key->cert->principals[key->cert->nprincipals++] = principal; 1897276707Sdes } 1898276707Sdes 1899295367Sdes /* 1900295367Sdes * Stash a copies of the critical options and extensions sections 1901295367Sdes * for later use. 1902295367Sdes */ 1903295367Sdes if ((ret = sshbuf_putb(key->cert->critical, crit)) != 0 || 1904295367Sdes (exts != NULL && 1905295367Sdes (ret = sshbuf_putb(key->cert->extensions, exts)) != 0)) 1906276707Sdes goto out; 1907276707Sdes 1908295367Sdes /* 1909295367Sdes * Validate critical options and extensions sections format. 1910295367Sdes */ 1911295367Sdes while (sshbuf_len(crit) != 0) { 1912295367Sdes if ((ret = sshbuf_get_string_direct(crit, NULL, NULL)) != 0 || 1913295367Sdes (ret = sshbuf_get_string_direct(crit, NULL, NULL)) != 0) { 1914295367Sdes sshbuf_reset(key->cert->critical); 1915276707Sdes ret = SSH_ERR_INVALID_FORMAT; 1916276707Sdes goto out; 1917276707Sdes } 1918276707Sdes } 1919295367Sdes while (exts != NULL && sshbuf_len(exts) != 0) { 1920295367Sdes if ((ret = sshbuf_get_string_direct(exts, NULL, NULL)) != 0 || 1921295367Sdes (ret = sshbuf_get_string_direct(exts, NULL, NULL)) != 0) { 1922295367Sdes sshbuf_reset(key->cert->extensions); 1923276707Sdes ret = SSH_ERR_INVALID_FORMAT; 1924276707Sdes goto out; 1925276707Sdes } 1926276707Sdes } 1927276707Sdes 1928295367Sdes /* Parse CA key and check signature */ 1929295367Sdes if (sshkey_from_blob_internal(ca, &key->cert->signature_key, 0) != 0) { 1930276707Sdes ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; 1931276707Sdes goto out; 1932276707Sdes } 1933276707Sdes if (!sshkey_type_is_valid_ca(key->cert->signature_key->type)) { 1934276707Sdes ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; 1935276707Sdes goto out; 1936276707Sdes } 1937276707Sdes if ((ret = sshkey_verify(key->cert->signature_key, sig, slen, 1938276707Sdes sshbuf_ptr(key->cert->certblob), signed_len, 0)) != 0) 1939276707Sdes goto out; 1940295367Sdes 1941295367Sdes /* Success */ 1942276707Sdes ret = 0; 1943276707Sdes out: 1944295367Sdes sshbuf_free(ca); 1945295367Sdes sshbuf_free(crit); 1946295367Sdes sshbuf_free(exts); 1947295367Sdes sshbuf_free(principals); 1948276707Sdes free(sig); 1949276707Sdes return ret; 1950276707Sdes} 1951276707Sdes 1952276707Sdesstatic int 1953295367Sdessshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp, 1954295367Sdes int allow_cert) 1955276707Sdes{ 1956295367Sdes int type, ret = SSH_ERR_INTERNAL_ERROR; 1957276707Sdes char *ktype = NULL, *curve = NULL; 1958276707Sdes struct sshkey *key = NULL; 1959276707Sdes size_t len; 1960276707Sdes u_char *pk = NULL; 1961295367Sdes struct sshbuf *copy; 1962276707Sdes#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) 1963276707Sdes EC_POINT *q = NULL; 1964276707Sdes#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ 1965276707Sdes 1966276707Sdes#ifdef DEBUG_PK /* XXX */ 1967295367Sdes sshbuf_dump(b, stderr); 1968276707Sdes#endif 1969276707Sdes *keyp = NULL; 1970295367Sdes if ((copy = sshbuf_fromb(b)) == NULL) { 1971295367Sdes ret = SSH_ERR_ALLOC_FAIL; 1972295367Sdes goto out; 1973295367Sdes } 1974276707Sdes if (sshbuf_get_cstring(b, &ktype, NULL) != 0) { 1975276707Sdes ret = SSH_ERR_INVALID_FORMAT; 1976276707Sdes goto out; 1977276707Sdes } 1978276707Sdes 1979276707Sdes type = sshkey_type_from_name(ktype); 1980276707Sdes if (!allow_cert && sshkey_type_is_cert(type)) { 1981276707Sdes ret = SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; 1982276707Sdes goto out; 1983276707Sdes } 1984276707Sdes switch (type) { 1985276707Sdes#ifdef WITH_OPENSSL 1986276707Sdes case KEY_RSA_CERT: 1987295367Sdes /* Skip nonce */ 1988276707Sdes if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { 1989276707Sdes ret = SSH_ERR_INVALID_FORMAT; 1990276707Sdes goto out; 1991276707Sdes } 1992276707Sdes /* FALLTHROUGH */ 1993276707Sdes case KEY_RSA: 1994276707Sdes if ((key = sshkey_new(type)) == NULL) { 1995276707Sdes ret = SSH_ERR_ALLOC_FAIL; 1996276707Sdes goto out; 1997276707Sdes } 1998295367Sdes if (sshbuf_get_bignum2(b, key->rsa->e) != 0 || 1999295367Sdes sshbuf_get_bignum2(b, key->rsa->n) != 0) { 2000276707Sdes ret = SSH_ERR_INVALID_FORMAT; 2001276707Sdes goto out; 2002276707Sdes } 2003276707Sdes#ifdef DEBUG_PK 2004276707Sdes RSA_print_fp(stderr, key->rsa, 8); 2005276707Sdes#endif 2006276707Sdes break; 2007276707Sdes case KEY_DSA_CERT: 2008295367Sdes /* Skip nonce */ 2009276707Sdes if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { 2010276707Sdes ret = SSH_ERR_INVALID_FORMAT; 2011276707Sdes goto out; 2012276707Sdes } 2013276707Sdes /* FALLTHROUGH */ 2014276707Sdes case KEY_DSA: 2015276707Sdes if ((key = sshkey_new(type)) == NULL) { 2016276707Sdes ret = SSH_ERR_ALLOC_FAIL; 2017276707Sdes goto out; 2018276707Sdes } 2019295367Sdes if (sshbuf_get_bignum2(b, key->dsa->p) != 0 || 2020295367Sdes sshbuf_get_bignum2(b, key->dsa->q) != 0 || 2021295367Sdes sshbuf_get_bignum2(b, key->dsa->g) != 0 || 2022295367Sdes sshbuf_get_bignum2(b, key->dsa->pub_key) != 0) { 2023276707Sdes ret = SSH_ERR_INVALID_FORMAT; 2024276707Sdes goto out; 2025276707Sdes } 2026276707Sdes#ifdef DEBUG_PK 2027276707Sdes DSA_print_fp(stderr, key->dsa, 8); 2028276707Sdes#endif 2029276707Sdes break; 2030276707Sdes case KEY_ECDSA_CERT: 2031295367Sdes /* Skip nonce */ 2032276707Sdes if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { 2033276707Sdes ret = SSH_ERR_INVALID_FORMAT; 2034276707Sdes goto out; 2035276707Sdes } 2036276707Sdes /* FALLTHROUGH */ 2037276707Sdes# ifdef OPENSSL_HAS_ECC 2038276707Sdes case KEY_ECDSA: 2039276707Sdes if ((key = sshkey_new(type)) == NULL) { 2040276707Sdes ret = SSH_ERR_ALLOC_FAIL; 2041276707Sdes goto out; 2042276707Sdes } 2043295367Sdes key->ecdsa_nid = sshkey_ecdsa_nid_from_name(ktype); 2044276707Sdes if (sshbuf_get_cstring(b, &curve, NULL) != 0) { 2045276707Sdes ret = SSH_ERR_INVALID_FORMAT; 2046276707Sdes goto out; 2047276707Sdes } 2048276707Sdes if (key->ecdsa_nid != sshkey_curve_name_to_nid(curve)) { 2049276707Sdes ret = SSH_ERR_EC_CURVE_MISMATCH; 2050276707Sdes goto out; 2051276707Sdes } 2052276707Sdes if (key->ecdsa != NULL) 2053276707Sdes EC_KEY_free(key->ecdsa); 2054276707Sdes if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid)) 2055276707Sdes == NULL) { 2056276707Sdes ret = SSH_ERR_EC_CURVE_INVALID; 2057276707Sdes goto out; 2058276707Sdes } 2059276707Sdes if ((q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL) { 2060276707Sdes ret = SSH_ERR_ALLOC_FAIL; 2061276707Sdes goto out; 2062276707Sdes } 2063276707Sdes if (sshbuf_get_ec(b, q, EC_KEY_get0_group(key->ecdsa)) != 0) { 2064276707Sdes ret = SSH_ERR_INVALID_FORMAT; 2065276707Sdes goto out; 2066276707Sdes } 2067276707Sdes if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa), 2068276707Sdes q) != 0) { 2069276707Sdes ret = SSH_ERR_KEY_INVALID_EC_VALUE; 2070276707Sdes goto out; 2071276707Sdes } 2072276707Sdes if (EC_KEY_set_public_key(key->ecdsa, q) != 1) { 2073276707Sdes /* XXX assume it is a allocation error */ 2074276707Sdes ret = SSH_ERR_ALLOC_FAIL; 2075276707Sdes goto out; 2076276707Sdes } 2077276707Sdes#ifdef DEBUG_PK 2078276707Sdes sshkey_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q); 2079276707Sdes#endif 2080276707Sdes break; 2081276707Sdes# endif /* OPENSSL_HAS_ECC */ 2082276707Sdes#endif /* WITH_OPENSSL */ 2083276707Sdes case KEY_ED25519_CERT: 2084295367Sdes /* Skip nonce */ 2085276707Sdes if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { 2086276707Sdes ret = SSH_ERR_INVALID_FORMAT; 2087276707Sdes goto out; 2088276707Sdes } 2089276707Sdes /* FALLTHROUGH */ 2090276707Sdes case KEY_ED25519: 2091276707Sdes if ((ret = sshbuf_get_string(b, &pk, &len)) != 0) 2092276707Sdes goto out; 2093276707Sdes if (len != ED25519_PK_SZ) { 2094276707Sdes ret = SSH_ERR_INVALID_FORMAT; 2095276707Sdes goto out; 2096276707Sdes } 2097276707Sdes if ((key = sshkey_new(type)) == NULL) { 2098276707Sdes ret = SSH_ERR_ALLOC_FAIL; 2099276707Sdes goto out; 2100276707Sdes } 2101276707Sdes key->ed25519_pk = pk; 2102276707Sdes pk = NULL; 2103276707Sdes break; 2104276707Sdes case KEY_UNSPEC: 2105276707Sdes if ((key = sshkey_new(type)) == NULL) { 2106276707Sdes ret = SSH_ERR_ALLOC_FAIL; 2107276707Sdes goto out; 2108276707Sdes } 2109276707Sdes break; 2110276707Sdes default: 2111276707Sdes ret = SSH_ERR_KEY_TYPE_UNKNOWN; 2112276707Sdes goto out; 2113276707Sdes } 2114276707Sdes 2115276707Sdes /* Parse certificate potion */ 2116295367Sdes if (sshkey_is_cert(key) && (ret = cert_parse(b, key, copy)) != 0) 2117276707Sdes goto out; 2118276707Sdes 2119276707Sdes if (key != NULL && sshbuf_len(b) != 0) { 2120276707Sdes ret = SSH_ERR_INVALID_FORMAT; 2121276707Sdes goto out; 2122276707Sdes } 2123276707Sdes ret = 0; 2124276707Sdes *keyp = key; 2125276707Sdes key = NULL; 2126276707Sdes out: 2127295367Sdes sshbuf_free(copy); 2128276707Sdes sshkey_free(key); 2129276707Sdes free(ktype); 2130276707Sdes free(curve); 2131276707Sdes free(pk); 2132276707Sdes#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) 2133276707Sdes if (q != NULL) 2134276707Sdes EC_POINT_free(q); 2135276707Sdes#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ 2136276707Sdes return ret; 2137276707Sdes} 2138276707Sdes 2139276707Sdesint 2140276707Sdessshkey_from_blob(const u_char *blob, size_t blen, struct sshkey **keyp) 2141276707Sdes{ 2142295367Sdes struct sshbuf *b; 2143295367Sdes int r; 2144295367Sdes 2145295367Sdes if ((b = sshbuf_from(blob, blen)) == NULL) 2146295367Sdes return SSH_ERR_ALLOC_FAIL; 2147295367Sdes r = sshkey_from_blob_internal(b, keyp, 1); 2148295367Sdes sshbuf_free(b); 2149295367Sdes return r; 2150276707Sdes} 2151276707Sdes 2152276707Sdesint 2153295367Sdessshkey_fromb(struct sshbuf *b, struct sshkey **keyp) 2154295367Sdes{ 2155295367Sdes return sshkey_from_blob_internal(b, keyp, 1); 2156295367Sdes} 2157295367Sdes 2158295367Sdesint 2159295367Sdessshkey_froms(struct sshbuf *buf, struct sshkey **keyp) 2160295367Sdes{ 2161295367Sdes struct sshbuf *b; 2162295367Sdes int r; 2163295367Sdes 2164295367Sdes if ((r = sshbuf_froms(buf, &b)) != 0) 2165295367Sdes return r; 2166295367Sdes r = sshkey_from_blob_internal(b, keyp, 1); 2167295367Sdes sshbuf_free(b); 2168295367Sdes return r; 2169295367Sdes} 2170295367Sdes 2171295367Sdesint 2172276707Sdessshkey_sign(const struct sshkey *key, 2173276707Sdes u_char **sigp, size_t *lenp, 2174296853Sdes const u_char *data, size_t datalen, const char *alg, u_int compat) 2175276707Sdes{ 2176276707Sdes if (sigp != NULL) 2177276707Sdes *sigp = NULL; 2178276707Sdes if (lenp != NULL) 2179276707Sdes *lenp = 0; 2180276707Sdes if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE) 2181276707Sdes return SSH_ERR_INVALID_ARGUMENT; 2182276707Sdes switch (key->type) { 2183276707Sdes#ifdef WITH_OPENSSL 2184276707Sdes case KEY_DSA_CERT: 2185276707Sdes case KEY_DSA: 2186276707Sdes return ssh_dss_sign(key, sigp, lenp, data, datalen, compat); 2187276707Sdes# ifdef OPENSSL_HAS_ECC 2188276707Sdes case KEY_ECDSA_CERT: 2189276707Sdes case KEY_ECDSA: 2190276707Sdes return ssh_ecdsa_sign(key, sigp, lenp, data, datalen, compat); 2191276707Sdes# endif /* OPENSSL_HAS_ECC */ 2192276707Sdes case KEY_RSA_CERT: 2193276707Sdes case KEY_RSA: 2194296853Sdes return ssh_rsa_sign(key, sigp, lenp, data, datalen, alg); 2195276707Sdes#endif /* WITH_OPENSSL */ 2196276707Sdes case KEY_ED25519: 2197276707Sdes case KEY_ED25519_CERT: 2198276707Sdes return ssh_ed25519_sign(key, sigp, lenp, data, datalen, compat); 2199276707Sdes default: 2200276707Sdes return SSH_ERR_KEY_TYPE_UNKNOWN; 2201276707Sdes } 2202276707Sdes} 2203276707Sdes 2204276707Sdes/* 2205276707Sdes * ssh_key_verify returns 0 for a correct signature and < 0 on error. 2206276707Sdes */ 2207276707Sdesint 2208276707Sdessshkey_verify(const struct sshkey *key, 2209276707Sdes const u_char *sig, size_t siglen, 2210276707Sdes const u_char *data, size_t dlen, u_int compat) 2211276707Sdes{ 2212295367Sdes if (siglen == 0 || dlen > SSH_KEY_MAX_SIGN_DATA_SIZE) 2213276707Sdes return SSH_ERR_INVALID_ARGUMENT; 2214276707Sdes switch (key->type) { 2215276707Sdes#ifdef WITH_OPENSSL 2216276707Sdes case KEY_DSA_CERT: 2217276707Sdes case KEY_DSA: 2218276707Sdes return ssh_dss_verify(key, sig, siglen, data, dlen, compat); 2219276707Sdes# ifdef OPENSSL_HAS_ECC 2220276707Sdes case KEY_ECDSA_CERT: 2221276707Sdes case KEY_ECDSA: 2222276707Sdes return ssh_ecdsa_verify(key, sig, siglen, data, dlen, compat); 2223276707Sdes# endif /* OPENSSL_HAS_ECC */ 2224276707Sdes case KEY_RSA_CERT: 2225276707Sdes case KEY_RSA: 2226296853Sdes return ssh_rsa_verify(key, sig, siglen, data, dlen); 2227276707Sdes#endif /* WITH_OPENSSL */ 2228276707Sdes case KEY_ED25519: 2229276707Sdes case KEY_ED25519_CERT: 2230276707Sdes return ssh_ed25519_verify(key, sig, siglen, data, dlen, compat); 2231276707Sdes default: 2232276707Sdes return SSH_ERR_KEY_TYPE_UNKNOWN; 2233276707Sdes } 2234276707Sdes} 2235276707Sdes 2236276707Sdes/* Converts a private to a public key */ 2237276707Sdesint 2238276707Sdessshkey_demote(const struct sshkey *k, struct sshkey **dkp) 2239276707Sdes{ 2240276707Sdes struct sshkey *pk; 2241276707Sdes int ret = SSH_ERR_INTERNAL_ERROR; 2242276707Sdes 2243296853Sdes *dkp = NULL; 2244276707Sdes if ((pk = calloc(1, sizeof(*pk))) == NULL) 2245276707Sdes return SSH_ERR_ALLOC_FAIL; 2246276707Sdes pk->type = k->type; 2247276707Sdes pk->flags = k->flags; 2248276707Sdes pk->ecdsa_nid = k->ecdsa_nid; 2249276707Sdes pk->dsa = NULL; 2250276707Sdes pk->ecdsa = NULL; 2251276707Sdes pk->rsa = NULL; 2252276707Sdes pk->ed25519_pk = NULL; 2253276707Sdes pk->ed25519_sk = NULL; 2254276707Sdes 2255276707Sdes switch (k->type) { 2256276707Sdes#ifdef WITH_OPENSSL 2257276707Sdes case KEY_RSA_CERT: 2258276707Sdes if ((ret = sshkey_cert_copy(k, pk)) != 0) 2259276707Sdes goto fail; 2260276707Sdes /* FALLTHROUGH */ 2261276707Sdes case KEY_RSA1: 2262276707Sdes case KEY_RSA: 2263276707Sdes if ((pk->rsa = RSA_new()) == NULL || 2264276707Sdes (pk->rsa->e = BN_dup(k->rsa->e)) == NULL || 2265276707Sdes (pk->rsa->n = BN_dup(k->rsa->n)) == NULL) { 2266276707Sdes ret = SSH_ERR_ALLOC_FAIL; 2267276707Sdes goto fail; 2268276707Sdes } 2269276707Sdes break; 2270276707Sdes case KEY_DSA_CERT: 2271276707Sdes if ((ret = sshkey_cert_copy(k, pk)) != 0) 2272276707Sdes goto fail; 2273276707Sdes /* FALLTHROUGH */ 2274276707Sdes case KEY_DSA: 2275276707Sdes if ((pk->dsa = DSA_new()) == NULL || 2276276707Sdes (pk->dsa->p = BN_dup(k->dsa->p)) == NULL || 2277276707Sdes (pk->dsa->q = BN_dup(k->dsa->q)) == NULL || 2278276707Sdes (pk->dsa->g = BN_dup(k->dsa->g)) == NULL || 2279276707Sdes (pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL) { 2280276707Sdes ret = SSH_ERR_ALLOC_FAIL; 2281276707Sdes goto fail; 2282276707Sdes } 2283276707Sdes break; 2284276707Sdes case KEY_ECDSA_CERT: 2285276707Sdes if ((ret = sshkey_cert_copy(k, pk)) != 0) 2286276707Sdes goto fail; 2287276707Sdes /* FALLTHROUGH */ 2288276707Sdes# ifdef OPENSSL_HAS_ECC 2289276707Sdes case KEY_ECDSA: 2290276707Sdes pk->ecdsa = EC_KEY_new_by_curve_name(pk->ecdsa_nid); 2291276707Sdes if (pk->ecdsa == NULL) { 2292276707Sdes ret = SSH_ERR_ALLOC_FAIL; 2293276707Sdes goto fail; 2294276707Sdes } 2295276707Sdes if (EC_KEY_set_public_key(pk->ecdsa, 2296276707Sdes EC_KEY_get0_public_key(k->ecdsa)) != 1) { 2297276707Sdes ret = SSH_ERR_LIBCRYPTO_ERROR; 2298276707Sdes goto fail; 2299276707Sdes } 2300276707Sdes break; 2301276707Sdes# endif /* OPENSSL_HAS_ECC */ 2302276707Sdes#endif /* WITH_OPENSSL */ 2303276707Sdes case KEY_ED25519_CERT: 2304276707Sdes if ((ret = sshkey_cert_copy(k, pk)) != 0) 2305276707Sdes goto fail; 2306276707Sdes /* FALLTHROUGH */ 2307276707Sdes case KEY_ED25519: 2308276707Sdes if (k->ed25519_pk != NULL) { 2309276707Sdes if ((pk->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) { 2310276707Sdes ret = SSH_ERR_ALLOC_FAIL; 2311276707Sdes goto fail; 2312276707Sdes } 2313276707Sdes memcpy(pk->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ); 2314276707Sdes } 2315276707Sdes break; 2316276707Sdes default: 2317276707Sdes ret = SSH_ERR_KEY_TYPE_UNKNOWN; 2318276707Sdes fail: 2319276707Sdes sshkey_free(pk); 2320276707Sdes return ret; 2321276707Sdes } 2322276707Sdes *dkp = pk; 2323276707Sdes return 0; 2324276707Sdes} 2325276707Sdes 2326276707Sdes/* Convert a plain key to their _CERT equivalent */ 2327276707Sdesint 2328295367Sdessshkey_to_certified(struct sshkey *k) 2329276707Sdes{ 2330276707Sdes int newtype; 2331276707Sdes 2332276707Sdes switch (k->type) { 2333276707Sdes#ifdef WITH_OPENSSL 2334276707Sdes case KEY_RSA: 2335295367Sdes newtype = KEY_RSA_CERT; 2336276707Sdes break; 2337276707Sdes case KEY_DSA: 2338295367Sdes newtype = KEY_DSA_CERT; 2339276707Sdes break; 2340276707Sdes case KEY_ECDSA: 2341276707Sdes newtype = KEY_ECDSA_CERT; 2342276707Sdes break; 2343276707Sdes#endif /* WITH_OPENSSL */ 2344276707Sdes case KEY_ED25519: 2345276707Sdes newtype = KEY_ED25519_CERT; 2346276707Sdes break; 2347276707Sdes default: 2348276707Sdes return SSH_ERR_INVALID_ARGUMENT; 2349276707Sdes } 2350276707Sdes if ((k->cert = cert_new()) == NULL) 2351276707Sdes return SSH_ERR_ALLOC_FAIL; 2352276707Sdes k->type = newtype; 2353276707Sdes return 0; 2354276707Sdes} 2355276707Sdes 2356276707Sdes/* Convert a certificate to its raw key equivalent */ 2357276707Sdesint 2358276707Sdessshkey_drop_cert(struct sshkey *k) 2359276707Sdes{ 2360276707Sdes if (!sshkey_type_is_cert(k->type)) 2361276707Sdes return SSH_ERR_KEY_TYPE_UNKNOWN; 2362276707Sdes cert_free(k->cert); 2363276707Sdes k->cert = NULL; 2364276707Sdes k->type = sshkey_type_plain(k->type); 2365276707Sdes return 0; 2366276707Sdes} 2367276707Sdes 2368276707Sdes/* Sign a certified key, (re-)generating the signed certblob. */ 2369276707Sdesint 2370276707Sdessshkey_certify(struct sshkey *k, struct sshkey *ca) 2371276707Sdes{ 2372276707Sdes struct sshbuf *principals = NULL; 2373276707Sdes u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32]; 2374276707Sdes size_t i, ca_len, sig_len; 2375276707Sdes int ret = SSH_ERR_INTERNAL_ERROR; 2376276707Sdes struct sshbuf *cert; 2377276707Sdes 2378276707Sdes if (k == NULL || k->cert == NULL || 2379276707Sdes k->cert->certblob == NULL || ca == NULL) 2380276707Sdes return SSH_ERR_INVALID_ARGUMENT; 2381276707Sdes if (!sshkey_is_cert(k)) 2382276707Sdes return SSH_ERR_KEY_TYPE_UNKNOWN; 2383276707Sdes if (!sshkey_type_is_valid_ca(ca->type)) 2384276707Sdes return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; 2385276707Sdes 2386276707Sdes if ((ret = sshkey_to_blob(ca, &ca_blob, &ca_len)) != 0) 2387276707Sdes return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; 2388276707Sdes 2389276707Sdes cert = k->cert->certblob; /* for readability */ 2390276707Sdes sshbuf_reset(cert); 2391276707Sdes if ((ret = sshbuf_put_cstring(cert, sshkey_ssh_name(k))) != 0) 2392276707Sdes goto out; 2393276707Sdes 2394276707Sdes /* -v01 certs put nonce first */ 2395276707Sdes arc4random_buf(&nonce, sizeof(nonce)); 2396295367Sdes if ((ret = sshbuf_put_string(cert, nonce, sizeof(nonce))) != 0) 2397295367Sdes goto out; 2398276707Sdes 2399276707Sdes /* XXX this substantially duplicates to_blob(); refactor */ 2400276707Sdes switch (k->type) { 2401276707Sdes#ifdef WITH_OPENSSL 2402276707Sdes case KEY_DSA_CERT: 2403276707Sdes if ((ret = sshbuf_put_bignum2(cert, k->dsa->p)) != 0 || 2404276707Sdes (ret = sshbuf_put_bignum2(cert, k->dsa->q)) != 0 || 2405276707Sdes (ret = sshbuf_put_bignum2(cert, k->dsa->g)) != 0 || 2406276707Sdes (ret = sshbuf_put_bignum2(cert, k->dsa->pub_key)) != 0) 2407276707Sdes goto out; 2408276707Sdes break; 2409276707Sdes# ifdef OPENSSL_HAS_ECC 2410276707Sdes case KEY_ECDSA_CERT: 2411276707Sdes if ((ret = sshbuf_put_cstring(cert, 2412276707Sdes sshkey_curve_nid_to_name(k->ecdsa_nid))) != 0 || 2413276707Sdes (ret = sshbuf_put_ec(cert, 2414276707Sdes EC_KEY_get0_public_key(k->ecdsa), 2415276707Sdes EC_KEY_get0_group(k->ecdsa))) != 0) 2416276707Sdes goto out; 2417276707Sdes break; 2418276707Sdes# endif /* OPENSSL_HAS_ECC */ 2419276707Sdes case KEY_RSA_CERT: 2420276707Sdes if ((ret = sshbuf_put_bignum2(cert, k->rsa->e)) != 0 || 2421276707Sdes (ret = sshbuf_put_bignum2(cert, k->rsa->n)) != 0) 2422276707Sdes goto out; 2423276707Sdes break; 2424276707Sdes#endif /* WITH_OPENSSL */ 2425276707Sdes case KEY_ED25519_CERT: 2426276707Sdes if ((ret = sshbuf_put_string(cert, 2427276707Sdes k->ed25519_pk, ED25519_PK_SZ)) != 0) 2428276707Sdes goto out; 2429276707Sdes break; 2430276707Sdes default: 2431276707Sdes ret = SSH_ERR_INVALID_ARGUMENT; 2432295367Sdes goto out; 2433276707Sdes } 2434276707Sdes 2435295367Sdes if ((ret = sshbuf_put_u64(cert, k->cert->serial)) != 0 || 2436295367Sdes (ret = sshbuf_put_u32(cert, k->cert->type)) != 0 || 2437276707Sdes (ret = sshbuf_put_cstring(cert, k->cert->key_id)) != 0) 2438276707Sdes goto out; 2439276707Sdes 2440276707Sdes if ((principals = sshbuf_new()) == NULL) { 2441276707Sdes ret = SSH_ERR_ALLOC_FAIL; 2442276707Sdes goto out; 2443276707Sdes } 2444276707Sdes for (i = 0; i < k->cert->nprincipals; i++) { 2445276707Sdes if ((ret = sshbuf_put_cstring(principals, 2446276707Sdes k->cert->principals[i])) != 0) 2447276707Sdes goto out; 2448276707Sdes } 2449276707Sdes if ((ret = sshbuf_put_stringb(cert, principals)) != 0 || 2450276707Sdes (ret = sshbuf_put_u64(cert, k->cert->valid_after)) != 0 || 2451276707Sdes (ret = sshbuf_put_u64(cert, k->cert->valid_before)) != 0 || 2452295367Sdes (ret = sshbuf_put_stringb(cert, k->cert->critical)) != 0 || 2453295367Sdes (ret = sshbuf_put_stringb(cert, k->cert->extensions)) != 0 || 2454295367Sdes (ret = sshbuf_put_string(cert, NULL, 0)) != 0 || /* Reserved */ 2455276707Sdes (ret = sshbuf_put_string(cert, ca_blob, ca_len)) != 0) 2456276707Sdes goto out; 2457276707Sdes 2458276707Sdes /* Sign the whole mess */ 2459276707Sdes if ((ret = sshkey_sign(ca, &sig_blob, &sig_len, sshbuf_ptr(cert), 2460296853Sdes sshbuf_len(cert), NULL, 0)) != 0) 2461276707Sdes goto out; 2462276707Sdes 2463276707Sdes /* Append signature and we are done */ 2464276707Sdes if ((ret = sshbuf_put_string(cert, sig_blob, sig_len)) != 0) 2465276707Sdes goto out; 2466276707Sdes ret = 0; 2467276707Sdes out: 2468276707Sdes if (ret != 0) 2469276707Sdes sshbuf_reset(cert); 2470296853Sdes free(sig_blob); 2471296853Sdes free(ca_blob); 2472296853Sdes sshbuf_free(principals); 2473276707Sdes return ret; 2474276707Sdes} 2475276707Sdes 2476276707Sdesint 2477276707Sdessshkey_cert_check_authority(const struct sshkey *k, 2478276707Sdes int want_host, int require_principal, 2479276707Sdes const char *name, const char **reason) 2480276707Sdes{ 2481276707Sdes u_int i, principal_matches; 2482276707Sdes time_t now = time(NULL); 2483276707Sdes 2484276707Sdes if (reason != NULL) 2485276707Sdes *reason = NULL; 2486276707Sdes 2487276707Sdes if (want_host) { 2488276707Sdes if (k->cert->type != SSH2_CERT_TYPE_HOST) { 2489276707Sdes *reason = "Certificate invalid: not a host certificate"; 2490276707Sdes return SSH_ERR_KEY_CERT_INVALID; 2491276707Sdes } 2492276707Sdes } else { 2493276707Sdes if (k->cert->type != SSH2_CERT_TYPE_USER) { 2494276707Sdes *reason = "Certificate invalid: not a user certificate"; 2495276707Sdes return SSH_ERR_KEY_CERT_INVALID; 2496276707Sdes } 2497276707Sdes } 2498276707Sdes if (now < 0) { 2499276707Sdes /* yikes - system clock before epoch! */ 2500276707Sdes *reason = "Certificate invalid: not yet valid"; 2501276707Sdes return SSH_ERR_KEY_CERT_INVALID; 2502276707Sdes } 2503276707Sdes if ((u_int64_t)now < k->cert->valid_after) { 2504276707Sdes *reason = "Certificate invalid: not yet valid"; 2505276707Sdes return SSH_ERR_KEY_CERT_INVALID; 2506276707Sdes } 2507276707Sdes if ((u_int64_t)now >= k->cert->valid_before) { 2508276707Sdes *reason = "Certificate invalid: expired"; 2509276707Sdes return SSH_ERR_KEY_CERT_INVALID; 2510276707Sdes } 2511276707Sdes if (k->cert->nprincipals == 0) { 2512276707Sdes if (require_principal) { 2513276707Sdes *reason = "Certificate lacks principal list"; 2514276707Sdes return SSH_ERR_KEY_CERT_INVALID; 2515276707Sdes } 2516276707Sdes } else if (name != NULL) { 2517276707Sdes principal_matches = 0; 2518276707Sdes for (i = 0; i < k->cert->nprincipals; i++) { 2519276707Sdes if (strcmp(name, k->cert->principals[i]) == 0) { 2520276707Sdes principal_matches = 1; 2521276707Sdes break; 2522276707Sdes } 2523276707Sdes } 2524276707Sdes if (!principal_matches) { 2525276707Sdes *reason = "Certificate invalid: name is not a listed " 2526276707Sdes "principal"; 2527276707Sdes return SSH_ERR_KEY_CERT_INVALID; 2528276707Sdes } 2529276707Sdes } 2530276707Sdes return 0; 2531276707Sdes} 2532276707Sdes 2533296853Sdessize_t 2534296853Sdessshkey_format_cert_validity(const struct sshkey_cert *cert, char *s, size_t l) 2535296853Sdes{ 2536296853Sdes char from[32], to[32], ret[64]; 2537296853Sdes time_t tt; 2538296853Sdes struct tm *tm; 2539296853Sdes 2540296853Sdes *from = *to = '\0'; 2541296853Sdes if (cert->valid_after == 0 && 2542296853Sdes cert->valid_before == 0xffffffffffffffffULL) 2543296853Sdes return strlcpy(s, "forever", l); 2544296853Sdes 2545296853Sdes if (cert->valid_after != 0) { 2546296853Sdes /* XXX revisit INT_MAX in 2038 :) */ 2547296853Sdes tt = cert->valid_after > INT_MAX ? 2548296853Sdes INT_MAX : cert->valid_after; 2549296853Sdes tm = localtime(&tt); 2550296853Sdes strftime(from, sizeof(from), "%Y-%m-%dT%H:%M:%S", tm); 2551296853Sdes } 2552296853Sdes if (cert->valid_before != 0xffffffffffffffffULL) { 2553296853Sdes /* XXX revisit INT_MAX in 2038 :) */ 2554296853Sdes tt = cert->valid_before > INT_MAX ? 2555296853Sdes INT_MAX : cert->valid_before; 2556296853Sdes tm = localtime(&tt); 2557296853Sdes strftime(to, sizeof(to), "%Y-%m-%dT%H:%M:%S", tm); 2558296853Sdes } 2559296853Sdes 2560296853Sdes if (cert->valid_after == 0) 2561296853Sdes snprintf(ret, sizeof(ret), "before %s", to); 2562296853Sdes else if (cert->valid_before == 0xffffffffffffffffULL) 2563296853Sdes snprintf(ret, sizeof(ret), "after %s", from); 2564296853Sdes else 2565296853Sdes snprintf(ret, sizeof(ret), "from %s to %s", from, to); 2566296853Sdes 2567296853Sdes return strlcpy(s, ret, l); 2568296853Sdes} 2569296853Sdes 2570276707Sdesint 2571276707Sdessshkey_private_serialize(const struct sshkey *key, struct sshbuf *b) 2572276707Sdes{ 2573276707Sdes int r = SSH_ERR_INTERNAL_ERROR; 2574276707Sdes 2575276707Sdes if ((r = sshbuf_put_cstring(b, sshkey_ssh_name(key))) != 0) 2576276707Sdes goto out; 2577276707Sdes switch (key->type) { 2578276707Sdes#ifdef WITH_OPENSSL 2579276707Sdes case KEY_RSA: 2580276707Sdes if ((r = sshbuf_put_bignum2(b, key->rsa->n)) != 0 || 2581276707Sdes (r = sshbuf_put_bignum2(b, key->rsa->e)) != 0 || 2582276707Sdes (r = sshbuf_put_bignum2(b, key->rsa->d)) != 0 || 2583276707Sdes (r = sshbuf_put_bignum2(b, key->rsa->iqmp)) != 0 || 2584276707Sdes (r = sshbuf_put_bignum2(b, key->rsa->p)) != 0 || 2585276707Sdes (r = sshbuf_put_bignum2(b, key->rsa->q)) != 0) 2586276707Sdes goto out; 2587276707Sdes break; 2588276707Sdes case KEY_RSA_CERT: 2589276707Sdes if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) { 2590276707Sdes r = SSH_ERR_INVALID_ARGUMENT; 2591276707Sdes goto out; 2592276707Sdes } 2593276707Sdes if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || 2594276707Sdes (r = sshbuf_put_bignum2(b, key->rsa->d)) != 0 || 2595276707Sdes (r = sshbuf_put_bignum2(b, key->rsa->iqmp)) != 0 || 2596276707Sdes (r = sshbuf_put_bignum2(b, key->rsa->p)) != 0 || 2597276707Sdes (r = sshbuf_put_bignum2(b, key->rsa->q)) != 0) 2598276707Sdes goto out; 2599276707Sdes break; 2600276707Sdes case KEY_DSA: 2601276707Sdes if ((r = sshbuf_put_bignum2(b, key->dsa->p)) != 0 || 2602276707Sdes (r = sshbuf_put_bignum2(b, key->dsa->q)) != 0 || 2603276707Sdes (r = sshbuf_put_bignum2(b, key->dsa->g)) != 0 || 2604276707Sdes (r = sshbuf_put_bignum2(b, key->dsa->pub_key)) != 0 || 2605276707Sdes (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0) 2606276707Sdes goto out; 2607276707Sdes break; 2608276707Sdes case KEY_DSA_CERT: 2609276707Sdes if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) { 2610276707Sdes r = SSH_ERR_INVALID_ARGUMENT; 2611276707Sdes goto out; 2612276707Sdes } 2613276707Sdes if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || 2614276707Sdes (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0) 2615276707Sdes goto out; 2616276707Sdes break; 2617276707Sdes# ifdef OPENSSL_HAS_ECC 2618276707Sdes case KEY_ECDSA: 2619276707Sdes if ((r = sshbuf_put_cstring(b, 2620276707Sdes sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 || 2621276707Sdes (r = sshbuf_put_eckey(b, key->ecdsa)) != 0 || 2622276707Sdes (r = sshbuf_put_bignum2(b, 2623276707Sdes EC_KEY_get0_private_key(key->ecdsa))) != 0) 2624276707Sdes goto out; 2625276707Sdes break; 2626276707Sdes case KEY_ECDSA_CERT: 2627276707Sdes if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) { 2628276707Sdes r = SSH_ERR_INVALID_ARGUMENT; 2629276707Sdes goto out; 2630276707Sdes } 2631276707Sdes if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || 2632276707Sdes (r = sshbuf_put_bignum2(b, 2633276707Sdes EC_KEY_get0_private_key(key->ecdsa))) != 0) 2634276707Sdes goto out; 2635276707Sdes break; 2636276707Sdes# endif /* OPENSSL_HAS_ECC */ 2637276707Sdes#endif /* WITH_OPENSSL */ 2638276707Sdes case KEY_ED25519: 2639276707Sdes if ((r = sshbuf_put_string(b, key->ed25519_pk, 2640276707Sdes ED25519_PK_SZ)) != 0 || 2641276707Sdes (r = sshbuf_put_string(b, key->ed25519_sk, 2642276707Sdes ED25519_SK_SZ)) != 0) 2643276707Sdes goto out; 2644276707Sdes break; 2645276707Sdes case KEY_ED25519_CERT: 2646276707Sdes if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) { 2647276707Sdes r = SSH_ERR_INVALID_ARGUMENT; 2648276707Sdes goto out; 2649276707Sdes } 2650276707Sdes if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || 2651276707Sdes (r = sshbuf_put_string(b, key->ed25519_pk, 2652276707Sdes ED25519_PK_SZ)) != 0 || 2653276707Sdes (r = sshbuf_put_string(b, key->ed25519_sk, 2654276707Sdes ED25519_SK_SZ)) != 0) 2655276707Sdes goto out; 2656276707Sdes break; 2657276707Sdes default: 2658276707Sdes r = SSH_ERR_INVALID_ARGUMENT; 2659276707Sdes goto out; 2660276707Sdes } 2661276707Sdes /* success */ 2662276707Sdes r = 0; 2663276707Sdes out: 2664276707Sdes return r; 2665276707Sdes} 2666276707Sdes 2667276707Sdesint 2668276707Sdessshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) 2669276707Sdes{ 2670276707Sdes char *tname = NULL, *curve = NULL; 2671276707Sdes struct sshkey *k = NULL; 2672295367Sdes size_t pklen = 0, sklen = 0; 2673276707Sdes int type, r = SSH_ERR_INTERNAL_ERROR; 2674276707Sdes u_char *ed25519_pk = NULL, *ed25519_sk = NULL; 2675276707Sdes#ifdef WITH_OPENSSL 2676276707Sdes BIGNUM *exponent = NULL; 2677276707Sdes#endif /* WITH_OPENSSL */ 2678276707Sdes 2679276707Sdes if (kp != NULL) 2680276707Sdes *kp = NULL; 2681276707Sdes if ((r = sshbuf_get_cstring(buf, &tname, NULL)) != 0) 2682276707Sdes goto out; 2683276707Sdes type = sshkey_type_from_name(tname); 2684276707Sdes switch (type) { 2685276707Sdes#ifdef WITH_OPENSSL 2686276707Sdes case KEY_DSA: 2687276707Sdes if ((k = sshkey_new_private(type)) == NULL) { 2688276707Sdes r = SSH_ERR_ALLOC_FAIL; 2689276707Sdes goto out; 2690276707Sdes } 2691276707Sdes if ((r = sshbuf_get_bignum2(buf, k->dsa->p)) != 0 || 2692276707Sdes (r = sshbuf_get_bignum2(buf, k->dsa->q)) != 0 || 2693276707Sdes (r = sshbuf_get_bignum2(buf, k->dsa->g)) != 0 || 2694276707Sdes (r = sshbuf_get_bignum2(buf, k->dsa->pub_key)) != 0 || 2695276707Sdes (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0) 2696276707Sdes goto out; 2697276707Sdes break; 2698276707Sdes case KEY_DSA_CERT: 2699295367Sdes if ((r = sshkey_froms(buf, &k)) != 0 || 2700276707Sdes (r = sshkey_add_private(k)) != 0 || 2701276707Sdes (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0) 2702276707Sdes goto out; 2703276707Sdes break; 2704276707Sdes# ifdef OPENSSL_HAS_ECC 2705276707Sdes case KEY_ECDSA: 2706276707Sdes if ((k = sshkey_new_private(type)) == NULL) { 2707276707Sdes r = SSH_ERR_ALLOC_FAIL; 2708276707Sdes goto out; 2709276707Sdes } 2710276707Sdes if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) { 2711276707Sdes r = SSH_ERR_INVALID_ARGUMENT; 2712276707Sdes goto out; 2713276707Sdes } 2714276707Sdes if ((r = sshbuf_get_cstring(buf, &curve, NULL)) != 0) 2715276707Sdes goto out; 2716276707Sdes if (k->ecdsa_nid != sshkey_curve_name_to_nid(curve)) { 2717276707Sdes r = SSH_ERR_EC_CURVE_MISMATCH; 2718276707Sdes goto out; 2719276707Sdes } 2720276707Sdes k->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid); 2721276707Sdes if (k->ecdsa == NULL || (exponent = BN_new()) == NULL) { 2722276707Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 2723276707Sdes goto out; 2724276707Sdes } 2725276707Sdes if ((r = sshbuf_get_eckey(buf, k->ecdsa)) != 0 || 2726276707Sdes (r = sshbuf_get_bignum2(buf, exponent))) 2727276707Sdes goto out; 2728276707Sdes if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) { 2729276707Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 2730276707Sdes goto out; 2731276707Sdes } 2732276707Sdes if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa), 2733296853Sdes EC_KEY_get0_public_key(k->ecdsa))) != 0 || 2734276707Sdes (r = sshkey_ec_validate_private(k->ecdsa)) != 0) 2735276707Sdes goto out; 2736276707Sdes break; 2737276707Sdes case KEY_ECDSA_CERT: 2738276707Sdes if ((exponent = BN_new()) == NULL) { 2739276707Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 2740276707Sdes goto out; 2741276707Sdes } 2742295367Sdes if ((r = sshkey_froms(buf, &k)) != 0 || 2743276707Sdes (r = sshkey_add_private(k)) != 0 || 2744276707Sdes (r = sshbuf_get_bignum2(buf, exponent)) != 0) 2745276707Sdes goto out; 2746276707Sdes if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) { 2747276707Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 2748276707Sdes goto out; 2749276707Sdes } 2750276707Sdes if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa), 2751296853Sdes EC_KEY_get0_public_key(k->ecdsa))) != 0 || 2752276707Sdes (r = sshkey_ec_validate_private(k->ecdsa)) != 0) 2753276707Sdes goto out; 2754276707Sdes break; 2755276707Sdes# endif /* OPENSSL_HAS_ECC */ 2756276707Sdes case KEY_RSA: 2757276707Sdes if ((k = sshkey_new_private(type)) == NULL) { 2758276707Sdes r = SSH_ERR_ALLOC_FAIL; 2759276707Sdes goto out; 2760276707Sdes } 2761276707Sdes if ((r = sshbuf_get_bignum2(buf, k->rsa->n)) != 0 || 2762276707Sdes (r = sshbuf_get_bignum2(buf, k->rsa->e)) != 0 || 2763276707Sdes (r = sshbuf_get_bignum2(buf, k->rsa->d)) != 0 || 2764276707Sdes (r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 || 2765276707Sdes (r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 || 2766276707Sdes (r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 || 2767276707Sdes (r = rsa_generate_additional_parameters(k->rsa)) != 0) 2768276707Sdes goto out; 2769276707Sdes break; 2770276707Sdes case KEY_RSA_CERT: 2771295367Sdes if ((r = sshkey_froms(buf, &k)) != 0 || 2772276707Sdes (r = sshkey_add_private(k)) != 0 || 2773296853Sdes (r = sshbuf_get_bignum2(buf, k->rsa->d)) != 0 || 2774296853Sdes (r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 || 2775296853Sdes (r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 || 2776296853Sdes (r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 || 2777276707Sdes (r = rsa_generate_additional_parameters(k->rsa)) != 0) 2778276707Sdes goto out; 2779276707Sdes break; 2780276707Sdes#endif /* WITH_OPENSSL */ 2781276707Sdes case KEY_ED25519: 2782276707Sdes if ((k = sshkey_new_private(type)) == NULL) { 2783276707Sdes r = SSH_ERR_ALLOC_FAIL; 2784276707Sdes goto out; 2785276707Sdes } 2786276707Sdes if ((r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 || 2787276707Sdes (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0) 2788276707Sdes goto out; 2789276707Sdes if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) { 2790276707Sdes r = SSH_ERR_INVALID_FORMAT; 2791276707Sdes goto out; 2792276707Sdes } 2793276707Sdes k->ed25519_pk = ed25519_pk; 2794276707Sdes k->ed25519_sk = ed25519_sk; 2795276707Sdes ed25519_pk = ed25519_sk = NULL; 2796276707Sdes break; 2797276707Sdes case KEY_ED25519_CERT: 2798295367Sdes if ((r = sshkey_froms(buf, &k)) != 0 || 2799276707Sdes (r = sshkey_add_private(k)) != 0 || 2800276707Sdes (r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 || 2801276707Sdes (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0) 2802276707Sdes goto out; 2803276707Sdes if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) { 2804276707Sdes r = SSH_ERR_INVALID_FORMAT; 2805276707Sdes goto out; 2806276707Sdes } 2807276707Sdes k->ed25519_pk = ed25519_pk; 2808276707Sdes k->ed25519_sk = ed25519_sk; 2809276707Sdes ed25519_pk = ed25519_sk = NULL; 2810276707Sdes break; 2811276707Sdes default: 2812276707Sdes r = SSH_ERR_KEY_TYPE_UNKNOWN; 2813276707Sdes goto out; 2814276707Sdes } 2815276707Sdes#ifdef WITH_OPENSSL 2816276707Sdes /* enable blinding */ 2817276707Sdes switch (k->type) { 2818276707Sdes case KEY_RSA: 2819276707Sdes case KEY_RSA_CERT: 2820276707Sdes case KEY_RSA1: 2821276707Sdes if (RSA_blinding_on(k->rsa, NULL) != 1) { 2822276707Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 2823276707Sdes goto out; 2824276707Sdes } 2825276707Sdes break; 2826276707Sdes } 2827276707Sdes#endif /* WITH_OPENSSL */ 2828276707Sdes /* success */ 2829276707Sdes r = 0; 2830276707Sdes if (kp != NULL) { 2831276707Sdes *kp = k; 2832276707Sdes k = NULL; 2833276707Sdes } 2834276707Sdes out: 2835276707Sdes free(tname); 2836276707Sdes free(curve); 2837276707Sdes#ifdef WITH_OPENSSL 2838276707Sdes if (exponent != NULL) 2839276707Sdes BN_clear_free(exponent); 2840276707Sdes#endif /* WITH_OPENSSL */ 2841276707Sdes sshkey_free(k); 2842276707Sdes if (ed25519_pk != NULL) { 2843276707Sdes explicit_bzero(ed25519_pk, pklen); 2844276707Sdes free(ed25519_pk); 2845276707Sdes } 2846276707Sdes if (ed25519_sk != NULL) { 2847276707Sdes explicit_bzero(ed25519_sk, sklen); 2848276707Sdes free(ed25519_sk); 2849276707Sdes } 2850276707Sdes return r; 2851276707Sdes} 2852276707Sdes 2853276707Sdes#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) 2854276707Sdesint 2855276707Sdessshkey_ec_validate_public(const EC_GROUP *group, const EC_POINT *public) 2856276707Sdes{ 2857276707Sdes BN_CTX *bnctx; 2858276707Sdes EC_POINT *nq = NULL; 2859276707Sdes BIGNUM *order, *x, *y, *tmp; 2860276707Sdes int ret = SSH_ERR_KEY_INVALID_EC_VALUE; 2861276707Sdes 2862276707Sdes if ((bnctx = BN_CTX_new()) == NULL) 2863276707Sdes return SSH_ERR_ALLOC_FAIL; 2864276707Sdes BN_CTX_start(bnctx); 2865276707Sdes 2866276707Sdes /* 2867276707Sdes * We shouldn't ever hit this case because bignum_get_ecpoint() 2868276707Sdes * refuses to load GF2m points. 2869276707Sdes */ 2870276707Sdes if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != 2871276707Sdes NID_X9_62_prime_field) 2872276707Sdes goto out; 2873276707Sdes 2874276707Sdes /* Q != infinity */ 2875276707Sdes if (EC_POINT_is_at_infinity(group, public)) 2876276707Sdes goto out; 2877276707Sdes 2878276707Sdes if ((x = BN_CTX_get(bnctx)) == NULL || 2879276707Sdes (y = BN_CTX_get(bnctx)) == NULL || 2880276707Sdes (order = BN_CTX_get(bnctx)) == NULL || 2881276707Sdes (tmp = BN_CTX_get(bnctx)) == NULL) { 2882276707Sdes ret = SSH_ERR_ALLOC_FAIL; 2883276707Sdes goto out; 2884276707Sdes } 2885276707Sdes 2886276707Sdes /* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */ 2887276707Sdes if (EC_GROUP_get_order(group, order, bnctx) != 1 || 2888276707Sdes EC_POINT_get_affine_coordinates_GFp(group, public, 2889276707Sdes x, y, bnctx) != 1) { 2890276707Sdes ret = SSH_ERR_LIBCRYPTO_ERROR; 2891276707Sdes goto out; 2892276707Sdes } 2893276707Sdes if (BN_num_bits(x) <= BN_num_bits(order) / 2 || 2894276707Sdes BN_num_bits(y) <= BN_num_bits(order) / 2) 2895276707Sdes goto out; 2896276707Sdes 2897276707Sdes /* nQ == infinity (n == order of subgroup) */ 2898276707Sdes if ((nq = EC_POINT_new(group)) == NULL) { 2899276707Sdes ret = SSH_ERR_ALLOC_FAIL; 2900276707Sdes goto out; 2901276707Sdes } 2902276707Sdes if (EC_POINT_mul(group, nq, NULL, public, order, bnctx) != 1) { 2903276707Sdes ret = SSH_ERR_LIBCRYPTO_ERROR; 2904276707Sdes goto out; 2905276707Sdes } 2906276707Sdes if (EC_POINT_is_at_infinity(group, nq) != 1) 2907276707Sdes goto out; 2908276707Sdes 2909276707Sdes /* x < order - 1, y < order - 1 */ 2910276707Sdes if (!BN_sub(tmp, order, BN_value_one())) { 2911276707Sdes ret = SSH_ERR_LIBCRYPTO_ERROR; 2912276707Sdes goto out; 2913276707Sdes } 2914276707Sdes if (BN_cmp(x, tmp) >= 0 || BN_cmp(y, tmp) >= 0) 2915276707Sdes goto out; 2916276707Sdes ret = 0; 2917276707Sdes out: 2918276707Sdes BN_CTX_free(bnctx); 2919276707Sdes if (nq != NULL) 2920276707Sdes EC_POINT_free(nq); 2921276707Sdes return ret; 2922276707Sdes} 2923276707Sdes 2924276707Sdesint 2925276707Sdessshkey_ec_validate_private(const EC_KEY *key) 2926276707Sdes{ 2927276707Sdes BN_CTX *bnctx; 2928276707Sdes BIGNUM *order, *tmp; 2929276707Sdes int ret = SSH_ERR_KEY_INVALID_EC_VALUE; 2930276707Sdes 2931276707Sdes if ((bnctx = BN_CTX_new()) == NULL) 2932276707Sdes return SSH_ERR_ALLOC_FAIL; 2933276707Sdes BN_CTX_start(bnctx); 2934276707Sdes 2935276707Sdes if ((order = BN_CTX_get(bnctx)) == NULL || 2936276707Sdes (tmp = BN_CTX_get(bnctx)) == NULL) { 2937276707Sdes ret = SSH_ERR_ALLOC_FAIL; 2938276707Sdes goto out; 2939276707Sdes } 2940276707Sdes 2941276707Sdes /* log2(private) > log2(order)/2 */ 2942276707Sdes if (EC_GROUP_get_order(EC_KEY_get0_group(key), order, bnctx) != 1) { 2943276707Sdes ret = SSH_ERR_LIBCRYPTO_ERROR; 2944276707Sdes goto out; 2945276707Sdes } 2946276707Sdes if (BN_num_bits(EC_KEY_get0_private_key(key)) <= 2947276707Sdes BN_num_bits(order) / 2) 2948276707Sdes goto out; 2949276707Sdes 2950276707Sdes /* private < order - 1 */ 2951276707Sdes if (!BN_sub(tmp, order, BN_value_one())) { 2952276707Sdes ret = SSH_ERR_LIBCRYPTO_ERROR; 2953276707Sdes goto out; 2954276707Sdes } 2955276707Sdes if (BN_cmp(EC_KEY_get0_private_key(key), tmp) >= 0) 2956276707Sdes goto out; 2957276707Sdes ret = 0; 2958276707Sdes out: 2959276707Sdes BN_CTX_free(bnctx); 2960276707Sdes return ret; 2961276707Sdes} 2962276707Sdes 2963276707Sdesvoid 2964276707Sdessshkey_dump_ec_point(const EC_GROUP *group, const EC_POINT *point) 2965276707Sdes{ 2966276707Sdes BIGNUM *x, *y; 2967276707Sdes BN_CTX *bnctx; 2968276707Sdes 2969276707Sdes if (point == NULL) { 2970276707Sdes fputs("point=(NULL)\n", stderr); 2971276707Sdes return; 2972276707Sdes } 2973276707Sdes if ((bnctx = BN_CTX_new()) == NULL) { 2974276707Sdes fprintf(stderr, "%s: BN_CTX_new failed\n", __func__); 2975276707Sdes return; 2976276707Sdes } 2977276707Sdes BN_CTX_start(bnctx); 2978276707Sdes if ((x = BN_CTX_get(bnctx)) == NULL || 2979276707Sdes (y = BN_CTX_get(bnctx)) == NULL) { 2980276707Sdes fprintf(stderr, "%s: BN_CTX_get failed\n", __func__); 2981276707Sdes return; 2982276707Sdes } 2983276707Sdes if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != 2984276707Sdes NID_X9_62_prime_field) { 2985276707Sdes fprintf(stderr, "%s: group is not a prime field\n", __func__); 2986276707Sdes return; 2987276707Sdes } 2988276707Sdes if (EC_POINT_get_affine_coordinates_GFp(group, point, x, y, 2989276707Sdes bnctx) != 1) { 2990276707Sdes fprintf(stderr, "%s: EC_POINT_get_affine_coordinates_GFp\n", 2991276707Sdes __func__); 2992276707Sdes return; 2993276707Sdes } 2994276707Sdes fputs("x=", stderr); 2995276707Sdes BN_print_fp(stderr, x); 2996276707Sdes fputs("\ny=", stderr); 2997276707Sdes BN_print_fp(stderr, y); 2998276707Sdes fputs("\n", stderr); 2999276707Sdes BN_CTX_free(bnctx); 3000276707Sdes} 3001276707Sdes 3002276707Sdesvoid 3003276707Sdessshkey_dump_ec_key(const EC_KEY *key) 3004276707Sdes{ 3005276707Sdes const BIGNUM *exponent; 3006276707Sdes 3007276707Sdes sshkey_dump_ec_point(EC_KEY_get0_group(key), 3008276707Sdes EC_KEY_get0_public_key(key)); 3009276707Sdes fputs("exponent=", stderr); 3010276707Sdes if ((exponent = EC_KEY_get0_private_key(key)) == NULL) 3011276707Sdes fputs("(NULL)", stderr); 3012276707Sdes else 3013276707Sdes BN_print_fp(stderr, EC_KEY_get0_private_key(key)); 3014276707Sdes fputs("\n", stderr); 3015276707Sdes} 3016276707Sdes#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ 3017276707Sdes 3018276707Sdesstatic int 3019276707Sdessshkey_private_to_blob2(const struct sshkey *prv, struct sshbuf *blob, 3020276707Sdes const char *passphrase, const char *comment, const char *ciphername, 3021276707Sdes int rounds) 3022276707Sdes{ 3023295367Sdes u_char *cp, *key = NULL, *pubkeyblob = NULL; 3024276707Sdes u_char salt[SALT_LEN]; 3025295367Sdes char *b64 = NULL; 3026276707Sdes size_t i, pubkeylen, keylen, ivlen, blocksize, authlen; 3027276707Sdes u_int check; 3028276707Sdes int r = SSH_ERR_INTERNAL_ERROR; 3029276707Sdes struct sshcipher_ctx ciphercontext; 3030276707Sdes const struct sshcipher *cipher; 3031276707Sdes const char *kdfname = KDFNAME; 3032276707Sdes struct sshbuf *encoded = NULL, *encrypted = NULL, *kdf = NULL; 3033276707Sdes 3034276707Sdes memset(&ciphercontext, 0, sizeof(ciphercontext)); 3035276707Sdes 3036276707Sdes if (rounds <= 0) 3037276707Sdes rounds = DEFAULT_ROUNDS; 3038276707Sdes if (passphrase == NULL || !strlen(passphrase)) { 3039276707Sdes ciphername = "none"; 3040276707Sdes kdfname = "none"; 3041276707Sdes } else if (ciphername == NULL) 3042276707Sdes ciphername = DEFAULT_CIPHERNAME; 3043276707Sdes else if (cipher_number(ciphername) != SSH_CIPHER_SSH2) { 3044276707Sdes r = SSH_ERR_INVALID_ARGUMENT; 3045276707Sdes goto out; 3046276707Sdes } 3047276707Sdes if ((cipher = cipher_by_name(ciphername)) == NULL) { 3048276707Sdes r = SSH_ERR_INTERNAL_ERROR; 3049276707Sdes goto out; 3050276707Sdes } 3051276707Sdes 3052276707Sdes if ((kdf = sshbuf_new()) == NULL || 3053276707Sdes (encoded = sshbuf_new()) == NULL || 3054276707Sdes (encrypted = sshbuf_new()) == NULL) { 3055276707Sdes r = SSH_ERR_ALLOC_FAIL; 3056276707Sdes goto out; 3057276707Sdes } 3058276707Sdes blocksize = cipher_blocksize(cipher); 3059276707Sdes keylen = cipher_keylen(cipher); 3060276707Sdes ivlen = cipher_ivlen(cipher); 3061276707Sdes authlen = cipher_authlen(cipher); 3062276707Sdes if ((key = calloc(1, keylen + ivlen)) == NULL) { 3063276707Sdes r = SSH_ERR_ALLOC_FAIL; 3064276707Sdes goto out; 3065276707Sdes } 3066276707Sdes if (strcmp(kdfname, "bcrypt") == 0) { 3067276707Sdes arc4random_buf(salt, SALT_LEN); 3068276707Sdes if (bcrypt_pbkdf(passphrase, strlen(passphrase), 3069276707Sdes salt, SALT_LEN, key, keylen + ivlen, rounds) < 0) { 3070276707Sdes r = SSH_ERR_INVALID_ARGUMENT; 3071276707Sdes goto out; 3072276707Sdes } 3073276707Sdes if ((r = sshbuf_put_string(kdf, salt, SALT_LEN)) != 0 || 3074276707Sdes (r = sshbuf_put_u32(kdf, rounds)) != 0) 3075276707Sdes goto out; 3076276707Sdes } else if (strcmp(kdfname, "none") != 0) { 3077276707Sdes /* Unsupported KDF type */ 3078276707Sdes r = SSH_ERR_KEY_UNKNOWN_CIPHER; 3079276707Sdes goto out; 3080276707Sdes } 3081276707Sdes if ((r = cipher_init(&ciphercontext, cipher, key, keylen, 3082276707Sdes key + keylen, ivlen, 1)) != 0) 3083276707Sdes goto out; 3084276707Sdes 3085276707Sdes if ((r = sshbuf_put(encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC))) != 0 || 3086276707Sdes (r = sshbuf_put_cstring(encoded, ciphername)) != 0 || 3087276707Sdes (r = sshbuf_put_cstring(encoded, kdfname)) != 0 || 3088276707Sdes (r = sshbuf_put_stringb(encoded, kdf)) != 0 || 3089276707Sdes (r = sshbuf_put_u32(encoded, 1)) != 0 || /* number of keys */ 3090276707Sdes (r = sshkey_to_blob(prv, &pubkeyblob, &pubkeylen)) != 0 || 3091276707Sdes (r = sshbuf_put_string(encoded, pubkeyblob, pubkeylen)) != 0) 3092276707Sdes goto out; 3093276707Sdes 3094276707Sdes /* set up the buffer that will be encrypted */ 3095276707Sdes 3096276707Sdes /* Random check bytes */ 3097276707Sdes check = arc4random(); 3098276707Sdes if ((r = sshbuf_put_u32(encrypted, check)) != 0 || 3099276707Sdes (r = sshbuf_put_u32(encrypted, check)) != 0) 3100276707Sdes goto out; 3101276707Sdes 3102276707Sdes /* append private key and comment*/ 3103276707Sdes if ((r = sshkey_private_serialize(prv, encrypted)) != 0 || 3104276707Sdes (r = sshbuf_put_cstring(encrypted, comment)) != 0) 3105276707Sdes goto out; 3106276707Sdes 3107276707Sdes /* padding */ 3108276707Sdes i = 0; 3109276707Sdes while (sshbuf_len(encrypted) % blocksize) { 3110276707Sdes if ((r = sshbuf_put_u8(encrypted, ++i & 0xff)) != 0) 3111276707Sdes goto out; 3112276707Sdes } 3113276707Sdes 3114276707Sdes /* length in destination buffer */ 3115276707Sdes if ((r = sshbuf_put_u32(encoded, sshbuf_len(encrypted))) != 0) 3116276707Sdes goto out; 3117276707Sdes 3118276707Sdes /* encrypt */ 3119276707Sdes if ((r = sshbuf_reserve(encoded, 3120276707Sdes sshbuf_len(encrypted) + authlen, &cp)) != 0) 3121276707Sdes goto out; 3122276707Sdes if ((r = cipher_crypt(&ciphercontext, 0, cp, 3123276707Sdes sshbuf_ptr(encrypted), sshbuf_len(encrypted), 0, authlen)) != 0) 3124276707Sdes goto out; 3125276707Sdes 3126276707Sdes /* uuencode */ 3127276707Sdes if ((b64 = sshbuf_dtob64(encoded)) == NULL) { 3128276707Sdes r = SSH_ERR_ALLOC_FAIL; 3129276707Sdes goto out; 3130276707Sdes } 3131276707Sdes 3132276707Sdes sshbuf_reset(blob); 3133276707Sdes if ((r = sshbuf_put(blob, MARK_BEGIN, MARK_BEGIN_LEN)) != 0) 3134276707Sdes goto out; 3135276707Sdes for (i = 0; i < strlen(b64); i++) { 3136276707Sdes if ((r = sshbuf_put_u8(blob, b64[i])) != 0) 3137276707Sdes goto out; 3138276707Sdes /* insert line breaks */ 3139276707Sdes if (i % 70 == 69 && (r = sshbuf_put_u8(blob, '\n')) != 0) 3140276707Sdes goto out; 3141276707Sdes } 3142276707Sdes if (i % 70 != 69 && (r = sshbuf_put_u8(blob, '\n')) != 0) 3143276707Sdes goto out; 3144276707Sdes if ((r = sshbuf_put(blob, MARK_END, MARK_END_LEN)) != 0) 3145276707Sdes goto out; 3146276707Sdes 3147276707Sdes /* success */ 3148276707Sdes r = 0; 3149276707Sdes 3150276707Sdes out: 3151276707Sdes sshbuf_free(kdf); 3152276707Sdes sshbuf_free(encoded); 3153276707Sdes sshbuf_free(encrypted); 3154276707Sdes cipher_cleanup(&ciphercontext); 3155276707Sdes explicit_bzero(salt, sizeof(salt)); 3156276707Sdes if (key != NULL) { 3157276707Sdes explicit_bzero(key, keylen + ivlen); 3158276707Sdes free(key); 3159276707Sdes } 3160276707Sdes if (pubkeyblob != NULL) { 3161276707Sdes explicit_bzero(pubkeyblob, pubkeylen); 3162276707Sdes free(pubkeyblob); 3163276707Sdes } 3164276707Sdes if (b64 != NULL) { 3165276707Sdes explicit_bzero(b64, strlen(b64)); 3166276707Sdes free(b64); 3167276707Sdes } 3168276707Sdes return r; 3169276707Sdes} 3170276707Sdes 3171276707Sdesstatic int 3172276707Sdessshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase, 3173276707Sdes struct sshkey **keyp, char **commentp) 3174276707Sdes{ 3175276707Sdes char *comment = NULL, *ciphername = NULL, *kdfname = NULL; 3176276707Sdes const struct sshcipher *cipher = NULL; 3177276707Sdes const u_char *cp; 3178276707Sdes int r = SSH_ERR_INTERNAL_ERROR; 3179276707Sdes size_t encoded_len; 3180295367Sdes size_t i, keylen = 0, ivlen = 0, authlen = 0, slen = 0; 3181276707Sdes struct sshbuf *encoded = NULL, *decoded = NULL; 3182276707Sdes struct sshbuf *kdf = NULL, *decrypted = NULL; 3183276707Sdes struct sshcipher_ctx ciphercontext; 3184276707Sdes struct sshkey *k = NULL; 3185276707Sdes u_char *key = NULL, *salt = NULL, *dp, pad, last; 3186276707Sdes u_int blocksize, rounds, nkeys, encrypted_len, check1, check2; 3187276707Sdes 3188276707Sdes memset(&ciphercontext, 0, sizeof(ciphercontext)); 3189276707Sdes if (keyp != NULL) 3190276707Sdes *keyp = NULL; 3191276707Sdes if (commentp != NULL) 3192276707Sdes *commentp = NULL; 3193276707Sdes 3194276707Sdes if ((encoded = sshbuf_new()) == NULL || 3195276707Sdes (decoded = sshbuf_new()) == NULL || 3196276707Sdes (decrypted = sshbuf_new()) == NULL) { 3197276707Sdes r = SSH_ERR_ALLOC_FAIL; 3198276707Sdes goto out; 3199276707Sdes } 3200276707Sdes 3201276707Sdes /* check preamble */ 3202276707Sdes cp = sshbuf_ptr(blob); 3203276707Sdes encoded_len = sshbuf_len(blob); 3204276707Sdes if (encoded_len < (MARK_BEGIN_LEN + MARK_END_LEN) || 3205276707Sdes memcmp(cp, MARK_BEGIN, MARK_BEGIN_LEN) != 0) { 3206276707Sdes r = SSH_ERR_INVALID_FORMAT; 3207276707Sdes goto out; 3208276707Sdes } 3209276707Sdes cp += MARK_BEGIN_LEN; 3210276707Sdes encoded_len -= MARK_BEGIN_LEN; 3211276707Sdes 3212276707Sdes /* Look for end marker, removing whitespace as we go */ 3213276707Sdes while (encoded_len > 0) { 3214276707Sdes if (*cp != '\n' && *cp != '\r') { 3215276707Sdes if ((r = sshbuf_put_u8(encoded, *cp)) != 0) 3216276707Sdes goto out; 3217276707Sdes } 3218276707Sdes last = *cp; 3219276707Sdes encoded_len--; 3220276707Sdes cp++; 3221276707Sdes if (last == '\n') { 3222276707Sdes if (encoded_len >= MARK_END_LEN && 3223276707Sdes memcmp(cp, MARK_END, MARK_END_LEN) == 0) { 3224276707Sdes /* \0 terminate */ 3225276707Sdes if ((r = sshbuf_put_u8(encoded, 0)) != 0) 3226276707Sdes goto out; 3227276707Sdes break; 3228276707Sdes } 3229276707Sdes } 3230276707Sdes } 3231276707Sdes if (encoded_len == 0) { 3232276707Sdes r = SSH_ERR_INVALID_FORMAT; 3233276707Sdes goto out; 3234276707Sdes } 3235276707Sdes 3236276707Sdes /* decode base64 */ 3237295367Sdes if ((r = sshbuf_b64tod(decoded, (char *)sshbuf_ptr(encoded))) != 0) 3238276707Sdes goto out; 3239276707Sdes 3240276707Sdes /* check magic */ 3241276707Sdes if (sshbuf_len(decoded) < sizeof(AUTH_MAGIC) || 3242276707Sdes memcmp(sshbuf_ptr(decoded), AUTH_MAGIC, sizeof(AUTH_MAGIC))) { 3243276707Sdes r = SSH_ERR_INVALID_FORMAT; 3244276707Sdes goto out; 3245276707Sdes } 3246276707Sdes /* parse public portion of key */ 3247276707Sdes if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 || 3248276707Sdes (r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 || 3249276707Sdes (r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 || 3250276707Sdes (r = sshbuf_froms(decoded, &kdf)) != 0 || 3251276707Sdes (r = sshbuf_get_u32(decoded, &nkeys)) != 0 || 3252276707Sdes (r = sshbuf_skip_string(decoded)) != 0 || /* pubkey */ 3253276707Sdes (r = sshbuf_get_u32(decoded, &encrypted_len)) != 0) 3254276707Sdes goto out; 3255276707Sdes 3256276707Sdes if ((cipher = cipher_by_name(ciphername)) == NULL) { 3257276707Sdes r = SSH_ERR_KEY_UNKNOWN_CIPHER; 3258276707Sdes goto out; 3259276707Sdes } 3260276707Sdes if ((passphrase == NULL || strlen(passphrase) == 0) && 3261276707Sdes strcmp(ciphername, "none") != 0) { 3262276707Sdes /* passphrase required */ 3263276707Sdes r = SSH_ERR_KEY_WRONG_PASSPHRASE; 3264276707Sdes goto out; 3265276707Sdes } 3266276707Sdes if (strcmp(kdfname, "none") != 0 && strcmp(kdfname, "bcrypt") != 0) { 3267276707Sdes r = SSH_ERR_KEY_UNKNOWN_CIPHER; 3268276707Sdes goto out; 3269276707Sdes } 3270276707Sdes if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) { 3271276707Sdes r = SSH_ERR_INVALID_FORMAT; 3272276707Sdes goto out; 3273276707Sdes } 3274276707Sdes if (nkeys != 1) { 3275276707Sdes /* XXX only one key supported */ 3276276707Sdes r = SSH_ERR_INVALID_FORMAT; 3277276707Sdes goto out; 3278276707Sdes } 3279276707Sdes 3280276707Sdes /* check size of encrypted key blob */ 3281276707Sdes blocksize = cipher_blocksize(cipher); 3282276707Sdes if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) { 3283276707Sdes r = SSH_ERR_INVALID_FORMAT; 3284276707Sdes goto out; 3285276707Sdes } 3286276707Sdes 3287276707Sdes /* setup key */ 3288276707Sdes keylen = cipher_keylen(cipher); 3289276707Sdes ivlen = cipher_ivlen(cipher); 3290295367Sdes authlen = cipher_authlen(cipher); 3291276707Sdes if ((key = calloc(1, keylen + ivlen)) == NULL) { 3292276707Sdes r = SSH_ERR_ALLOC_FAIL; 3293276707Sdes goto out; 3294276707Sdes } 3295276707Sdes if (strcmp(kdfname, "bcrypt") == 0) { 3296276707Sdes if ((r = sshbuf_get_string(kdf, &salt, &slen)) != 0 || 3297276707Sdes (r = sshbuf_get_u32(kdf, &rounds)) != 0) 3298276707Sdes goto out; 3299276707Sdes if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen, 3300276707Sdes key, keylen + ivlen, rounds) < 0) { 3301276707Sdes r = SSH_ERR_INVALID_FORMAT; 3302276707Sdes goto out; 3303276707Sdes } 3304276707Sdes } 3305276707Sdes 3306295367Sdes /* check that an appropriate amount of auth data is present */ 3307295367Sdes if (sshbuf_len(decoded) < encrypted_len + authlen) { 3308295367Sdes r = SSH_ERR_INVALID_FORMAT; 3309295367Sdes goto out; 3310295367Sdes } 3311295367Sdes 3312276707Sdes /* decrypt private portion of key */ 3313276707Sdes if ((r = sshbuf_reserve(decrypted, encrypted_len, &dp)) != 0 || 3314276707Sdes (r = cipher_init(&ciphercontext, cipher, key, keylen, 3315276707Sdes key + keylen, ivlen, 0)) != 0) 3316276707Sdes goto out; 3317276707Sdes if ((r = cipher_crypt(&ciphercontext, 0, dp, sshbuf_ptr(decoded), 3318295367Sdes encrypted_len, 0, authlen)) != 0) { 3319276707Sdes /* an integrity error here indicates an incorrect passphrase */ 3320276707Sdes if (r == SSH_ERR_MAC_INVALID) 3321276707Sdes r = SSH_ERR_KEY_WRONG_PASSPHRASE; 3322276707Sdes goto out; 3323276707Sdes } 3324295367Sdes if ((r = sshbuf_consume(decoded, encrypted_len + authlen)) != 0) 3325276707Sdes goto out; 3326276707Sdes /* there should be no trailing data */ 3327276707Sdes if (sshbuf_len(decoded) != 0) { 3328276707Sdes r = SSH_ERR_INVALID_FORMAT; 3329276707Sdes goto out; 3330276707Sdes } 3331276707Sdes 3332276707Sdes /* check check bytes */ 3333276707Sdes if ((r = sshbuf_get_u32(decrypted, &check1)) != 0 || 3334276707Sdes (r = sshbuf_get_u32(decrypted, &check2)) != 0) 3335276707Sdes goto out; 3336276707Sdes if (check1 != check2) { 3337276707Sdes r = SSH_ERR_KEY_WRONG_PASSPHRASE; 3338276707Sdes goto out; 3339276707Sdes } 3340276707Sdes 3341276707Sdes /* Load the private key and comment */ 3342276707Sdes if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 || 3343276707Sdes (r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0) 3344276707Sdes goto out; 3345276707Sdes 3346276707Sdes /* Check deterministic padding */ 3347276707Sdes i = 0; 3348276707Sdes while (sshbuf_len(decrypted)) { 3349276707Sdes if ((r = sshbuf_get_u8(decrypted, &pad)) != 0) 3350276707Sdes goto out; 3351276707Sdes if (pad != (++i & 0xff)) { 3352276707Sdes r = SSH_ERR_INVALID_FORMAT; 3353276707Sdes goto out; 3354276707Sdes } 3355276707Sdes } 3356276707Sdes 3357276707Sdes /* XXX decode pubkey and check against private */ 3358276707Sdes 3359276707Sdes /* success */ 3360276707Sdes r = 0; 3361276707Sdes if (keyp != NULL) { 3362276707Sdes *keyp = k; 3363276707Sdes k = NULL; 3364276707Sdes } 3365276707Sdes if (commentp != NULL) { 3366276707Sdes *commentp = comment; 3367276707Sdes comment = NULL; 3368276707Sdes } 3369276707Sdes out: 3370276707Sdes pad = 0; 3371276707Sdes cipher_cleanup(&ciphercontext); 3372276707Sdes free(ciphername); 3373276707Sdes free(kdfname); 3374276707Sdes free(comment); 3375276707Sdes if (salt != NULL) { 3376276707Sdes explicit_bzero(salt, slen); 3377276707Sdes free(salt); 3378276707Sdes } 3379276707Sdes if (key != NULL) { 3380276707Sdes explicit_bzero(key, keylen + ivlen); 3381276707Sdes free(key); 3382276707Sdes } 3383276707Sdes sshbuf_free(encoded); 3384276707Sdes sshbuf_free(decoded); 3385276707Sdes sshbuf_free(kdf); 3386276707Sdes sshbuf_free(decrypted); 3387276707Sdes sshkey_free(k); 3388276707Sdes return r; 3389276707Sdes} 3390276707Sdes 3391276707Sdes#if WITH_SSH1 3392276707Sdes/* 3393276707Sdes * Serialises the authentication (private) key to a blob, encrypting it with 3394276707Sdes * passphrase. The identification of the blob (lowest 64 bits of n) will 3395276707Sdes * precede the key to provide identification of the key without needing a 3396276707Sdes * passphrase. 3397276707Sdes */ 3398276707Sdesstatic int 3399276707Sdessshkey_private_rsa1_to_blob(struct sshkey *key, struct sshbuf *blob, 3400276707Sdes const char *passphrase, const char *comment) 3401276707Sdes{ 3402276707Sdes struct sshbuf *buffer = NULL, *encrypted = NULL; 3403276707Sdes u_char buf[8]; 3404276707Sdes int r, cipher_num; 3405276707Sdes struct sshcipher_ctx ciphercontext; 3406276707Sdes const struct sshcipher *cipher; 3407276707Sdes u_char *cp; 3408276707Sdes 3409276707Sdes /* 3410276707Sdes * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting 3411276707Sdes * to another cipher; otherwise use SSH_AUTHFILE_CIPHER. 3412276707Sdes */ 3413276707Sdes cipher_num = (strcmp(passphrase, "") == 0) ? 3414276707Sdes SSH_CIPHER_NONE : SSH_CIPHER_3DES; 3415276707Sdes if ((cipher = cipher_by_number(cipher_num)) == NULL) 3416276707Sdes return SSH_ERR_INTERNAL_ERROR; 3417276707Sdes 3418276707Sdes /* This buffer is used to build the secret part of the private key. */ 3419276707Sdes if ((buffer = sshbuf_new()) == NULL) 3420276707Sdes return SSH_ERR_ALLOC_FAIL; 3421276707Sdes 3422276707Sdes /* Put checkbytes for checking passphrase validity. */ 3423276707Sdes if ((r = sshbuf_reserve(buffer, 4, &cp)) != 0) 3424276707Sdes goto out; 3425276707Sdes arc4random_buf(cp, 2); 3426276707Sdes memcpy(cp + 2, cp, 2); 3427276707Sdes 3428276707Sdes /* 3429276707Sdes * Store the private key (n and e will not be stored because they 3430276707Sdes * will be stored in plain text, and storing them also in encrypted 3431276707Sdes * format would just give known plaintext). 3432276707Sdes * Note: q and p are stored in reverse order to SSL. 3433276707Sdes */ 3434276707Sdes if ((r = sshbuf_put_bignum1(buffer, key->rsa->d)) != 0 || 3435276707Sdes (r = sshbuf_put_bignum1(buffer, key->rsa->iqmp)) != 0 || 3436276707Sdes (r = sshbuf_put_bignum1(buffer, key->rsa->q)) != 0 || 3437276707Sdes (r = sshbuf_put_bignum1(buffer, key->rsa->p)) != 0) 3438276707Sdes goto out; 3439276707Sdes 3440276707Sdes /* Pad the part to be encrypted to a size that is a multiple of 8. */ 3441276707Sdes explicit_bzero(buf, 8); 3442276707Sdes if ((r = sshbuf_put(buffer, buf, 8 - (sshbuf_len(buffer) % 8))) != 0) 3443276707Sdes goto out; 3444276707Sdes 3445276707Sdes /* This buffer will be used to contain the data in the file. */ 3446276707Sdes if ((encrypted = sshbuf_new()) == NULL) { 3447276707Sdes r = SSH_ERR_ALLOC_FAIL; 3448276707Sdes goto out; 3449276707Sdes } 3450276707Sdes 3451276707Sdes /* First store keyfile id string. */ 3452276707Sdes if ((r = sshbuf_put(encrypted, LEGACY_BEGIN, 3453276707Sdes sizeof(LEGACY_BEGIN))) != 0) 3454276707Sdes goto out; 3455276707Sdes 3456276707Sdes /* Store cipher type and "reserved" field. */ 3457276707Sdes if ((r = sshbuf_put_u8(encrypted, cipher_num)) != 0 || 3458276707Sdes (r = sshbuf_put_u32(encrypted, 0)) != 0) 3459276707Sdes goto out; 3460276707Sdes 3461276707Sdes /* Store public key. This will be in plain text. */ 3462276707Sdes if ((r = sshbuf_put_u32(encrypted, BN_num_bits(key->rsa->n))) != 0 || 3463296853Sdes (r = sshbuf_put_bignum1(encrypted, key->rsa->n)) != 0 || 3464296853Sdes (r = sshbuf_put_bignum1(encrypted, key->rsa->e)) != 0 || 3465296853Sdes (r = sshbuf_put_cstring(encrypted, comment)) != 0) 3466276707Sdes goto out; 3467276707Sdes 3468276707Sdes /* Allocate space for the private part of the key in the buffer. */ 3469276707Sdes if ((r = sshbuf_reserve(encrypted, sshbuf_len(buffer), &cp)) != 0) 3470276707Sdes goto out; 3471276707Sdes 3472276707Sdes if ((r = cipher_set_key_string(&ciphercontext, cipher, passphrase, 3473276707Sdes CIPHER_ENCRYPT)) != 0) 3474276707Sdes goto out; 3475276707Sdes if ((r = cipher_crypt(&ciphercontext, 0, cp, 3476276707Sdes sshbuf_ptr(buffer), sshbuf_len(buffer), 0, 0)) != 0) 3477276707Sdes goto out; 3478276707Sdes if ((r = cipher_cleanup(&ciphercontext)) != 0) 3479276707Sdes goto out; 3480276707Sdes 3481276707Sdes r = sshbuf_putb(blob, encrypted); 3482276707Sdes 3483276707Sdes out: 3484276707Sdes explicit_bzero(&ciphercontext, sizeof(ciphercontext)); 3485276707Sdes explicit_bzero(buf, sizeof(buf)); 3486296853Sdes sshbuf_free(buffer); 3487296853Sdes sshbuf_free(encrypted); 3488276707Sdes 3489276707Sdes return r; 3490276707Sdes} 3491276707Sdes#endif /* WITH_SSH1 */ 3492276707Sdes 3493276707Sdes#ifdef WITH_OPENSSL 3494276707Sdes/* convert SSH v2 key in OpenSSL PEM format */ 3495276707Sdesstatic int 3496276707Sdessshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *blob, 3497276707Sdes const char *_passphrase, const char *comment) 3498276707Sdes{ 3499276707Sdes int success, r; 3500276707Sdes int blen, len = strlen(_passphrase); 3501276707Sdes u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; 3502276707Sdes#if (OPENSSL_VERSION_NUMBER < 0x00907000L) 3503276707Sdes const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; 3504276707Sdes#else 3505276707Sdes const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; 3506276707Sdes#endif 3507276707Sdes const u_char *bptr; 3508276707Sdes BIO *bio = NULL; 3509276707Sdes 3510276707Sdes if (len > 0 && len <= 4) 3511276707Sdes return SSH_ERR_PASSPHRASE_TOO_SHORT; 3512276707Sdes if ((bio = BIO_new(BIO_s_mem())) == NULL) 3513276707Sdes return SSH_ERR_ALLOC_FAIL; 3514276707Sdes 3515276707Sdes switch (key->type) { 3516276707Sdes case KEY_DSA: 3517276707Sdes success = PEM_write_bio_DSAPrivateKey(bio, key->dsa, 3518276707Sdes cipher, passphrase, len, NULL, NULL); 3519276707Sdes break; 3520276707Sdes#ifdef OPENSSL_HAS_ECC 3521276707Sdes case KEY_ECDSA: 3522276707Sdes success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa, 3523276707Sdes cipher, passphrase, len, NULL, NULL); 3524276707Sdes break; 3525276707Sdes#endif 3526276707Sdes case KEY_RSA: 3527276707Sdes success = PEM_write_bio_RSAPrivateKey(bio, key->rsa, 3528276707Sdes cipher, passphrase, len, NULL, NULL); 3529276707Sdes break; 3530276707Sdes default: 3531276707Sdes success = 0; 3532276707Sdes break; 3533276707Sdes } 3534276707Sdes if (success == 0) { 3535276707Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 3536276707Sdes goto out; 3537276707Sdes } 3538276707Sdes if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) { 3539276707Sdes r = SSH_ERR_INTERNAL_ERROR; 3540276707Sdes goto out; 3541276707Sdes } 3542276707Sdes if ((r = sshbuf_put(blob, bptr, blen)) != 0) 3543276707Sdes goto out; 3544276707Sdes r = 0; 3545276707Sdes out: 3546276707Sdes BIO_free(bio); 3547276707Sdes return r; 3548276707Sdes} 3549276707Sdes#endif /* WITH_OPENSSL */ 3550276707Sdes 3551276707Sdes/* Serialise "key" to buffer "blob" */ 3552276707Sdesint 3553276707Sdessshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob, 3554276707Sdes const char *passphrase, const char *comment, 3555276707Sdes int force_new_format, const char *new_format_cipher, int new_format_rounds) 3556276707Sdes{ 3557276707Sdes switch (key->type) { 3558295367Sdes#ifdef WITH_SSH1 3559276707Sdes case KEY_RSA1: 3560276707Sdes return sshkey_private_rsa1_to_blob(key, blob, 3561276707Sdes passphrase, comment); 3562295367Sdes#endif /* WITH_SSH1 */ 3563295367Sdes#ifdef WITH_OPENSSL 3564276707Sdes case KEY_DSA: 3565276707Sdes case KEY_ECDSA: 3566276707Sdes case KEY_RSA: 3567276707Sdes if (force_new_format) { 3568276707Sdes return sshkey_private_to_blob2(key, blob, passphrase, 3569276707Sdes comment, new_format_cipher, new_format_rounds); 3570276707Sdes } 3571276707Sdes return sshkey_private_pem_to_blob(key, blob, 3572276707Sdes passphrase, comment); 3573276707Sdes#endif /* WITH_OPENSSL */ 3574276707Sdes case KEY_ED25519: 3575276707Sdes return sshkey_private_to_blob2(key, blob, passphrase, 3576276707Sdes comment, new_format_cipher, new_format_rounds); 3577276707Sdes default: 3578276707Sdes return SSH_ERR_KEY_TYPE_UNKNOWN; 3579276707Sdes } 3580276707Sdes} 3581276707Sdes 3582276707Sdes#ifdef WITH_SSH1 3583276707Sdes/* 3584276707Sdes * Parse the public, unencrypted portion of a RSA1 key. 3585276707Sdes */ 3586276707Sdesint 3587276707Sdessshkey_parse_public_rsa1_fileblob(struct sshbuf *blob, 3588276707Sdes struct sshkey **keyp, char **commentp) 3589276707Sdes{ 3590276707Sdes int r; 3591276707Sdes struct sshkey *pub = NULL; 3592276707Sdes struct sshbuf *copy = NULL; 3593276707Sdes 3594276707Sdes if (keyp != NULL) 3595276707Sdes *keyp = NULL; 3596276707Sdes if (commentp != NULL) 3597276707Sdes *commentp = NULL; 3598276707Sdes 3599276707Sdes /* Check that it is at least big enough to contain the ID string. */ 3600276707Sdes if (sshbuf_len(blob) < sizeof(LEGACY_BEGIN)) 3601276707Sdes return SSH_ERR_INVALID_FORMAT; 3602276707Sdes 3603276707Sdes /* 3604276707Sdes * Make sure it begins with the id string. Consume the id string 3605276707Sdes * from the buffer. 3606276707Sdes */ 3607276707Sdes if (memcmp(sshbuf_ptr(blob), LEGACY_BEGIN, sizeof(LEGACY_BEGIN)) != 0) 3608276707Sdes return SSH_ERR_INVALID_FORMAT; 3609276707Sdes /* Make a working copy of the keyblob and skip past the magic */ 3610276707Sdes if ((copy = sshbuf_fromb(blob)) == NULL) 3611276707Sdes return SSH_ERR_ALLOC_FAIL; 3612276707Sdes if ((r = sshbuf_consume(copy, sizeof(LEGACY_BEGIN))) != 0) 3613276707Sdes goto out; 3614276707Sdes 3615276707Sdes /* Skip cipher type, reserved data and key bits. */ 3616276707Sdes if ((r = sshbuf_get_u8(copy, NULL)) != 0 || /* cipher type */ 3617276707Sdes (r = sshbuf_get_u32(copy, NULL)) != 0 || /* reserved */ 3618276707Sdes (r = sshbuf_get_u32(copy, NULL)) != 0) /* key bits */ 3619276707Sdes goto out; 3620276707Sdes 3621276707Sdes /* Read the public key from the buffer. */ 3622276707Sdes if ((pub = sshkey_new(KEY_RSA1)) == NULL || 3623276707Sdes (r = sshbuf_get_bignum1(copy, pub->rsa->n)) != 0 || 3624276707Sdes (r = sshbuf_get_bignum1(copy, pub->rsa->e)) != 0) 3625276707Sdes goto out; 3626276707Sdes 3627276707Sdes /* Finally, the comment */ 3628276707Sdes if ((r = sshbuf_get_string(copy, (u_char**)commentp, NULL)) != 0) 3629276707Sdes goto out; 3630276707Sdes 3631276707Sdes /* The encrypted private part is not parsed by this function. */ 3632276707Sdes 3633276707Sdes r = 0; 3634276707Sdes if (keyp != NULL) 3635276707Sdes *keyp = pub; 3636276707Sdes else 3637276707Sdes sshkey_free(pub); 3638276707Sdes pub = NULL; 3639276707Sdes 3640276707Sdes out: 3641296853Sdes sshbuf_free(copy); 3642296853Sdes sshkey_free(pub); 3643276707Sdes return r; 3644276707Sdes} 3645276707Sdes 3646276707Sdesstatic int 3647276707Sdessshkey_parse_private_rsa1(struct sshbuf *blob, const char *passphrase, 3648276707Sdes struct sshkey **keyp, char **commentp) 3649276707Sdes{ 3650276707Sdes int r; 3651276707Sdes u_int16_t check1, check2; 3652276707Sdes u_int8_t cipher_type; 3653276707Sdes struct sshbuf *decrypted = NULL, *copy = NULL; 3654276707Sdes u_char *cp; 3655276707Sdes char *comment = NULL; 3656276707Sdes struct sshcipher_ctx ciphercontext; 3657276707Sdes const struct sshcipher *cipher; 3658276707Sdes struct sshkey *prv = NULL; 3659276707Sdes 3660276707Sdes *keyp = NULL; 3661276707Sdes if (commentp != NULL) 3662276707Sdes *commentp = NULL; 3663276707Sdes 3664276707Sdes /* Check that it is at least big enough to contain the ID string. */ 3665276707Sdes if (sshbuf_len(blob) < sizeof(LEGACY_BEGIN)) 3666276707Sdes return SSH_ERR_INVALID_FORMAT; 3667276707Sdes 3668276707Sdes /* 3669276707Sdes * Make sure it begins with the id string. Consume the id string 3670276707Sdes * from the buffer. 3671276707Sdes */ 3672276707Sdes if (memcmp(sshbuf_ptr(blob), LEGACY_BEGIN, sizeof(LEGACY_BEGIN)) != 0) 3673276707Sdes return SSH_ERR_INVALID_FORMAT; 3674276707Sdes 3675276707Sdes if ((prv = sshkey_new_private(KEY_RSA1)) == NULL) { 3676276707Sdes r = SSH_ERR_ALLOC_FAIL; 3677276707Sdes goto out; 3678276707Sdes } 3679276707Sdes if ((copy = sshbuf_fromb(blob)) == NULL || 3680276707Sdes (decrypted = sshbuf_new()) == NULL) { 3681276707Sdes r = SSH_ERR_ALLOC_FAIL; 3682276707Sdes goto out; 3683276707Sdes } 3684276707Sdes if ((r = sshbuf_consume(copy, sizeof(LEGACY_BEGIN))) != 0) 3685276707Sdes goto out; 3686276707Sdes 3687276707Sdes /* Read cipher type. */ 3688276707Sdes if ((r = sshbuf_get_u8(copy, &cipher_type)) != 0 || 3689276707Sdes (r = sshbuf_get_u32(copy, NULL)) != 0) /* reserved */ 3690276707Sdes goto out; 3691276707Sdes 3692276707Sdes /* Read the public key and comment from the buffer. */ 3693276707Sdes if ((r = sshbuf_get_u32(copy, NULL)) != 0 || /* key bits */ 3694276707Sdes (r = sshbuf_get_bignum1(copy, prv->rsa->n)) != 0 || 3695276707Sdes (r = sshbuf_get_bignum1(copy, prv->rsa->e)) != 0 || 3696276707Sdes (r = sshbuf_get_cstring(copy, &comment, NULL)) != 0) 3697276707Sdes goto out; 3698276707Sdes 3699276707Sdes /* Check that it is a supported cipher. */ 3700276707Sdes cipher = cipher_by_number(cipher_type); 3701276707Sdes if (cipher == NULL) { 3702276707Sdes r = SSH_ERR_KEY_UNKNOWN_CIPHER; 3703276707Sdes goto out; 3704276707Sdes } 3705276707Sdes /* Initialize space for decrypted data. */ 3706276707Sdes if ((r = sshbuf_reserve(decrypted, sshbuf_len(copy), &cp)) != 0) 3707276707Sdes goto out; 3708276707Sdes 3709276707Sdes /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ 3710276707Sdes if ((r = cipher_set_key_string(&ciphercontext, cipher, passphrase, 3711276707Sdes CIPHER_DECRYPT)) != 0) 3712276707Sdes goto out; 3713276707Sdes if ((r = cipher_crypt(&ciphercontext, 0, cp, 3714276707Sdes sshbuf_ptr(copy), sshbuf_len(copy), 0, 0)) != 0) { 3715276707Sdes cipher_cleanup(&ciphercontext); 3716276707Sdes goto out; 3717276707Sdes } 3718276707Sdes if ((r = cipher_cleanup(&ciphercontext)) != 0) 3719276707Sdes goto out; 3720276707Sdes 3721276707Sdes if ((r = sshbuf_get_u16(decrypted, &check1)) != 0 || 3722276707Sdes (r = sshbuf_get_u16(decrypted, &check2)) != 0) 3723276707Sdes goto out; 3724276707Sdes if (check1 != check2) { 3725276707Sdes r = SSH_ERR_KEY_WRONG_PASSPHRASE; 3726276707Sdes goto out; 3727276707Sdes } 3728276707Sdes 3729276707Sdes /* Read the rest of the private key. */ 3730276707Sdes if ((r = sshbuf_get_bignum1(decrypted, prv->rsa->d)) != 0 || 3731276707Sdes (r = sshbuf_get_bignum1(decrypted, prv->rsa->iqmp)) != 0 || 3732276707Sdes (r = sshbuf_get_bignum1(decrypted, prv->rsa->q)) != 0 || 3733276707Sdes (r = sshbuf_get_bignum1(decrypted, prv->rsa->p)) != 0) 3734276707Sdes goto out; 3735276707Sdes 3736276707Sdes /* calculate p-1 and q-1 */ 3737276707Sdes if ((r = rsa_generate_additional_parameters(prv->rsa)) != 0) 3738276707Sdes goto out; 3739276707Sdes 3740276707Sdes /* enable blinding */ 3741276707Sdes if (RSA_blinding_on(prv->rsa, NULL) != 1) { 3742276707Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 3743276707Sdes goto out; 3744276707Sdes } 3745276707Sdes r = 0; 3746276707Sdes *keyp = prv; 3747276707Sdes prv = NULL; 3748276707Sdes if (commentp != NULL) { 3749276707Sdes *commentp = comment; 3750276707Sdes comment = NULL; 3751276707Sdes } 3752276707Sdes out: 3753276707Sdes explicit_bzero(&ciphercontext, sizeof(ciphercontext)); 3754296853Sdes free(comment); 3755296853Sdes sshkey_free(prv); 3756296853Sdes sshbuf_free(copy); 3757296853Sdes sshbuf_free(decrypted); 3758276707Sdes return r; 3759276707Sdes} 3760276707Sdes#endif /* WITH_SSH1 */ 3761276707Sdes 3762276707Sdes#ifdef WITH_OPENSSL 3763295367Sdesstatic int 3764276707Sdessshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, 3765295367Sdes const char *passphrase, struct sshkey **keyp) 3766276707Sdes{ 3767276707Sdes EVP_PKEY *pk = NULL; 3768276707Sdes struct sshkey *prv = NULL; 3769276707Sdes BIO *bio = NULL; 3770276707Sdes int r; 3771276707Sdes 3772276707Sdes *keyp = NULL; 3773276707Sdes 3774276707Sdes if ((bio = BIO_new(BIO_s_mem())) == NULL || sshbuf_len(blob) > INT_MAX) 3775276707Sdes return SSH_ERR_ALLOC_FAIL; 3776276707Sdes if (BIO_write(bio, sshbuf_ptr(blob), sshbuf_len(blob)) != 3777276707Sdes (int)sshbuf_len(blob)) { 3778276707Sdes r = SSH_ERR_ALLOC_FAIL; 3779276707Sdes goto out; 3780276707Sdes } 3781276707Sdes 3782276707Sdes if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, 3783276707Sdes (char *)passphrase)) == NULL) { 3784276707Sdes r = SSH_ERR_KEY_WRONG_PASSPHRASE; 3785276707Sdes goto out; 3786276707Sdes } 3787276707Sdes if (pk->type == EVP_PKEY_RSA && 3788276707Sdes (type == KEY_UNSPEC || type == KEY_RSA)) { 3789276707Sdes if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) { 3790276707Sdes r = SSH_ERR_ALLOC_FAIL; 3791276707Sdes goto out; 3792276707Sdes } 3793276707Sdes prv->rsa = EVP_PKEY_get1_RSA(pk); 3794276707Sdes prv->type = KEY_RSA; 3795276707Sdes#ifdef DEBUG_PK 3796276707Sdes RSA_print_fp(stderr, prv->rsa, 8); 3797276707Sdes#endif 3798276707Sdes if (RSA_blinding_on(prv->rsa, NULL) != 1) { 3799276707Sdes r = SSH_ERR_LIBCRYPTO_ERROR; 3800276707Sdes goto out; 3801276707Sdes } 3802276707Sdes } else if (pk->type == EVP_PKEY_DSA && 3803276707Sdes (type == KEY_UNSPEC || type == KEY_DSA)) { 3804276707Sdes if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) { 3805276707Sdes r = SSH_ERR_ALLOC_FAIL; 3806276707Sdes goto out; 3807276707Sdes } 3808276707Sdes prv->dsa = EVP_PKEY_get1_DSA(pk); 3809276707Sdes prv->type = KEY_DSA; 3810276707Sdes#ifdef DEBUG_PK 3811276707Sdes DSA_print_fp(stderr, prv->dsa, 8); 3812276707Sdes#endif 3813276707Sdes#ifdef OPENSSL_HAS_ECC 3814276707Sdes } else if (pk->type == EVP_PKEY_EC && 3815276707Sdes (type == KEY_UNSPEC || type == KEY_ECDSA)) { 3816276707Sdes if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) { 3817276707Sdes r = SSH_ERR_ALLOC_FAIL; 3818276707Sdes goto out; 3819276707Sdes } 3820276707Sdes prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk); 3821276707Sdes prv->type = KEY_ECDSA; 3822276707Sdes prv->ecdsa_nid = sshkey_ecdsa_key_to_nid(prv->ecdsa); 3823276707Sdes if (prv->ecdsa_nid == -1 || 3824276707Sdes sshkey_curve_nid_to_name(prv->ecdsa_nid) == NULL || 3825276707Sdes sshkey_ec_validate_public(EC_KEY_get0_group(prv->ecdsa), 3826276707Sdes EC_KEY_get0_public_key(prv->ecdsa)) != 0 || 3827276707Sdes sshkey_ec_validate_private(prv->ecdsa) != 0) { 3828276707Sdes r = SSH_ERR_INVALID_FORMAT; 3829276707Sdes goto out; 3830276707Sdes } 3831276707Sdes# ifdef DEBUG_PK 3832276707Sdes if (prv != NULL && prv->ecdsa != NULL) 3833276707Sdes sshkey_dump_ec_key(prv->ecdsa); 3834276707Sdes# endif 3835276707Sdes#endif /* OPENSSL_HAS_ECC */ 3836276707Sdes } else { 3837276707Sdes r = SSH_ERR_INVALID_FORMAT; 3838276707Sdes goto out; 3839276707Sdes } 3840276707Sdes r = 0; 3841276707Sdes *keyp = prv; 3842276707Sdes prv = NULL; 3843276707Sdes out: 3844276707Sdes BIO_free(bio); 3845276707Sdes if (pk != NULL) 3846276707Sdes EVP_PKEY_free(pk); 3847296853Sdes sshkey_free(prv); 3848276707Sdes return r; 3849276707Sdes} 3850276707Sdes#endif /* WITH_OPENSSL */ 3851276707Sdes 3852276707Sdesint 3853276707Sdessshkey_parse_private_fileblob_type(struct sshbuf *blob, int type, 3854276707Sdes const char *passphrase, struct sshkey **keyp, char **commentp) 3855276707Sdes{ 3856276707Sdes *keyp = NULL; 3857276707Sdes if (commentp != NULL) 3858276707Sdes *commentp = NULL; 3859276707Sdes 3860276707Sdes switch (type) { 3861295367Sdes#ifdef WITH_SSH1 3862276707Sdes case KEY_RSA1: 3863276707Sdes return sshkey_parse_private_rsa1(blob, passphrase, 3864276707Sdes keyp, commentp); 3865295367Sdes#endif /* WITH_SSH1 */ 3866295367Sdes#ifdef WITH_OPENSSL 3867276707Sdes case KEY_DSA: 3868276707Sdes case KEY_ECDSA: 3869276707Sdes case KEY_RSA: 3870295367Sdes return sshkey_parse_private_pem_fileblob(blob, type, 3871295367Sdes passphrase, keyp); 3872276707Sdes#endif /* WITH_OPENSSL */ 3873276707Sdes case KEY_ED25519: 3874276707Sdes return sshkey_parse_private2(blob, type, passphrase, 3875276707Sdes keyp, commentp); 3876276707Sdes case KEY_UNSPEC: 3877296853Sdes if (sshkey_parse_private2(blob, type, passphrase, keyp, 3878296853Sdes commentp) == 0) 3879276707Sdes return 0; 3880276707Sdes#ifdef WITH_OPENSSL 3881295367Sdes return sshkey_parse_private_pem_fileblob(blob, type, 3882295367Sdes passphrase, keyp); 3883276707Sdes#else 3884276707Sdes return SSH_ERR_INVALID_FORMAT; 3885276707Sdes#endif /* WITH_OPENSSL */ 3886276707Sdes default: 3887276707Sdes return SSH_ERR_KEY_TYPE_UNKNOWN; 3888276707Sdes } 3889276707Sdes} 3890276707Sdes 3891276707Sdesint 3892276707Sdessshkey_parse_private_fileblob(struct sshbuf *buffer, const char *passphrase, 3893296853Sdes struct sshkey **keyp, char **commentp) 3894276707Sdes{ 3895276707Sdes if (keyp != NULL) 3896276707Sdes *keyp = NULL; 3897276707Sdes if (commentp != NULL) 3898276707Sdes *commentp = NULL; 3899276707Sdes 3900276707Sdes#ifdef WITH_SSH1 3901276707Sdes /* it's a SSH v1 key if the public key part is readable */ 3902296853Sdes if (sshkey_parse_public_rsa1_fileblob(buffer, NULL, NULL) == 0) { 3903276707Sdes return sshkey_parse_private_fileblob_type(buffer, KEY_RSA1, 3904276707Sdes passphrase, keyp, commentp); 3905276707Sdes } 3906276707Sdes#endif /* WITH_SSH1 */ 3907296853Sdes return sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC, 3908296853Sdes passphrase, keyp, commentp); 3909276707Sdes} 3910