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