📄 import.c
字号:
/* * Code for PuTTY to import and export private key files in other * SSH clients' formats. */#include <stdio.h>#include <stdlib.h>#include <assert.h>#include <ctype.h>#include "putty.h"#include "ssh.h"#include "misc.h"#define PUT_32BIT(cp, value) do { \ (cp)[3] = (unsigned char)(value); \ (cp)[2] = (unsigned char)((value) >> 8); \ (cp)[1] = (unsigned char)((value) >> 16); \ (cp)[0] = (unsigned char)((value) >> 24); } while (0)#define GET_32BIT(cp) \ (((unsigned long)(unsigned char)(cp)[0] << 24) | \ ((unsigned long)(unsigned char)(cp)[1] << 16) | \ ((unsigned long)(unsigned char)(cp)[2] << 8) | \ ((unsigned long)(unsigned char)(cp)[3]))int openssh_encrypted(const Filename *filename);struct ssh2_userkey *openssh_read(const Filename *filename, char *passphrase);int openssh_write(const Filename *filename, struct ssh2_userkey *key, char *passphrase);int sshcom_encrypted(const Filename *filename, char **comment);struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase);int sshcom_write(const Filename *filename, struct ssh2_userkey *key, char *passphrase);/* * Given a key type, determine whether we know how to import it. */int import_possible(int type){ if (type == SSH_KEYTYPE_OPENSSH) return 1; if (type == SSH_KEYTYPE_SSHCOM) return 1; return 0;}/* * Given a key type, determine what native key type * (SSH_KEYTYPE_SSH1 or SSH_KEYTYPE_SSH2) it will come out as once * we've imported it. */int import_target_type(int type){ /* * There are no known foreign SSH1 key formats. */ return SSH_KEYTYPE_SSH2;}/* * Determine whether a foreign key is encrypted. */int import_encrypted(const Filename *filename, int type, char **comment){ if (type == SSH_KEYTYPE_OPENSSH) { /* OpenSSH doesn't do key comments */ *comment = dupstr(filename_to_str(filename)); return openssh_encrypted(filename); } if (type == SSH_KEYTYPE_SSHCOM) { return sshcom_encrypted(filename, comment); } return 0;}/* * Import an SSH1 key. */int import_ssh1(const Filename *filename, int type, struct RSAKey *key, char *passphrase){ return 0;}/* * Import an SSH2 key. */struct ssh2_userkey *import_ssh2(const Filename *filename, int type, char *passphrase){ if (type == SSH_KEYTYPE_OPENSSH) return openssh_read(filename, passphrase); if (type == SSH_KEYTYPE_SSHCOM) return sshcom_read(filename, passphrase); return NULL;}/* * Export an SSH1 key. */int export_ssh1(const Filename *filename, int type, struct RSAKey *key, char *passphrase){ return 0;}/* * Export an SSH2 key. */int export_ssh2(const Filename *filename, int type, struct ssh2_userkey *key, char *passphrase){ if (type == SSH_KEYTYPE_OPENSSH) return openssh_write(filename, key, passphrase); if (type == SSH_KEYTYPE_SSHCOM) return sshcom_write(filename, key, passphrase); return 0;}/* ---------------------------------------------------------------------- * Helper routines. (The base64 ones are defined in sshpubk.c.) */#define isbase64(c) ( ((c) >= 'A' && (c) <= 'Z') || \ ((c) >= 'a' && (c) <= 'z') || \ ((c) >= '0' && (c) <= '9') || \ (c) == '+' || (c) == '/' || (c) == '=' \ )/* * Read an ASN.1/BER identifier and length pair. * * Flags are a combination of the #defines listed below. * * Returns -1 if unsuccessful; otherwise returns the number of * bytes used out of the source data. *//* ASN.1 tag classes. */#define ASN1_CLASS_UNIVERSAL (0 << 6)#define ASN1_CLASS_APPLICATION (1 << 6)#define ASN1_CLASS_CONTEXT_SPECIFIC (2 << 6)#define ASN1_CLASS_PRIVATE (3 << 6)#define ASN1_CLASS_MASK (3 << 6)/* Primitive versus constructed bit. */#define ASN1_CONSTRUCTED (1 << 5)static int ber_read_id_len(void *source, int sourcelen, int *id, int *length, int *flags){ unsigned char *p = (unsigned char *) source; if (sourcelen == 0) return -1; *flags = (*p & 0xE0); if ((*p & 0x1F) == 0x1F) { *id = 0; while (*p & 0x80) { p++, sourcelen--; if (sourcelen == 0) return -1; *id = (*id << 7) | (*p & 0x7F); } p++, sourcelen--; } else { *id = *p & 0x1F; p++, sourcelen--; } if (sourcelen == 0) return -1; if (*p & 0x80) { int n = *p & 0x7F; p++, sourcelen--; if (sourcelen < n) return -1; *length = 0; while (n--) *length = (*length << 8) | (*p++); sourcelen -= n; } else { *length = *p; p++, sourcelen--; } return p - (unsigned char *) source;}/* * Write an ASN.1/BER identifier and length pair. Returns the * number of bytes consumed. Assumes dest contains enough space. * Will avoid writing anything if dest is NULL, but still return * amount of space required. */static int ber_write_id_len(void *dest, int id, int length, int flags){ unsigned char *d = (unsigned char *)dest; int len = 0; if (id <= 30) { /* * Identifier is one byte. */ len++; if (d) *d++ = id | flags; } else { int n; /* * Identifier is multiple bytes: the first byte is 11111 * plus the flags, and subsequent bytes encode the value of * the identifier, 7 bits at a time, with the top bit of * each byte 1 except the last one which is 0. */ len++; if (d) *d++ = 0x1F | flags; for (n = 1; (id >> (7*n)) > 0; n++) continue; /* count the bytes */ while (n--) { len++; if (d) *d++ = (n ? 0x80 : 0) | ((id >> (7*n)) & 0x7F); } } if (length < 128) { /* * Length is one byte. */ len++; if (d) *d++ = length; } else { int n; /* * Length is multiple bytes. The first is 0x80 plus the * number of subsequent bytes, and the subsequent bytes * encode the actual length. */ for (n = 1; (length >> (8*n)) > 0; n++) continue; /* count the bytes */ len++; if (d) *d++ = 0x80 | n; while (n--) { len++; if (d) *d++ = (length >> (8*n)) & 0xFF; } } return len;}static int put_string(void *target, void *data, int len){ unsigned char *d = (unsigned char *)target; PUT_32BIT(d, len); memcpy(d+4, data, len); return len+4;}static int put_mp(void *target, void *data, int len){ unsigned char *d = (unsigned char *)target; unsigned char *i = (unsigned char *)data; if (*i & 0x80) { PUT_32BIT(d, len+1); d[4] = 0; memcpy(d+5, data, len); return len+5; } else { PUT_32BIT(d, len); memcpy(d+4, data, len); return len+4; }}/* Simple structure to point to an mp-int within a blob. */struct mpint_pos { void *start; int bytes; };static int ssh2_read_mpint(void *data, int len, struct mpint_pos *ret){ int bytes; unsigned char *d = (unsigned char *) data; if (len < 4) goto error; bytes = GET_32BIT(d); if (len < 4+bytes) goto error; ret->start = d + 4; ret->bytes = bytes; return bytes+4; error: ret->start = NULL; ret->bytes = -1; return len; /* ensure further calls fail as well */}/* ---------------------------------------------------------------------- * Code to read and write OpenSSH private keys. */enum { OSSH_DSA, OSSH_RSA };struct openssh_key { int type; int encrypted; char iv[32]; unsigned char *keyblob; int keyblob_len, keyblob_size;};static struct openssh_key *load_openssh_key(const Filename *filename){ struct openssh_key *ret; FILE *fp; char buffer[256]; char *errmsg, *p; int headers_done; char base64_bit[4]; int base64_chars = 0; ret = snew(struct openssh_key); ret->keyblob = NULL; ret->keyblob_len = ret->keyblob_size = 0; ret->encrypted = 0; memset(ret->iv, 0, sizeof(ret->iv)); fp = f_open(*filename, "r"); if (!fp) { errmsg = "Unable to open key file"; goto error; } if (!fgets(buffer, sizeof(buffer), fp) || 0 != strncmp(buffer, "-----BEGIN ", 11) || 0 != strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) { errmsg = "File does not begin with OpenSSH key header"; goto error; } if (!strcmp(buffer, "-----BEGIN RSA PRIVATE KEY-----\n")) ret->type = OSSH_RSA; else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n")) ret->type = OSSH_DSA; else { errmsg = "Unrecognised key type"; goto error; } headers_done = 0; while (1) { if (!fgets(buffer, sizeof(buffer), fp)) { errmsg = "Unexpected end of file"; goto error; } if (0 == strncmp(buffer, "-----END ", 9) && 0 == strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) break; /* done */ if ((p = strchr(buffer, ':')) != NULL) { if (headers_done) { errmsg = "Header found in body of key data"; goto error; } *p++ = '\0'; while (*p && isspace((unsigned char)*p)) p++; if (!strcmp(buffer, "Proc-Type")) { if (p[0] != '4' || p[1] != ',') { errmsg = "Proc-Type is not 4 (only 4 is supported)"; goto error; } p += 2; if (!strcmp(p, "ENCRYPTED\n")) ret->encrypted = 1; } else if (!strcmp(buffer, "DEK-Info")) { int i, j; if (strncmp(p, "DES-EDE3-CBC,", 13)) { errmsg = "Ciphers other than DES-EDE3-CBC not supported"; goto error; } p += 13; for (i = 0; i < 8; i++) { if (1 != sscanf(p, "%2x", &j)) break; ret->iv[i] = j; p += 2; } if (i < 8) { errmsg = "Expected 16-digit iv in DEK-Info"; goto error; } } } else { headers_done = 1; p = buffer; while (isbase64(*p)) { base64_bit[base64_chars++] = *p; if (base64_chars == 4) { unsigned char out[3]; int len; base64_chars = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -