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