source: trunk/third/ssh/authfile.c @ 12646

Revision 12646, 10.2 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12645, which included commits to RCS files with non-trunk default branches.
Line 
1/*
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
17/*
18 * $Id: authfile.c,v 1.1.1.2 1999-03-08 17:43:17 danw Exp $
19 * $Log: not supported by cvs2svn $
20 * Revision 1.2  1997/03/19  22:18:27  kivinen
21 *      Removed check that SSH_CIPHER_NONE is in cipher_mask because
22 *      it is always internally supported, even if not in cipher_mask.
23 *
24 * Revision 1.1.1.1  1996/02/18 21:38:11  ylo
25 *      Imported ssh-1.2.13.
26 *
27 * Revision 1.6  1995/10/02  01:19:48  ylo
28 *      Added some casts to avoid compiler warnings.
29 *
30 * Revision 1.5  1995/09/09  21:26:39  ylo
31 * /m/shadows/u2/users/ylo/ssh/README
32 *
33 * Revision 1.4  1995/08/21  23:21:56  ylo
34 *      Don't complain about bad passphrase if passphrase was empty.
35 *
36 * Revision 1.3  1995/07/13  01:16:38  ylo
37 *      Removed "Last modified" header.
38 *
39 * Revision 1.2  1995/07/13  01:11:52  ylo
40 *      Added cvs log.
41 *
42 * $Endlog$
43 */
44
45#include "includes.h"
46#include <gmp.h>
47#include "xmalloc.h"
48#include "idea.h"
49#include "buffer.h"
50#include "bufaux.h"
51#include "cipher.h"
52#include "ssh.h"
53#include "userfile.h"
54
55/* Version identification string for identity files. */
56#define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n"
57
58/* Saves the authentication (private) key in a file, encrypting it with
59   passphrase.  The identification of the file (lowest 64 bits of n)
60   will precede the key to provide identification of the key without
61   needing a passphrase.  File I/O will be done with the given uid using
62   userfile. */
63
64int save_private_key(uid_t uid, const char *filename, const char *passphrase,
65                     RSAPrivateKey *key, const char *comment,
66                     RandomState *state)
67{
68  Buffer buffer, encrypted;
69  char buf[100], *cp;
70  int i;
71  UserFile uf;
72  CipherContext cipher;
73  int cipher_type;
74
75  /* If the passphrase is empty, use SSH_CIPHER_NONE to ease converting to
76     another cipher; otherwise use SSH_AUTHFILE_CIPHER. */
77  if (strcmp(passphrase, "") == 0)
78    cipher_type = SSH_CIPHER_NONE;
79  else
80    cipher_type = SSH_AUTHFILE_CIPHER;
81
82  /* This buffer is used to built the secret part of the private key. */
83  buffer_init(&buffer);
84 
85  /* Put checkbytes for checking passphrase validity. */
86  buf[0] = random_get_byte(state);
87  buf[1] = random_get_byte(state);
88  buf[2] = buf[0];
89  buf[3] = buf[1];
90  buffer_append(&buffer, buf, 4);
91
92  /* Store the private key (n and e will not be stored because they will
93     be stored in plain text, and storing them also in encrypted format
94     would just give known plaintext). */
95  buffer_put_mp_int(&buffer, &key->d);
96  buffer_put_mp_int(&buffer, &key->u);
97  buffer_put_mp_int(&buffer, &key->p);
98  buffer_put_mp_int(&buffer, &key->q);
99
100  /* Pad the part to be encrypted until its size is a multiple of 8. */
101  while (buffer_len(&buffer) % 8 != 0)
102    buffer_put_char(&buffer, 0);
103
104  /* This buffer will be used to contain the data in the file. */
105  buffer_init(&encrypted);
106
107  /* First store keyfile id string. */
108  cp = AUTHFILE_ID_STRING;
109  for (i = 0; cp[i]; i++)
110    buffer_put_char(&encrypted, cp[i]);
111  buffer_put_char(&encrypted, 0);
112
113  /* Store cipher type. */
114  buffer_put_char(&encrypted, cipher_type);
115  buffer_put_int(&encrypted, 0);  /* For future extension */
116
117  /* Store public key.  This will be in plain text. */
118  buffer_put_int(&encrypted, key->bits);
119  buffer_put_mp_int(&encrypted, &key->n);
120  buffer_put_mp_int(&encrypted, &key->e);
121  buffer_put_string(&encrypted, comment, strlen(comment));
122
123  /* Allocate space for the private part of the key in the buffer. */
124  buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
125
126  cipher_set_key_string(&cipher, cipher_type, passphrase, 1);
127  cipher_encrypt(&cipher, (unsigned char *)cp,
128                 (unsigned char *)buffer_ptr(&buffer),
129                 buffer_len(&buffer));
130  memset(&cipher, 0, sizeof(cipher));
131
132  /* Destroy temporary data. */
133  memset(buf, 0, sizeof(buf));
134  buffer_free(&buffer);
135
136  /* Write to a file. */
137  uf = userfile_open(uid, filename, O_WRONLY|O_CREAT|O_TRUNC, 0600);
138  if (uf == NULL)
139    return 0;
140
141  if (userfile_write(uf, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
142      buffer_len(&encrypted))
143    {
144      debug("Write to key file %.200s failed: %.100s", filename,
145            strerror(errno));
146      buffer_free(&encrypted);
147      userfile_close(uf);
148      userfile_remove(uid, filename);
149      return 0;
150    }
151  userfile_close(uf);
152  buffer_free(&encrypted);
153  return 1;
154}
155
156/* Loads the public part of the key file.  Returns 0 if an error
157   was encountered (the file does not exist or is not readable), and
158   non-zero otherwise.  File I/O will be done using the given uid with
159   userfile. */
160
161int load_public_key(uid_t uid, const char *filename, RSAPublicKey *pub,
162                    char **comment_return)
163{
164  int i;
165  UserFile uf;
166  unsigned long len;
167  Buffer buffer;
168  char *cp;
169
170  /* Read data from the file into the buffer. */
171  uf = userfile_open(uid, filename, O_RDONLY, 0);
172  if (uf == NULL)
173    return 0;
174
175  len = userfile_lseek(uf, (off_t)0L, 2);
176  userfile_lseek(uf, (off_t)0L, 0);
177 
178  if (len > 32000)
179    {
180      userfile_close(uf);
181      debug("Authentication file too big: %.200s", filename);
182      return 0;
183    }
184
185  buffer_init(&buffer);
186  buffer_append_space(&buffer, &cp, len);
187
188  if (userfile_read(uf, cp, len) != len)
189    {
190      debug("Read from key file %.200s failed: %.100s", filename,
191            strerror(errno));
192      buffer_free(&buffer);
193      userfile_close(uf);
194      return 0;
195    }
196  userfile_close(uf);
197
198  /* Check that it is at least big enought to contain the ID string. */
199  if (len < strlen(AUTHFILE_ID_STRING) + 1)
200    {
201      debug("Bad key file %.200s.", filename);
202      buffer_free(&buffer);
203      return 0;
204    }
205
206  /* Make sure it begins with the id string.  Consume the id string from
207     the buffer. */
208  for (i = 0; i < (unsigned int)strlen(AUTHFILE_ID_STRING) + 1; i++)
209    if (buffer_get_char(&buffer) != (unsigned char)AUTHFILE_ID_STRING[i])
210      {
211        debug("Bad key file %.200s.", filename);
212        buffer_free(&buffer);
213        return 0;
214      }
215
216  /* Skip cipher type and reserved data. */
217  (void)buffer_get_char(&buffer); /* cipher type */
218  (void)buffer_get_int(&buffer); /* reserved */
219
220  /* Read the public key from the buffer. */
221  pub->bits = buffer_get_int(&buffer);
222  mpz_init(&pub->n);
223  buffer_get_mp_int(&buffer, &pub->n);
224  mpz_init(&pub->e);
225  buffer_get_mp_int(&buffer, &pub->e);
226  if (comment_return)
227    *comment_return = buffer_get_string(&buffer, NULL);
228  /* The encrypted private part is not parsed by this function. */
229
230  buffer_free(&buffer);
231 
232  return 1;
233}
234
235/* Loads the private key from the file.  Returns 0 if an error is encountered
236   (file does not exist or is not readable, or passphrase is bad).
237   This initializes the private key.  The I/O will be done using the given
238   uid with userfile. */
239
240int load_private_key(uid_t uid, const char *filename, const char *passphrase,
241                     RSAPrivateKey *prv, char **comment_return)
242{
243  int i, check1, check2, cipher_type;
244  UserFile uf;
245  unsigned long len;
246  Buffer buffer, decrypted;
247  char *cp;
248  CipherContext cipher;
249
250  /* Read the file into the buffer. */
251  uf = userfile_open(uid, filename, O_RDONLY, 0);
252  if (uf == NULL)
253    return 0;
254
255  len = userfile_lseek(uf, (off_t)0L, 2);
256  userfile_lseek(uf, (off_t)0L, 0);
257 
258  if (len > 32000)
259    {
260      userfile_close(uf);
261      debug("Authentication file too big: %.200s", filename);
262      return 0;
263    }
264 
265  buffer_init(&buffer);
266  buffer_append_space(&buffer, &cp, len);
267
268  if (userfile_read(uf, cp, len) != len)
269    {
270      debug("Read from key file %.200s failed: %.100s", filename,
271            strerror(errno));
272      buffer_free(&buffer);
273      userfile_close(uf);
274      return 0;
275    }
276  userfile_close(uf);
277
278  /* Check that it is at least big enought to contain the ID string. */
279  if (len < strlen(AUTHFILE_ID_STRING) + 1)
280    {
281      debug("Bad key file %.200s.", filename);
282      buffer_free(&buffer);
283      return 0;
284    }
285
286  /* Make sure it begins with the id string.  Consume the id string from
287     the buffer. */
288  for (i = 0; i < (unsigned int)strlen(AUTHFILE_ID_STRING) + 1; i++)
289    if (buffer_get_char(&buffer) != (unsigned char)AUTHFILE_ID_STRING[i])
290      {
291        debug("Bad key file %.200s.", filename);
292        buffer_free(&buffer);
293        return 0;
294      }
295
296  /* Read cipher type. */
297  cipher_type = buffer_get_char(&buffer);
298  (void)buffer_get_int(&buffer);  /* Reserved data. */
299
300  /* Read the public key from the buffer. */
301  prv->bits = buffer_get_int(&buffer);
302  mpz_init(&prv->n);
303  buffer_get_mp_int(&buffer, &prv->n);
304  mpz_init(&prv->e);
305  buffer_get_mp_int(&buffer, &prv->e);
306  if (comment_return)
307    *comment_return = buffer_get_string(&buffer, NULL);
308  else
309    xfree(buffer_get_string(&buffer, NULL));
310
311  /* Check that it is a supported cipher. */
312  if (cipher_type != SSH_CIPHER_NONE &&
313      (cipher_mask() & (1 << cipher_type)) == 0)
314    {
315      debug("Unsupported cipher %.100s used in key file %.200s.",
316            cipher_name(cipher_type), filename);
317      buffer_free(&buffer);
318      goto fail;
319    }
320
321  /* Initialize space for decrypted data. */
322  buffer_init(&decrypted);
323  buffer_append_space(&decrypted, &cp, buffer_len(&buffer));
324     
325  /* Rest of the buffer is encrypted.  Decrypt it using the passphrase. */
326  cipher_set_key_string(&cipher, cipher_type, passphrase, 0);
327  cipher_decrypt(&cipher, (unsigned char *)cp,
328                 (unsigned char *)buffer_ptr(&buffer),
329                 buffer_len(&buffer));
330
331  buffer_free(&buffer);
332
333  check1 = buffer_get_char(&decrypted);
334  check2 = buffer_get_char(&decrypted);
335  if (check1 != buffer_get_char(&decrypted) ||
336      check2 != buffer_get_char(&decrypted))
337    {
338      if (strcmp(passphrase, "") != 0)
339        debug("Bad passphrase supplied for key file %.200s.", filename);
340      /* Bad passphrase. */
341      buffer_free(&decrypted);
342    fail:
343      mpz_clear(&prv->n);
344      mpz_clear(&prv->e);
345      if (comment_return)
346        xfree(*comment_return);
347      return 0;
348    }
349
350  /* Read the rest of the private key. */
351  mpz_init(&prv->d);
352  buffer_get_mp_int(&decrypted, &prv->d);
353  mpz_init(&prv->u);
354  buffer_get_mp_int(&decrypted, &prv->u);
355  mpz_init(&prv->p);
356  buffer_get_mp_int(&decrypted, &prv->p);
357  mpz_init(&prv->q);
358  buffer_get_mp_int(&decrypted, &prv->q);
359 
360  buffer_free(&decrypted);
361
362  return 1;
363}
Note: See TracBrowser for help on using the repository browser.