[BACK]Return to ssh-keygen.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/ssh-keygen.c, Revision 1.47

1.1       deraadt     1: /*
1.13      deraadt     2:  * Author: Tatu Ylonen <ylo@cs.hut.fi>
                      3:  * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
                      4:  *                    All rights reserved
                      5:  * Identity and host key generation and maintenance.
1.31      deraadt     6:  *
                      7:  * As far as I am concerned, the code I have written for this software
                      8:  * can be used freely for any purpose.  Any derived versions of this
                      9:  * software must be clearly marked as such, and if the derived work is
                     10:  * incompatible with the protocol description in the RFC file, it must be
                     11:  * called by a name other than "ssh" or "Secure Shell".
1.13      deraadt    12:  */
1.1       deraadt    13:
                     14: #include "includes.h"
1.47    ! jakob      15: RCSID("$OpenBSD: ssh-keygen.c,v 1.46 2001/03/09 03:14:39 deraadt Exp $");
1.19      markus     16:
                     17: #include <openssl/evp.h>
                     18: #include <openssl/pem.h>
1.1       deraadt    19:
                     20: #include "xmalloc.h"
1.19      markus     21: #include "key.h"
                     22: #include "authfile.h"
                     23: #include "uuencode.h"
1.32      markus     24: #include "buffer.h"
                     25: #include "bufaux.h"
1.40      markus     26: #include "pathnames.h"
1.41      markus     27: #include "log.h"
                     28: #include "readpass.h"
1.32      markus     29:
1.19      markus     30: /* Number of bits in the RSA/DSA key.  This value can be changed on the command line. */
1.1       deraadt    31: int bits = 1024;
                     32:
1.14      markus     33: /*
                     34:  * Flag indicating that we just want to change the passphrase.  This can be
                     35:  * set on the command line.
                     36:  */
1.1       deraadt    37: int change_passphrase = 0;
                     38:
1.14      markus     39: /*
                     40:  * Flag indicating that we just want to change the comment.  This can be set
                     41:  * on the command line.
                     42:  */
1.1       deraadt    43: int change_comment = 0;
                     44:
1.2       provos     45: int quiet = 0;
                     46:
1.8       markus     47: /* Flag indicating that we just want to see the key fingerprint */
                     48: int print_fingerprint = 0;
                     49:
1.10      markus     50: /* The identity file name, given on the command line or entered by the user. */
                     51: char identity_file[1024];
                     52: int have_identity = 0;
1.1       deraadt    53:
                     54: /* This is set to the passphrase if given on the command line. */
                     55: char *identity_passphrase = NULL;
                     56:
                     57: /* This is set to the new passphrase if given on the command line. */
                     58: char *identity_new_passphrase = NULL;
                     59:
                     60: /* This is set to the new comment if given on the command line. */
                     61: char *identity_comment = NULL;
                     62:
1.19      markus     63: /* Dump public key file in format used by real and the original SSH 2 */
                     64: int convert_to_ssh2 = 0;
                     65: int convert_from_ssh2 = 0;
                     66: int print_public = 0;
1.47    ! jakob      67: int print_verbose = 0;
1.33      markus     68:
1.35      markus     69: /* default to RSA for SSH-1 */
                     70: char *key_type_name = "rsa1";
1.19      markus     71:
1.10      markus     72: /* argv0 */
                     73: extern char *__progname;
1.1       deraadt    74:
1.19      markus     75: char hostname[MAXHOSTNAMELEN];
                     76:
1.10      markus     77: void
                     78: ask_filename(struct passwd *pw, const char *prompt)
1.1       deraadt    79: {
1.12      markus     80:        char buf[1024];
1.35      markus     81:        char *name = NULL;
                     82:
                     83:        switch (key_type_from_name(key_type_name)) {
                     84:        case KEY_RSA1:
1.40      markus     85:                name = _PATH_SSH_CLIENT_IDENTITY;
1.35      markus     86:                break;
                     87:        case KEY_DSA:
1.40      markus     88:                name = _PATH_SSH_CLIENT_ID_DSA;
1.35      markus     89:                break;
                     90:        case KEY_RSA:
1.40      markus     91:                name = _PATH_SSH_CLIENT_ID_RSA;
1.35      markus     92:                break;
                     93:        default:
                     94:                fprintf(stderr, "bad key type");
                     95:                exit(1);
                     96:                break;
                     97:        }
                     98:        snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
1.37      markus     99:        fprintf(stderr, "%s (%s): ", prompt, identity_file);
                    100:        fflush(stderr);
1.12      markus    101:        if (fgets(buf, sizeof(buf), stdin) == NULL)
                    102:                exit(1);
                    103:        if (strchr(buf, '\n'))
                    104:                *strchr(buf, '\n') = 0;
                    105:        if (strcmp(buf, "") != 0)
                    106:                strlcpy(identity_file, buf, sizeof(identity_file));
                    107:        have_identity = 1;
1.7       markus    108: }
                    109:
