10Sstevel@tonic-gate /* 2*2757Sjp161948 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate /* 60Sstevel@tonic-gate * Author: Tatu Ylonen <ylo@cs.hut.fi> 70Sstevel@tonic-gate * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 80Sstevel@tonic-gate * All rights reserved 90Sstevel@tonic-gate * Identity and host key generation and maintenance. 100Sstevel@tonic-gate * 110Sstevel@tonic-gate * As far as I am concerned, the code I have written for this software 120Sstevel@tonic-gate * can be used freely for any purpose. Any derived versions of this 130Sstevel@tonic-gate * software must be clearly marked as such, and if the derived work is 140Sstevel@tonic-gate * incompatible with the protocol description in the RFC file, it must be 150Sstevel@tonic-gate * called by a name other than "ssh" or "Secure Shell". 160Sstevel@tonic-gate */ 170Sstevel@tonic-gate 180Sstevel@tonic-gate #include "includes.h" 190Sstevel@tonic-gate RCSID("$OpenBSD: ssh-keygen.c,v 1.101 2002/06/23 09:39:55 deraadt Exp $"); 200Sstevel@tonic-gate 210Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 220Sstevel@tonic-gate 230Sstevel@tonic-gate #include <openssl/evp.h> 240Sstevel@tonic-gate #include <openssl/pem.h> 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include "xmalloc.h" 270Sstevel@tonic-gate #include "key.h" 280Sstevel@tonic-gate #include "rsa.h" 290Sstevel@tonic-gate #include "authfile.h" 300Sstevel@tonic-gate #include "uuencode.h" 310Sstevel@tonic-gate #include "buffer.h" 320Sstevel@tonic-gate #include "bufaux.h" 330Sstevel@tonic-gate #include "pathnames.h" 340Sstevel@tonic-gate #include "log.h" 350Sstevel@tonic-gate #include "readpass.h" 36*2757Sjp161948 #include "misc.h" 370Sstevel@tonic-gate #include <langinfo.h> 380Sstevel@tonic-gate 390Sstevel@tonic-gate #ifdef SMARTCARD 400Sstevel@tonic-gate #include "scard.h" 410Sstevel@tonic-gate #endif 420Sstevel@tonic-gate 430Sstevel@tonic-gate /* Number of bits in the RSA/DSA key. This value can be changed on the command line. */ 440Sstevel@tonic-gate int bits = 1024; 450Sstevel@tonic-gate 460Sstevel@tonic-gate /* 470Sstevel@tonic-gate * Flag indicating that we just want to change the passphrase. This can be 480Sstevel@tonic-gate * set on the command line. 490Sstevel@tonic-gate */ 500Sstevel@tonic-gate int change_passphrase = 0; 510Sstevel@tonic-gate 520Sstevel@tonic-gate /* 530Sstevel@tonic-gate * Flag indicating that we just want to change the comment. This can be set 540Sstevel@tonic-gate * on the command line. 550Sstevel@tonic-gate */ 560Sstevel@tonic-gate int change_comment = 0; 570Sstevel@tonic-gate 580Sstevel@tonic-gate int quiet = 0; 590Sstevel@tonic-gate 600Sstevel@tonic-gate /* Flag indicating that we just want to see the key fingerprint */ 610Sstevel@tonic-gate int print_fingerprint = 0; 620Sstevel@tonic-gate int print_bubblebabble = 0; 630Sstevel@tonic-gate 640Sstevel@tonic-gate /* The identity file name, given on the command line or entered by the user. */ 650Sstevel@tonic-gate char identity_file[1024]; 660Sstevel@tonic-gate int have_identity = 0; 670Sstevel@tonic-gate 680Sstevel@tonic-gate /* This is set to the passphrase if given on the command line. */ 690Sstevel@tonic-gate char *identity_passphrase = NULL; 700Sstevel@tonic-gate 710Sstevel@tonic-gate /* This is set to the new passphrase if given on the command line. */ 720Sstevel@tonic-gate char *identity_new_passphrase = NULL; 730Sstevel@tonic-gate 740Sstevel@tonic-gate /* This is set to the new comment if given on the command line. */ 750Sstevel@tonic-gate char *identity_comment = NULL; 760Sstevel@tonic-gate 770Sstevel@tonic-gate /* Dump public key file in format used by real and the original SSH 2 */ 780Sstevel@tonic-gate int convert_to_ssh2 = 0; 790Sstevel@tonic-gate int convert_from_ssh2 = 0; 800Sstevel@tonic-gate int print_public = 0; 810Sstevel@tonic-gate 820Sstevel@tonic-gate char *key_type_name = NULL; 830Sstevel@tonic-gate 840Sstevel@tonic-gate /* argv0 */ 850Sstevel@tonic-gate #ifdef HAVE___PROGNAME 860Sstevel@tonic-gate extern char *__progname; 870Sstevel@tonic-gate #else 880Sstevel@tonic-gate char *__progname; 890Sstevel@tonic-gate #endif 900Sstevel@tonic-gate 910Sstevel@tonic-gate char hostname[MAXHOSTNAMELEN]; 920Sstevel@tonic-gate 930Sstevel@tonic-gate static void 940Sstevel@tonic-gate ask_filename(struct passwd *pw, const char *prompt) 950Sstevel@tonic-gate { 960Sstevel@tonic-gate char buf[1024]; 970Sstevel@tonic-gate char *name = NULL; 980Sstevel@tonic-gate 990Sstevel@tonic-gate if (key_type_name == NULL) 1000Sstevel@tonic-gate name = _PATH_SSH_CLIENT_ID_RSA; 1010Sstevel@tonic-gate else 1020Sstevel@tonic-gate switch (key_type_from_name(key_type_name)) { 1030Sstevel@tonic-gate case KEY_RSA1: 1040Sstevel@tonic-gate name = _PATH_SSH_CLIENT_IDENTITY; 1050Sstevel@tonic-gate break; 1060Sstevel@tonic-gate case KEY_DSA: 1070Sstevel@tonic-gate name = _PATH_SSH_CLIENT_ID_DSA; 1080Sstevel@tonic-gate break; 1090Sstevel@tonic-gate case KEY_RSA: 1100Sstevel@tonic-gate name = _PATH_SSH_CLIENT_ID_RSA; 1110Sstevel@tonic-gate break; 1120Sstevel@tonic-gate default: 1130Sstevel@tonic-gate (void) fprintf(stderr, gettext("bad key type")); 1140Sstevel@tonic-gate exit(1); 1150Sstevel@tonic-gate break; 1160Sstevel@tonic-gate } 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate (void) snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name); 1190Sstevel@tonic-gate (void) fprintf(stderr, "%s (%s): ", gettext(prompt), identity_file); 1200Sstevel@tonic-gate (void) fflush(stderr); 1210Sstevel@tonic-gate if (fgets(buf, sizeof(buf), stdin) == NULL) 1220Sstevel@tonic-gate exit(1); 1230Sstevel@tonic-gate if (strchr(buf, '\n')) 1240Sstevel@tonic-gate *strchr(buf, '\n') = 0; 1250Sstevel@tonic-gate if (strcmp(buf, "") != 0) 1260Sstevel@tonic-gate (void) strlcpy(identity_file, buf, sizeof(identity_file)); 1270Sstevel@tonic-gate have_identity = 1; 1280Sstevel@tonic-gate } 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate static Key * 1310Sstevel@tonic-gate load_identity(char *filename) 1320Sstevel@tonic-gate { 1330Sstevel@tonic-gate char *pass; 1340Sstevel@tonic-gate Key *prv; 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate prv = key_load_private(filename, "", NULL); 1370Sstevel@tonic-gate if (prv == NULL) { 1380Sstevel@tonic-gate if (identity_passphrase) 1390Sstevel@tonic-gate pass = xstrdup(identity_passphrase); 1400Sstevel@tonic-gate else 1410Sstevel@tonic-gate pass = read_passphrase(gettext("Enter passphrase: "), 1420Sstevel@tonic-gate RP_ALLOW_STDIN); 1430Sstevel@tonic-gate prv = key_load_private(filename, pass, NULL); 1440Sstevel@tonic-gate (void) memset(pass, 0, strlen(pass)); 1450Sstevel@tonic-gate xfree(pass); 1460Sstevel@tonic-gate } 1470Sstevel@tonic-gate return prv; 1480Sstevel@tonic-gate } 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate #define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----" 1510Sstevel@tonic-gate #define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----" 1520Sstevel@tonic-gate #define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----" 1530Sstevel@tonic-gate #define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate static void 1560Sstevel@tonic-gate do_convert_to_ssh2(struct passwd *pw) 1570Sstevel@tonic-gate { 1580Sstevel@tonic-gate Key *k; 1590Sstevel@tonic-gate u_int len; 1600Sstevel@tonic-gate u_char *blob; 1610Sstevel@tonic-gate struct stat st; 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate if (!have_identity) 1640Sstevel@tonic-gate ask_filename(pw, gettext("Enter file in which the key is")); 1650Sstevel@tonic-gate if (stat(identity_file, &st) < 0) { 1660Sstevel@tonic-gate perror(identity_file); 1670Sstevel@tonic-gate exit(1); 1680Sstevel@tonic-gate } 1690Sstevel@tonic-gate if ((k = key_load_public(identity_file, NULL)) == NULL) { 1700Sstevel@tonic-gate if ((k = load_identity(identity_file)) == NULL) { 1710Sstevel@tonic-gate (void) fprintf(stderr, gettext("load failed\n")); 1720Sstevel@tonic-gate exit(1); 1730Sstevel@tonic-gate } 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate if (key_to_blob(k, &blob, &len) <= 0) { 1760Sstevel@tonic-gate (void) fprintf(stderr, gettext("key_to_blob failed\n")); 1770Sstevel@tonic-gate exit(1); 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate (void) fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); 1800Sstevel@tonic-gate (void) fprintf(stdout, gettext( 1810Sstevel@tonic-gate "Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n"), 1820Sstevel@tonic-gate key_size(k), key_type(k), 1830Sstevel@tonic-gate pw->pw_name, hostname); 1840Sstevel@tonic-gate dump_base64(stdout, blob, len); 1850Sstevel@tonic-gate (void) fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); 1860Sstevel@tonic-gate key_free(k); 1870Sstevel@tonic-gate xfree(blob); 1880Sstevel@tonic-gate exit(0); 1890Sstevel@tonic-gate } 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate static void 1920Sstevel@tonic-gate buffer_get_bignum_bits(Buffer *b, BIGNUM *value) 1930Sstevel@tonic-gate { 1940Sstevel@tonic-gate int bits = buffer_get_int(b); 1950Sstevel@tonic-gate int bytes = (bits + 7) / 8; 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate if (buffer_len(b) < bytes) 1980Sstevel@tonic-gate fatal("buffer_get_bignum_bits: input buffer too small: " 1990Sstevel@tonic-gate "need %d have %d", bytes, buffer_len(b)); 2000Sstevel@tonic-gate (void) BN_bin2bn(buffer_ptr(b), bytes, value); 2010Sstevel@tonic-gate buffer_consume(b, bytes); 2020Sstevel@tonic-gate } 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate static Key * 2050Sstevel@tonic-gate do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) 2060Sstevel@tonic-gate { 2070Sstevel@tonic-gate Buffer b; 2080Sstevel@tonic-gate Key *key = NULL; 2090Sstevel@tonic-gate char *type, *cipher; 2100Sstevel@tonic-gate u_char *sig, data[] = "abcde12345"; 2110Sstevel@tonic-gate int magic, rlen, ktype, i1, i2, i3, i4; 2120Sstevel@tonic-gate u_int slen; 2130Sstevel@tonic-gate u_long e; 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate buffer_init(&b); 2160Sstevel@tonic-gate buffer_append(&b, blob, blen); 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate magic = buffer_get_int(&b); 2190Sstevel@tonic-gate if (magic != SSH_COM_PRIVATE_KEY_MAGIC) { 2200Sstevel@tonic-gate error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC); 2210Sstevel@tonic-gate buffer_free(&b); 2220Sstevel@tonic-gate return NULL; 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate i1 = buffer_get_int(&b); 2250Sstevel@tonic-gate type = buffer_get_string(&b, NULL); 2260Sstevel@tonic-gate cipher = buffer_get_string(&b, NULL); 2270Sstevel@tonic-gate i2 = buffer_get_int(&b); 2280Sstevel@tonic-gate i3 = buffer_get_int(&b); 2290Sstevel@tonic-gate i4 = buffer_get_int(&b); 2300Sstevel@tonic-gate debug("ignore (%d %d %d %d)", i1,i2,i3,i4); 2310Sstevel@tonic-gate if (strcmp(cipher, "none") != 0) { 2320Sstevel@tonic-gate error("unsupported cipher %s", cipher); 2330Sstevel@tonic-gate xfree(cipher); 2340Sstevel@tonic-gate buffer_free(&b); 2350Sstevel@tonic-gate xfree(type); 2360Sstevel@tonic-gate return NULL; 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate xfree(cipher); 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate if (strstr(type, "dsa")) { 2410Sstevel@tonic-gate ktype = KEY_DSA; 2420Sstevel@tonic-gate } else if (strstr(type, "rsa")) { 2430Sstevel@tonic-gate ktype = KEY_RSA; 2440Sstevel@tonic-gate } else { 2450Sstevel@tonic-gate xfree(type); 2460Sstevel@tonic-gate return NULL; 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate key = key_new_private(ktype); 2490Sstevel@tonic-gate xfree(type); 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate switch (key->type) { 2520Sstevel@tonic-gate case KEY_DSA: 2530Sstevel@tonic-gate buffer_get_bignum_bits(&b, key->dsa->p); 2540Sstevel@tonic-gate buffer_get_bignum_bits(&b, key->dsa->g); 2550Sstevel@tonic-gate buffer_get_bignum_bits(&b, key->dsa->q); 2560Sstevel@tonic-gate buffer_get_bignum_bits(&b, key->dsa->pub_key); 2570Sstevel@tonic-gate buffer_get_bignum_bits(&b, key->dsa->priv_key); 2580Sstevel@tonic-gate break; 2590Sstevel@tonic-gate case KEY_RSA: 2600Sstevel@tonic-gate e = buffer_get_char(&b); 2610Sstevel@tonic-gate debug("e %lx", e); 2620Sstevel@tonic-gate if (e < 30) { 2630Sstevel@tonic-gate e <<= 8; 2640Sstevel@tonic-gate e += buffer_get_char(&b); 2650Sstevel@tonic-gate debug("e %lx", e); 2660Sstevel@tonic-gate e <<= 8; 2670Sstevel@tonic-gate e += buffer_get_char(&b); 2680Sstevel@tonic-gate debug("e %lx", e); 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate if (!BN_set_word(key->rsa->e, e)) { 2710Sstevel@tonic-gate buffer_free(&b); 2720Sstevel@tonic-gate key_free(key); 2730Sstevel@tonic-gate return NULL; 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate buffer_get_bignum_bits(&b, key->rsa->d); 2760Sstevel@tonic-gate buffer_get_bignum_bits(&b, key->rsa->n); 2770Sstevel@tonic-gate buffer_get_bignum_bits(&b, key->rsa->iqmp); 2780Sstevel@tonic-gate buffer_get_bignum_bits(&b, key->rsa->q); 2790Sstevel@tonic-gate buffer_get_bignum_bits(&b, key->rsa->p); 2800Sstevel@tonic-gate rsa_generate_additional_parameters(key->rsa); 2810Sstevel@tonic-gate break; 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate rlen = buffer_len(&b); 2840Sstevel@tonic-gate if (rlen != 0) 2850Sstevel@tonic-gate error("do_convert_private_ssh2_from_blob: " 2860Sstevel@tonic-gate "remaining bytes in key blob %d", rlen); 2870Sstevel@tonic-gate buffer_free(&b); 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate /* try the key */ 2900Sstevel@tonic-gate (void) key_sign(key, &sig, &slen, data, sizeof(data)); 2910Sstevel@tonic-gate key_verify(key, sig, slen, data, sizeof(data)); 2920Sstevel@tonic-gate xfree(sig); 2930Sstevel@tonic-gate return key; 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate static void 2970Sstevel@tonic-gate do_convert_from_ssh2(struct passwd *pw) 2980Sstevel@tonic-gate { 2990Sstevel@tonic-gate Key *k; 3000Sstevel@tonic-gate int blen; 3010Sstevel@tonic-gate u_int len; 3020Sstevel@tonic-gate char line[1024], *p; 3030Sstevel@tonic-gate u_char blob[8096]; 3040Sstevel@tonic-gate char encoded[8096]; 3050Sstevel@tonic-gate struct stat st; 3060Sstevel@tonic-gate int escaped = 0, private = 0, ok; 3070Sstevel@tonic-gate FILE *fp; 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate if (!have_identity) 3100Sstevel@tonic-gate ask_filename(pw, gettext("Enter file in which the key is")); 3110Sstevel@tonic-gate if (stat(identity_file, &st) < 0) { 3120Sstevel@tonic-gate perror(identity_file); 3130Sstevel@tonic-gate exit(1); 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate fp = fopen(identity_file, "r"); 3160Sstevel@tonic-gate if (fp == NULL) { 3170Sstevel@tonic-gate perror(identity_file); 3180Sstevel@tonic-gate exit(1); 3190Sstevel@tonic-gate } 3200Sstevel@tonic-gate encoded[0] = '\0'; 3210Sstevel@tonic-gate while (fgets(line, sizeof(line), fp)) { 3220Sstevel@tonic-gate if (!(p = strchr(line, '\n'))) { 3230Sstevel@tonic-gate (void) fprintf(stderr, gettext("input line too long.\n")); 3240Sstevel@tonic-gate exit(1); 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate if (p > line && p[-1] == '\\') 3270Sstevel@tonic-gate escaped++; 3280Sstevel@tonic-gate if (strncmp(line, "----", 4) == 0 || 3290Sstevel@tonic-gate strstr(line, ": ") != NULL) { 3300Sstevel@tonic-gate if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL) 3310Sstevel@tonic-gate private = 1; 3320Sstevel@tonic-gate if (strstr(line, " END ") != NULL) { 3330Sstevel@tonic-gate break; 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate /* fprintf(stderr, "ignore: %s", line); */ 3360Sstevel@tonic-gate continue; 3370Sstevel@tonic-gate } 3380Sstevel@tonic-gate if (escaped) { 3390Sstevel@tonic-gate escaped--; 3400Sstevel@tonic-gate /* fprintf(stderr, "escaped: %s", line); */ 3410Sstevel@tonic-gate continue; 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate *p = '\0'; 3440Sstevel@tonic-gate (void) strlcat(encoded, line, sizeof(encoded)); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate len = strlen(encoded); 3470Sstevel@tonic-gate if (((len % 4) == 3) && 3480Sstevel@tonic-gate (encoded[len-1] == '=') && 3490Sstevel@tonic-gate (encoded[len-2] == '=') && 3500Sstevel@tonic-gate (encoded[len-3] == '=')) 3510Sstevel@tonic-gate encoded[len-3] = '\0'; 3520Sstevel@tonic-gate blen = uudecode(encoded, blob, sizeof(blob)); 3530Sstevel@tonic-gate if (blen < 0) { 3540Sstevel@tonic-gate (void) fprintf(stderr, gettext("uudecode failed.\n")); 3550Sstevel@tonic-gate exit(1); 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate k = private ? 3580Sstevel@tonic-gate do_convert_private_ssh2_from_blob(blob, blen) : 3590Sstevel@tonic-gate key_from_blob(blob, blen); 3600Sstevel@tonic-gate if (k == NULL) { 3610Sstevel@tonic-gate (void) fprintf(stderr, gettext("decode blob failed.\n")); 3620Sstevel@tonic-gate exit(1); 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate ok = private ? 3650Sstevel@tonic-gate (k->type == KEY_DSA ? 3660Sstevel@tonic-gate PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) : 3670Sstevel@tonic-gate PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) : 3680Sstevel@tonic-gate key_write(k, stdout); 3690Sstevel@tonic-gate if (!ok) { 3700Sstevel@tonic-gate (void) fprintf(stderr, gettext("key write failed")); 3710Sstevel@tonic-gate exit(1); 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate key_free(k); 3740Sstevel@tonic-gate if (!private) 3750Sstevel@tonic-gate (void) fprintf(stdout, "\n"); 3760Sstevel@tonic-gate (void) fclose(fp); 3770Sstevel@tonic-gate exit(0); 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate static void 3810Sstevel@tonic-gate do_print_public(struct passwd *pw) 3820Sstevel@tonic-gate { 3830Sstevel@tonic-gate Key *prv; 3840Sstevel@tonic-gate struct stat st; 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate if (!have_identity) 3870Sstevel@tonic-gate ask_filename(pw, gettext("Enter file in which the key is")); 3880Sstevel@tonic-gate if (stat(identity_file, &st) < 0) { 3890Sstevel@tonic-gate perror(identity_file); 3900Sstevel@tonic-gate exit(1); 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate prv = load_identity(identity_file); 3930Sstevel@tonic-gate if (prv == NULL) { 3940Sstevel@tonic-gate (void) fprintf(stderr, gettext("load failed\n")); 3950Sstevel@tonic-gate exit(1); 3960Sstevel@tonic-gate } 3970Sstevel@tonic-gate if (!key_write(prv, stdout)) 3980Sstevel@tonic-gate (void) fprintf(stderr, gettext("key_write failed")); 3990Sstevel@tonic-gate key_free(prv); 4000Sstevel@tonic-gate (void) fprintf(stdout, "\n"); 4010Sstevel@tonic-gate exit(0); 4020Sstevel@tonic-gate } 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate #ifdef SMARTCARD 4050Sstevel@tonic-gate static void 4060Sstevel@tonic-gate do_upload(struct passwd *pw, const char *sc_reader_id) 4070Sstevel@tonic-gate { 4080Sstevel@tonic-gate Key *prv = NULL; 4090Sstevel@tonic-gate struct stat st; 4100Sstevel@tonic-gate int ret; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate if (!have_identity) 4130Sstevel@tonic-gate ask_filename(pw, gettext("Enter file in which the key is")); 4140Sstevel@tonic-gate if (stat(identity_file, &st) < 0) { 4150Sstevel@tonic-gate perror(identity_file); 4160Sstevel@tonic-gate exit(1); 4170Sstevel@tonic-gate } 4180Sstevel@tonic-gate prv = load_identity(identity_file); 4190Sstevel@tonic-gate if (prv == NULL) { 4200Sstevel@tonic-gate error("load failed"); 4210Sstevel@tonic-gate exit(1); 4220Sstevel@tonic-gate } 4230Sstevel@tonic-gate ret = sc_put_key(prv, sc_reader_id); 4240Sstevel@tonic-gate key_free(prv); 4250Sstevel@tonic-gate if (ret < 0) 4260Sstevel@tonic-gate exit(1); 4270Sstevel@tonic-gate log("loading key done"); 4280Sstevel@tonic-gate exit(0); 4290Sstevel@tonic-gate } 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate static void 4320Sstevel@tonic-gate do_download(struct passwd *pw, const char *sc_reader_id) 4330Sstevel@tonic-gate { 4340Sstevel@tonic-gate Key **keys = NULL; 4350Sstevel@tonic-gate int i; 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate keys = sc_get_keys(sc_reader_id, NULL); 4380Sstevel@tonic-gate if (keys == NULL) 4390Sstevel@tonic-gate fatal("cannot read public key from smartcard"); 4400Sstevel@tonic-gate for (i = 0; keys[i]; i++) { 4410Sstevel@tonic-gate key_write(keys[i], stdout); 4420Sstevel@tonic-gate key_free(keys[i]); 4430Sstevel@tonic-gate (void) fprintf(stdout, "\n"); 4440Sstevel@tonic-gate } 4450Sstevel@tonic-gate xfree(keys); 4460Sstevel@tonic-gate exit(0); 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate #endif /* SMARTCARD */ 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate static void 4510Sstevel@tonic-gate do_fingerprint(struct passwd *pw) 4520Sstevel@tonic-gate { 4530Sstevel@tonic-gate FILE *f; 4540Sstevel@tonic-gate Key *public; 4550Sstevel@tonic-gate char *comment = NULL, *cp, *ep, line[16*1024], *fp; 4560Sstevel@tonic-gate int i, skip = 0, num = 1, invalid = 1; 4570Sstevel@tonic-gate enum fp_rep rep; 4580Sstevel@tonic-gate enum fp_type fptype; 4590Sstevel@tonic-gate struct stat st; 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; 4620Sstevel@tonic-gate rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate if (!have_identity) 4650Sstevel@tonic-gate ask_filename(pw, gettext("Enter file in which the key is")); 4660Sstevel@tonic-gate if (stat(identity_file, &st) < 0) { 4670Sstevel@tonic-gate perror(identity_file); 4680Sstevel@tonic-gate exit(1); 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate public = key_load_public(identity_file, &comment); 4710Sstevel@tonic-gate if (public != NULL) { 4720Sstevel@tonic-gate fp = key_fingerprint(public, fptype, rep); 4730Sstevel@tonic-gate (void) printf("%u %s %s\n", key_size(public), fp, comment); 4740Sstevel@tonic-gate key_free(public); 4750Sstevel@tonic-gate xfree(comment); 4760Sstevel@tonic-gate xfree(fp); 4770Sstevel@tonic-gate exit(0); 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate if (comment) 4800Sstevel@tonic-gate xfree(comment); 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate f = fopen(identity_file, "r"); 4830Sstevel@tonic-gate if (f != NULL) { 4840Sstevel@tonic-gate while (fgets(line, sizeof(line), f)) { 4850Sstevel@tonic-gate i = strlen(line) - 1; 4860Sstevel@tonic-gate if (line[i] != '\n') { 4870Sstevel@tonic-gate error("line %d too long: %.40s...", num, line); 4880Sstevel@tonic-gate skip = 1; 4890Sstevel@tonic-gate continue; 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate num++; 4920Sstevel@tonic-gate if (skip) { 4930Sstevel@tonic-gate skip = 0; 4940Sstevel@tonic-gate continue; 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate line[i] = '\0'; 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate /* Skip leading whitespace, empty and comment lines. */ 4990Sstevel@tonic-gate for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 5000Sstevel@tonic-gate ; 5010Sstevel@tonic-gate if (!*cp || *cp == '\n' || *cp == '#') 5020Sstevel@tonic-gate continue ; 5030Sstevel@tonic-gate i = strtol(cp, &ep, 10); 5040Sstevel@tonic-gate if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { 5050Sstevel@tonic-gate int quoted = 0; 5060Sstevel@tonic-gate comment = cp; 5070Sstevel@tonic-gate for (; *cp && (quoted || (*cp != ' ' && 5080Sstevel@tonic-gate *cp != '\t')); cp++) { 5090Sstevel@tonic-gate if (*cp == '\\' && cp[1] == '"') 5100Sstevel@tonic-gate cp++; /* Skip both */ 5110Sstevel@tonic-gate else if (*cp == '"') 5120Sstevel@tonic-gate quoted = !quoted; 5130Sstevel@tonic-gate } 5140Sstevel@tonic-gate if (!*cp) 5150Sstevel@tonic-gate continue; 5160Sstevel@tonic-gate *cp++ = '\0'; 5170Sstevel@tonic-gate } 5180Sstevel@tonic-gate ep = cp; 5190Sstevel@tonic-gate public = key_new(KEY_RSA1); 5200Sstevel@tonic-gate if (key_read(public, &cp) != 1) { 5210Sstevel@tonic-gate cp = ep; 5220Sstevel@tonic-gate key_free(public); 5230Sstevel@tonic-gate public = key_new(KEY_UNSPEC); 5240Sstevel@tonic-gate if (key_read(public, &cp) != 1) { 5250Sstevel@tonic-gate key_free(public); 5260Sstevel@tonic-gate continue; 5270Sstevel@tonic-gate } 5280Sstevel@tonic-gate } 5290Sstevel@tonic-gate comment = *cp ? cp : comment; 5300Sstevel@tonic-gate fp = key_fingerprint(public, fptype, rep); 5310Sstevel@tonic-gate (void) printf("%u %s %s\n", key_size(public), fp, 5320Sstevel@tonic-gate comment ? comment : gettext("no comment")); 5330Sstevel@tonic-gate xfree(fp); 5340Sstevel@tonic-gate key_free(public); 5350Sstevel@tonic-gate invalid = 0; 5360Sstevel@tonic-gate } 5370Sstevel@tonic-gate (void) fclose(f); 5380Sstevel@tonic-gate } 5390Sstevel@tonic-gate if (invalid) { 5400Sstevel@tonic-gate (void) printf(gettext("%s is not a public key file.\n"), 5410Sstevel@tonic-gate identity_file); 5420Sstevel@tonic-gate exit(1); 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate exit(0); 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate /* 5480Sstevel@tonic-gate * Perform changing a passphrase. The argument is the passwd structure 5490Sstevel@tonic-gate * for the current user. 5500Sstevel@tonic-gate */ 5510Sstevel@tonic-gate static void 5520Sstevel@tonic-gate do_change_passphrase(struct passwd *pw) 5530Sstevel@tonic-gate { 5540Sstevel@tonic-gate char *comment; 5550Sstevel@tonic-gate char *old_passphrase, *passphrase1, *passphrase2; 5560Sstevel@tonic-gate struct stat st; 5570Sstevel@tonic-gate Key *private; 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate if (!have_identity) 5600Sstevel@tonic-gate ask_filename(pw, gettext("Enter file in which the key is")); 5610Sstevel@tonic-gate if (stat(identity_file, &st) < 0) { 5620Sstevel@tonic-gate perror(identity_file); 5630Sstevel@tonic-gate exit(1); 5640Sstevel@tonic-gate } 5650Sstevel@tonic-gate /* Try to load the file with empty passphrase. */ 5660Sstevel@tonic-gate private = key_load_private(identity_file, "", &comment); 5670Sstevel@tonic-gate if (private == NULL) { 5680Sstevel@tonic-gate if (identity_passphrase) 5690Sstevel@tonic-gate old_passphrase = xstrdup(identity_passphrase); 5700Sstevel@tonic-gate else 5710Sstevel@tonic-gate old_passphrase = 5720Sstevel@tonic-gate read_passphrase(gettext("Enter old passphrase: "), 5730Sstevel@tonic-gate RP_ALLOW_STDIN); 5740Sstevel@tonic-gate private = key_load_private(identity_file, old_passphrase, 5750Sstevel@tonic-gate &comment); 5760Sstevel@tonic-gate (void) memset(old_passphrase, 0, strlen(old_passphrase)); 5770Sstevel@tonic-gate xfree(old_passphrase); 5780Sstevel@tonic-gate if (private == NULL) { 5790Sstevel@tonic-gate (void) printf(gettext("Bad passphrase.\n")); 5800Sstevel@tonic-gate exit(1); 5810Sstevel@tonic-gate } 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate (void) printf(gettext("Key has comment '%s'\n"), comment); 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate /* Ask the new passphrase (twice). */ 5860Sstevel@tonic-gate if (identity_new_passphrase) { 5870Sstevel@tonic-gate passphrase1 = xstrdup(identity_new_passphrase); 5880Sstevel@tonic-gate passphrase2 = NULL; 5890Sstevel@tonic-gate } else { 5900Sstevel@tonic-gate passphrase1 = 5910Sstevel@tonic-gate read_passphrase(gettext("Enter new passphrase (empty" 5920Sstevel@tonic-gate " for no passphrase): "), RP_ALLOW_STDIN); 5930Sstevel@tonic-gate passphrase2 = read_passphrase(gettext("Enter same " 5940Sstevel@tonic-gate "passphrase again: "), RP_ALLOW_STDIN); 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate /* Verify that they are the same. */ 5970Sstevel@tonic-gate if (strcmp(passphrase1, passphrase2) != 0) { 5980Sstevel@tonic-gate (void) memset(passphrase1, 0, strlen(passphrase1)); 5990Sstevel@tonic-gate (void) memset(passphrase2, 0, strlen(passphrase2)); 6000Sstevel@tonic-gate xfree(passphrase1); 6010Sstevel@tonic-gate xfree(passphrase2); 6020Sstevel@tonic-gate (void) printf(gettext("Pass phrases do not match. Try " 6030Sstevel@tonic-gate "again.\n")); 6040Sstevel@tonic-gate exit(1); 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate /* Destroy the other copy. */ 6070Sstevel@tonic-gate (void) memset(passphrase2, 0, strlen(passphrase2)); 6080Sstevel@tonic-gate xfree(passphrase2); 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate /* Save the file using the new passphrase. */ 6120Sstevel@tonic-gate if (!key_save_private(private, identity_file, passphrase1, comment)) { 6130Sstevel@tonic-gate (void) printf(gettext("Saving the key failed: %s.\n"), identity_file); 6140Sstevel@tonic-gate (void) memset(passphrase1, 0, strlen(passphrase1)); 6150Sstevel@tonic-gate xfree(passphrase1); 6160Sstevel@tonic-gate key_free(private); 6170Sstevel@tonic-gate xfree(comment); 6180Sstevel@tonic-gate exit(1); 6190Sstevel@tonic-gate } 6200Sstevel@tonic-gate /* Destroy the passphrase and the copy of the key in memory. */ 6210Sstevel@tonic-gate (void) memset(passphrase1, 0, strlen(passphrase1)); 6220Sstevel@tonic-gate xfree(passphrase1); 6230Sstevel@tonic-gate key_free(private); /* Destroys contents */ 6240Sstevel@tonic-gate xfree(comment); 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate (void) printf(gettext("Your identification has been saved with the new " 6270Sstevel@tonic-gate "passphrase.\n")); 6280Sstevel@tonic-gate exit(0); 6290Sstevel@tonic-gate } 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate /* 6320Sstevel@tonic-gate * Change the comment of a private key file. 6330Sstevel@tonic-gate */ 6340Sstevel@tonic-gate static void 6350Sstevel@tonic-gate do_change_comment(struct passwd *pw) 6360Sstevel@tonic-gate { 6370Sstevel@tonic-gate char new_comment[1024], *comment, *passphrase; 6380Sstevel@tonic-gate Key *private; 6390Sstevel@tonic-gate Key *public; 6400Sstevel@tonic-gate struct stat st; 6410Sstevel@tonic-gate FILE *f; 6420Sstevel@tonic-gate int fd; 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate if (!have_identity) 6450Sstevel@tonic-gate ask_filename(pw, gettext("Enter file in which the key is")); 6460Sstevel@tonic-gate if (stat(identity_file, &st) < 0) { 6470Sstevel@tonic-gate perror(identity_file); 6480Sstevel@tonic-gate exit(1); 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate private = key_load_private(identity_file, "", &comment); 6510Sstevel@tonic-gate if (private == NULL) { 6520Sstevel@tonic-gate if (identity_passphrase) 6530Sstevel@tonic-gate passphrase = xstrdup(identity_passphrase); 6540Sstevel@tonic-gate else if (identity_new_passphrase) 6550Sstevel@tonic-gate passphrase = xstrdup(identity_new_passphrase); 6560Sstevel@tonic-gate else 6570Sstevel@tonic-gate passphrase = 6580Sstevel@tonic-gate read_passphrase(gettext("Enter passphrase: "), 6590Sstevel@tonic-gate RP_ALLOW_STDIN); 6600Sstevel@tonic-gate /* Try to load using the passphrase. */ 6610Sstevel@tonic-gate private = key_load_private(identity_file, passphrase, &comment); 6620Sstevel@tonic-gate if (private == NULL) { 6630Sstevel@tonic-gate (void) memset(passphrase, 0, strlen(passphrase)); 6640Sstevel@tonic-gate xfree(passphrase); 6650Sstevel@tonic-gate (void) printf(gettext("Bad passphrase.\n")); 6660Sstevel@tonic-gate exit(1); 6670Sstevel@tonic-gate } 6680Sstevel@tonic-gate } else { 6690Sstevel@tonic-gate passphrase = xstrdup(""); 6700Sstevel@tonic-gate } 6710Sstevel@tonic-gate if (private->type != KEY_RSA1) { 6720Sstevel@tonic-gate (void) fprintf(stderr, gettext("Comments are only supported for " 6730Sstevel@tonic-gate "RSA1 keys.\n")); 6740Sstevel@tonic-gate key_free(private); 6750Sstevel@tonic-gate exit(1); 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate (void) printf(gettext("Key now has comment '%s'\n"), comment); 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate if (identity_comment) { 6800Sstevel@tonic-gate (void) strlcpy(new_comment, identity_comment, sizeof(new_comment)); 6810Sstevel@tonic-gate } else { 6820Sstevel@tonic-gate (void) printf(gettext("Enter new comment: ")); 6830Sstevel@tonic-gate (void) fflush(stdout); 6840Sstevel@tonic-gate if (!fgets(new_comment, sizeof(new_comment), stdin)) { 6850Sstevel@tonic-gate (void) memset(passphrase, 0, strlen(passphrase)); 6860Sstevel@tonic-gate key_free(private); 6870Sstevel@tonic-gate exit(1); 6880Sstevel@tonic-gate } 6890Sstevel@tonic-gate if (strchr(new_comment, '\n')) 6900Sstevel@tonic-gate *strchr(new_comment, '\n') = 0; 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate 6930Sstevel@tonic-gate /* Save the file using the new passphrase. */ 6940Sstevel@tonic-gate if (!key_save_private(private, identity_file, passphrase, new_comment)) { 6950Sstevel@tonic-gate (void) printf(gettext("Saving the key failed: %s.\n"), identity_file); 6960Sstevel@tonic-gate (void) memset(passphrase, 0, strlen(passphrase)); 6970Sstevel@tonic-gate xfree(passphrase); 6980Sstevel@tonic-gate key_free(private); 6990Sstevel@tonic-gate xfree(comment); 7000Sstevel@tonic-gate exit(1); 7010Sstevel@tonic-gate } 7020Sstevel@tonic-gate (void) memset(passphrase, 0, strlen(passphrase)); 7030Sstevel@tonic-gate xfree(passphrase); 7040Sstevel@tonic-gate public = key_from_private(private); 7050Sstevel@tonic-gate key_free(private); 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate (void) strlcat(identity_file, ".pub", sizeof(identity_file)); 7080Sstevel@tonic-gate fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); 7090Sstevel@tonic-gate if (fd == -1) { 7100Sstevel@tonic-gate (void) printf(gettext("Could not save your public key in %s\n"), 7110Sstevel@tonic-gate identity_file); 7120Sstevel@tonic-gate exit(1); 7130Sstevel@tonic-gate } 7140Sstevel@tonic-gate f = fdopen(fd, "w"); 7150Sstevel@tonic-gate if (f == NULL) { 7160Sstevel@tonic-gate (void) printf(gettext("fdopen %s failed"), identity_file); 7170Sstevel@tonic-gate exit(1); 7180Sstevel@tonic-gate } 7190Sstevel@tonic-gate if (!key_write(public, f)) 7200Sstevel@tonic-gate (void) fprintf(stderr, gettext("write key failed")); 7210Sstevel@tonic-gate key_free(public); 7220Sstevel@tonic-gate (void) fprintf(f, " %s\n", new_comment); 7230Sstevel@tonic-gate (void) fclose(f); 7240Sstevel@tonic-gate 7250Sstevel@tonic-gate xfree(comment); 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate (void) printf(gettext("The comment in your key file has been changed.\n")); 7280Sstevel@tonic-gate exit(0); 7290Sstevel@tonic-gate } 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate static void 7320Sstevel@tonic-gate usage(void) 7330Sstevel@tonic-gate { 7340Sstevel@tonic-gate (void) fprintf(stderr, gettext( 7350Sstevel@tonic-gate "Usage: %s [options]\n" 7360Sstevel@tonic-gate "Options:\n" 7370Sstevel@tonic-gate " -b bits Number of bits in the key to create.\n" 7380Sstevel@tonic-gate " -c Change comment in private and public key files.\n" 7390Sstevel@tonic-gate " -e Convert OpenSSH to IETF SECSH key file.\n" 7400Sstevel@tonic-gate " -f filename Filename of the key file.\n" 7410Sstevel@tonic-gate " -i Convert IETF SECSH to OpenSSH key file.\n" 7420Sstevel@tonic-gate " -l Show fingerprint of key file.\n" 7430Sstevel@tonic-gate " -p Change passphrase of private key file.\n" 7440Sstevel@tonic-gate " -q Quiet.\n" 7450Sstevel@tonic-gate " -y Read private key file and print public key.\n" 7460Sstevel@tonic-gate " -t type Specify type of key to create.\n" 7470Sstevel@tonic-gate " -B Show bubblebabble digest of key file.\n" 7480Sstevel@tonic-gate " -C comment Provide new comment.\n" 7490Sstevel@tonic-gate " -N phrase Provide new passphrase.\n" 7500Sstevel@tonic-gate " -P phrase Provide old passphrase.\n" 7510Sstevel@tonic-gate #ifdef SMARTCARD 7520Sstevel@tonic-gate " -D reader Download public key from smartcard.\n" 7530Sstevel@tonic-gate " -U reader Upload private key to smartcard.\n" 7540Sstevel@tonic-gate #endif /* SMARTCARD */ 7550Sstevel@tonic-gate ), __progname); 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate exit(1); 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate /* 7610Sstevel@tonic-gate * Main program for key management. 7620Sstevel@tonic-gate */ 7630Sstevel@tonic-gate int 7640Sstevel@tonic-gate main(int ac, char **av) 7650Sstevel@tonic-gate { 7660Sstevel@tonic-gate char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; 7670Sstevel@tonic-gate char *reader_id = NULL; 7680Sstevel@tonic-gate Key *private, *public; 7690Sstevel@tonic-gate struct passwd *pw; 7700Sstevel@tonic-gate struct stat st; 7710Sstevel@tonic-gate int opt, type, fd; 7720Sstevel@tonic-gate #ifdef SMARTCARD 7730Sstevel@tonic-gate int download = 0; 7740Sstevel@tonic-gate #endif /* SMARTCARD */ 7750Sstevel@tonic-gate FILE *f; 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate extern int optind; 7780Sstevel@tonic-gate extern char *optarg; 7790Sstevel@tonic-gate 7800Sstevel@tonic-gate __progname = get_progname(av[0]); 7810Sstevel@tonic-gate 7820Sstevel@tonic-gate (void) g11n_setlocale(LC_ALL, ""); 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate SSLeay_add_all_algorithms(); 7850Sstevel@tonic-gate init_rng(); 7860Sstevel@tonic-gate seed_rng(); 7870Sstevel@tonic-gate 7880Sstevel@tonic-gate /* we need this for the home * directory. */ 7890Sstevel@tonic-gate pw = getpwuid(getuid()); 7900Sstevel@tonic-gate if (!pw) { 7910Sstevel@tonic-gate (void) printf(gettext("You don't exist, go away!\n")); 7920Sstevel@tonic-gate exit(1); 7930Sstevel@tonic-gate } 7940Sstevel@tonic-gate if (gethostname(hostname, sizeof(hostname)) < 0) { 7950Sstevel@tonic-gate perror("gethostname"); 7960Sstevel@tonic-gate exit(1); 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate #ifdef SMARTCARD 8000Sstevel@tonic-gate #define GETOPT_ARGS "deiqpclBRxXyb:f:t:U:D:P:N:C:" 8010Sstevel@tonic-gate #else 8020Sstevel@tonic-gate #define GETOPT_ARGS "deiqpclBRxXyb:f:t:P:N:C:" 8030Sstevel@tonic-gate #endif /* SMARTCARD */ 8040Sstevel@tonic-gate while ((opt = getopt(ac, av, GETOPT_ARGS)) != -1) { 8050Sstevel@tonic-gate switch (opt) { 8060Sstevel@tonic-gate case 'b': 8070Sstevel@tonic-gate bits = atoi(optarg); 8080Sstevel@tonic-gate if (bits < 512 || bits > 32768) { 8090Sstevel@tonic-gate (void) printf(gettext("Bits has bad value.\n")); 8100Sstevel@tonic-gate exit(1); 8110Sstevel@tonic-gate } 8120Sstevel@tonic-gate break; 8130Sstevel@tonic-gate case 'l': 8140Sstevel@tonic-gate print_fingerprint = 1; 8150Sstevel@tonic-gate break; 8160Sstevel@tonic-gate case 'B': 8170Sstevel@tonic-gate print_bubblebabble = 1; 8180Sstevel@tonic-gate break; 8190Sstevel@tonic-gate case 'p': 8200Sstevel@tonic-gate change_passphrase = 1; 8210Sstevel@tonic-gate break; 8220Sstevel@tonic-gate case 'c': 8230Sstevel@tonic-gate change_comment = 1; 8240Sstevel@tonic-gate break; 8250Sstevel@tonic-gate case 'f': 8260Sstevel@tonic-gate (void) strlcpy(identity_file, optarg, sizeof(identity_file)); 8270Sstevel@tonic-gate have_identity = 1; 8280Sstevel@tonic-gate break; 8290Sstevel@tonic-gate case 'P': 8300Sstevel@tonic-gate identity_passphrase = optarg; 8310Sstevel@tonic-gate break; 8320Sstevel@tonic-gate case 'N': 8330Sstevel@tonic-gate identity_new_passphrase = optarg; 8340Sstevel@tonic-gate break; 8350Sstevel@tonic-gate case 'C': 8360Sstevel@tonic-gate identity_comment = optarg; 8370Sstevel@tonic-gate break; 8380Sstevel@tonic-gate case 'q': 8390Sstevel@tonic-gate quiet = 1; 8400Sstevel@tonic-gate break; 8410Sstevel@tonic-gate case 'R': 8420Sstevel@tonic-gate /* unused */ 8430Sstevel@tonic-gate exit(0); 8440Sstevel@tonic-gate break; 8450Sstevel@tonic-gate case 'e': 8460Sstevel@tonic-gate case 'x': 8470Sstevel@tonic-gate /* export key */ 8480Sstevel@tonic-gate convert_to_ssh2 = 1; 8490Sstevel@tonic-gate break; 8500Sstevel@tonic-gate case 'i': 8510Sstevel@tonic-gate case 'X': 8520Sstevel@tonic-gate /* import key */ 8530Sstevel@tonic-gate convert_from_ssh2 = 1; 8540Sstevel@tonic-gate break; 8550Sstevel@tonic-gate case 'y': 8560Sstevel@tonic-gate print_public = 1; 8570Sstevel@tonic-gate break; 8580Sstevel@tonic-gate case 'd': 8590Sstevel@tonic-gate key_type_name = "dsa"; 8600Sstevel@tonic-gate break; 8610Sstevel@tonic-gate case 't': 8620Sstevel@tonic-gate key_type_name = optarg; 8630Sstevel@tonic-gate break; 8640Sstevel@tonic-gate #ifdef SMARTCARD 8650Sstevel@tonic-gate case 'D': 8660Sstevel@tonic-gate download = 1; 8670Sstevel@tonic-gate case 'U': 8680Sstevel@tonic-gate reader_id = optarg; 8690Sstevel@tonic-gate break; 8700Sstevel@tonic-gate #endif 8710Sstevel@tonic-gate case '?': 8720Sstevel@tonic-gate default: 8730Sstevel@tonic-gate usage(); 8740Sstevel@tonic-gate } 8750Sstevel@tonic-gate } 8760Sstevel@tonic-gate if (optind < ac) { 8770Sstevel@tonic-gate (void) printf(gettext("Too many arguments.\n")); 8780Sstevel@tonic-gate usage(); 8790Sstevel@tonic-gate } 8800Sstevel@tonic-gate if (change_passphrase && change_comment) { 8810Sstevel@tonic-gate (void) printf(gettext("Can only have one of -p and -c.\n")); 8820Sstevel@tonic-gate usage(); 8830Sstevel@tonic-gate } 8840Sstevel@tonic-gate if (print_fingerprint || print_bubblebabble) 8850Sstevel@tonic-gate do_fingerprint(pw); 8860Sstevel@tonic-gate if (change_passphrase) 8870Sstevel@tonic-gate do_change_passphrase(pw); 8880Sstevel@tonic-gate if (change_comment) 8890Sstevel@tonic-gate do_change_comment(pw); 8900Sstevel@tonic-gate if (convert_to_ssh2) 8910Sstevel@tonic-gate do_convert_to_ssh2(pw); 8920Sstevel@tonic-gate if (convert_from_ssh2) 8930Sstevel@tonic-gate do_convert_from_ssh2(pw); 8940Sstevel@tonic-gate if (print_public) 8950Sstevel@tonic-gate do_print_public(pw); 8960Sstevel@tonic-gate if (reader_id != NULL) { 8970Sstevel@tonic-gate #ifdef SMARTCARD 8980Sstevel@tonic-gate if (download) 8990Sstevel@tonic-gate do_download(pw, reader_id); 9000Sstevel@tonic-gate else 9010Sstevel@tonic-gate do_upload(pw, reader_id); 9020Sstevel@tonic-gate #else /* SMARTCARD */ 9030Sstevel@tonic-gate fatal("no support for smartcards."); 9040Sstevel@tonic-gate #endif /* SMARTCARD */ 9050Sstevel@tonic-gate } 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate arc4random_stir(); 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate if (key_type_name == NULL) { 9100Sstevel@tonic-gate (void) printf(gettext("You must specify a key type (-t).\n")); 9110Sstevel@tonic-gate usage(); 9120Sstevel@tonic-gate } 9130Sstevel@tonic-gate type = key_type_from_name(key_type_name); 9140Sstevel@tonic-gate if (type == KEY_UNSPEC) { 9150Sstevel@tonic-gate (void) fprintf(stderr, gettext("unknown key type %s\n"), 9160Sstevel@tonic-gate key_type_name); 9170Sstevel@tonic-gate exit(1); 9180Sstevel@tonic-gate } 9190Sstevel@tonic-gate if (!quiet) 9200Sstevel@tonic-gate (void) printf(gettext("Generating public/private %s key pair.\n"), 9210Sstevel@tonic-gate key_type_name); 9220Sstevel@tonic-gate private = key_generate(type, bits); 9230Sstevel@tonic-gate if (private == NULL) { 9240Sstevel@tonic-gate (void) fprintf(stderr, gettext("key_generate failed")); 9250Sstevel@tonic-gate exit(1); 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate public = key_from_private(private); 9280Sstevel@tonic-gate 9290Sstevel@tonic-gate if (!have_identity) 9300Sstevel@tonic-gate ask_filename(pw, gettext("Enter file in which to save the key")); 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate /* Create ~/.ssh directory if it doesn\'t already exist. */ 9330Sstevel@tonic-gate (void) snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR); 9340Sstevel@tonic-gate if (strstr(identity_file, dotsshdir) != NULL && 9350Sstevel@tonic-gate stat(dotsshdir, &st) < 0) { 9360Sstevel@tonic-gate if (mkdir(dotsshdir, 0700) < 0) 9370Sstevel@tonic-gate error("Could not create directory '%s'.", dotsshdir); 9380Sstevel@tonic-gate else if (!quiet) 9390Sstevel@tonic-gate (void) printf(gettext("Created directory '%s'.\n"), dotsshdir); 9400Sstevel@tonic-gate } 9410Sstevel@tonic-gate /* If the file already exists, ask the user to confirm. */ 9420Sstevel@tonic-gate if (stat(identity_file, &st) >= 0) { 9430Sstevel@tonic-gate char yesno[128]; 9440Sstevel@tonic-gate (void) printf(gettext("%s already exists.\n"), identity_file); 9450Sstevel@tonic-gate (void) printf(gettext("Overwrite (%s/%s)? "), 9460Sstevel@tonic-gate nl_langinfo(YESSTR), nl_langinfo(NOSTR)); 9470Sstevel@tonic-gate (void) fflush(stdout); 9480Sstevel@tonic-gate if (fgets(yesno, sizeof(yesno), stdin) == NULL) 9490Sstevel@tonic-gate exit(1); 950*2757Sjp161948 if (strcasecmp(chop(yesno), nl_langinfo(YESSTR)) != 0) 9510Sstevel@tonic-gate exit(1); 9520Sstevel@tonic-gate } 9530Sstevel@tonic-gate /* Ask for a passphrase (twice). */ 9540Sstevel@tonic-gate if (identity_passphrase) 9550Sstevel@tonic-gate passphrase1 = xstrdup(identity_passphrase); 9560Sstevel@tonic-gate else if (identity_new_passphrase) 9570Sstevel@tonic-gate passphrase1 = xstrdup(identity_new_passphrase); 9580Sstevel@tonic-gate else { 9590Sstevel@tonic-gate passphrase_again: 9600Sstevel@tonic-gate passphrase1 = 9610Sstevel@tonic-gate read_passphrase(gettext("Enter passphrase (empty " 9620Sstevel@tonic-gate "for no passphrase): "), RP_ALLOW_STDIN); 9630Sstevel@tonic-gate passphrase2 = read_passphrase(gettext("Enter same " 9640Sstevel@tonic-gate "passphrase again: "), RP_ALLOW_STDIN); 9650Sstevel@tonic-gate if (strcmp(passphrase1, passphrase2) != 0) { 9660Sstevel@tonic-gate /* 9670Sstevel@tonic-gate * The passphrases do not match. Clear them and 9680Sstevel@tonic-gate * retry. 9690Sstevel@tonic-gate */ 9700Sstevel@tonic-gate (void) memset(passphrase1, 0, strlen(passphrase1)); 9710Sstevel@tonic-gate (void) memset(passphrase2, 0, strlen(passphrase2)); 9720Sstevel@tonic-gate xfree(passphrase1); 9730Sstevel@tonic-gate xfree(passphrase2); 9740Sstevel@tonic-gate (void) printf(gettext("Passphrases do not match. Try " 9750Sstevel@tonic-gate "again.\n")); 9760Sstevel@tonic-gate goto passphrase_again; 9770Sstevel@tonic-gate } 9780Sstevel@tonic-gate /* Clear the other copy of the passphrase. */ 9790Sstevel@tonic-gate (void) memset(passphrase2, 0, strlen(passphrase2)); 9800Sstevel@tonic-gate xfree(passphrase2); 9810Sstevel@tonic-gate } 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate if (identity_comment) { 9840Sstevel@tonic-gate (void) strlcpy(comment, identity_comment, sizeof(comment)); 9850Sstevel@tonic-gate } else { 9860Sstevel@tonic-gate /* Create default commend field for the passphrase. */ 9870Sstevel@tonic-gate (void) snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); 9880Sstevel@tonic-gate } 9890Sstevel@tonic-gate 9900Sstevel@tonic-gate /* Save the key with the given passphrase and comment. */ 9910Sstevel@tonic-gate if (!key_save_private(private, identity_file, passphrase1, comment)) { 9920Sstevel@tonic-gate (void) printf(gettext("Saving the key failed: %s.\n"), identity_file); 9930Sstevel@tonic-gate (void) memset(passphrase1, 0, strlen(passphrase1)); 9940Sstevel@tonic-gate xfree(passphrase1); 9950Sstevel@tonic-gate exit(1); 9960Sstevel@tonic-gate } 9970Sstevel@tonic-gate /* Clear the passphrase. */ 9980Sstevel@tonic-gate (void) memset(passphrase1, 0, strlen(passphrase1)); 9990Sstevel@tonic-gate xfree(passphrase1); 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate /* Clear the private key and the random number generator. */ 10020Sstevel@tonic-gate key_free(private); 10030Sstevel@tonic-gate arc4random_stir(); 10040Sstevel@tonic-gate 10050Sstevel@tonic-gate if (!quiet) 10060Sstevel@tonic-gate (void) printf(gettext("Your identification has been saved in %s.\n"), 10070Sstevel@tonic-gate identity_file); 10080Sstevel@tonic-gate 10090Sstevel@tonic-gate (void) strlcat(identity_file, ".pub", sizeof(identity_file)); 10100Sstevel@tonic-gate fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); 10110Sstevel@tonic-gate if (fd == -1) { 10120Sstevel@tonic-gate (void) printf(gettext("Could not save your public key in %s\n"), 10130Sstevel@tonic-gate identity_file); 10140Sstevel@tonic-gate exit(1); 10150Sstevel@tonic-gate } 10160Sstevel@tonic-gate f = fdopen(fd, "w"); 10170Sstevel@tonic-gate if (f == NULL) { 10180Sstevel@tonic-gate (void) printf(gettext("fdopen %s failed"), identity_file); 10190Sstevel@tonic-gate exit(1); 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate if (!key_write(public, f)) 10220Sstevel@tonic-gate (void) fprintf(stderr, gettext("write key failed")); 10230Sstevel@tonic-gate (void) fprintf(f, " %s\n", comment); 10240Sstevel@tonic-gate (void) fclose(f); 10250Sstevel@tonic-gate 10260Sstevel@tonic-gate if (!quiet) { 10270Sstevel@tonic-gate char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); 10280Sstevel@tonic-gate (void) printf(gettext("Your public key has been saved in %s.\n"), 10290Sstevel@tonic-gate identity_file); 10300Sstevel@tonic-gate (void) printf(gettext("The key fingerprint is:\n")); 10310Sstevel@tonic-gate (void) printf("%s %s\n", fp, comment); 10320Sstevel@tonic-gate xfree(fp); 10330Sstevel@tonic-gate } 10340Sstevel@tonic-gate 10350Sstevel@tonic-gate key_free(public); 10360Sstevel@tonic-gate return(0); 10370Sstevel@tonic-gate /* NOTREACHED */ 10380Sstevel@tonic-gate } 1039