/* $Id: fish-keygen.c,v 1.25 1999/08/19 23:33:10 levitte Exp $ */ #include "gnu_extras.h" #if defined(__DECC) || defined(__GNUC__) #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __GNUC__ #define __DECC #endif #include #include #include #ifdef __GNUC__ #undef __DECC #endif #include "fish.h" #include "ssh.h" #include "util.h" #include "vms.h" #include "fishmsg.h" #include "fish-keygen.h" #include "buffer.h" #include "userkey.h" /* Because it isn't really supported with DEC C 4.0 source */ #if defined(__DECC) && !defined(__MODE_T) # define __MODE_T 1 typedef __mode_t mode_t; #endif /* The identity file has the following format: Unencrypted section: 33 bytes: AUTHFILE_ID_STRING (including a NUL!) 1 byte: cipher type number 1 32bit: a dummy? 1 32bit: number of RSA key bits 1 bignum: RSA n 1 bignum: RSA e 1 string: comment string Encrypted section (encrypted with the cipher type given in the unencrypted section, with a user-provided password that has been run through MD5): 4 bytes: byte 1 == byte 3 and byte 2 == byte 4 1 bignum: RSA d 1 bignum: RSA q mod p 1 bignum: RSA p 1 bignum: RSA q */ #if defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER < 0x00904000L) static void rsa_cb(int p, int n, char *arg) #else static void rsa_cb(int p, int n, void *arg) #endif { char c = '.'; if (p == 1) c = '+'; if (p == 2) c = '*'; if (p == 3) c = '\n'; putc(c, stderr); fflush(stderr); } int create_keyfile(ssh_prefs *sshprefs, userkey *uk, general_buffer *passphrase, char *passphrase_prompt1, char *passphrase_prompt2) { int fd; FILE *f; int status; char buf[1024], ret[1024], ret2[1024], *p; char auth_id[] = AUTHFILE_ID_STRING; mode_t save_mask; int bytes_written; general_buffer *keybuf = buf_init(0); if (access(sshprefs->identity_file, F_OK) >= 0 && sshprefs->whattodo == KEYGEN) { buf_destroy(keybuf); return FISH_M_NOOVERWR; } if (uk == 0) { uk = userkey_init(); uk->cipher_type = sshprefs->cipher_type; uk->bits = sshprefs->bits; uk->comment = sshprefs->comment; uk->encrypted_data = 0; uk->encrypted_len = 0; uk->key = 0; } if (uk->comment == 0) uk->comment = sshprefs->comment; if (uk->key == 0) uk->key = RSA_generate_key(uk->bits, 65537, rsa_cb, NULL); if (passphrase_prompt1 == 0) passphrase_prompt1 = "Passphrase for '%s': "; if (passphrase_prompt2 == 0) passphrase_prompt2 = "Verify passphrase for '%s': "; if (passphrase == 0) { passphrase_again: sprintf(buf, passphrase_prompt1, uk->comment); if (!read_prompted("TT:", buf, ret, 1023, 0, 0, &status)) { lib_put_output(""); lib$signal(status); } lib_put_output(""); sprintf(buf, passphrase_prompt2, uk->comment); if (!read_prompted("TT:", buf, ret2, 1023, 0, 0, &status)) { lib_put_output(""); lib$signal(status); } lib_put_output(""); if (strcmp(ret, ret2) != 0) { /* Passphrases do not match. Zero passphrases and exit! */ memset(ret, 0, sizeof(ret)); memset(ret2, 0, sizeof(ret2)); lib$signal(FISH_M_PWDNOTVER); goto passphrase_again; } passphrase = buf_init(strlen(ret)); buf_append_chars_nocount(passphrase, ret); memset(ret2, 0, sizeof(ret2)); memset(ret, 0, sizeof(ret)); } status = userkey_encrypt_private_part(uk, passphrase); buf_destroy(passphrase); if (!$VMS_STATUS_SUCCESS(status)) { buf_destroy(keybuf); lib$signal(status); return status | 0x10000000; } status = userkey_encode_buffer(uk, &keybuf); if (!$VMS_STATUS_SUCCESS(status)) { buf_destroy(keybuf); lib$signal(status); return status | 0x10000000; } if (access(sshprefs->identity_file, F_OK) >= 0 && sshprefs->whattodo == KEYGEN) { buf_destroy(keybuf); return FISH_M_NOOVERWR; } if ((fd = open(sshprefs->identity_file, O_CREAT|O_WRONLY, 0600)) == -1) { char *p,*end,*end2; /* Rough but fine */ p = (char *) xmalloc( sizeof(char) * strlen(sshprefs->identity_file)); strcpy(p,sshprefs->identity_file); end = strrchr(p,']')+1; end2 = strrchr(p,'>')+1; if (end2 > end) end = end2; *end = '\0'; /* I used mask 0 i.e. the protection set by SET FILE/PROT[=...]/DEFAULT */ if( mkdir(p,0) != 0){ lib$signal(FISH_M_CREATEFAIL, 1, p, vaxc$errno); } lib$signal(FISH_M_CREATED, 1, p); _xfree(p); /* Now we try again */ if ((fd = open(sshprefs->identity_file, O_CREAT|O_WRONLY, 0600)) == -1) { lib$signal(FISH_M_INVFILE, 2, sshprefs->identity_file, strerror(errno, vaxc$errno)); return FISH_M_INVFILE | 0x10000000; } } write(fd, buf_bytes(keybuf), buf_amount(keybuf)); buf_destroy(keybuf); close(fd); /* Uhmmm, keybuf is now not really used for keys any more... */ keybuf = buf_init(0); buf_append_chars_nocount(keybuf, "Your identification has been saved in "); buf_append_chars_nocount(keybuf, sshprefs->identity_file); lib_put_output(buf_chars(keybuf)); buf_destroy(keybuf); lib_put_output("Your public key is:"); keybuf = buf_init(30); sprintf(buf_bytes(keybuf), "%d ", sshprefs->bits); buf_adjust_amount_by(keybuf, strlen(buf_bytes(keybuf))); buf_append_chars_nocount(keybuf, p = BN_bn2dec(uk->key->e)); xfree(p); buf_append_chars_nocount(keybuf, " "); buf_append_chars_nocount(keybuf, p = BN_bn2dec(uk->key->n)); xfree(p); buf_append_chars_nocount(keybuf, " "); buf_append_chars_nocount(keybuf, sshprefs->comment); lib_put_output(buf_chars(keybuf)); strcpy(ret, sshprefs->identity_file); strcat(ret, "-PUB"); if ((f = fopen(ret, "w")) == NULL) { lib$signal(FISH_M_INVFILE, 2, ret, strerror(errno, vaxc$errno)); return FISH_M_INVFILE | 0x10000000; } fprintf(f, "%s\n", buf_chars(keybuf)); buf_destroy(keybuf); fclose(f); keybuf = buf_init(80); buf_append_chars_nocount(keybuf, "Your public key has been saved in "); buf_append_chars_nocount(keybuf, ret); lib_put_output(buf_chars(keybuf)); buf_destroy(keybuf); userkey_destroy(uk); return SS$_NORMAL; } int change_keyfile(ssh_prefs *sshprefs) { userkey uk; int passphrase_times = 3; general_buffer *passphrase = buf_init(0); int status; status = userkey_read_keyfile(&uk, sshprefs->identity_file, sshprefs->uai.uic); if (!$VMS_STATUS_SUCCESS(status)) { lib$signal(FISH_M_INVFILE, 2, sshprefs->identity_file, strerror(errno, vaxc$errno), status); return FISH_M_INVFILE | 0x10000000; } while ((status = userkey_decrypt_private_part(&uk, passphrase)) == FISH_M_UKBADPASS && (!buf_amount(passphrase) || passphrase_times-- > 0)) { general_buffer *buf = buf_init(1); char ret[1024]; buf_append_chars_nocount(buf, "Enter passphrase for "); buf_append_chars_nocount(buf, uk.comment); buf_append_chars_nocount(buf, " :"); if (!read_prompted("TT:", (char *) buf_chars_noadjust(buf), ret, 1023, 0, 0, &status)) { lib_put_output(""); lib$signal(status); } lib_put_output(""); buf_destroy(passphrase); passphrase = buf_init(strlen(ret)); buf_append_chars_nocount(passphrase, ret); } if (status != SS$_NORMAL) userkey_destroy_static(&uk); if (status != SS$_NORMAL) { if (status == FISH_M_UKBADPASS) return status; lib$signal(FISH_M_INVFILE, 2, sshprefs->identity_file, strerror(errno, vaxc$errno), status); return FISH_M_INVFILE | 0x10000000; } xfree(uk.encrypted_data); uk.encrypted_data = 0; uk.encrypted_len = 0; if (sshprefs->todo_flags & CH_BITS && sshprefs->bits != uk.bits) { uk.bits = sshprefs->bits; RSA_free(uk.key); } if (sshprefs->todo_flags & CH_CIPHER_TYPE) uk.cipher_type = sshprefs->cipher_type; if (sshprefs->todo_flags & CH_COMMENT) uk.comment = sshprefs->comment; if (sshprefs->todo_flags & CH_PASSPHRASE) { buf_destroy(passphrase); passphrase = 0; } return create_keyfile(sshprefs, &uk, passphrase, "New passphrase for '%s': ", "Verify new passphrase for '%s': "); } /* Emacs local variables Local variables: eval: (set-c-style "BSD") end: */