typedef unsigned int __u_int; typedef unsigned long int __u_long; __extension__ typedef unsigned int __uid_t; __extension__ typedef long int __time_t; __extension__ typedef int __ssize_t; typedef __u_int u_int; typedef __u_long u_long; typedef __ssize_t ssize_t; typedef __time_t time_t; typedef unsigned int size_t; typedef unsigned int u_int32_t __attribute__ ((__mode__(__SI__))); typedef unsigned int u_int64_t __attribute__ ((__mode__(__DI__))); struct stat { }; extern int *__errno_location(void) __attribute__ ((__nothrow__, __leaf__)) __attribute__ ((__const__)); struct passwd { char *pw_name; __uid_t pw_uid; char *pw_dir; }; typedef struct _IO_FILE FILE; extern struct _IO_FILE *stdin; extern struct _IO_FILE *stdout; extern struct _IO_FILE *stderr; typedef struct { } Buffer; typedef struct bignum_st BIGNUM; extern ssize_t write(int __fd, const void *__buf, size_t __n) __attribute__ ((__warn_unused_result__)); typedef struct Key Key; enum types { KEY_RSA1, KEY_RSA, KEY_DSA, KEY_ECDSA, KEY_ED25519, KEY_RSA_CERT, KEY_DSA_CERT, KEY_ECDSA_CERT, KEY_ED25519_CERT, KEY_RSA_CERT_V00, KEY_DSA_CERT_V00, KEY_UNSPEC }; enum fp_type { SSH_FP_SHA1, SSH_FP_MD5, SSH_FP_SHA256 }; enum fp_rep { SSH_FP_HEX, SSH_FP_BUBBLEBABBLE, SSH_FP_RANDOMART }; struct KeyCert { u_int64_t serial; char *key_id; u_int nprincipals; char **principals; u_int64_t valid_after, valid_before; Buffer critical; Buffer extensions; Key *signature_key; }; struct Key { int type; struct KeyCert *cert; }; typedef enum { SYSLOG_FACILITY_DAEMON, SYSLOG_FACILITY_USER, SYSLOG_FACILITY_AUTH, SYSLOG_FACILITY_LOCAL0, SYSLOG_FACILITY_LOCAL1, SYSLOG_FACILITY_LOCAL2, SYSLOG_FACILITY_LOCAL3, SYSLOG_FACILITY_LOCAL4, SYSLOG_FACILITY_LOCAL5, SYSLOG_FACILITY_LOCAL6, SYSLOG_FACILITY_LOCAL7, SYSLOG_FACILITY_NOT_SET = -1 } SyslogFacility; typedef enum { SYSLOG_LEVEL_QUIET, SYSLOG_LEVEL_FATAL, SYSLOG_LEVEL_ERROR, SYSLOG_LEVEL_INFO, SYSLOG_LEVEL_VERBOSE, SYSLOG_LEVEL_DEBUG1, SYSLOG_LEVEL_DEBUG2, SYSLOG_LEVEL_DEBUG3, SYSLOG_LEVEL_NOT_SET = -1 } LogLevel; u_int32_t bits = 0; int change_passphrase = 0; int change_comment = 0; int quiet = 0; int log_level = SYSLOG_LEVEL_INFO; int hash_hosts = 0; int find_host = 0; int delete_host = 0; int show_cert = 0; int print_fingerprint = 0; int print_bubblebabble = 0; char identity_file[1024]; int have_identity = 0; char *identity_passphrase = ((void *)0); char *identity_new_passphrase = ((void *)0); char *identity_comment = ((void *)0); char *ca_key_path = ((void *)0); unsigned long long cert_serial = 0; u_int cert_key_type = 1; char *cert_key_id = ((void *)0); char *cert_principals = ((void *)0); u_int32_t certflags_flags = ((1) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4)); int convert_to = 0; int convert_from = 0; enum { FMT_RFC4716, FMT_PKCS8, FMT_PEM } convert_format = FMT_RFC4716; int print_public = 0; int print_generic = 0; char *key_type_name = ((void *)0); char *pkcs11provider = ((void *)0); int use_new_format = 0; char *new_format_cipher = ((void *)0); int rounds = 0; extern char *__progname; char hostname[64]; static void do_download(struct passwd *pw) { Key **keys = ((void *)0); int i, nkeys; enum fp_rep rep; enum fp_type fptype; char *fp, *ra; fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; pkcs11_init(0); nkeys = pkcs11_add_provider(pkcs11provider, ((void *)0), &keys); if (nkeys <= 0) fatal("cannot read public key from pkcs11"); for (i = 0; i < nkeys; i++) { if (print_fingerprint) { fp = key_fingerprint(keys[i], fptype, rep); ra = key_fingerprint(keys[i], SSH_FP_MD5, SSH_FP_RANDOMART); printf("%u %s %s (PKCS11 key)\n", key_size(keys[i]), fp, key_type(keys[i])); if (log_level >= SYSLOG_LEVEL_VERBOSE) printf("%s\n", ra); free(ra); free(fp); key_write(keys[i], stdout); fprintf(stdout, "\n"); } key_free(keys[i]); } free(keys); exit(0); } static void do_fingerprint(struct passwd *pw) { FILE *f; Key *public; char *comment = ((void *)0), *cp, *ep, line[16 * 1024], *fp, *ra; int i, skip = 0, num = 0, invalid = 1; enum fp_rep rep; enum fp_type fptype; struct stat st; fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) { perror(identity_file); exit(1); } public = key_load_public(identity_file, &comment); if (public != ((void *)0)) { fp = key_fingerprint(public, fptype, rep); ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); printf("%u %s %s (%s)\n", key_size(public), fp, comment, key_type(public)); if (log_level >= SYSLOG_LEVEL_VERBOSE) printf("%s\n", ra); key_free(public); free(comment); free(ra); free(fp); exit(0); } if (comment) { free(comment); } if ((f = fopen(identity_file, "r")) == ((void *)0)) fatal("%s: %s: %s", __progname, identity_file, strerror((*__errno_location()))); while (fgets(line, sizeof(line), f)) { if ((cp = (__extension__ (__builtin_constant_p('\n') && !__builtin_constant_p(line) && ('\n') == '\0' ? (char *)__rawmemchr(line, '\n') : __builtin_strchr(line, '\n')))) == ((void *)0)) { error("line %d too long: %.40s...", num + 1, line); skip = 1; } num++; if (skip) { continue; } *cp = '\0'; for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; i = strtol(cp, &ep, 10); if (i == 0 || ep == ((void *)0) || (*ep != ' ' && *ep != '\t')) { int quoted = 0; comment = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; else if (*cp == '"') quoted = !quoted; } if (!*cp) continue; *cp++ = '\0'; } ep = cp; public = key_new(KEY_RSA1); if (key_read(public, &cp) != 1) { cp = ep; key_free(public); public = key_new(KEY_UNSPEC); if (key_read(public, &cp) != 1) { key_free(public); } } comment = *cp ? cp : comment; fp = key_fingerprint(public, fptype, rep); ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); printf("%u %s %s (%s)\n", key_size(public), fp, comment ? comment : "no comment", key_type(public)); if (log_level >= SYSLOG_LEVEL_VERBOSE) printf("%s\n", ra); free(ra); free(fp); key_free(public); invalid = 0; } fclose(f); if (invalid) { printf("%s is not a public key file.\n", identity_file); exit(1); } } static void do_gen_all_hostkeys(struct passwd *pw) { struct { char *key_type; char *key_type_display; char *path; } key_types[] = { { "rsa1", "RSA1", "/etc/ssh" "/ssh_host_key"} , { "rsa", "RSA", "/etc/ssh" "/ssh_host_rsa_key"} , { ((void *)0), ((void *)0), ((void *)0)} }; int first = 0; struct stat st; Key *private, *public; char comment[1024]; int i, type, fd; FILE *f; for (i = 0; key_types[i].key_type; i++) { if (stat(key_types[i].path, &st) == 0) continue; if ((*__errno_location()) != 2) { printf("Could not stat %s: %s", key_types[i].path, strerror((*__errno_location()))); } if (first == 0) { first = 1; printf("%s: generating new host keys: ", __progname); } printf("%s ", key_types[i].key_type_display); fflush(stdout); type = key_type_from_name(key_types[i].key_type); strlcpy(identity_file, key_types[i].path, sizeof(identity_file)); bits = 0; type_bits_valid(type, &bits); private = key_generate(type, bits); if (private == ((void *)0)) { fprintf(stderr, "key_generate failed\n"); } public = key_from_private(private); snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); if (!key_save_private (private, identity_file, "", comment, use_new_format, new_format_cipher, rounds)) { printf("Saving the key failed: %s.\n", identity_file); key_free(private); key_free(public); } key_free(private); strlcat(identity_file, ".pub", sizeof(identity_file)); fd = open(identity_file, 01 | 00000400 | 01000, 0644); if (fd == -1) { printf("Could not save your public key in %s\n", identity_file); key_free(public); } f = fdopen(fd, "w"); if (f == ((void *)0)) { printf("fdopen %s failed\n", identity_file); key_free(public); } if (!key_write(public, f)) { fprintf(stderr, "write key failed\n"); key_free(public); } fprintf(f, " %s\n", comment); fclose(f); key_free(public); } if (first != 0) printf("\n"); } static void do_known_hosts(struct passwd *pw, const char *name) { FILE *in, *out = stdout; Key *pub; char *cp, *cp2, *kp, *kp2; char line[16 * 1024], tmp[4096], old[4096]; int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0; int ca; int found_key = 0; if (!have_identity) { cp = tilde_expand_filename("~/" ".ssh" "/known_hosts", pw->pw_uid); if (strlcpy(identity_file, cp, sizeof(identity_file)) >= sizeof(identity_file)) fatal("Specified known hosts path too long"); free(cp); } if ((in = fopen(identity_file, "r")) == ((void *)0)) fatal("%s: %s: %s", __progname, identity_file, strerror((*__errno_location()))); if (!find_host && (hash_hosts || delete_host)) { if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) || strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) || strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) || strlcat(old, ".old", sizeof(old)) >= sizeof(old)) fatal("known_hosts path too long"); umask(077); if ((c = mkstemp(tmp)) == -1) fatal("mkstemp: %s", strerror((*__errno_location()))); if ((out = fdopen(c, "w")) == ((void *)0)) { c = (*__errno_location()); unlink(tmp); fatal("fdopen: %s", strerror(c)); } inplace = 1; } while (fgets(line, sizeof(line), in)) { if ((cp = (__extension__ (__builtin_constant_p('\n') && !__builtin_constant_p(line) && ('\n') == '\0' ? (char *)__rawmemchr(line, '\n') : __builtin_strchr(line, '\n')))) == ((void *)0)) { error("line %d too long: %.40s...", num + 1, line); skip = 1; invalid = 1; continue; } num++; if (skip) { continue; } for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') { if (inplace) fprintf(out, "%s\n", cp); } if (strncasecmp (cp, "@cert-authority", sizeof("@cert-authority") - 1) == 0 && (cp[sizeof("@cert-authority") - 1] == ' ' || cp[sizeof("@cert-authority") - 1] == '\t')) { ca = 1; cp += sizeof("@cert-authority"); } else ca = 0; for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++) ; if (*kp == '\0' || *(kp + 1) == '\0') { error("line %d missing key: %.40s...", num, line); } *kp++ = '\0'; pub = key_new(KEY_RSA1); if (key_read(pub, &kp) != 1) { kp = kp2; key_free(pub); pub = key_new(KEY_UNSPEC); if (key_read(pub, &kp) != 1) { error("line %d invalid key: %.40s...", num, line); key_free(pub); } } if (*cp == '|') { if (find_host || delete_host) { cp2 = host_hash(name, cp, strlen(cp)); if (cp2 == ((void *)0)) { error("line %d: invalid hashed " "name: %.64s...", num, line); } c = (__extension__( { size_t __s1_len, __s2_len; (__builtin_constant_p(cp2) && __builtin_constant_p(cp) && (__s1_len = strlen(cp2), __s2_len = strlen(cp), (!((size_t) (const void *)((cp2) + 1) - (size_t) (const void *)(cp2) == 1) || __s1_len >= 4) && (!((size_t) (const void *)((cp) + 1) - (size_t) (const void *)(cp) == 1) || __s2_len >= 4)) ? __builtin_strcmp(cp2, cp) : (__builtin_constant_p(cp2) && ((size_t) (const void *) ((cp2) + 1) - (size_t) (const void *)(cp2) == 1) && (__s1_len = strlen(cp2), __s1_len < 4) ? (__builtin_constant_p (cp) && ((size_t) (const void *)((cp) + 1) - (size_t) (const void *)(cp) == 1) ? __builtin_strcmp(cp2, cp) : (__extension__( { const unsigned char *__s2 = (const unsigned char *) (const char *) (cp); register int __result = (((const unsigned char *)(const char *)(cp2))[0] - __s2[0]); if (__s1_len > 0 && __result == 0) { } __result;} ))): (__builtin_constant_p(cp) && ((size_t) (const void *) ((cp) + 1) - (size_t) (const void *)(cp) == 1) && (__s2_len = strlen(cp), __s2_len < 4) ? (__builtin_constant_p (cp2) && ((size_t) (const void *)((cp2) + 1) - (size_t) (const void *)(cp2) == 1) ? __builtin_strcmp(cp2, cp) : (__extension__( { const unsigned char *__s1 = (const unsigned char *) (const char *) (cp2); register int __result = __s1 [0] - ((const unsigned char *)(const char *)(cp))[0]; __result;} ))): __builtin_strcmp(cp2, cp))));} ) == 0) ; if (find_host && c) { if (!quiet) printf("# Host %s found: " "line %d type %s%s\n", name, num, key_type(pub), ca ? " (CA key)" : ""); printhost(out, cp, pub, ca, 0); found_key = 1; } if (delete_host) { if (!c && !ca) printhost(out, cp, pub, ca, 0); else printf("# Host %s found: " "line %d type %s\n", name, num, key_type(pub)); } } else if (hash_hosts) printhost(out, cp, pub, ca, 0); if (find_host || delete_host) { c = (match_hostname(name, cp, strlen(cp)) == 1); if (find_host && c) { if (!quiet) printf("# Host %s found: " "line %d type %s%s\n", name, num, key_type(pub), ca ? " (CA key)" : ""); printhost(out, name, pub, ca, hash_hosts && !ca); } if (delete_host) { if (!c && !ca) printhost(out, cp, pub, ca, 0); else printf("# Host %s found: " "line %d type %s\n", name, num, key_type(pub)); } } else if (hash_hosts) { for (cp2 = __extension__( { char __r0, __r1, __r2; (__builtin_constant_p (",") && ((size_t) (const void *)((",") + 1) - (size_t) (const void *)(",") == 1) && (__r0 = ((const char *)(","))[0], ((const char *)(","))[0] != '\0') ? ((__r1 = ((const char *) (",")) [1], ((const char *) (",")) [1] == '\0') ? __strsep_1c (&cp, __r0) : ((__r2 = ((const char *)(","))[2], __r2 == '\0') ? __strsep_2c(&cp, __r0, __r1) : (((const char *)(","))[3] == '\0' ? __strsep_3c(&cp, __r0, __r1, __r2) : __strsep_g(&cp, ",")))) : __strsep_g(&cp, ","));} ); cp2 != ((void *)0) && *cp2 != '\0'; cp2 = __extension__( { char __r0, __r1, __r2; (__builtin_constant_p (",") && ((size_t) (const void *)((",") + 1) - (size_t) (const void *)(",") == 1) && (__r0 = ((const char *)(","))[0], ((const char *)(","))[0] != '\0') ? ((__r1 = ((const char *) (",")) [1], ((const char *) (",")) [1] == '\0') ? __strsep_1c (&cp, __r0) : ((__r2 = ((const char *)(","))[2], __r2 == '\0') ? __strsep_2c(&cp, __r0, __r1) : (((const char *)(","))[3] == '\0' ? __strsep_3c(&cp, __r0, __r1, __r2) : __strsep_g(&cp, ",")))) : __strsep_g(&cp, ","));} )) { if (ca) { fprintf(stderr, "Warning: " "ignoring CA key for host: " "%.64s\n", cp2); printhost(out, cp2, pub, ca, 0); } else if (__extension__( { char __r0, __r1, __r2; (__builtin_constant_p ("*?!") && ((size_t) (const void *)(("*?!") + 1) - (size_t) (const void *)("*?!") == 1) ? ((__builtin_constant_p(cp2) && ((size_t) (const void *)((cp2) + 1) - (size_t) (const void *)(cp2) == 1)) ? __builtin_strcspn(cp2, "*?!") : ((__r0 = ((const char *)("*?!"))[0], __r0 == '\0') ? strlen(cp2) : ((__r1 = ((const char *)("*?!"))[1], __r1 == '\0') ? __strcspn_c1(cp2, __r0) : ((__r2 = ((const char *)("*?!"))[2], __r2 == '\0') ? __strcspn_c2(cp2, __r0, __r1) : (((const char *)("*?!"))[3] == '\0' ? __strcspn_c3(cp2, __r0, __r1, __r2) : __builtin_strcspn(cp2, "*?!")))))) : __builtin_strcspn(cp2, "*?!"));} ) != strlen(cp2)) { fprintf(stderr, "Warning: " "ignoring host name with " "metacharacters: %.64s\n", cp2); printhost(out, cp2, pub, ca, 0); } else printhost(out, cp2, pub, ca, 1); } has_unhashed = 1; } } key_free(pub); } fclose(in); if (invalid) { fprintf(stderr, "%s is not a valid known_hosts file.\n", identity_file); if (inplace) { fprintf(stderr, "Not replacing existing known_hosts " "file because of errors\n"); fclose(out); unlink(tmp); } exit(1); } if (inplace) { fclose(out); if (unlink(old) == -1 && (*__errno_location()) != 2) fatal("unlink %.100s: %s", old, strerror((*__errno_location()))); if (link(identity_file, old) == -1) fatal("link %.100s to %.100s: %s", identity_file, old, strerror((*__errno_location()))); if (rename(tmp, identity_file) == -1) { error("rename\"%s\" to \"%s\": %s", tmp, identity_file, strerror((*__errno_location()))); unlink(tmp); unlink(old); exit(1); } fprintf(stderr, "%s updated.\n", identity_file); fprintf(stderr, "Original contents retained as %s\n", old); if (has_unhashed) { fprintf(stderr, "WARNING: %s contains unhashed " "entries\n", old); fprintf(stderr, "Delete this file to ensure privacy " "of hostnames\n"); } } exit(find_host && !found_key); } static void do_change_passphrase(struct passwd *pw) { char *comment; char *old_passphrase, *passphrase1, *passphrase2; struct stat st; Key *private; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) { perror(identity_file); exit(1); } private = key_load_private(identity_file, "", &comment); if (private == ((void *)0)) { if (identity_passphrase) old_passphrase = xstrdup(identity_passphrase); else old_passphrase = read_passphrase("Enter old passphrase: ", 0x0002); private = key_load_private(identity_file, old_passphrase, &comment); explicit_bzero(old_passphrase, strlen(old_passphrase)); free(old_passphrase); if (private == ((void *)0)) { printf("Bad passphrase.\n"); exit(1); } } printf("Key has comment '%s'\n", comment); if (identity_new_passphrase) { passphrase1 = xstrdup(identity_new_passphrase); } else { passphrase1 = read_passphrase("Enter new passphrase (empty for no " "passphrase): ", 0x0002); passphrase2 = read_passphrase("Enter same passphrase again: ", 0x0002); if (__extension__( { size_t __s1_len, __s2_len; (__builtin_constant_p(passphrase1) && __builtin_constant_p(passphrase2) && (__s1_len = strlen(passphrase1), __s2_len = strlen(passphrase2), (!((size_t) (const void *) ((passphrase1) + 1) - (size_t) (const void *)(passphrase1) == 1) || __s1_len >= 4) && (!((size_t) (const void *) ((passphrase2) + 1) - (size_t) (const void *)(passphrase2) == 1) || __s2_len >= 4)) ? __builtin_strcmp(passphrase1, passphrase2) : (__builtin_constant_p(passphrase1) && ((size_t) (const void *) ((passphrase1) + 1) - (size_t) (const void *)(passphrase1) == 1) && (__s1_len = strlen(passphrase1), __s1_len < 4) ? (__builtin_constant_p(passphrase2) && ((size_t) (const void *) ((passphrase2) + 1) - (size_t) (const void *)(passphrase2) == 1) ? __builtin_strcmp(passphrase1, passphrase2) : (__extension__( { const unsigned char *__s2 = (const unsigned char *)(const char *)(passphrase2); register int __result = (((const unsigned char *)(const char *)(passphrase1)) [0] - __s2[0]); __result;} ))): (__builtin_constant_p(passphrase2) && ((size_t) (const void *) ((passphrase2) + 1) - (size_t) (const void *)(passphrase2) == 1) && (__s2_len = strlen(passphrase2), __s2_len < 4) ? (__builtin_constant_p (passphrase1) && ((size_t) (const void *) ((passphrase1) + 1) - (size_t) (const void *)(passphrase1) == 1) ? __builtin_strcmp(passphrase1, passphrase2) : (__extension__( { const unsigned char *__s1 = (const unsigned char *)(const char *) (passphrase1); register int __result = __s1[0] - ((const unsigned char *)(const char *) (passphrase2)) [0]; if (__s2_len > 0 && __result == 0) { } __result;} ))): __builtin_strcmp(passphrase1, passphrase2))));} ) != 0) { explicit_bzero(passphrase1, strlen(passphrase1)); explicit_bzero(passphrase2, strlen(passphrase2)); free(passphrase1); free(passphrase2); printf("Pass phrases do not match. Try again.\n"); exit(1); } explicit_bzero(passphrase2, strlen(passphrase2)); free(passphrase2); } if (!key_save_private (private, identity_file, passphrase1, comment, use_new_format, new_format_cipher, rounds)) { printf("Saving the key failed: %s.\n", identity_file); explicit_bzero(passphrase1, strlen(passphrase1)); free(passphrase1); key_free(private); free(comment); exit(1); } explicit_bzero(passphrase1, strlen(passphrase1)); free(passphrase1); key_free(private); free(comment); printf("Your identification has been saved with the new passphrase.\n"); exit(0); } static void do_change_comment(struct passwd *pw) { char new_comment[1024], *comment, *passphrase; Key *private; Key *public; struct stat st; FILE *f; int fd; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) { perror(identity_file); exit(1); } private = key_load_private(identity_file, "", &comment); if (private == ((void *)0)) { if (identity_passphrase) passphrase = xstrdup(identity_passphrase); else if (identity_new_passphrase) passphrase = xstrdup(identity_new_passphrase); else passphrase = read_passphrase("Enter passphrase: ", 0x0002); private = key_load_private(identity_file, passphrase, &comment); if (private == ((void *)0)) { explicit_bzero(passphrase, strlen(passphrase)); free(passphrase); printf("Bad passphrase.\n"); exit(1); } passphrase = xstrdup(""); } if (private->type != KEY_RSA1) { fprintf(stderr, "Comments are only supported for RSA1 keys.\n"); key_free(private); exit(1); } printf("Key now has comment '%s'\n", comment); if (identity_comment) { strlcpy(new_comment, identity_comment, sizeof(new_comment)); printf("Enter new comment: "); fflush(stdout); if (!fgets(new_comment, sizeof(new_comment), stdin)) { explicit_bzero(passphrase, strlen(passphrase)); key_free(private); exit(1); } new_comment[__extension__( { char __r0, __r1, __r2; (__builtin_constant_p("\n") && ((size_t) (const void *)(("\n") + 1) - (size_t) (const void *)("\n") == 1) ? ((__builtin_constant_p(new_comment) && ((size_t) (const void *) ((new_comment) + 1) - (size_t) (const void *)(new_comment) == 1)) ? __builtin_strcspn(new_comment, "\n") : ((__r0 = ((const char *)("\n"))[0], __r0 == '\0') ? strlen(new_comment) : ((__r1 = ((const char *)("\n"))[1], __r1 == '\0') ? __strcspn_c1(new_comment, __r0) : ((__r2 = ((const char *)("\n"))[2], __r2 == '\0') ? __strcspn_c2(new_comment, __r0, __r1) : (((const char *)("\n"))[3] == '\0' ? __strcspn_c3(new_comment, __r0, __r1, __r2) : __builtin_strcspn(new_comment, "\n")))))) : __builtin_strcspn(new_comment, "\n"));} )] = '\0'; } if (!key_save_private (private, identity_file, passphrase, new_comment, use_new_format, new_format_cipher, rounds)) { printf("Saving the key failed: %s.\n", identity_file); explicit_bzero(passphrase, strlen(passphrase)); free(passphrase); key_free(private); free(comment); exit(1); } explicit_bzero(passphrase, strlen(passphrase)); free(passphrase); public = key_from_private(private); key_free(private); strlcat(identity_file, ".pub", sizeof(identity_file)); fd = open(identity_file, 01 | 00000400 | 01000, 0644); if (fd == -1) { printf("Could not save your public key in %s\n", identity_file); exit(1); } f = fdopen(fd, "w"); if (f == ((void *)0)) { printf("fdopen %s failed\n", identity_file); exit(1); } if (!key_write(public, f)) fprintf(stderr, "write key failed\n"); key_free(public); fprintf(f, " %s\n", new_comment); fclose(f); free(comment); printf("The comment in your key file has been changed.\n"); exit(0); } static const char *fmt_validity(u_int64_t valid_from, u_int64_t valid_to) { char from[32], to[32]; static char ret[64]; time_t tt; struct tm *tm; *from = *to = '\0'; if (valid_from == 0 && valid_to == 0xffffffffffffffffULL) return "forever"; if (valid_from != 0) { tt = valid_from > 2147483647 ? 2147483647 : valid_from; tm = localtime(&tt); strftime(from, sizeof(from), "%Y-%m-%dT%H:%M:%S", tm); } if (valid_to != 0xffffffffffffffffULL) { tt = valid_to > 2147483647 ? 2147483647 : valid_to; tm = localtime(&tt); strftime(to, sizeof(to), "%Y-%m-%dT%H:%M:%S", tm); } if (valid_from == 0) { snprintf(ret, sizeof(ret), "before %s", to); } if (valid_to == 0xffffffffffffffffULL) { snprintf(ret, sizeof(ret), "after %s", from); } snprintf(ret, sizeof(ret), "from %s to %s", from, to); } static void do_show_cert(struct passwd *pw) { Key *key; struct stat st; char *key_fp, *ca_fp; u_int i, v00; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); if (stat(identity_file, &st) < 0) fatal("%s: %s: %s", __progname, identity_file, strerror((*__errno_location()))); if ((key = key_load_public(identity_file, ((void *)0))) == ((void *)0)) fatal("%s is not a public key", identity_file); if (!key_is_cert(key)) fatal("%s is not a certificate", identity_file); v00 = key->type == KEY_RSA_CERT_V00 || key->type == KEY_DSA_CERT_V00; key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); ca_fp = key_fingerprint(key->cert->signature_key, SSH_FP_MD5, SSH_FP_HEX); printf("%s:\n", identity_file); printf(" Type: %s %s certificate\n", key_ssh_name(key), key_cert_type(key)); printf(" Public key: %s %s\n", key_type(key), key_fp); printf(" Signing CA: %s %s\n", key_type(key->cert->signature_key), ca_fp); printf(" Key ID: \"%s\"\n", key->cert->key_id); if (!v00) { printf(" Serial: %llu\n", (unsigned long long)key->cert->serial); } printf(" Valid: %s\n", fmt_validity(key->cert->valid_after, key->cert->valid_before)); printf(" Principals: "); if (key->cert->nprincipals == 0) printf("(none)\n"); else { for (i = 0; i < key->cert->nprincipals; i++) printf("\n %s", key->cert->principals[i]); printf("\n"); } printf(" Critical Options: "); if (buffer_len(&key->cert->critical) == 0) printf("(none)\n"); else { printf("\n"); show_options(&key->cert->critical, v00, 1); } if (!v00) { printf(" Extensions: "); if (buffer_len(&key->cert->extensions) == 0) printf("(none)\n"); else { printf("\n"); show_options(&key->cert->extensions, v00, 0); } } exit(0); } static void do_gen_krl(struct passwd *pw, int updating, int argc, char **argv) { struct ssh_krl *krl; struct stat sb; Key *ca = ((void *)0); int fd, i; char *tmp; Buffer kbuf; if (*identity_file == '\0') fatal("KRL generation requires an output file"); if (stat(identity_file, &sb) == -1) { if ((*__errno_location()) != 2) fatal("Cannot access KRL \"%s\": %s", identity_file, strerror((*__errno_location()))); if (updating) fatal("KRL \"%s\" does not exist", identity_file); } if (ca_key_path != ((void *)0)) { tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); if ((ca = key_load_public(tmp, ((void *)0))) == ((void *)0)) fatal("Cannot load CA public key %s", tmp); free(tmp); } if (updating) load_krl(identity_file, &krl); else if ((krl = ssh_krl_init()) == ((void *)0)) fatal("couldn't create KRL"); if (cert_serial != 0) ssh_krl_set_version(krl, cert_serial); if (identity_comment != ((void *)0)) ssh_krl_set_comment(krl, identity_comment); for (i = 0; i < argc; i++) update_krl_from_file(pw, argv[i], ca, krl); buffer_init(&kbuf); if (ssh_krl_to_blob(krl, &kbuf, ((void *)0), 0) != 0) fatal("Couldn't generate KRL"); if ((fd = open(identity_file, 01 | 00000400 | 01000, 0644)) == -1) fatal("open %s: %s", identity_file, strerror((*__errno_location()))); if (atomicio ((ssize_t(*)(int, void *, size_t))write, fd, buffer_ptr(&kbuf), buffer_len(&kbuf)) != buffer_len(&kbuf)) fatal("write %s: %s", identity_file, strerror((*__errno_location()))); close(fd); buffer_free(&kbuf); ssh_krl_free(krl); if (ca != ((void *)0)) key_free(ca); } static void usage(void) { exit(1); } int main(int argc, char **argv) { char dotsshdir[4096], comment[1024], *passphrase1, *passphrase2; char *checkpoint = ((void *)0); char out_file[4096], *ep, *rr_hostname = ((void *)0); Key *private, *public; struct passwd *pw; struct stat st; int opt, type, fd; u_int32_t memory = 0, generator_wanted = 0; int do_gen_candidates = 0, do_screen_candidates = 0; int gen_all_hostkeys = 0, gen_krl = 0, update_krl = 0, check_krl = 0; unsigned long start_lineno = 0, lines_to_process = 0; BIGNUM *start = ((void *)0); FILE *f; const char *errstr; extern char *BSDoptarg; sanitise_stdfd(); __progname = ssh_get_progname(argv[0]); ssh_OpenSSL_add_all_algorithms(); log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1); seed_rng(); pw = getpwuid(getuid()); if (!pw) { printf("No user exists for uid %lu\n", (u_long) getuid()); exit(1); } if (gethostname(hostname, sizeof(hostname)) < 0) { perror("gethostname"); exit(1); } while ((opt = BSDgetopt(argc, argv, "ABHLQXceghiklopquvxy" "C:D:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:a:b:f:g:j:m:n:r:s:t:z:")) != -1) { switch (opt) { case 'A': gen_all_hostkeys = 1; case 'b': bits = (u_int32_t) strtonum(BSDoptarg, 256, 32768, &errstr); if (errstr) fatal("Bits has bad value %s (%s)", BSDoptarg, errstr); case 'F': find_host = 1; rr_hostname = BSDoptarg; break; case 'H': hash_hosts = 1; case 'I': cert_key_id = BSDoptarg; case 'J': lines_to_process = strtoul(BSDoptarg, ((void *)0), 10); case 'j': start_lineno = strtoul(BSDoptarg, ((void *)0), 10); case 'R': delete_host = 1; rr_hostname = BSDoptarg; break; case 'L': show_cert = 1; case 'l': print_fingerprint = 1; case 'B': print_bubblebabble = 1; case 'm': if (strcasecmp(BSDoptarg, "RFC4716") == 0 || strcasecmp(BSDoptarg, "ssh2") == 0) { convert_format = FMT_RFC4716; } if (strcasecmp(BSDoptarg, "PKCS8") == 0) { convert_format = FMT_PKCS8; } if (strcasecmp(BSDoptarg, "PEM") == 0) { convert_format = FMT_PEM; } fatal("Unsupported conversion format \"%s\"", BSDoptarg); case 'n': cert_principals = BSDoptarg; case 'o': use_new_format = 1; case 'p': change_passphrase = 1; case 'c': change_comment = 1; case 'f': if (strlcpy (identity_file, BSDoptarg, sizeof(identity_file)) >= sizeof(identity_file)) fatal("Identity filename too long"); have_identity = 1; case 'g': print_generic = 1; case 'P': identity_passphrase = BSDoptarg; case 'N': identity_new_passphrase = BSDoptarg; case 'Q': check_krl = 1; case 'O': add_cert_option(BSDoptarg); case 'Z': new_format_cipher = BSDoptarg; case 'C': identity_comment = BSDoptarg; case 'q': quiet = 1; case 'e': case 'x': convert_to = 1; case 'h': cert_key_type = 2; certflags_flags = 0; case 'k': gen_krl = 1; case 'i': case 'X': convert_from = 1; case 'y': print_public = 1; case 's': ca_key_path = BSDoptarg; case 't': key_type_name = BSDoptarg; case 'D': pkcs11provider = BSDoptarg; case 'u': update_krl = 1; case 'v': if (log_level == SYSLOG_LEVEL_INFO) log_level = SYSLOG_LEVEL_DEBUG1; else { if (log_level >= SYSLOG_LEVEL_DEBUG1 && log_level < SYSLOG_LEVEL_DEBUG3) log_level++; } case 'r': rr_hostname = BSDoptarg; case 'W': generator_wanted = (u_int32_t) strtonum(BSDoptarg, 1, (2147483647 * 2U + 1U), &errstr); if (errstr) fatal ("Desired generator has bad value: %s (%s)", BSDoptarg, errstr); case 'a': rounds = (int)strtonum(BSDoptarg, 1, 2147483647, &errstr); if (errstr) fatal("Invalid number: %s (%s)", BSDoptarg, errstr); case 'M': memory = (u_int32_t) strtonum(BSDoptarg, 1, (2147483647 * 2U + 1U), &errstr); if (errstr) fatal("Memory limit is %s: %s", errstr, BSDoptarg); case 'G': do_gen_candidates = 1; if (strlcpy(out_file, BSDoptarg, sizeof(out_file)) >= sizeof(out_file)) fatal("Output filename too long"); case 'T': do_screen_candidates = 1; if (strlcpy(out_file, BSDoptarg, sizeof(out_file)) >= sizeof(out_file)) fatal("Output filename too long"); case 'K': if (strlen(BSDoptarg) >= 4096) fatal("Checkpoint filename too long"); checkpoint = xstrdup(BSDoptarg); break; case 'S': if (BN_hex2bn(&start, BSDoptarg) == 0) fatal("Invalid start point."); case 'V': parse_cert_times(BSDoptarg); case 'z': (*__errno_location()) = 0; cert_serial = strtoull(BSDoptarg, &ep, 10); if (*BSDoptarg < '0' || *BSDoptarg > '9' || *ep != '\0' || ((*__errno_location()) == 34 && cert_serial == (9223372036854775807LL * 2ULL + 1))) fatal("Invalid serial number \"%s\"", BSDoptarg); case '?': default: usage(); } } log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1); if (ca_key_path != ((void *)0)) { if (argc < 1 && !gen_krl) { printf("Too few arguments.\n"); usage(); } } else if (argc > 0 && !gen_krl && !check_krl) { printf("Too many arguments.\n"); } if (change_passphrase && change_comment) { printf("Can only have one of -p and -c.\n"); usage(); } if (print_fingerprint && (delete_host || hash_hosts)) { printf("Cannot use -l with -H or -R.\n"); usage(); } if (gen_krl) { do_gen_krl(pw, update_krl, argc, argv); return (0); } if (check_krl) { do_check_krl(pw, argc, argv); } if (ca_key_path != ((void *)0)) { if (cert_key_id == ((void *)0)) fatal("Must specify key id (-I) when certifying"); do_ca_sign(pw, argc, argv); } if (show_cert) do_show_cert(pw); if (delete_host || hash_hosts || find_host) do_known_hosts(pw, rr_hostname); if (pkcs11provider != ((void *)0)) do_download(pw); if (print_fingerprint || print_bubblebabble) do_fingerprint(pw); if (change_passphrase) do_change_passphrase(pw); if (change_comment) do_change_comment(pw); if (convert_to) do_convert_to(pw); if (convert_from) do_convert_from(pw); if (print_public) do_print_public(pw); if (rr_hostname != ((void *)0)) { unsigned int n = 0; if (have_identity) { n = do_print_resource_record(pw, identity_file, rr_hostname); if (n == 0) { perror(identity_file); exit(1); } exit(0); } else { n += do_print_resource_record(pw, "/etc/ssh" "/ssh_host_rsa_key", rr_hostname); n += do_print_resource_record(pw, "/etc/ssh" "/ssh_host_dsa_key", rr_hostname); n += do_print_resource_record(pw, "/etc/ssh" "/ssh_host_ecdsa_key", rr_hostname); if (n == 0) fatal("no keys found."); exit(0); } } if (do_gen_candidates) { FILE *out = fopen(out_file, "w"); if (out == ((void *)0)) { error("Couldn't open modulus candidate file \"%s\": %s", out_file, strerror((*__errno_location()))); } if (bits == 0) bits = 2048; if (gen_candidates(out, memory, bits, start) != 0) fatal("modulus candidate generation failed"); } if (do_screen_candidates) { FILE *in; FILE *out = fopen(out_file, "a"); if (have_identity && __extension__( { size_t __s1_len, __s2_len; (__builtin_constant_p (identity_file) && __builtin_constant_p("-") && (__s1_len = strlen(identity_file), __s2_len = strlen("-"), (!((size_t) (const void *)((identity_file) + 1) - (size_t) (const void *) (identity_file) == 1) || __s1_len >= 4) && (!((size_t) (const void *)(("-") + 1) - (size_t) (const void *)("-") == 1) || __s2_len >= 4)) ? __builtin_strcmp (identity_file, "-") : (__builtin_constant_p (identity_file) && ((size_t) (const void *) ((identity_file) + 1) - (size_t) (const void *) (identity_file) == 1) && (__s1_len = strlen (identity_file), __s1_len < 4) ? (__builtin_constant_p ("-") && ((size_t) (const void *)(("-") + 1) - (size_t) (const void *)("-") == 1) ? __builtin_strcmp (identity_file, "-") : (__extension__( { const unsigned char *__s2 = (const unsigned char *) (const char *) ("-"); register int __result = (((const unsigned char *)(const char *)(identity_file))[0] - __s2[0]); __result;} ))): (__builtin_constant_p ("-") && ((size_t) (const void *) (("-") + 1) - (size_t) (const void *)("-") == 1) && (__s2_len = strlen("-"), __s2_len < 4) ? (__builtin_constant_p (identity_file) && ((size_t) (const void *)((identity_file) + 1) - (size_t) (const void *) (identity_file) == 1) ? __builtin_strcmp (identity_file, "-") : (__extension__( { const unsigned char *__s1 = (const unsigned char *) (const char *) (identity_file); register int __result = __s1 [0] - ((const unsigned char *)(const char *)("-"))[0]; if (__s2_len > 0 && __result == 0) { __result = (__s1 [1] - ((const unsigned char *)(const char *)("-"))[1]);} __result;} ))): __builtin_strcmp (identity_file, "-"))));} ) != 0) { if ((in = fopen(identity_file, "r")) == ((void *)0)) { fatal("Couldn't open modulus candidate " "file \"%s\": %s", identity_file, strerror((*__errno_location()))); } } else in = stdin; if (out == ((void *)0)) { fatal("Couldn't open moduli file \"%s\": %s", out_file, strerror((*__errno_location()))); } if (prime_test (in, out, rounds == 0 ? 100 : rounds, generator_wanted, checkpoint, start_lineno, lines_to_process) != 0) fatal("modulus screening failed"); } if (gen_all_hostkeys) { do_gen_all_hostkeys(pw); } if (key_type_name == ((void *)0)) key_type_name = "rsa"; type = key_type_from_name(key_type_name); type_bits_valid(type, &bits); if (!quiet) printf("Generating public/private %s key pair.\n", key_type_name); private = key_generate(type, bits); if (private == ((void *)0)) { fprintf(stderr, "key_generate failed\n"); exit(1); } public = key_from_private(private); if (!have_identity) ask_filename(pw, "Enter file in which to save the key"); snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, ".ssh"); if (strstr(identity_file, dotsshdir) != ((void *)0)) { if (stat(dotsshdir, &st) < 0) { if ((*__errno_location()) != 2) { error("Could not stat %s: %s", dotsshdir, strerror((*__errno_location()))); } else if (mkdir(dotsshdir, 0700) < 0) { error("Could not create directory '%s': %s", dotsshdir, strerror((*__errno_location()))); } else if (!quiet) printf("Created directory '%s'.\n", dotsshdir); } } if (stat(identity_file, &st) >= 0) { char yesno[3]; printf("%s already exists.\n", identity_file); printf("Overwrite (y/n)? "); fflush(stdout); if (fgets(yesno, sizeof(yesno), stdin) == ((void *)0)) exit(1); if (yesno[0] != 'y' && yesno[0] != 'Y') exit(1); } if (identity_passphrase) passphrase1 = xstrdup(identity_passphrase); else if (identity_new_passphrase) passphrase1 = xstrdup(identity_new_passphrase); else { passphrase_again:passphrase1 = read_passphrase("Enter passphrase (empty for no " "passphrase): ", 0x0002); passphrase2 = read_passphrase("Enter same passphrase again: ", 0x0002); if (__extension__( { size_t __s1_len, __s2_len; (__builtin_constant_p(passphrase1) && __builtin_constant_p(passphrase2) && (__s1_len = strlen(passphrase1), __s2_len = strlen(passphrase2), (!((size_t) (const void *) ((passphrase1) + 1) - (size_t) (const void *)(passphrase1) == 1) || __s1_len >= 4) && (!((size_t) (const void *) ((passphrase2) + 1) - (size_t) (const void *)(passphrase2) == 1) || __s2_len >= 4)) ? __builtin_strcmp(passphrase1, passphrase2) : (__builtin_constant_p(passphrase1) && ((size_t) (const void *) ((passphrase1) + 1) - (size_t) (const void *)(passphrase1) == 1) && (__s1_len = strlen(passphrase1), __s1_len < 4) ? (__builtin_constant_p(passphrase2) && ((size_t) (const void *) ((passphrase2) + 1) - (size_t) (const void *)(passphrase2) == 1) ? __builtin_strcmp(passphrase1, passphrase2) : (__extension__( { const unsigned char *__s2 = (const unsigned char *)(const char *)(passphrase2); register int __result = (((const unsigned char *)(const char *)(passphrase1)) [0] - __s2[0]); __result;} ))): (__builtin_constant_p(passphrase2) && ((size_t) (const void *) ((passphrase2) + 1) - (size_t) (const void *)(passphrase2) == 1) && (__s2_len = strlen(passphrase2), __s2_len < 4) ? (__builtin_constant_p (passphrase1) && ((size_t) (const void *) ((passphrase1) + 1) - (size_t) (const void *)(passphrase1) == 1) ? __builtin_strcmp(passphrase1, passphrase2) : (__extension__( { const unsigned char *__s1 = (const unsigned char *)(const char *) (passphrase1); register int __result = __s1[0] - ((const unsigned char *)(const char *) (passphrase2)) [0]; __result;} ))): __builtin_strcmp(passphrase1, passphrase2))));} ) != 0) { explicit_bzero(passphrase1, strlen(passphrase1)); explicit_bzero(passphrase2, strlen(passphrase2)); free(passphrase1); free(passphrase2); printf("Passphrases do not match. Try again.\n"); } explicit_bzero(passphrase2, strlen(passphrase2)); free(passphrase2); } if (identity_comment) { strlcpy(comment, identity_comment, sizeof(comment)); snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); } if (!key_save_private (private, identity_file, passphrase1, comment, use_new_format, new_format_cipher, rounds)) { printf("Saving the key failed: %s.\n", identity_file); explicit_bzero(passphrase1, strlen(passphrase1)); free(passphrase1); exit(1); } explicit_bzero(passphrase1, strlen(passphrase1)); free(passphrase1); if (!quiet) printf("Your identification has been saved in %s.\n", identity_file); strlcat(identity_file, ".pub", sizeof(identity_file)); if (!key_write(public, f)) fprintf(stderr, "write key failed\n"); fprintf(f, " %s\n", comment); fclose(f); if (!quiet) { char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); char *ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART); printf("Your public key has been saved in %s.\n", identity_file); printf("The key fingerprint is:\n"); printf("%s %s\n", fp, comment); printf("The key's randomart image is:\n"); printf("%s\n", ra); free(ra); free(fp); } }