blob: edd1cd9a2f864fa5d156c7bff46d312153d104eb [file] [log] [blame]
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001/*
2
3authfile.c
4
5Author: Tatu Ylonen <ylo@cs.hut.fi>
6
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved
9
10Created: Mon Mar 27 03:52:05 1995 ylo
11
12This file contains functions for reading and writing identity files, and
13for reading the passphrase from the user.
14
15*/
16
Damien Miller7f6ea021999-10-28 13:25:17 +100017#include "config.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100018#include "includes.h"
Damien Miller7f6ea021999-10-28 13:25:17 +100019RCSID("$Id: authfile.c,v 1.2 1999/10/28 03:25:17 damien Exp $");
Damien Millerd4a8b7e1999-10-27 13:42:43 +100020
Damien Miller7f6ea021999-10-28 13:25:17 +100021#ifdef HAVE_OPENSSL
Damien Millerd4a8b7e1999-10-27 13:42:43 +100022#include <openssl/bn.h>
Damien Miller7f6ea021999-10-28 13:25:17 +100023#endif
24#ifdef HAVE_SSL
25#include <ssl/bn.h>
26#endif
27
Damien Millerd4a8b7e1999-10-27 13:42:43 +100028#include "xmalloc.h"
29#include "buffer.h"
30#include "bufaux.h"
31#include "cipher.h"
32#include "ssh.h"
33
34/* Version identification string for identity files. */
35#define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
36
37/* Saves the authentication (private) key in a file, encrypting it with
38 passphrase. The identification of the file (lowest 64 bits of n)
39 will precede the key to provide identification of the key without
40 needing a passphrase. */
41
42int
43save_private_key(const char *filename, const char *passphrase,
44 RSA *key, const char *comment)
45{
46 Buffer buffer, encrypted;
47 char buf[100], *cp;
48 int f, i;
49 CipherContext cipher;
50 int cipher_type;
51 u_int32_t rand;
52
53 /* If the passphrase is empty, use SSH_CIPHER_NONE to ease converting to
54 another cipher; otherwise use SSH_AUTHFILE_CIPHER. */
55 if (strcmp(passphrase, "") == 0)
56 cipher_type = SSH_CIPHER_NONE;
57 else
58 cipher_type = SSH_AUTHFILE_CIPHER;
59
60 /* This buffer is used to built the secret part of the private key. */
61 buffer_init(&buffer);
62
63 /* Put checkbytes for checking passphrase validity. */
64 rand = arc4random();
65 buf[0] = rand & 0xff;
66 buf[1] = (rand >> 8) & 0xff;
67 buf[2] = buf[0];
68 buf[3] = buf[1];
69 buffer_append(&buffer, buf, 4);
70
71 /* Store the private key (n and e will not be stored because they will
72 be stored in plain text, and storing them also in encrypted format
73 would just give known plaintext). */
74 buffer_put_bignum(&buffer, key->d);
75 buffer_put_bignum(&buffer, key->iqmp);
76 buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */
77 buffer_put_bignum(&buffer, key->p); /* reverse from SSL q */
78
79 /* Pad the part to be encrypted until its size is a multiple of 8. */
80 while (buffer_len(&buffer) % 8 != 0)
81 buffer_put_char(&buffer, 0);
82
83 /* This buffer will be used to contain the data in the file. */
84 buffer_init(&encrypted);
85
86 /* First store keyfile id string. */
87 cp = AUTHFILE_ID_STRING;
88 for (i = 0; cp[i]; i++)
89 buffer_put_char(&encrypted, cp[i]);
90 buffer_put_char(&encrypted, 0);
91
92 /* Store cipher type. */
93 buffer_put_char(&encrypted, cipher_type);
94 buffer_put_int(&encrypted, 0); /* For future extension */
95
96 /* Store public key. This will be in plain text. */
97 buffer_put_int(&encrypted, BN_num_bits(key->n));
98 buffer_put_bignum(&encrypted, key->n);
99 buffer_put_bignum(&encrypted, key->e);
100 buffer_put_string(&encrypted, comment, strlen(comment));
101
102 /* Allocate space for the private part of the key in the buffer. */
103 buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
104
105 cipher_set_key_string(&cipher, cipher_type, passphrase, 1);
106 cipher_encrypt(&cipher, (unsigned char *)cp,
107 (unsigned char *)buffer_ptr(&buffer),
108 buffer_len(&buffer));
109 memset(&cipher, 0, sizeof(cipher));
110
111 /* Destroy temporary data. */
112 memset(buf, 0, sizeof(buf));
113 buffer_free(&buffer);
114
115 /* Write to a file. */
116 f = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0600);
117 if (f < 0)
118 return 0;
119
120 if (write(f, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
121 buffer_len(&encrypted))
122 {
123 debug("Write to key file %.200s failed: %.100s", filename,
124 strerror(errno));
125 buffer_free(&encrypted);
126 close(f);
127 remove(filename);
128 return 0;
129 }
130 close(f);
131 buffer_free(&encrypted);
132 return 1;
133}
134
135/* Loads the public part of the key file. Returns 0 if an error
136 was encountered (the file does not exist or is not readable), and
137 non-zero otherwise. */
138
139int
140load_public_key(const char *filename, RSA *pub,
141 char **comment_return)
142{
143 int f, i;
144 off_t len;
145 Buffer buffer;
146 char *cp;
147
148 /* Read data from the file into the buffer. */
149 f = open(filename, O_RDONLY);
150 if (f < 0)
151 return 0;
152
153 len = lseek(f, (off_t)0, SEEK_END);
154 lseek(f, (off_t)0, SEEK_SET);
155
156 buffer_init(&buffer);
157 buffer_append_space(&buffer, &cp, len);
158
159 if (read(f, cp, (size_t)len) != (size_t)len)
160 {
161 debug("Read from key file %.200s failed: %.100s", filename,
162 strerror(errno));
163 buffer_free(&buffer);
164 close(f);
165 return 0;
166 }
167 close(f);
168
169 /* Check that it is at least big enought to contain the ID string. */
170 if (len < strlen(AUTHFILE_ID_STRING) + 1)
171 {
172 debug("Bad key file %.200s.", filename);
173 buffer_free(&buffer);
174 return 0;
175 }
176
177 /* Make sure it begins with the id string. Consume the id string from
178 the buffer. */
179 for (i = 0; i < (unsigned int)strlen(AUTHFILE_ID_STRING) + 1; i++)
180 if (buffer_get_char(&buffer) != (unsigned char)AUTHFILE_ID_STRING[i])
181 {
182 debug("Bad key file %.200s.", filename);
183 buffer_free(&buffer);
184 return 0;
185 }
186
187 /* Skip cipher type and reserved data. */
188 (void)buffer_get_char(&buffer); /* cipher type */
189 (void)buffer_get_int(&buffer); /* reserved */
190
191 /* Read the public key from the buffer. */
192 buffer_get_int(&buffer);
193 pub->n = BN_new();
194 buffer_get_bignum(&buffer, pub->n);
195 pub->e = BN_new();
196 buffer_get_bignum(&buffer, pub->e);
197 if (comment_return)
198 *comment_return = buffer_get_string(&buffer, NULL);
199 /* The encrypted private part is not parsed by this function. */
200
201 buffer_free(&buffer);
202
203 return 1;
204}
205
206/* Loads the private key from the file. Returns 0 if an error is encountered
207 (file does not exist or is not readable, or passphrase is bad).
208 This initializes the private key. */
209
210int
211load_private_key(const char *filename, const char *passphrase,
212 RSA *prv, char **comment_return)
213{
214 int f, i, check1, check2, cipher_type;
215 off_t len;
216 Buffer buffer, decrypted;
217 char *cp;
218 CipherContext cipher;
219 BN_CTX *ctx;
220 BIGNUM *aux;
221 struct stat st;
222
223 /* Read the file into the buffer. */
224 f = open(filename, O_RDONLY);
225 if (f < 0)
226 return 0;
227
228 /* We assume we are called under uid of the owner of the file */
229 if (fstat(f, &st) < 0 ||
230 (st.st_uid != 0 && st.st_uid != getuid()) ||
231 (st.st_mode & 077) != 0) {
232 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
233 error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
234 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
235 error("Bad ownership or mode(0%3.3o) for '%s'.",
236 st.st_mode & 0777, filename);
237 error("It is recommended that your private key files are NOT accessible by others.");
238 return 0;
239 }
240
241 len = lseek(f, (off_t)0, SEEK_END);
242 lseek(f, (off_t)0, SEEK_SET);
243
244 buffer_init(&buffer);
245 buffer_append_space(&buffer, &cp, len);
246
247 if (read(f, cp, (size_t)len) != (size_t)len)
248 {
249 debug("Read from key file %.200s failed: %.100s", filename,
250 strerror(errno));
251 buffer_free(&buffer);
252 close(f);
253 return 0;
254 }
255 close(f);
256
257 /* Check that it is at least big enought to contain the ID string. */
258 if (len < strlen(AUTHFILE_ID_STRING) + 1)
259 {
260 debug("Bad key file %.200s.", filename);
261 buffer_free(&buffer);
262 return 0;
263 }
264
265 /* Make sure it begins with the id string. Consume the id string from
266 the buffer. */
267 for (i = 0; i < (unsigned int)strlen(AUTHFILE_ID_STRING) + 1; i++)
268 if (buffer_get_char(&buffer) != (unsigned char)AUTHFILE_ID_STRING[i])
269 {
270 debug("Bad key file %.200s.", filename);
271 buffer_free(&buffer);
272 return 0;
273 }
274
275 /* Read cipher type. */
276 cipher_type = buffer_get_char(&buffer);
277 (void)buffer_get_int(&buffer); /* Reserved data. */
278
279 /* Read the public key from the buffer. */
280 buffer_get_int(&buffer);
281 prv->n = BN_new();
282 buffer_get_bignum(&buffer, prv->n);
283 prv->e = BN_new();
284 buffer_get_bignum(&buffer, prv->e);
285 if (comment_return)
286 *comment_return = buffer_get_string(&buffer, NULL);
287 else
288 xfree(buffer_get_string(&buffer, NULL));
289
290 /* Check that it is a supported cipher. */
291 if (((cipher_mask() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) &
292 (1 << cipher_type)) == 0)
293 {
294 debug("Unsupported cipher %.100s used in key file %.200s.",
295 cipher_name(cipher_type), filename);
296 buffer_free(&buffer);
297 goto fail;
298 }
299
300 /* Initialize space for decrypted data. */
301 buffer_init(&decrypted);
302 buffer_append_space(&decrypted, &cp, buffer_len(&buffer));
303
304 /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
305 cipher_set_key_string(&cipher, cipher_type, passphrase, 0);
306 cipher_decrypt(&cipher, (unsigned char *)cp,
307 (unsigned char *)buffer_ptr(&buffer),
308 buffer_len(&buffer));
309
310 buffer_free(&buffer);
311
312 check1 = buffer_get_char(&decrypted);
313 check2 = buffer_get_char(&decrypted);
314 if (check1 != buffer_get_char(&decrypted) ||
315 check2 != buffer_get_char(&decrypted))
316 {
317 if (strcmp(passphrase, "") != 0)
318 debug("Bad passphrase supplied for key file %.200s.", filename);
319 /* Bad passphrase. */
320 buffer_free(&decrypted);
321 fail:
322 BN_clear_free(prv->n);
323 BN_clear_free(prv->e);
324 if (comment_return)
325 xfree(*comment_return);
326 return 0;
327 }
328
329 /* Read the rest of the private key. */
330 prv->d = BN_new();
331 buffer_get_bignum(&decrypted, prv->d);
332 prv->iqmp = BN_new();
333 buffer_get_bignum(&decrypted, prv->iqmp); /* u */
334 /* in SSL and SSH p and q are exchanged */
335 prv->q = BN_new();
336 buffer_get_bignum(&decrypted, prv->q); /* p */
337 prv->p = BN_new();
338 buffer_get_bignum(&decrypted, prv->p); /* q */
339
340 ctx = BN_CTX_new();
341 aux = BN_new();
342
343 BN_sub(aux, prv->q, BN_value_one());
344 prv->dmq1 = BN_new();
345 BN_mod(prv->dmq1, prv->d, aux, ctx);
346
347 BN_sub(aux, prv->p, BN_value_one());
348 prv->dmp1 = BN_new();
349 BN_mod(prv->dmp1, prv->d, aux, ctx);
350
351 BN_clear_free(aux);
352 BN_CTX_free(ctx);
353
354 buffer_free(&decrypted);
355
356 return 1;
357}