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