1.19      markus    110: int
                    111: try_load_key(char *filename, Key *k)
                    112: {
                    113:        int success = 1;
                    114:        if (!load_private_key(filename, "", k, NULL)) {
                    115:                char *pass = read_passphrase("Enter passphrase: ", 1);
                    116:                if (!load_private_key(filename, pass, k, NULL)) {
                    117:                        success = 0;
                    118:                }
                    119:                memset(pass, 0, strlen(pass));
                    120:                xfree(pass);
                    121:        }
                    122:        return success;
                    123: }
                    124:
1.32      markus    125: #define SSH_COM_PUBLIC_BEGIN           "---- BEGIN SSH2 PUBLIC KEY ----"
                    126: #define SSH_COM_PUBLIC_END             "---- END SSH2 PUBLIC KEY ----"
                    127: #define SSH_COM_PRIVATE_BEGIN          "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
1.42      stevesk   128: #define        SSH_COM_PRIVATE_KEY_MAGIC       0x3f6ff9eb
1.19      markus    129:
                    130: void
                    131: do_convert_to_ssh2(struct passwd *pw)
                    132: {
                    133:        Key *k;
                    134:        int len;
1.36      markus    135:        u_char *blob;
1.19      markus    136:        struct stat st;
                    137:
                    138:        if (!have_identity)
                    139:                ask_filename(pw, "Enter file in which the key is");
                    140:        if (stat(identity_file, &st) < 0) {
                    141:                perror(identity_file);
                    142:                exit(1);
                    143:        }
1.33      markus    144:        k = key_new(KEY_UNSPEC);
1.19      markus    145:        if (!try_load_key(identity_file, k)) {
                    146:                fprintf(stderr, "load failed\n");
                    147:                exit(1);
                    148:        }
1.33      markus    149:        key_to_blob(k, &blob, &len);
1.32      markus    150:        fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
1.19      markus    151:        fprintf(stdout,
1.32      markus    152:            "Comment: \"%d-bit %s, converted from OpenSSH by %s@%s\"\n",
                    153:            key_size(k), key_type(k),
1.19      markus    154:            pw->pw_name, hostname);
                    155:        dump_base64(stdout, blob, len);
1.32      markus    156:        fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
1.19      markus    157:        key_free(k);
1.21      markus    158:        xfree(blob);
1.19      markus    159:        exit(0);
                    160: }
                    161:
                    162: void
1.32      markus    163: buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
                    164: {
                    165:        int bits = buffer_get_int(b);
                    166:        int bytes = (bits + 7) / 8;
                    167:        if (buffer_len(b) < bytes)
                    168:                fatal("buffer_get_bignum_bits: input buffer too small");
1.36      markus    169:        BN_bin2bn((u_char *)buffer_ptr(b), bytes, value);
1.32      markus    170:        buffer_consume(b, bytes);
                    171: }
                    172:
                    173: Key *
                    174: do_convert_private_ssh2_from_blob(char *blob, int blen)
                    175: {
                    176:        Buffer b;
                    177:        DSA *dsa;
                    178:        Key *key = NULL;
                    179:        int ignore, magic, rlen;
                    180:        char *type, *cipher;
                    181:
                    182:        buffer_init(&b);
                    183:        buffer_append(&b, blob, blen);
                    184:
                    185:        magic  = buffer_get_int(&b);
                    186:        if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
                    187:                error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC);
                    188:                buffer_free(&b);
                    189:                return NULL;
                    190:        }
                    191:        ignore = buffer_get_int(&b);
                    192:        type   = buffer_get_string(&b, NULL);
                    193:        cipher = buffer_get_string(&b, NULL);
                    194:        ignore = buffer_get_int(&b);
                    195:        ignore = buffer_get_int(&b);
                    196:        ignore = buffer_get_int(&b);
                    197:        xfree(type);
                    198:
                    199:        if (strcmp(cipher, "none") != 0) {
                    200:                error("unsupported cipher %s", cipher);
                    201:                xfree(cipher);
                    202:                buffer_free(&b);
                    203:                return NULL;
                    204:        }
                    205:        xfree(cipher);
                    206:
                    207:        key = key_new(KEY_DSA);
                    208:        dsa = key->dsa;
                    209:        dsa->priv_key = BN_new();
                    210:        if (dsa->priv_key == NULL) {
                    211:                error("alloc priv_key failed");
                    212:                key_free(key);
                    213:                return NULL;
                    214:        }
                    215:        buffer_get_bignum_bits(&b, dsa->p);
                    216:        buffer_get_bignum_bits(&b, dsa->g);
                    217:        buffer_get_bignum_bits(&b, dsa->q);
                    218:        buffer_get_bignum_bits(&b, dsa->pub_key);
                    219:        buffer_get_bignum_bits(&b, dsa->priv_key);
                    220:        rlen = buffer_len(&b);
                    221:        if(rlen != 0)
                    222:                error("do_convert_private_ssh2_from_blob: remaining bytes in key blob %d", rlen);
                    223:        buffer_free(&b);
                    224:        return key;
                    225: }
                    226:
                    227: void
