⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 import.c

📁 远程登陆工具软件源码 用于远程登陆unix
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
 * 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 + -