]> asedeno.scripts.mit.edu Git - PuTTY_svn.git/blob - sshpubk.c
Rationalise ordering of authentication operations. Still some work to do,
[PuTTY_svn.git] / sshpubk.c
1 /*
2  * Generic SSH public-key handling operations. In particular,
3  * reading of SSH public-key files, and also the generic `sign'
4  * operation for ssh2 (which checks the type of the key and
5  * dispatches to the appropriate key-type specific function).
6  */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10
11 #include <stdarg.h> /* FIXME */
12 #include <windows.h> /* FIXME */
13
14 #include "putty.h"
15 #include "ssh.h"
16
17 #define GET_32BIT(cp) \
18     (((unsigned long)(unsigned char)(cp)[0] << 24) | \
19     ((unsigned long)(unsigned char)(cp)[1] << 16) | \
20     ((unsigned long)(unsigned char)(cp)[2] << 8) | \
21     ((unsigned long)(unsigned char)(cp)[3]))
22
23 #define rsa_signature "SSH PRIVATE KEY FILE FORMAT 1.1\n"
24 #define dss_signature "-----BEGIN DSA PRIVATE KEY-----\n"
25
26 #define BASE64_TOINT(x) ( (x)-'A'<26 ? (x)-'A'+0 :\
27                           (x)-'a'<26 ? (x)-'a'+26 :\
28                           (x)-'0'<10 ? (x)-'0'+52 :\
29                           (x)=='+' ? 62 : \
30                           (x)=='/' ? 63 : 0 )
31
32 static int loadrsakey_main(FILE *fp, struct RSAKey *key,
33                            char **commentptr, char *passphrase) {
34     unsigned char buf[16384];
35     unsigned char keybuf[16];
36     int len;
37     int i, j, ciphertype;
38     int ret = 0;
39     struct MD5Context md5c;
40     char *comment;
41
42     /* Slurp the whole file (minus the header) into a buffer. */
43     len = fread(buf, 1, sizeof(buf), fp);
44     fclose(fp);
45     if (len < 0 || len == sizeof(buf))
46         goto end;                      /* file too big or not read */
47
48     i = 0;
49
50     /*
51      * A zero byte. (The signature includes a terminating NUL.)
52      */
53     if (len-i < 1 || buf[i] != 0)
54         goto end;
55     i++;
56
57     /* One byte giving encryption type, and one reserved uint32. */
58     if (len-i < 1)
59         goto end;
60     ciphertype = buf[i];
61     if (ciphertype != 0 && ciphertype != SSH_CIPHER_3DES)
62         goto end;
63     i++;
64     if (len-i < 4)
65         goto end;                      /* reserved field not present */
66     if (buf[i] != 0 || buf[i+1] != 0 || buf[i+2] != 0 || buf[i+3] != 0)
67         goto end;                      /* reserved field nonzero, panic! */
68     i += 4;
69
70     /* Now the serious stuff. An ordinary SSH 1 public key. */
71     i += makekey(buf+i, key, NULL, 1);
72     if (len-i < 0)
73         goto end;                      /* overran */
74
75     /* Next, the comment field. */
76     j = GET_32BIT(buf+i);
77     i += 4;
78     if (len-i < j) goto end;
79     comment = malloc(j+1);
80     if (comment) {
81         memcpy(comment, buf+i, j);
82         comment[j] = '\0';
83     }
84     i += j;
85     if (commentptr)
86         *commentptr = comment;
87     if (key)
88         key->comment = comment;
89     if (!key) {
90         return ciphertype != 0;
91     }
92
93     /*
94      * Decrypt remainder of buffer.
95      */
96     if (ciphertype) {
97         MD5Init(&md5c);
98         MD5Update(&md5c, passphrase, strlen(passphrase));
99         MD5Final(keybuf, &md5c);
100         des3_decrypt_pubkey(keybuf, buf+i, (len-i+7)&~7);
101         memset(keybuf, 0, sizeof(keybuf));    /* burn the evidence */
102     }
103
104     /*
105      * We are now in the secret part of the key. The first four
106      * bytes should be of the form a, b, a, b.
107      */
108     if (len-i < 4) goto end;
109     if (buf[i] != buf[i+2] || buf[i+1] != buf[i+3]) { ret = -1; goto end; }
110     i += 4;
111
112     /*
113      * After that, we have one further bignum which is our
114      * decryption modulus, and then we're done.
115      */
116     i += makeprivate(buf+i, key);
117     if (len-i < 0) goto end;
118
119     ret = 1;
120     end:
121     memset(buf, 0, sizeof(buf));       /* burn the evidence */
122     return ret;
123 }
124
125 int loadrsakey(char *filename, struct RSAKey *key, char *passphrase) {
126     FILE *fp;
127     unsigned char buf[64];
128
129     fp = fopen(filename, "rb");
130     if (!fp)
131         return 0;                      /* doesn't even exist */
132
133     /*
134      * Read the first line of the file and see if it's a v1 private
135      * key file.
136      */
137     if (fgets(buf, sizeof(buf), fp) &&
138         !strcmp(buf, rsa_signature)) {
139         return loadrsakey_main(fp, key, NULL, passphrase);
140     }
141
142     /*
143      * Otherwise, we have nothing. Return empty-handed.
144      */
145     fclose(fp);
146     return 0;
147 }
148
149 /*
150  * See whether an RSA key is encrypted. Return its comment field as
151  * well.
152  */
153 int rsakey_encrypted(char *filename, char **comment) {
154     FILE *fp;
155     unsigned char buf[64];
156
157     fp = fopen(filename, "rb");
158     if (!fp)
159         return 0;                      /* doesn't even exist */
160
161     /*
162      * Read the first line of the file and see if it's a v1 private
163      * key file.
164      */
165     if (fgets(buf, sizeof(buf), fp) &&
166         !strcmp(buf, rsa_signature)) {
167         return loadrsakey_main(fp, NULL, comment, NULL);
168     }
169     return 0;                          /* wasn't the right kind of file */
170 }