1.19      markus    228: do_convert_from_ssh2(struct passwd *pw)
                    229: {
                    230:        Key *k;
                    231:        int blen;
                    232:        char line[1024], *p;
                    233:        char blob[8096];
                    234:        char encoded[8096];
                    235:        struct stat st;
1.32      markus    236:        int escaped = 0, private = 0, ok;
1.19      markus    237:        FILE *fp;
                    238:
                    239:        if (!have_identity)
                    240:                ask_filename(pw, "Enter file in which the key is");
                    241:        if (stat(identity_file, &st) < 0) {
                    242:                perror(identity_file);
                    243:                exit(1);
                    244:        }
                    245:        fp = fopen(identity_file, "r");
                    246:        if (fp == NULL) {
                    247:                perror(identity_file);
                    248:                exit(1);
                    249:        }
                    250:        encoded[0] = '\0';
                    251:        while (fgets(line, sizeof(line), fp)) {
1.25      markus    252:                if (!(p = strchr(line, '\n'))) {
                    253:                        fprintf(stderr, "input line too long.\n");
                    254:                        exit(1);
                    255:                }
                    256:                if (p > line && p[-1] == '\\')
                    257:                        escaped++;
1.19      markus    258:                if (strncmp(line, "----", 4) == 0 ||
                    259:                    strstr(line, ": ") != NULL) {
1.32      markus    260:                        if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
                    261:                                private = 1;
1.19      markus    262:                        fprintf(stderr, "ignore: %s", line);
                    263:                        continue;
                    264:                }
1.25      markus    265:                if (escaped) {
                    266:                        escaped--;
                    267:                        fprintf(stderr, "escaped: %s", line);
                    268:                        continue;
1.19      markus    269:                }
                    270:                *p = '\0';
                    271:                strlcat(encoded, line, sizeof(encoded));
                    272:        }
1.36      markus    273:        blen = uudecode(encoded, (u_char *)blob, sizeof(blob));
1.19      markus    274:        if (blen < 0) {
                    275:                fprintf(stderr, "uudecode failed.\n");
                    276:                exit(1);
                    277:        }
1.32      markus    278:        k = private ?
                    279:            do_convert_private_ssh2_from_blob(blob, blen) :
1.33      markus    280:            key_from_blob(blob, blen);
1.32      markus    281:        if (k == NULL) {
                    282:                fprintf(stderr, "decode blob failed.\n");
                    283:                exit(1);
                    284:        }
                    285:        ok = private ?
                    286:            PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
                    287:            key_write(k, stdout);
                    288:        if (!ok) {
                    289:                fprintf(stderr, "key write failed");
                    290:                exit(1);
                    291:        }
1.19      markus    292:        key_free(k);
                    293:        fprintf(stdout, "\n");
                    294:        fclose(fp);
                    295:        exit(0);
                    296: }
                    297:
                    298: void
                    299: do_print_public(struct passwd *pw)
                    300: {
                    301:        Key *k;
                    302:        struct stat st;
                    303:
                    304:        if (!have_identity)
                    305:                ask_filename(pw, "Enter file in which the key is");
                    306:        if (stat(identity_file, &st) < 0) {
                    307:                perror(identity_file);
                    308:                exit(1);
                    309:        }
1.33      markus    310:        k = key_new(KEY_UNSPEC);
1.19      markus    311:        if (!try_load_key(identity_file, k)) {
                    312:                fprintf(stderr, "load failed\n");
                    313:                exit(1);
                    314:        }
                    315:        if (!key_write(k, stdout))
                    316:                fprintf(stderr, "key_write failed");
                    317:        key_free(k);
                    318:        fprintf(stdout, "\n");
                    319:        exit(0);
                    320: }
                    321:
