source: trunk/third/openssh/authfile.c @ 22570

Revision 22570, 17.9 KB checked in by ghudson, 18 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r22569, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 *                    All rights reserved
5 * This file contains functions for reading and writing identity files, and
6 * for reading the passphrase from the user.
7 *
8 * As far as I am concerned, the code I have written for this software
9 * can be used freely for any purpose.  Any derived versions of this
10 * software must be clearly marked as such, and if the derived work is
11 * incompatible with the protocol description in the RFC file, it must be
12 * called by a name other than "ssh" or "Secure Shell".
13 *
14 *
15 * Copyright (c) 2000 Markus Friedl.  All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 * 1. Redistributions of source code must retain the above copyright
21 *    notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 *    notice, this list of conditions and the following disclaimer in the
24 *    documentation and/or other materials provided with the distribution.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#include "includes.h"
39RCSID("$OpenBSD: authfile.c,v 1.61 2005/06/17 02:44:32 djm Exp $");
40
41#include <openssl/err.h>
42#include <openssl/evp.h>
43#include <openssl/pem.h>
44
45#include "cipher.h"
46#include "xmalloc.h"
47#include "buffer.h"
48#include "bufaux.h"
49#include "key.h"
50#include "ssh.h"
51#include "log.h"
52#include "authfile.h"
53#include "rsa.h"
54#include "misc.h"
55#include "atomicio.h"
56
57/* Version identification string for SSH v1 identity files. */
58static const char authfile_id_string[] =
59    "SSH PRIVATE KEY FILE FORMAT 1.1\n";
60
61/*
62 * Saves the authentication (private) key in a file, encrypting it with
63 * passphrase.  The identification of the file (lowest 64 bits of n) will
64 * precede the key to provide identification of the key without needing a
65 * passphrase.
66 */
67
68static int
69key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
70    const char *comment)
71{
72        Buffer buffer, encrypted;
73        u_char buf[100], *cp;
74        int fd, i, cipher_num;
75        CipherContext ciphercontext;
76        Cipher *cipher;
77        u_int32_t rnd;
78
79        /*
80         * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
81         * to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
82         */
83        cipher_num = (strcmp(passphrase, "") == 0) ?
84            SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER;
85        if ((cipher = cipher_by_number(cipher_num)) == NULL)
86                fatal("save_private_key_rsa: bad cipher");
87
88        /* This buffer is used to built the secret part of the private key. */
89        buffer_init(&buffer);
90
91        /* Put checkbytes for checking passphrase validity. */
92        rnd = arc4random();
93        buf[0] = rnd & 0xff;
94        buf[1] = (rnd >> 8) & 0xff;
95        buf[2] = buf[0];
96        buf[3] = buf[1];
97        buffer_append(&buffer, buf, 4);
98
99        /*
100         * Store the private key (n and e will not be stored because they
101         * will be stored in plain text, and storing them also in encrypted
102         * format would just give known plaintext).
103         */
104        buffer_put_bignum(&buffer, key->rsa->d);
105        buffer_put_bignum(&buffer, key->rsa->iqmp);
106        buffer_put_bignum(&buffer, key->rsa->q);        /* reverse from SSL p */
107        buffer_put_bignum(&buffer, key->rsa->p);        /* reverse from SSL q */
108
109        /* Pad the part to be encrypted until its size is a multiple of 8. */
110        while (buffer_len(&buffer) % 8 != 0)
111                buffer_put_char(&buffer, 0);
112
113        /* This buffer will be used to contain the data in the file. */
114        buffer_init(&encrypted);
115
116        /* First store keyfile id string. */
117        for (i = 0; authfile_id_string[i]; i++)
118                buffer_put_char(&encrypted, authfile_id_string[i]);
119        buffer_put_char(&encrypted, 0);
120
121        /* Store cipher type. */
122        buffer_put_char(&encrypted, cipher_num);
123        buffer_put_int(&encrypted, 0);  /* For future extension */
124
125        /* Store public key.  This will be in plain text. */
126        buffer_put_int(&encrypted, BN_num_bits(key->rsa->n));
127        buffer_put_bignum(&encrypted, key->rsa->n);
128        buffer_put_bignum(&encrypted, key->rsa->e);
129        buffer_put_cstring(&encrypted, comment);
130
131        /* Allocate space for the private part of the key in the buffer. */
132        cp = buffer_append_space(&encrypted, buffer_len(&buffer));
133
134        cipher_set_key_string(&ciphercontext, cipher, passphrase,
135            CIPHER_ENCRYPT);
136        cipher_crypt(&ciphercontext, cp,
137            buffer_ptr(&buffer), buffer_len(&buffer));
138        cipher_cleanup(&ciphercontext);
139        memset(&ciphercontext, 0, sizeof(ciphercontext));
140
141        /* Destroy temporary data. */
142        memset(buf, 0, sizeof(buf));
143        buffer_free(&buffer);
144
145        fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
146        if (fd < 0) {
147                error("open %s failed: %s.", filename, strerror(errno));
148                buffer_free(&encrypted);
149                return 0;
150        }
151        if (atomicio(vwrite, fd, buffer_ptr(&encrypted),
152            buffer_len(&encrypted)) != buffer_len(&encrypted)) {
153                error("write to key file %s failed: %s", filename,
154                    strerror(errno));
155                buffer_free(&encrypted);
156                close(fd);
157                unlink(filename);
158                return 0;
159        }
160        close(fd);
161        buffer_free(&encrypted);
162        return 1;
163}
164
165/* save SSH v2 key in OpenSSL PEM format */
166static int
167key_save_private_pem(Key *key, const char *filename, const char *_passphrase,
168    const char *comment)
169{
170        FILE *fp;
171        int fd;
172        int success = 0;
173        int len = strlen(_passphrase);
174        u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
175        const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
176
177        if (len > 0 && len <= 4) {
178                error("passphrase too short: have %d bytes, need > 4", len);
179                return 0;
180        }
181        fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
182        if (fd < 0) {
183                error("open %s failed: %s.", filename, strerror(errno));
184                return 0;
185        }
186        fp = fdopen(fd, "w");
187        if (fp == NULL ) {
188                error("fdopen %s failed: %s.", filename, strerror(errno));
189                close(fd);
190                return 0;
191        }
192        switch (key->type) {
193        case KEY_DSA:
194                success = PEM_write_DSAPrivateKey(fp, key->dsa,
195                    cipher, passphrase, len, NULL, NULL);
196                break;
197        case KEY_RSA:
198                success = PEM_write_RSAPrivateKey(fp, key->rsa,
199                    cipher, passphrase, len, NULL, NULL);
200                break;
201        }
202        fclose(fp);
203        return success;
204}
205
206int
207key_save_private(Key *key, const char *filename, const char *passphrase,
208    const char *comment)
209{
210        switch (key->type) {
211        case KEY_RSA1:
212                return key_save_private_rsa1(key, filename, passphrase,
213                    comment);
214                break;
215        case KEY_DSA:
216        case KEY_RSA:
217                return key_save_private_pem(key, filename, passphrase,
218                    comment);
219                break;
220        default:
221                break;
222        }
223        error("key_save_private: cannot save key type %d", key->type);
224        return 0;
225}
226
227/*
228 * Loads the public part of the ssh v1 key file.  Returns NULL if an error was
229 * encountered (the file does not exist or is not readable), and the key
230 * otherwise.
231 */
232
233static Key *
234key_load_public_rsa1(int fd, const char *filename, char **commentp)
235{
236        Buffer buffer;
237        Key *pub;
238        struct stat st;
239        char *cp;
240        u_int i;
241        size_t len;
242
243        if (fstat(fd, &st) < 0) {
244                error("fstat for key file %.200s failed: %.100s",
245                    filename, strerror(errno));
246                return NULL;
247        }
248        if (st.st_size > 1*1024*1024) {
249                error("key file %.200s too large", filename);
250                return NULL;
251        }
252        len = (size_t)st.st_size;               /* truncated */
253
254        buffer_init(&buffer);
255        cp = buffer_append_space(&buffer, len);
256
257        if (atomicio(read, fd, cp, len) != len) {
258                debug("Read from key file %.200s failed: %.100s", filename,
259                    strerror(errno));
260                buffer_free(&buffer);
261                return NULL;
262        }
263
264        /* Check that it is at least big enough to contain the ID string. */
265        if (len < sizeof(authfile_id_string)) {
266                debug3("Not a RSA1 key file %.200s.", filename);
267                buffer_free(&buffer);
268                return NULL;
269        }
270        /*
271         * Make sure it begins with the id string.  Consume the id string
272         * from the buffer.
273         */
274        for (i = 0; i < sizeof(authfile_id_string); i++)
275                if (buffer_get_char(&buffer) != authfile_id_string[i]) {
276                        debug3("Not a RSA1 key file %.200s.", filename);
277                        buffer_free(&buffer);
278                        return NULL;
279                }
280        /* Skip cipher type and reserved data. */
281        (void) buffer_get_char(&buffer);        /* cipher type */
282        (void) buffer_get_int(&buffer);         /* reserved */
283
284        /* Read the public key from the buffer. */
285        (void) buffer_get_int(&buffer);
286        pub = key_new(KEY_RSA1);
287        buffer_get_bignum(&buffer, pub->rsa->n);
288        buffer_get_bignum(&buffer, pub->rsa->e);
289        if (commentp)
290                *commentp = buffer_get_string(&buffer, NULL);
291        /* The encrypted private part is not parsed by this function. */
292
293        buffer_free(&buffer);
294        return pub;
295}
296
297/* load public key from private-key file, works only for SSH v1 */
298Key *
299key_load_public_type(int type, const char *filename, char **commentp)
300{
301        Key *pub;
302        int fd;
303
304        if (type == KEY_RSA1) {
305                fd = open(filename, O_RDONLY);
306                if (fd < 0)
307                        return NULL;
308                pub = key_load_public_rsa1(fd, filename, commentp);
309                close(fd);
310                return pub;
311        }
312        return NULL;
313}
314
315/*
316 * Loads the private key from the file.  Returns 0 if an error is encountered
317 * (file does not exist or is not readable, or passphrase is bad). This
318 * initializes the private key.
319 * Assumes we are called under uid of the owner of the file.
320 */
321
322static Key *
323key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
324    char **commentp)
325{
326        u_int i;
327        int check1, check2, cipher_type;
328        size_t len;
329        Buffer buffer, decrypted;
330        u_char *cp;
331        CipherContext ciphercontext;
332        Cipher *cipher;
333        Key *prv = NULL;
334        struct stat st;
335
336        if (fstat(fd, &st) < 0) {
337                error("fstat for key file %.200s failed: %.100s",
338                    filename, strerror(errno));
339                close(fd);
340                return NULL;
341        }
342        if (st.st_size > 1*1024*1024) {
343                error("key file %.200s too large", filename);
344                close(fd);
345                return (NULL);
346        }
347        len = (size_t)st.st_size;               /* truncated */
348
349        buffer_init(&buffer);
350        cp = buffer_append_space(&buffer, len);
351
352        if (atomicio(read, fd, cp, len) != len) {
353                debug("Read from key file %.200s failed: %.100s", filename,
354                    strerror(errno));
355                buffer_free(&buffer);
356                close(fd);
357                return NULL;
358        }
359
360        /* Check that it is at least big enough to contain the ID string. */
361        if (len < sizeof(authfile_id_string)) {
362                debug3("Not a RSA1 key file %.200s.", filename);
363                buffer_free(&buffer);
364                close(fd);
365                return NULL;
366        }
367        /*
368         * Make sure it begins with the id string.  Consume the id string
369         * from the buffer.
370         */
371        for (i = 0; i < sizeof(authfile_id_string); i++)
372                if (buffer_get_char(&buffer) != authfile_id_string[i]) {
373                        debug3("Not a RSA1 key file %.200s.", filename);
374                        buffer_free(&buffer);
375                        close(fd);
376                        return NULL;
377                }
378
379        /* Read cipher type. */
380        cipher_type = buffer_get_char(&buffer);
381        (void) buffer_get_int(&buffer); /* Reserved data. */
382
383        /* Read the public key from the buffer. */
384        (void) buffer_get_int(&buffer);
385        prv = key_new_private(KEY_RSA1);
386
387        buffer_get_bignum(&buffer, prv->rsa->n);
388        buffer_get_bignum(&buffer, prv->rsa->e);
389        if (commentp)
390                *commentp = buffer_get_string(&buffer, NULL);
391        else
392                xfree(buffer_get_string(&buffer, NULL));
393
394        /* Check that it is a supported cipher. */
395        cipher = cipher_by_number(cipher_type);
396        if (cipher == NULL) {
397                debug("Unsupported cipher %d used in key file %.200s.",
398                    cipher_type, filename);
399                buffer_free(&buffer);
400                goto fail;
401        }
402        /* Initialize space for decrypted data. */
403        buffer_init(&decrypted);
404        cp = buffer_append_space(&decrypted, buffer_len(&buffer));
405
406        /* Rest of the buffer is encrypted.  Decrypt it using the passphrase. */
407        cipher_set_key_string(&ciphercontext, cipher, passphrase,
408            CIPHER_DECRYPT);
409        cipher_crypt(&ciphercontext, cp,
410            buffer_ptr(&buffer), buffer_len(&buffer));
411        cipher_cleanup(&ciphercontext);
412        memset(&ciphercontext, 0, sizeof(ciphercontext));
413        buffer_free(&buffer);
414
415        check1 = buffer_get_char(&decrypted);
416        check2 = buffer_get_char(&decrypted);
417        if (check1 != buffer_get_char(&decrypted) ||
418            check2 != buffer_get_char(&decrypted)) {
419                if (strcmp(passphrase, "") != 0)
420                        debug("Bad passphrase supplied for key file %.200s.",
421                            filename);
422                /* Bad passphrase. */
423                buffer_free(&decrypted);
424                goto fail;
425        }
426        /* Read the rest of the private key. */
427        buffer_get_bignum(&decrypted, prv->rsa->d);
428        buffer_get_bignum(&decrypted, prv->rsa->iqmp);          /* u */
429        /* in SSL and SSH v1 p and q are exchanged */
430        buffer_get_bignum(&decrypted, prv->rsa->q);             /* p */
431        buffer_get_bignum(&decrypted, prv->rsa->p);             /* q */
432
433        /* calculate p-1 and q-1 */
434        rsa_generate_additional_parameters(prv->rsa);
435
436        buffer_free(&decrypted);
437
438        /* enable blinding */
439        if (RSA_blinding_on(prv->rsa, NULL) != 1) {
440                error("key_load_private_rsa1: RSA_blinding_on failed");
441                goto fail;
442        }
443        close(fd);
444        return prv;
445
446fail:
447        if (commentp)
448                xfree(*commentp);
449        close(fd);
450        key_free(prv);
451        return NULL;
452}
453
454Key *
455key_load_private_pem(int fd, int type, const char *passphrase,
456    char **commentp)
457{
458        FILE *fp;
459        EVP_PKEY *pk = NULL;
460        Key *prv = NULL;
461        char *name = "<no key>";
462
463        fp = fdopen(fd, "r");
464        if (fp == NULL) {
465                error("fdopen failed: %s", strerror(errno));
466                close(fd);
467                return NULL;
468        }
469        pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase);
470        if (pk == NULL) {
471                debug("PEM_read_PrivateKey failed");
472                (void)ERR_get_error();
473        } else if (pk->type == EVP_PKEY_RSA &&
474            (type == KEY_UNSPEC||type==KEY_RSA)) {
475                prv = key_new(KEY_UNSPEC);
476                prv->rsa = EVP_PKEY_get1_RSA(pk);
477                prv->type = KEY_RSA;
478                name = "rsa w/o comment";
479#ifdef DEBUG_PK
480                RSA_print_fp(stderr, prv->rsa, 8);
481#endif
482                if (RSA_blinding_on(prv->rsa, NULL) != 1) {
483                        error("key_load_private_pem: RSA_blinding_on failed");
484                        key_free(prv);
485                        prv = NULL;
486                }
487        } else if (pk->type == EVP_PKEY_DSA &&
488            (type == KEY_UNSPEC||type==KEY_DSA)) {
489                prv = key_new(KEY_UNSPEC);
490                prv->dsa = EVP_PKEY_get1_DSA(pk);
491                prv->type = KEY_DSA;
492                name = "dsa w/o comment";
493#ifdef DEBUG_PK
494                DSA_print_fp(stderr, prv->dsa, 8);
495#endif
496        } else {
497                error("PEM_read_PrivateKey: mismatch or "
498                    "unknown EVP_PKEY save_type %d", pk->save_type);
499        }
500        fclose(fp);
501        if (pk != NULL)
502                EVP_PKEY_free(pk);
503        if (prv != NULL && commentp)
504                *commentp = xstrdup(name);
505        debug("read PEM private key done: type %s",
506            prv ? key_type(prv) : "<unknown>");
507        return prv;
508}
509
510static int
511key_perm_ok(int fd, const char *filename)
512{
513        struct stat st;
514
515        if (fstat(fd, &st) < 0)
516                return 0;
517        /*
518         * if a key owned by the user is accessed, then we check the
519         * permissions of the file. if the key owned by a different user,
520         * then we don't care.
521         */
522#ifdef HAVE_CYGWIN
523        if (check_ntsec(filename))
524#endif
525        if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
526                error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
527                error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
528                error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
529                error("Permissions 0%3.3o for '%s' are too open.",
530                    (u_int)st.st_mode & 0777, filename);
531                error("It is recommended that your private key files are NOT accessible by others.");
532                error("This private key will be ignored.");
533                return 0;
534        }
535        return 1;
536}
537
538Key *
539key_load_private_type(int type, const char *filename, const char *passphrase,
540    char **commentp)
541{
542        int fd;
543
544        fd = open(filename, O_RDONLY);
545        if (fd < 0)
546                return NULL;
547        if (!key_perm_ok(fd, filename)) {
548                error("bad permissions: ignore key: %s", filename);
549                close(fd);
550                return NULL;
551        }
552        switch (type) {
553        case KEY_RSA1:
554                return key_load_private_rsa1(fd, filename, passphrase,
555                    commentp);
556                /* closes fd */
557                break;
558        case KEY_DSA:
559        case KEY_RSA:
560        case KEY_UNSPEC:
561                return key_load_private_pem(fd, type, passphrase, commentp);
562                /* closes fd */
563                break;
564        default:
565                close(fd);
566                break;
567        }
568        return NULL;
569}
570
571Key *
572key_load_private(const char *filename, const char *passphrase,
573    char **commentp)
574{
575        Key *pub, *prv;
576        int fd;
577
578        fd = open(filename, O_RDONLY);
579        if (fd < 0)
580                return NULL;
581        if (!key_perm_ok(fd, filename)) {
582                error("bad permissions: ignore key: %s", filename);
583                close(fd);
584                return NULL;
585        }
586        pub = key_load_public_rsa1(fd, filename, commentp);
587        lseek(fd, (off_t) 0, SEEK_SET);         /* rewind */
588        if (pub == NULL) {
589                /* closes fd */
590                prv = key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL);
591                /* use the filename as a comment for PEM */
592                if (commentp && prv)
593                        *commentp = xstrdup(filename);
594        } else {
595                /* it's a SSH v1 key if the public key part is readable */
596                key_free(pub);
597                /* closes fd */
598                prv = key_load_private_rsa1(fd, filename, passphrase, NULL);
599        }
600        return prv;
601}
602
603static int
604key_try_load_public(Key *k, const char *filename, char **commentp)
605{
606        FILE *f;
607        char line[SSH_MAX_PUBKEY_BYTES];
608        char *cp;
609        u_long linenum = 0;
610
611        f = fopen(filename, "r");
612        if (f != NULL) {
613                while (read_keyfile_line(f, filename, line, sizeof(line),
614                            &linenum) != -1) {
615                        cp = line;
616                        switch (*cp) {
617                        case '#':
618                        case '\n':
619                        case '\0':
620                                continue;
621                        }
622                        /* Skip leading whitespace. */
623                        for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
624                                ;
625                        if (*cp) {
626                                if (key_read(k, &cp) == 1) {
627                                        if (commentp)
628                                                *commentp=xstrdup(filename);
629                                        fclose(f);
630                                        return 1;
631                                }
632                        }
633                }
634                fclose(f);
635        }
636        return 0;
637}
638
639/* load public key from ssh v1 private or any pubkey file */
640Key *
641key_load_public(const char *filename, char **commentp)
642{
643        Key *pub;
644        char file[MAXPATHLEN];
645
646        /* try rsa1 private key */
647        pub = key_load_public_type(KEY_RSA1, filename, commentp);
648        if (pub != NULL)
649                return pub;
650
651        /* try rsa1 public key */
652        pub = key_new(KEY_RSA1);
653        if (key_try_load_public(pub, filename, commentp) == 1)
654                return pub;
655        key_free(pub);
656
657        /* try ssh2 public key */
658        pub = key_new(KEY_UNSPEC);
659        if (key_try_load_public(pub, filename, commentp) == 1)
660                return pub;
661        if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
662            (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
663            (key_try_load_public(pub, file, commentp) == 1))
664                return pub;
665        key_free(pub);
666        return NULL;
667}
Note: See TracBrowser for help on using the repository browser.