3eca8453 |
1 | /* |
2 | * Read SSH public keys from files. |
3 | * |
4 | * First implementation: only supports unencrypted SSH 1.1 format |
5 | * RSA keys. Encryption, and SSH 2 DSS keys, to be supported later. |
6 | */ |
7 | |
8 | #include <stdio.h> |
9 | |
10 | #include <stdio.h> /* FIXME */ |
11 | #include <stdarg.h> /* FIXME */ |
12 | #include <windows.h> /* FIXME */ |
13 | #include "putty.h" /* FIXME */ |
14 | |
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 | |
25 | int loadrsakey(char *filename, struct RSAKey *key, char *passphrase) { |
26 | FILE *fp; |
27 | unsigned char buf[16384]; |
28 | unsigned char keybuf[16]; |
29 | int len; |
30 | int i, j, ciphertype; |
31 | int ret = 0; |
32 | struct MD5Context md5c; |
33 | |
34 | fp = fopen(filename, "rb"); |
35 | if (!fp) |
36 | goto end; |
37 | |
38 | /* Slurp the whole file into a buffer. */ |
39 | len = fread(buf, 1, sizeof(buf), fp); |
40 | fclose(fp); |
41 | if (len < 0 || len == sizeof(buf)) |
42 | goto end; /* file too big or not read */ |
43 | |
44 | if (len < sizeof(rsa_signature) || |
45 | memcmp(buf, rsa_signature, sizeof(rsa_signature)) != 0) |
46 | goto end; /* failure to have sig at front */ |
47 | |
48 | i = sizeof(rsa_signature); |
49 | |
50 | /* Next, one byte giving encryption type, and one reserved uint32. */ |
51 | if (len-i < 1) |
52 | goto end; |
53 | ciphertype = buf[i]; |
54 | if (ciphertype != 0 && ciphertype != SSH_CIPHER_3DES) |
55 | goto end; |
56 | i++; |
57 | if (len-i < 4) |
58 | goto end; /* reserved field not present */ |
59 | if (buf[i] != 0 || buf[i+1] != 0 || buf[i+2] != 0 || buf[i+3] != 0) |
60 | goto end; /* reserved field nonzero, panic! */ |
61 | i += 4; |
62 | |
63 | /* Now the serious stuff. An ordinary SSH 1 public key. */ |
64 | i += makekey(buf+i, key, NULL, 1); |
65 | if (len-i < 0) |
66 | goto end; /* overran */ |
67 | |
68 | /* Next, the comment field. */ |
69 | j = GET_32BIT(buf+i); |
5c58ad2d |
70 | i += 4; |
71 | if (len-i < j) goto end; |
72 | key->comment = malloc(j+1); |
73 | if (key->comment) { |
74 | memcpy(key->comment, buf+i, j); |
75 | key->comment[j] = '\0'; |
76 | } |
77 | i += j; |
3eca8453 |
78 | |
79 | /* |
80 | * Decrypt remainder of buffer. |
81 | */ |
82 | if (ciphertype) { |
83 | MD5Init(&md5c); |
84 | MD5Update(&md5c, passphrase, strlen(passphrase)); |
85 | MD5Final(keybuf, &md5c); |
86 | des3_decrypt_pubkey(keybuf, buf+i, (len-i+7)&~7); |
5c58ad2d |
87 | memset(keybuf, 0, sizeof(keybuf)); /* burn the evidence */ |
3eca8453 |
88 | } |
89 | |
90 | /* |
91 | * We are now in the secret part of the key. The first four |
92 | * bytes should be of the form a, b, a, b. |
93 | */ |
94 | if (len-i < 4) goto end; |
95 | if (buf[i] != buf[i+2] || buf[i+1] != buf[i+3]) { ret = -1; goto end; } |
96 | i += 4; |
97 | |
98 | /* |
99 | * After that, we have one further bignum which is our |
100 | * decryption modulus, and then we're done. |
101 | */ |
102 | i += makeprivate(buf+i, key); |
103 | if (len-i < 0) goto end; |
104 | |
105 | ret = 1; |
106 | end: |
107 | memset(buf, 0, sizeof(buf)); /* burn the evidence */ |
108 | return ret; |
109 | } |
110 | |
111 | /* |
112 | * See whether an RSA key is encrypted. |
113 | */ |
114 | int rsakey_encrypted(char *filename) { |
115 | FILE *fp; |
116 | unsigned char buf[1+sizeof(rsa_signature)]; |
117 | int len; |
118 | |
119 | fp = fopen(filename, "rb"); |
120 | if (!fp) |
121 | return 0; /* doesn't even exist */ |
122 | |
123 | /* Slurp the whole file into a buffer. */ |
124 | len = fread(buf, 1, sizeof(buf), fp); |
125 | fclose(fp); |
126 | if (len < sizeof(buf)) |
127 | return 0; /* not even valid */ |
128 | if (buf[sizeof(buf)-1]) |
129 | return 1; /* encrypted */ |
130 | return 0; |
131 | } |