1.7       markus    322: void
1.8       markus    323: do_fingerprint(struct passwd *pw)
                    324: {
1.30      markus    325:
1.15      markus    326:        FILE *f;
1.19      markus    327:        Key *public;
1.16      markus    328:        char *comment = NULL, *cp, *ep, line[16*1024];
1.33      markus    329:        int i, skip = 0, num = 1, invalid = 1, success = 0;
1.12      markus    330:        struct stat st;
                    331:
                    332:        if (!have_identity)
                    333:                ask_filename(pw, "Enter file in which the key is");
                    334:        if (stat(identity_file, &st) < 0) {
                    335:                perror(identity_file);
                    336:                exit(1);
                    337:        }
1.33      markus    338:        public = key_new(KEY_RSA1);
1.19      markus    339:        if (load_public_key(identity_file, public, &comment)) {
1.33      markus    340:                success = 1;
                    341:        } else {
1.19      markus    342:                key_free(public);
1.33      markus    343:                public = key_new(KEY_UNSPEC);
                    344:                if (try_load_public_key(identity_file, public, &comment))
                    345:                        success = 1;
                    346:                else
1.38      markus    347:                        debug("try_load_public_key KEY_UNSPEC failed");
1.33      markus    348:        }
                    349:        if (success) {
1.47    ! jakob     350:                char *digest_md5, *digest_sha1, *digest_bubblebabble;
        !           351:
        !           352:                digest_md5 = key_fingerprint_ex(public, SSH_FP_MD5, SSH_FP_HEX);
        !           353:                digest_sha1 = key_fingerprint_ex(public, SSH_FP_SHA1, SSH_FP_HEX);
        !           354:                digest_bubblebabble = key_fingerprint_ex(public, SSH_FP_SHA1, SSH_FP_BUBBLEBABBLE);
        !           355:
        !           356:                if(print_verbose) {
        !           357:                        printf("comment:      %s\n", comment);
        !           358:                        printf("size:         %d\n", key_size(public));
        !           359:                        printf("md5:          %s\n", digest_md5);
        !           360:                        printf("sha1:         %s\n", digest_sha1);
        !           361:                        printf("bubblebabble: %s\n", digest_bubblebabble);
        !           362:                } else {
        !           363:                        printf("%d %s %s\n", key_size(public), digest_md5, comment);
        !           364:                }
        !           365:
1.33      markus    366:                key_free(public);
                    367:                xfree(comment);
1.47    ! jakob     368:                xfree(digest_md5);
        !           369:                xfree(digest_sha1);
        !           370:                xfree(digest_bubblebabble);
        !           371:
1.15      markus    372:                exit(0);
                    373:        }
                    374:
                    375:        f = fopen(identity_file, "r");
                    376:        if (f != NULL) {
                    377:                while (fgets(line, sizeof(line), f)) {
                    378:                        i = strlen(line) - 1;
                    379:                        if (line[i] != '\n') {
                    380:                                error("line %d too long: %.40s...", num, line);
                    381:                                skip = 1;
                    382:                                continue;
                    383:                        }
                    384:                        num++;
                    385:                        if (skip) {
                    386:                                skip = 0;
                    387:                                continue;
                    388:                        }
                    389:                        line[i] = '\0';
                    390:
                    391:                        /* Skip leading whitespace, empty and comment lines. */
                    392:                        for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
                    393:                                ;
                    394:                        if (!*cp || *cp == '\n' || *cp == '#')
                    395:                                continue ;
                    396:                        i = strtol(cp, &ep, 10);
                    397:                        if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
                    398:                                int quoted = 0;
                    399:                                comment = cp;
                    400:                                for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
                    401:                                        if (*cp == '\\' && cp[1] == '"')
                    402:                                                cp++;   /* Skip both */
                    403:                                        else if (*cp == '"')
                    404:                                                quoted = !quoted;
                    405:                                }
                    406:                                if (!*cp)
                    407:                                        continue;
                    408:                                *cp++ = '\0';
                    409:                        }
                    410:                        ep = cp;
1.38      markus    411:                        public = key_new(KEY_RSA1);
                    412:                        if (key_read(public, &cp) != 1) {
                    413:                                cp = ep;
                    414:                                key_free(public);
                    415:                                public = key_new(KEY_UNSPEC);
                    416:                                if (key_read(public, &cp) != 1) {
                    417:                                        key_free(public);
                    418:                                        continue;
                    419:                                }
1.12      markus    420:                        }
1.38      markus    421:                        comment = *cp ? cp : comment;
                    422:                        printf("%d %s %s\n", key_size(public),
                    423:                            key_fingerprint(public),
                    424:                            comment ? comment : "no comment");
                    425:                        invalid = 0;
1.12      markus    426:                }
1.15      markus    427:                fclose(f);
                    428:        }
1.30      markus    429:        key_free(public);
1.15      markus    430:        if (invalid) {
                    431:                printf("%s is not a valid key file.\n", identity_file);
                    432:                exit(1);
1.12      markus    433:        }
                    434:        exit(0);
