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