ssh-keygen.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
* Identity and host key generation and maintenance.
*
* As far as I am concerned, the code I have written for this software
* can be used freely for any purpose. Any derived versions of this
* software must be clearly marked as such, and if the derived work is
* incompatible with the protocol description in the RFC file, it must be
* called by a name other than "ssh" or "Secure Shell".
*/
#include "includes.h"
RCSID("$OpenBSD: ssh-keygen.c,v 1.101 2002/06/23 09:39:55 deraadt Exp $");
#pragma ident "%Z%%M% %I% %E% SMI"
#include "xmalloc.h"
#include "key.h"
#include "rsa.h"
#include "authfile.h"
#include "uuencode.h"
#include "buffer.h"
#include "bufaux.h"
#include "pathnames.h"
#include "log.h"
#include "readpass.h"
#include <langinfo.h>
#ifdef SMARTCARD
#include "scard.h"
#endif
int bits = 1024;
/*
* Flag indicating that we just want to change the passphrase. This can be
* set on the command line.
*/
int change_passphrase = 0;
/*
* Flag indicating that we just want to change the comment. This can be set
* on the command line.
*/
int change_comment = 0;
int quiet = 0;
/* Flag indicating that we just want to see the key fingerprint */
int print_fingerprint = 0;
int print_bubblebabble = 0;
/* The identity file name, given on the command line or entered by the user. */
char identity_file[1024];
int have_identity = 0;
/* This is set to the passphrase if given on the command line. */
char *identity_passphrase = NULL;
/* This is set to the new passphrase if given on the command line. */
char *identity_new_passphrase = NULL;
/* This is set to the new comment if given on the command line. */
char *identity_comment = NULL;
/* Dump public key file in format used by real and the original SSH 2 */
int convert_to_ssh2 = 0;
int convert_from_ssh2 = 0;
int print_public = 0;
char *key_type_name = NULL;
/* argv0 */
#ifdef HAVE___PROGNAME
extern char *__progname;
#else
char *__progname;
#endif
char hostname[MAXHOSTNAMELEN];
static void
{
char buf[1024];
if (key_type_name == NULL)
else
switch (key_type_from_name(key_type_name)) {
case KEY_RSA1:
break;
case KEY_DSA:
break;
case KEY_RSA:
break;
default:
exit(1);
break;
}
exit(1);
have_identity = 1;
}
static Key *
load_identity(char *filename)
{
char *pass;
if (identity_passphrase)
else
}
return prv;
}
#define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
#define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----"
#define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
#define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb
static void
{
Key *k;
if (!have_identity)
exit(1);
}
exit(1);
}
}
exit(1);
}
"Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n"),
key_free(k);
exit(0);
}
static void
{
int bits = buffer_get_int(b);
if (buffer_len(b) < bytes)
fatal("buffer_get_bignum_bits: input buffer too small: "
buffer_consume(b, bytes);
}
static Key *
{
Buffer b;
u_long e;
buffer_init(&b);
magic = buffer_get_int(&b);
if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
buffer_free(&b);
return NULL;
}
i1 = buffer_get_int(&b);
i2 = buffer_get_int(&b);
i3 = buffer_get_int(&b);
i4 = buffer_get_int(&b);
buffer_free(&b);
return NULL;
}
} else {
return NULL;
}
case KEY_DSA:
break;
case KEY_RSA:
e = buffer_get_char(&b);
debug("e %lx", e);
if (e < 30) {
e <<= 8;
e += buffer_get_char(&b);
debug("e %lx", e);
e <<= 8;
e += buffer_get_char(&b);
debug("e %lx", e);
}
buffer_free(&b);
return NULL;
}
break;
}
rlen = buffer_len(&b);
if (rlen != 0)
error("do_convert_private_ssh2_from_blob: "
"remaining bytes in key blob %d", rlen);
buffer_free(&b);
/* try the key */
return key;
}
static void
{
Key *k;
int blen;
char line[1024], *p;
char encoded[8096];
if (!have_identity)
exit(1);
}
exit(1);
}
encoded[0] = '\0';
exit(1);
}
escaped++;
private = 1;
break;
}
/* fprintf(stderr, "ignore: %s", line); */
continue;
}
if (escaped) {
escaped--;
/* fprintf(stderr, "escaped: %s", line); */
continue;
}
*p = '\0';
}
if (blen < 0) {
exit(1);
}
k = private ?
if (k == NULL) {
exit(1);
}
if (!ok) {
exit(1);
}
key_free(k);
if (!private)
exit(0);
}
static void
{
if (!have_identity)
exit(1);
}
exit(1);
}
exit(0);
}
#ifdef SMARTCARD
static void
{
int ret;
if (!have_identity)
exit(1);
}
error("load failed");
exit(1);
}
if (ret < 0)
exit(1);
log("loading key done");
exit(0);
}
static void
{
int i;
fatal("cannot read public key from smartcard");
for (i = 0; keys[i]; i++) {
}
exit(0);
}
#endif /* SMARTCARD */
static void
{
FILE *f;
if (!have_identity)
exit(1);
}
exit(0);
}
if (comment)
if (f != NULL) {
if (line[i] != '\n') {
skip = 1;
continue;
}
num++;
if (skip) {
skip = 0;
continue;
}
line[i] = '\0';
/* Skip leading whitespace, empty and comment lines. */
;
continue ;
int quoted = 0;
cp++; /* Skip both */
else if (*cp == '"')
}
if (!*cp)
continue;
*cp++ = '\0';
}
continue;
}
}
invalid = 0;
}
(void) fclose(f);
}
if (invalid) {
exit(1);
}
exit(0);
}
/*
* Perform changing a passphrase. The argument is the passwd structure
* for the current user.
*/
static void
{
char *comment;
if (!have_identity)
exit(1);
}
/* Try to load the file with empty passphrase. */
if (identity_passphrase)
else
&comment);
exit(1);
}
}
/* Ask the new passphrase (twice). */
if (identity_new_passphrase) {
passphrase2 = NULL;
} else {
" for no passphrase): "), RP_ALLOW_STDIN);
"passphrase again: "), RP_ALLOW_STDIN);
/* Verify that they are the same. */
"again.\n"));
exit(1);
}
/* Destroy the other copy. */
}
/* Save the file using the new passphrase. */
exit(1);
}
/* Destroy the passphrase and the copy of the key in memory. */
"passphrase.\n"));
exit(0);
}
/*
* Change the comment of a private key file.
*/
static void
{
FILE *f;
int fd;
if (!have_identity)
exit(1);
}
if (identity_passphrase)
else if (identity_new_passphrase)
else
/* Try to load using the passphrase. */
exit(1);
}
} else {
}
"RSA1 keys.\n"));
exit(1);
}
if (identity_comment) {
} else {
exit(1);
}
}
/* Save the file using the new passphrase. */
exit(1);
}
if (fd == -1) {
exit(1);
}
if (f == NULL) {
exit(1);
}
(void) fclose(f);
exit(0);
}
static void
usage(void)
{
"Usage: %s [options]\n"
"Options:\n"
" -b bits Number of bits in the key to create.\n"
" -c Change comment in private and public key files.\n"
" -e Convert OpenSSH to IETF SECSH key file.\n"
" -f filename Filename of the key file.\n"
" -i Convert IETF SECSH to OpenSSH key file.\n"
" -l Show fingerprint of key file.\n"
" -p Change passphrase of private key file.\n"
" -q Quiet.\n"
" -y Read private key file and print public key.\n"
" -t type Specify type of key to create.\n"
" -B Show bubblebabble digest of key file.\n"
" -C comment Provide new comment.\n"
" -N phrase Provide new passphrase.\n"
" -P phrase Provide old passphrase.\n"
#ifdef SMARTCARD
" -D reader Download public key from smartcard.\n"
" -U reader Upload private key to smartcard.\n"
#endif /* SMARTCARD */
), __progname);
exit(1);
}
/*
* Main program for key management.
*/
int
{
#ifdef SMARTCARD
int download = 0;
#endif /* SMARTCARD */
FILE *f;
extern int optind;
extern char *optarg;
init_rng();
seed_rng();
/* we need this for the home * directory. */
if (!pw) {
exit(1);
}
perror("gethostname");
exit(1);
}
#ifdef SMARTCARD
#define GETOPT_ARGS "deiqpclBRxXyb:f:t:U:D:P:N:C:"
#else
#define GETOPT_ARGS "deiqpclBRxXyb:f:t:P:N:C:"
#endif /* SMARTCARD */
switch (opt) {
case 'b':
exit(1);
}
break;
case 'l':
print_fingerprint = 1;
break;
case 'B':
print_bubblebabble = 1;
break;
case 'p':
change_passphrase = 1;
break;
case 'c':
change_comment = 1;
break;
case 'f':
have_identity = 1;
break;
case 'P':
break;
case 'N':
break;
case 'C':
break;
case 'q':
quiet = 1;
break;
case 'R':
/* unused */
exit(0);
break;
case 'e':
case 'x':
/* export key */
convert_to_ssh2 = 1;
break;
case 'i':
case 'X':
/* import key */
convert_from_ssh2 = 1;
break;
case 'y':
print_public = 1;
break;
case 'd':
key_type_name = "dsa";
break;
case 't':
break;
#ifdef SMARTCARD
case 'D':
download = 1;
case 'U':
break;
#endif
case '?':
default:
usage();
}
}
usage();
}
if (change_passphrase && change_comment) {
usage();
}
if (print_fingerprint || print_bubblebabble)
if (change_passphrase)
if (change_comment)
if (convert_to_ssh2)
if (convert_from_ssh2)
if (print_public)
#ifdef SMARTCARD
if (download)
else
#else /* SMARTCARD */
fatal("no support for smartcards.");
#endif /* SMARTCARD */
}
if (key_type_name == NULL) {
usage();
}
if (type == KEY_UNSPEC) {
exit(1);
}
if (!quiet)
exit(1);
}
if (!have_identity)
/* Create ~/.ssh directory if it doesn\'t already exist. */
else if (!quiet)
}
/* If the file already exists, ask the user to confirm. */
char yesno[128];
exit(1);
exit(1);
}
/* Ask for a passphrase (twice). */
if (identity_passphrase)
else if (identity_new_passphrase)
else {
"for no passphrase): "), RP_ALLOW_STDIN);
"passphrase again: "), RP_ALLOW_STDIN);
/*
* The passphrases do not match. Clear them and
* retry.
*/
"again.\n"));
goto passphrase_again;
}
/* Clear the other copy of the passphrase. */
}
if (identity_comment) {
} else {
/* Create default commend field for the passphrase. */
}
/* Save the key with the given passphrase and comment. */
exit(1);
}
/* Clear the passphrase. */
/* Clear the private key and the random number generator. */
if (!quiet)
if (fd == -1) {
exit(1);
}
if (f == NULL) {
exit(1);
}
(void) fclose(f);
if (!quiet) {
}
return(0);
/* NOTREACHED */
}