1.8       markus    435: }
                    436:
1.13      deraadt   437: /*
                    438:  * Perform changing a passphrase.  The argument is the passwd structure
                    439:  * for the current user.
                    440:  */
1.8       markus    441: void
1.7       markus    442: do_change_passphrase(struct passwd *pw)
                    443: {
1.12      markus    444:        char *comment;
                    445:        char *old_passphrase, *passphrase1, *passphrase2;
                    446:        struct stat st;
1.19      markus    447:        Key *private;
                    448:        Key *public;
1.33      markus    449:        int type = KEY_RSA1;
1.12      markus    450:
                    451:        if (!have_identity)
                    452:                ask_filename(pw, "Enter file in which the key is");
                    453:        if (stat(identity_file, &st) < 0) {
                    454:                perror(identity_file);
                    455:                exit(1);
                    456:        }
1.33      markus    457:        public = key_new(type);
                    458:        if (!load_public_key(identity_file, public, NULL)) {
                    459:                type = KEY_UNSPEC;
                    460:        } else {
1.19      markus    461:                /* Clear the public key since we are just about to load the whole file. */
                    462:                key_free(public);
1.12      markus    463:        }
                    464:        /* Try to load the file with empty passphrase. */
1.19      markus    465:        private = key_new(type);
                    466:        if (!load_private_key(identity_file, "", private, &comment)) {
1.12      markus    467:                if (identity_passphrase)
                    468:                        old_passphrase = xstrdup(identity_passphrase);
                    469:                else
                    470:                        old_passphrase = read_passphrase("Enter old passphrase: ", 1);
1.19      markus    471:                if (!load_private_key(identity_file, old_passphrase, private, &comment)) {
1.12      markus    472:                        memset(old_passphrase, 0, strlen(old_passphrase));
                    473:                        xfree(old_passphrase);
                    474:                        printf("Bad passphrase.\n");
                    475:                        exit(1);
                    476:                }
                    477:                memset(old_passphrase, 0, strlen(old_passphrase));
                    478:                xfree(old_passphrase);
                    479:        }
                    480:        printf("Key has comment '%s'\n", comment);
                    481:
                    482:        /* Ask the new passphrase (twice). */
                    483:        if (identity_new_passphrase) {
                    484:                passphrase1 = xstrdup(identity_new_passphrase);
                    485:                passphrase2 = NULL;
                    486:        } else {
                    487:                passphrase1 =
                    488:                        read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
                    489:                passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
                    490:
                    491:                /* Verify that they are the same. */
                    492:                if (strcmp(passphrase1, passphrase2) != 0) {
                    493:                        memset(passphrase1, 0, strlen(passphrase1));
                    494:                        memset(passphrase2, 0, strlen(passphrase2));
                    495:                        xfree(passphrase1);
                    496:                        xfree(passphrase2);
                    497:                        printf("Pass phrases do not match.  Try again.\n");
                    498:                        exit(1);
                    499:                }
                    500:                /* Destroy the other copy. */
                    501:                memset(passphrase2, 0, strlen(passphrase2));
                    502:                xfree(passphrase2);
                    503:        }
                    504:
                    505:        /* Save the file using the new passphrase. */
1.19      markus    506:        if (!save_private_key(identity_file, passphrase1, private, comment)) {
1.12      markus    507:                printf("Saving the key failed: %s: %s.\n",
                    508:                       identity_file, strerror(errno));
                    509:                memset(passphrase1, 0, strlen(passphrase1));
                    510:                xfree(passphrase1);
1.19      markus    511:                key_free(private);
1.12      markus    512:                xfree(comment);
                    513:                exit(1);
                    514:        }
                    515:        /* Destroy the passphrase and the copy of the key in memory. */
                    516:        memset(passphrase1, 0, strlen(passphrase1));
                    517:        xfree(passphrase1);
1.19      markus    518:        key_free(private);               /* Destroys contents */
1.12      markus    519:        xfree(comment);
1.1       deraadt   520:
1.12      markus    521:        printf("Your identification has been saved with the new passphrase.\n");
                    522:        exit(0);
1.1       deraadt   523: }
                    524:
1.13      deraadt   525: /*
                    526:  * Change the comment of a private key file.
                    527:  */
1.2       provos    528: void
                    529: do_change_comment(struct passwd *pw)
