]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - sshpubk.c
first pass
[PuTTY.git] / sshpubk.c
index fd43725eb6766f145ddedb50c323e97aaf0a9565..1a27c313974506ec4fd9e6051b47e3f414a87c97 100644 (file)
--- a/sshpubk.c
+++ b/sshpubk.c
@@ -309,6 +309,8 @@ int rsakey_pubblob(const Filename *filename, void **blob, int *bloblen,
             *commentptr = commentp ? dupstr(commentp) : NULL;
         *blob = rsa_public_blob(&key, bloblen);
         freersakey(&key);
+        sfree(line);
+        fclose(fp);
         return 1;
 
       not_public_either:
@@ -853,7 +855,7 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
     ret = snew(struct ssh2_userkey);
     ret->alg = alg;
     ret->comment = comment;
-    ret->data = alg->createkey(public_blob, public_blob_len,
+    ret->data = alg->createkey(alg, public_blob, public_blob_len,
                               private_blob, private_blob_len);
     if (!ret->data) {
        sfree(ret);
@@ -944,6 +946,7 @@ unsigned char *rfc4716_loadpub(FILE *fp, char **algorithm,
             }
 
             *q = '\0';
+            sfree(comment);   /* *just* in case of multiple Comment headers */
             comment = dupstr(line);
         } else if (!strcmp(line, "Subject") ||
                    !strncmp(line, "x-", 2)) {
@@ -1089,6 +1092,7 @@ unsigned char *openssh_loadpub(FILE *fp, char **algorithm,
         *commentptr = comment;
     else
         sfree(comment);
+    sfree(line);
     return pubblob;
 
   error:
@@ -1191,7 +1195,7 @@ unsigned char *ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
     if (pub_blob_len)
        *pub_blob_len = public_blob_len;
     if (algorithm)
-       *algorithm = alg->name;
+       *algorithm = dupstr(alg->name);
     return public_blob;
 
     /*
@@ -1276,7 +1280,7 @@ int base64_lines(int datalen)
     return (datalen + 47) / 48;
 }
 
-void base64_encode(FILE * fp, unsigned char *data, int datalen, int cpl)
+void base64_encode(FILE *fp, const unsigned char *data, int datalen, int cpl)
 {
     int linelen = 0;
     char out[4];
@@ -1308,7 +1312,7 @@ int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
     int passlen;
     int cipherblk;
     int i;
-    char *cipherstr;
+    const char *cipherstr;
     unsigned char priv_mac[20];
 
     /*
@@ -1433,6 +1437,197 @@ int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
     return 1;
 }
 
+/* ----------------------------------------------------------------------
+ * Output public keys.
+ */
+char *ssh1_pubkey_str(struct RSAKey *key)
+{
+    char *buffer;
+    char *dec1, *dec2;
+
+    dec1 = bignum_decimal(key->exponent);
+    dec2 = bignum_decimal(key->modulus);
+    buffer = dupprintf("%d %s %s%s%s", bignum_bitcount(key->modulus),
+                      dec1, dec2,
+                       key->comment ? " " : "",
+                       key->comment ? key->comment : "");
+    sfree(dec1);
+    sfree(dec2);
+    return buffer;
+}
+
+void ssh1_write_pubkey(FILE *fp, struct RSAKey *key)
+{
+    char *buffer = ssh1_pubkey_str(key);
+    fprintf(fp, "%s\n", buffer);
+    sfree(buffer);
+}
+
+static char *ssh2_pubkey_openssh_str_internal(const char *comment,
+                                              const void *v_pub_blob,
+                                              int pub_len)
+{
+    const unsigned char *ssh2blob = (const unsigned char *)v_pub_blob;
+    const char *alg;
+    int alglen;
+    char *buffer, *p;
+    int i;
+
+    if (pub_len < 4) {
+        alg = NULL;
+    } else {
+        alglen = GET_32BIT(ssh2blob);
+        if (alglen > 0 && alglen < pub_len - 4) {
+            alg = (const char *)ssh2blob + 4;
+        } else {
+            alg = NULL;
+        }
+    }
+
+    if (!alg) {
+        alg = "INVALID-ALGORITHM";
+        alglen = strlen(alg);
+    }
+
+    buffer = snewn(alglen +
+                   4 * ((pub_len+2) / 3) +
+                   (comment ? strlen(comment) : 0) + 3, char);
+    p = buffer + sprintf(buffer, "%.*s ", alglen, alg);
+    i = 0;
+    while (i < pub_len) {
+        int n = (pub_len - i < 3 ? pub_len - i : 3);
+        base64_encode_atom(ssh2blob + i, n, p);
+        i += n;
+        p += 4;
+    }
+    if (*comment) {
+        *p++ = ' ';
+        strcpy(p, comment);
+    } else
+        *p++ = '\0';
+
+    return buffer;
+}
+
+char *ssh2_pubkey_openssh_str(struct ssh2_userkey *key)
+{
+    int bloblen;
+    unsigned char *blob;
+    char *ret;
+
+    blob = key->alg->public_blob(key->data, &bloblen);
+    ret = ssh2_pubkey_openssh_str_internal(key->comment, blob, bloblen);
+    sfree(blob);
+
+    return ret;
+}
+
+void ssh2_write_pubkey(FILE *fp, const char *comment,
+                       const void *v_pub_blob, int pub_len,
+                       int keytype)
+{
+    unsigned char *pub_blob = (unsigned char *)v_pub_blob;
+
+    if (keytype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716) {
+        const char *p;
+        int i, column;
+
+        fprintf(fp, "---- BEGIN SSH2 PUBLIC KEY ----\n");
+
+        if (comment) {
+            fprintf(fp, "Comment: \"");
+            for (p = comment; *p; p++) {
+                if (*p == '\\' || *p == '\"')
+                    fputc('\\', fp);
+                fputc(*p, fp);
+            }
+            fprintf(fp, "\"\n");
+        }
+
+        i = 0;
+        column = 0;
+        while (i < pub_len) {
+            char buf[5];
+            int n = (pub_len - i < 3 ? pub_len - i : 3);
+            base64_encode_atom(pub_blob + i, n, buf);
+            i += n;
+            buf[4] = '\0';
+            fputs(buf, fp);
+            if (++column >= 16) {
+                fputc('\n', fp);
+                column = 0;
+            }
+        }
+        if (column > 0)
+            fputc('\n', fp);
+
+        fprintf(fp, "---- END SSH2 PUBLIC KEY ----\n");
+    } else if (keytype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) {
+        char *buffer = ssh2_pubkey_openssh_str_internal(comment,
+                                                        v_pub_blob, pub_len);
+        fprintf(fp, "%s\n", buffer);
+        sfree(buffer);
+    } else {
+        assert(0 && "Bad key type in ssh2_write_pubkey");
+    }
+}
+
+/* ----------------------------------------------------------------------
+ * Utility functions to compute SSH-2 fingerprints in a uniform way.
+ */
+char *ssh2_fingerprint_blob(const void *blob, int bloblen)
+{
+    unsigned char digest[16];
+    char fingerprint_str[16*3];
+    const char *algstr;
+    int alglen;
+    const struct ssh_signkey *alg;
+    int i;
+
+    /*
+     * The fingerprint hash itself is always just the MD5 of the blob.
+     */
+    MD5Simple(blob, bloblen, digest);
+    for (i = 0; i < 16; i++)
+        sprintf(fingerprint_str + i*3, "%02x%s", digest[i], i==15 ? "" : ":");
+
+    /*
+     * Identify the key algorithm, if possible.
+     */
+    alglen = toint(GET_32BIT((const unsigned char *)blob));
+    if (alglen > 0 && alglen < bloblen-4) {
+        algstr = (const char *)blob + 4;
+
+        /*
+         * If we can actually identify the algorithm as one we know
+         * about, get hold of the key's bit count too.
+         */
+        alg = find_pubkey_alg_len(alglen, algstr);
+        if (alg) {
+            int bits = alg->pubkey_bits(alg, blob, bloblen);
+            return dupprintf("%.*s %d %s", alglen, algstr,
+                             bits, fingerprint_str);
+        } else {
+            return dupprintf("%.*s %s", alglen, algstr, fingerprint_str);
+        }
+    } else {
+        /*
+         * No algorithm available (which means a seriously confused
+         * key blob, but there we go). Return only the hash.
+         */
+        return dupstr(fingerprint_str);
+    }
+}
+
+char *ssh2_fingerprint(const struct ssh_signkey *alg, void *data)
+{
+    int len;
+    unsigned char *blob = alg->public_blob(data, &len);
+    char *ret = ssh2_fingerprint_blob(blob, len);
+    sfree(blob);
+    return ret;
+}
+
 /* ----------------------------------------------------------------------
  * Determine the type of a private key file.
  */
@@ -1497,7 +1692,7 @@ int key_type(const Filename *filename)
  * Convert the type word to a string, for `wrong type' error
  * messages.
  */
-char *key_type_to_str(int type)
+const char *key_type_to_str(int type)
 {
     switch (type) {
       case SSH_KEYTYPE_UNOPENABLE: return "unable to open file"; break;