1.1       deraadt   530: {
1.46      deraadt   531:        char new_comment[1024], *comment, *passphrase;
                    532:        Key *private, *public;
1.12      markus    533:        struct stat st;
                    534:        FILE *f;
1.46      deraadt   535:        int fd;
1.12      markus    536:
                    537:        if (!have_identity)
                    538:                ask_filename(pw, "Enter file in which the key is");
                    539:        if (stat(identity_file, &st) < 0) {
                    540:                perror(identity_file);
                    541:                exit(1);
                    542:        }
1.14      markus    543:        /*
                    544:         * Try to load the public key from the file the verify that it is
                    545:         * readable and of the proper format.
                    546:         */
1.33      markus    547:        public = key_new(KEY_RSA1);
1.19      markus    548:        if (!load_public_key(identity_file, public, NULL)) {
1.12      markus    549:                printf("%s is not a valid key file.\n", identity_file);
1.43      markus    550:                printf("Comments are only supported in RSA1 keys\n");
1.12      markus    551:                exit(1);
                    552:        }
1.14      markus    553:
1.33      markus    554:        private = key_new(KEY_RSA1);
1.19      markus    555:        if (load_private_key(identity_file, "", private, &comment))
1.12      markus    556:                passphrase = xstrdup("");
                    557:        else {
                    558:                if (identity_passphrase)
                    559:                        passphrase = xstrdup(identity_passphrase);
                    560:                else if (identity_new_passphrase)
                    561:                        passphrase = xstrdup(identity_new_passphrase);
                    562:                else
                    563:                        passphrase = read_passphrase("Enter passphrase: ", 1);
                    564:                /* Try to load using the passphrase. */
1.19      markus    565:                if (!load_private_key(identity_file, passphrase, private, &comment)) {
1.12      markus    566:                        memset(passphrase, 0, strlen(passphrase));
                    567:                        xfree(passphrase);
                    568:                        printf("Bad passphrase.\n");
                    569:                        exit(1);
                    570:                }
                    571:        }
                    572:        printf("Key now has comment '%s'\n", comment);
                    573:
                    574:        if (identity_comment) {
                    575:                strlcpy(new_comment, identity_comment, sizeof(new_comment));
                    576:        } else {
                    577:                printf("Enter new comment: ");
                    578:                fflush(stdout);
                    579:                if (!fgets(new_comment, sizeof(new_comment), stdin)) {
                    580:                        memset(passphrase, 0, strlen(passphrase));
1.19      markus    581:                        key_free(private);
1.12      markus    582:                        exit(1);
                    583:                }
                    584:                if (strchr(new_comment, '\n'))
                    585:                        *strchr(new_comment, '\n') = 0;
                    586:        }
                    587:
                    588:        /* Save the file using the new passphrase. */
1.19      markus    589:        if (!save_private_key(identity_file, passphrase, private, new_comment)) {
1.12      markus    590:                printf("Saving the key failed: %s: %s.\n",
                    591:                       identity_file, strerror(errno));
                    592:                memset(passphrase, 0, strlen(passphrase));
                    593:                xfree(passphrase);
1.19      markus    594:                key_free(private);
1.12      markus    595:                xfree(comment);
                    596:                exit(1);
                    597:        }
                    598:        memset(passphrase, 0, strlen(passphrase));
                    599:        xfree(passphrase);
1.19      markus    600:        key_free(private);
1.12      markus    601:
                    602:        strlcat(identity_file, ".pub", sizeof(identity_file));
1.46      deraadt   603:        fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
                    604:        if (fd == -1) {
1.12      markus    605:                printf("Could not save your public key in %s\n", identity_file);
                    606:                exit(1);
                    607:        }
1.46      deraadt   608:        f = fdopen(fd, "w");
                    609:        if (f == NULL) {
                    610:                printf("fdopen %s failed", identity_file);
                    611:                exit(1);
                    612:        }
1.19      markus    613:        if (!key_write(public, f))
                    614:                fprintf(stderr, "write key failed");
                    615:        key_free(public);
                    616:        fprintf(f, " %s\n", new_comment);
1.12      markus    617:        fclose(f);
1.1       deraadt   618:
1.12      markus    619:        xfree(comment);
1.1       deraadt   620:
1.12      markus    621:        printf("The comment in your key file has been changed.\n");
                    622:        exit(0);
1.1       deraadt   623: }
                    624:
1.10      markus    625: void
                    626: usage(void)
                    627: {
1.45      deraadt   628:        printf("Usage: %s [-lpqxXyc] [-t type] [-b bits] [-f file] [-C comment] "
1.44      deraadt   629:            "[-N new-pass] [-P pass]\n", __progname);
1.12      markus    630:        exit(1);
1.10      markus    631: }
                    632:
1.13      deraadt   633: /*
                    634:  * Main program for key management.
                    635:  */
1.2       provos    636: int
                    637: main(int ac, char **av)
1.1       deraadt   638: {
1.12      markus    639:        char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
1.46      deraadt   640:        Key *private, *public;
1.12      markus    641:        struct passwd *pw;
1.46      deraadt   642:        int opt, type, fd;
1.12      markus    643:        struct stat st;
                    644:        FILE *f;
1.33      markus    645:
1.12      markus    646:        extern int optind;
                    647:        extern char *optarg;
                    648:
1.26      markus    649:        SSLeay_add_all_algorithms();
1.19      markus    650:
1.14      markus    651:        /* we need this for the home * directory.  */
1.12      markus    652:        pw = getpwuid(getuid());
                    653:        if (!pw) {
                    654:                printf("You don't exist, go away!\n");
                    655:                exit(1);
                    656:        }
1.19      markus    657:        if (gethostname(hostname, sizeof(hostname)) < 0) {
                    658:                perror("gethostname");
                    659:                exit(1);
                    660:        }
1.14      markus    661:
1.47    ! jakob     662:        while ((opt = getopt(ac, av, "dqpclRxXyvb:f:t:P:N:C:")) != -1) {
1.12      markus    663:                switch (opt) {
                    664:                case 'b':
                    665:                        bits = atoi(optarg);
                    666:                        if (bits < 512 || bits > 32768) {
                    667:                                printf("Bits has bad value.\n");
                    668:                                exit(1);
                    669:                        }
                    670:                        break;
                    671:
                    672:                case 'l':
                    673:                        print_fingerprint = 1;
                    674:                        break;
                    675:
                    676:                case 'p':
                    677:                        change_passphrase = 1;
                    678:                        break;
                    679:
                    680:                case 'c':
                    681:                        change_comment = 1;
                    682:                        break;
                    683:
                    684:                case 'f':
                    685:                        strlcpy(identity_file, optarg, sizeof(identity_file));
                    686:                        have_identity = 1;
                    687:                        break;
                    688:
                    689:                case 'P':
                    690:                        identity_passphrase = optarg;
                    691:                        break;
                    692:
                    693:                case 'N':
                    694:                        identity_new_passphrase = optarg;
                    695:                        break;
                    696:
                    697:                case 'C':
                    698:                        identity_comment = optarg;
                    699:                        break;
                    700:
                    701:                case 'q':
                    702:                        quiet = 1;
1.20      deraadt   703:                        break;
                    704:
                    705:                case 'R':
1.33      markus    706:                        /* unused */
                    707:                        exit(0);
1.12      markus    708:                        break;
                    709:
1.19      markus    710:                case 'x':
                    711:                        convert_to_ssh2 = 1;
                    712:                        break;
                    713:
                    714:                case 'X':
                    715:                        convert_from_ssh2 = 1;
                    716:                        break;
                    717:
                    718:                case 'y':
                    719:                        print_public = 1;
1.47    ! jakob     720:                        break;
        !           721:
        !           722:                case 'v':
        !           723:                        print_verbose = 1;
1.19      markus    724:                        break;
                    725:
                    726:                case 'd':
1.33      markus    727:                        key_type_name = "dsa";
1.19      markus    728:                        break;
                    729:
1.33      markus    730:                case 't':
                    731:                        key_type_name = optarg;
                    732:                        break;
                    733:
1.12      markus    734:                case '?':
                    735:                default:
                    736:                        usage();
                    737:                }
                    738:        }
                    739:        if (optind < ac) {
                    740:                printf("Too many arguments.\n");
                    741:                usage();
                    742:        }
                    743:        if (change_passphrase && change_comment) {
                    744:                printf("Can only have one of -p and -c.\n");
                    745:                usage();
                    746:        }
                    747:        if (print_fingerprint)
                    748:                do_fingerprint(pw);
                    749:        if (change_passphrase)
                    750:                do_change_passphrase(pw);
                    751:        if (change_comment)
                    752:                do_change_comment(pw);
1.19      markus    753:        if (convert_to_ssh2)
                    754:                do_convert_to_ssh2(pw);
                    755:        if (convert_from_ssh2)
                    756:                do_convert_from_ssh2(pw);
                    757:        if (print_public)
                    758:                do_print_public(pw);
1.12      markus    759:
                    760:        arc4random_stir();
                    761:
1.35      markus    762:        type = key_type_from_name(key_type_name);
                    763:        if (type == KEY_UNSPEC) {
                    764:                fprintf(stderr, "unknown key type %s\n", key_type_name);
                    765:                exit(1);
1.19      markus    766:        }
1.33      markus    767:        if (!quiet)
1.35      markus    768:                printf("Generating public/private %s key pair.\n", key_type_name);
1.33      markus    769:        private = key_generate(type, bits);
                    770:        if (private == NULL) {
                    771:                fprintf(stderr, "key_generate failed");
                    772:                exit(1);
                    773:        }
                    774:        public  = key_from_private(private);
1.12      markus    775:
                    776:        if (!have_identity)
                    777:                ask_filename(pw, "Enter file in which to save the key");
                    778:
                    779:        /* Create ~/.ssh directory if it doesn\'t already exist. */
1.40      markus    780:        snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
1.12      markus    781:        if (strstr(identity_file, dotsshdir) != NULL &&
                    782:            stat(dotsshdir, &st) < 0) {
1.29      djm       783:                if (mkdir(dotsshdir, 0700) < 0)
1.12      markus    784:                        error("Could not create directory '%s'.", dotsshdir);
                    785:                else if (!quiet)
                    786:                        printf("Created directory '%s'.\n", dotsshdir);
                    787:        }
                    788:        /* If the file already exists, ask the user to confirm. */
                    789:        if (stat(identity_file, &st) >= 0) {
                    790:                char yesno[3];
                    791:                printf("%s already exists.\n", identity_file);
                    792:                printf("Overwrite (y/n)? ");
                    793:                fflush(stdout);
                    794:                if (fgets(yesno, sizeof(yesno), stdin) == NULL)
                    795:                        exit(1);
                    796:                if (yesno[0] != 'y' && yesno[0] != 'Y')
                    797:                        exit(1);
                    798:        }
                    799:        /* Ask for a passphrase (twice). */
                    800:        if (identity_passphrase)
                    801:                passphrase1 = xstrdup(identity_passphrase);
                    802:        else if (identity_new_passphrase)
                    803:                passphrase1 = xstrdup(identity_new_passphrase);
                    804:        else {
                    805: passphrase_again:
                    806:                passphrase1 =
                    807:                        read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
                    808:                passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
                    809:                if (strcmp(passphrase1, passphrase2) != 0) {
                    810:                        /* The passphrases do not match.  Clear them and retry. */
                    811:                        memset(passphrase1, 0, strlen(passphrase1));
                    812:                        memset(passphrase2, 0, strlen(passphrase2));
                    813:                        xfree(passphrase1);
                    814:                        xfree(passphrase2);
                    815:                        printf("Passphrases do not match.  Try again.\n");
                    816:                        goto passphrase_again;
                    817:                }
                    818:                /* Clear the other copy of the passphrase. */
                    819:                memset(passphrase2, 0, strlen(passphrase2));
                    820:                xfree(passphrase2);
                    821:        }
                    822:
                    823:        if (identity_comment) {
                    824:                strlcpy(comment, identity_comment, sizeof(comment));
                    825:        } else {
1.18      markus    826:                /* Create default commend field for the passphrase. */
1.12      markus    827:                snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
                    828:        }
                    829:
                    830:        /* Save the key with the given passphrase and comment. */
1.19      markus    831:        if (!save_private_key(identity_file, passphrase1, private, comment)) {
1.12      markus    832:                printf("Saving the key failed: %s: %s.\n",
1.19      markus    833:                    identity_file, strerror(errno));
1.12      markus    834:                memset(passphrase1, 0, strlen(passphrase1));
                    835:                xfree(passphrase1);
                    836:                exit(1);
                    837:        }
                    838:        /* Clear the passphrase. */
                    839:        memset(passphrase1, 0, strlen(passphrase1));
                    840:        xfree(passphrase1);
                    841:
                    842:        /* Clear the private key and the random number generator. */
1.33      markus    843:        key_free(private);
1.12      markus    844:        arc4random_stir();
                    845:
                    846:        if (!quiet)
                    847:                printf("Your identification has been saved in %s.\n", identity_file);
                    848:
                    849:        strlcat(identity_file, ".pub", sizeof(identity_file));
1.46      deraadt   850:        fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
                    851:        if (fd == -1) {
1.12      markus    852:                printf("Could not save your public key in %s\n", identity_file);
1.46      deraadt   853:                exit(1);
                    854:        }
                    855:        f = fdopen(fd, "w");
                    856:        if (f == NULL) {
                    857:                printf("fdopen %s failed", identity_file);
1.12      markus    858:                exit(1);
                    859:        }
1.19      markus    860:        if (!key_write(public, f))
                    861:                fprintf(stderr, "write key failed");
                    862:        fprintf(f, " %s\n", comment);
1.12      markus    863:        fclose(f);
                    864:
                    865:        if (!quiet) {
1.19      markus    866:                printf("Your public key has been saved in %s.\n",
                    867:                    identity_file);
1.12      markus    868:                printf("The key fingerprint is:\n");
1.19      markus    869:                printf("%s %s\n", key_fingerprint(public), comment);
1.12      markus    870:        }
1.19      markus    871:
                    872:        key_free(public);
1.12      markus    873:        exit(0);
1.1       deraadt   874: }