Annotation of src/usr.bin/ssh/authfile.c, Revision 1.29
1.1 deraadt 1: /*
1.9 deraadt 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.
1.14 markus 7: *
1.19 deraadt 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.
1.9 deraadt 36: */
1.1 deraadt 37:
38: #include "includes.h"
1.29 ! markus 39: RCSID("$OpenBSD: authfile.c,v 1.28 2001/02/21 09:05:54 deraadt Exp $");
1.1 deraadt 40:
1.21 markus 41: #include <openssl/err.h>
1.25 markus 42: #include <openssl/evp.h>
1.15 markus 43: #include <openssl/pem.h>
44:
1.25 markus 45: #include "cipher.h"
1.1 deraadt 46: #include "xmalloc.h"
47: #include "buffer.h"
48: #include "bufaux.h"
1.25 markus 49: #include "key.h"
1.1 deraadt 50: #include "ssh.h"
1.25 markus 51: #include "log.h"
1.27 itojun 52: #include "authfile.h"
1.1 deraadt 53:
1.29 ! markus 54: /* Version identification string for SSH v1 identity files. */
1.26 stevesk 55: static const char authfile_id_string[] =
56: "SSH PRIVATE KEY FILE FORMAT 1.1\n";
1.1 deraadt 57:
1.10 markus 58: /*
59: * Saves the authentication (private) key in a file, encrypting it with
60: * passphrase. The identification of the file (lowest 64 bits of n) will
61: * precede the key to provide identification of the key without needing a
62: * passphrase.
63: */
1.1 deraadt 64:
1.3 provos 65: int
1.29 ! markus 66: key_save_private_rsa1(Key *key, const char *filename, const char *passphrase,
! 67: const char *comment)
1.1 deraadt 68: {
1.8 markus 69: Buffer buffer, encrypted;
70: char buf[100], *cp;
1.11 deraadt 71: int fd, i;
1.20 markus 72: CipherContext ciphercontext;
73: Cipher *cipher;
1.8 markus 74: u_int32_t rand;
75:
1.10 markus 76: /*
77: * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
78: * to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
79: */
1.8 markus 80: if (strcmp(passphrase, "") == 0)
1.20 markus 81: cipher = cipher_by_number(SSH_CIPHER_NONE);
1.8 markus 82: else
1.20 markus 83: cipher = cipher_by_number(SSH_AUTHFILE_CIPHER);
84: if (cipher == NULL)
85: fatal("save_private_key_rsa: bad cipher");
1.8 markus 86:
87: /* This buffer is used to built the secret part of the private key. */
88: buffer_init(&buffer);
89:
90: /* Put checkbytes for checking passphrase validity. */
91: rand = arc4random();
92: buf[0] = rand & 0xff;
93: buf[1] = (rand >> 8) & 0xff;
94: buf[2] = buf[0];
95: buf[3] = buf[1];
96: buffer_append(&buffer, buf, 4);
97:
1.10 markus 98: /*
99: * Store the private key (n and e will not be stored because they
100: * will be stored in plain text, and storing them also in encrypted
101: * format would just give known plaintext).
102: */
1.29 ! markus 103: buffer_put_bignum(&buffer, key->rsa->d);
! 104: buffer_put_bignum(&buffer, key->rsa->iqmp);
! 105: buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */
! 106: buffer_put_bignum(&buffer, key->rsa->p); /* reverse from SSL q */
1.8 markus 107:
108: /* Pad the part to be encrypted until its size is a multiple of 8. */
109: while (buffer_len(&buffer) % 8 != 0)
110: buffer_put_char(&buffer, 0);
111:
112: /* This buffer will be used to contain the data in the file. */
113: buffer_init(&encrypted);
114:
115: /* First store keyfile id string. */
1.26 stevesk 116: for (i = 0; authfile_id_string[i]; i++)
117: buffer_put_char(&encrypted, authfile_id_string[i]);
1.8 markus 118: buffer_put_char(&encrypted, 0);
119:
120: /* Store cipher type. */
1.20 markus 121: buffer_put_char(&encrypted, cipher->number);
1.8 markus 122: buffer_put_int(&encrypted, 0); /* For future extension */
123:
124: /* Store public key. This will be in plain text. */
1.29 ! markus 125: buffer_put_int(&encrypted, BN_num_bits(key->rsa->n));
! 126: buffer_put_bignum(&encrypted, key->rsa->n);
! 127: buffer_put_bignum(&encrypted, key->rsa->e);
1.8 markus 128: buffer_put_string(&encrypted, comment, strlen(comment));
129:
130: /* Allocate space for the private part of the key in the buffer. */
131: buffer_append_space(&encrypted, &cp, buffer_len(&buffer));
132:
1.20 markus 133: cipher_set_key_string(&ciphercontext, cipher, passphrase);
1.23 markus 134: cipher_encrypt(&ciphercontext, (u_char *) cp,
135: (u_char *) buffer_ptr(&buffer), buffer_len(&buffer));
1.20 markus 136: memset(&ciphercontext, 0, sizeof(ciphercontext));
1.8 markus 137:
138: /* Destroy temporary data. */
139: memset(buf, 0, sizeof(buf));
140: buffer_free(&buffer);
141:
1.11 deraadt 142: fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
143: if (fd < 0)
1.8 markus 144: return 0;
1.11 deraadt 145: if (write(fd, buffer_ptr(&encrypted), buffer_len(&encrypted)) !=
1.8 markus 146: buffer_len(&encrypted)) {
147: debug("Write to key file %.200s failed: %.100s", filename,
148: strerror(errno));
149: buffer_free(&encrypted);
1.11 deraadt 150: close(fd);
1.22 markus 151: unlink(filename);
1.8 markus 152: return 0;
153: }
1.11 deraadt 154: close(fd);
1.8 markus 155: buffer_free(&encrypted);
156: return 1;
1.1 deraadt 157: }
158:
1.29 ! markus 159: /* save SSH v2 key in OpenSSL PEM format */
1.15 markus 160: int
1.29 ! markus 161: key_save_private_pem(Key *key, const char *filename, const char *_passphrase,
! 162: const char *comment)
1.15 markus 163: {
164: FILE *fp;
165: int fd;
1.21 markus 166: int success = 0;
167: int len = strlen(_passphrase);
168: char *passphrase = (len > 0) ? (char *)_passphrase : NULL;
169: EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
1.15 markus 170:
171: if (len > 0 && len <= 4) {
172: error("passphrase too short: %d bytes", len);
173: errno = 0;
174: return 0;
175: }
176: fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
177: if (fd < 0) {
178: debug("open %s failed", filename);
179: return 0;
180: }
181: fp = fdopen(fd, "w");
182: if (fp == NULL ) {
183: debug("fdopen %s failed", filename);
184: close(fd);
185: return 0;
186: }
1.21 markus 187: switch (key->type) {
188: case KEY_DSA:
189: success = PEM_write_DSAPrivateKey(fp, key->dsa,
190: cipher, passphrase, len, NULL, NULL);
191: break;
192: case KEY_RSA:
193: success = PEM_write_RSAPrivateKey(fp, key->rsa,
194: cipher, passphrase, len, NULL, NULL);
195: break;
1.15 markus 196: }
197: fclose(fp);
198: return success;
199: }
200:
201: int
1.29 ! markus 202: key_save_private(Key *key, const char *filename, const char *passphrase,
1.15 markus 203: const char *comment)
204: {
205: switch (key->type) {
1.21 markus 206: case KEY_RSA1:
1.29 ! markus 207: return key_save_private_rsa1(key, filename, passphrase,
! 208: comment);
1.15 markus 209: break;
210: case KEY_DSA:
1.21 markus 211: case KEY_RSA:
1.29 ! markus 212: return key_save_private_pem(key, filename, passphrase,
! 213: comment);
1.15 markus 214: break;
215: default:
216: break;
217: }
218: return 0;
219: }
220:
1.10 markus 221: /*
1.29 ! markus 222: * Loads the public part of the ssh v1 key file. Returns NULL if an error was
! 223: * encountered (the file does not exist or is not readable), and the key
1.10 markus 224: * otherwise.
225: */
1.1 deraadt 226:
1.29 ! markus 227: Key *
! 228: key_load_public_rsa1(int fd, const char *filename, char **commentp)
1.1 deraadt 229: {
1.8 markus 230: Buffer buffer;
1.29 ! markus 231: Key *pub;
1.8 markus 232: char *cp;
1.29 ! markus 233: int i;
! 234: off_t len;
1.8 markus 235:
1.11 deraadt 236: len = lseek(fd, (off_t) 0, SEEK_END);
237: lseek(fd, (off_t) 0, SEEK_SET);
1.8 markus 238:
239: buffer_init(&buffer);
240: buffer_append_space(&buffer, &cp, len);
241:
1.11 deraadt 242: if (read(fd, cp, (size_t) len) != (size_t) len) {
1.8 markus 243: debug("Read from key file %.200s failed: %.100s", filename,
1.15 markus 244: strerror(errno));
1.8 markus 245: buffer_free(&buffer);
1.29 ! markus 246: return NULL;
1.8 markus 247: }
248:
1.26 stevesk 249: /* Check that it is at least big enough to contain the ID string. */
250: if (len < sizeof(authfile_id_string)) {
1.21 markus 251: debug3("Bad RSA1 key file %.200s.", filename);
1.8 markus 252: buffer_free(&buffer);
1.29 ! markus 253: return NULL;
1.8 markus 254: }
1.10 markus 255: /*
256: * Make sure it begins with the id string. Consume the id string
257: * from the buffer.
258: */
1.26 stevesk 259: for (i = 0; i < sizeof(authfile_id_string); i++)
260: if (buffer_get_char(&buffer) != authfile_id_string[i]) {
1.21 markus 261: debug3("Bad RSA1 key file %.200s.", filename);
1.8 markus 262: buffer_free(&buffer);
1.29 ! markus 263: return NULL;
1.8 markus 264: }
265: /* Skip cipher type and reserved data. */
266: (void) buffer_get_char(&buffer); /* cipher type */
267: (void) buffer_get_int(&buffer); /* reserved */
268:
269: /* Read the public key from the buffer. */
270: buffer_get_int(&buffer);
1.29 ! markus 271: pub = key_new(KEY_RSA1);
! 272: buffer_get_bignum(&buffer, pub->rsa->n);
! 273: buffer_get_bignum(&buffer, pub->rsa->e);
! 274: if (commentp)
! 275: *commentp = buffer_get_string(&buffer, NULL);
1.8 markus 276: /* The encrypted private part is not parsed by this function. */
277:
1.1 deraadt 278: buffer_free(&buffer);
1.29 ! markus 279: return pub;
1.1 deraadt 280: }
281:
1.29 ! markus 282: /* load public key from private-key file, works only for SSH v1 */
! 283: Key *
! 284: key_load_public_type(int type, const char *filename, char **commentp)
1.15 markus 285: {
1.29 ! markus 286: Key *pub;
! 287: int fd;
! 288:
! 289: if (type == KEY_RSA1) {
! 290: fd = open(filename, O_RDONLY);
! 291: if (fd < 0)
! 292: return NULL;
! 293: pub = key_load_public_rsa1(fd, filename, commentp);
! 294: close(fd);
! 295: return pub;
1.15 markus 296: }
1.29 ! markus 297: return NULL;
1.15 markus 298: }
299:
1.10 markus 300: /*
301: * Loads the private key from the file. Returns 0 if an error is encountered
302: * (file does not exist or is not readable, or passphrase is bad). This
303: * initializes the private key.
304: * Assumes we are called under uid of the owner of the file.
305: */
1.1 deraadt 306:
1.29 ! markus 307: Key *
! 308: key_load_private_rsa1(int fd, const char *filename, const char *passphrase,
! 309: char **commentp)
1.1 deraadt 310: {
1.15 markus 311: int i, check1, check2, cipher_type;
1.8 markus 312: off_t len;
313: Buffer buffer, decrypted;
314: char *cp;
1.20 markus 315: CipherContext ciphercontext;
316: Cipher *cipher;
1.8 markus 317: BN_CTX *ctx;
318: BIGNUM *aux;
1.29 ! markus 319: Key *prv = NULL;
1.8 markus 320:
1.11 deraadt 321: len = lseek(fd, (off_t) 0, SEEK_END);
322: lseek(fd, (off_t) 0, SEEK_SET);
1.8 markus 323:
324: buffer_init(&buffer);
325: buffer_append_space(&buffer, &cp, len);
326:
1.11 deraadt 327: if (read(fd, cp, (size_t) len) != (size_t) len) {
1.8 markus 328: debug("Read from key file %.200s failed: %.100s", filename,
1.21 markus 329: strerror(errno));
1.8 markus 330: buffer_free(&buffer);
1.11 deraadt 331: close(fd);
1.29 ! markus 332: return NULL;
1.8 markus 333: }
334:
1.26 stevesk 335: /* Check that it is at least big enough to contain the ID string. */
336: if (len < sizeof(authfile_id_string)) {
1.21 markus 337: debug3("Bad RSA1 key file %.200s.", filename);
1.8 markus 338: buffer_free(&buffer);
1.28 deraadt 339: close(fd);
1.29 ! markus 340: return NULL;
1.8 markus 341: }
1.10 markus 342: /*
343: * Make sure it begins with the id string. Consume the id string
344: * from the buffer.
345: */
1.26 stevesk 346: for (i = 0; i < sizeof(authfile_id_string); i++)
347: if (buffer_get_char(&buffer) != authfile_id_string[i]) {
1.21 markus 348: debug3("Bad RSA1 key file %.200s.", filename);
1.8 markus 349: buffer_free(&buffer);
1.28 deraadt 350: close(fd);
1.29 ! markus 351: return NULL;
1.8 markus 352: }
1.28 deraadt 353:
1.8 markus 354: /* Read cipher type. */
355: cipher_type = buffer_get_char(&buffer);
356: (void) buffer_get_int(&buffer); /* Reserved data. */
357:
358: /* Read the public key from the buffer. */
359: buffer_get_int(&buffer);
1.29 ! markus 360: prv = key_new_private(KEY_RSA1);
! 361:
! 362: buffer_get_bignum(&buffer, prv->rsa->n);
! 363: buffer_get_bignum(&buffer, prv->rsa->e);
! 364: if (commentp)
! 365: *commentp = buffer_get_string(&buffer, NULL);
1.8 markus 366: else
367: xfree(buffer_get_string(&buffer, NULL));
368:
369: /* Check that it is a supported cipher. */
1.20 markus 370: cipher = cipher_by_number(cipher_type);
371: if (cipher == NULL) {
372: debug("Unsupported cipher %d used in key file %.200s.",
373: cipher_type, filename);
1.8 markus 374: buffer_free(&buffer);
375: goto fail;
376: }
377: /* Initialize space for decrypted data. */
378: buffer_init(&decrypted);
379: buffer_append_space(&decrypted, &cp, buffer_len(&buffer));
380:
381: /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
1.20 markus 382: cipher_set_key_string(&ciphercontext, cipher, passphrase);
1.23 markus 383: cipher_decrypt(&ciphercontext, (u_char *) cp,
384: (u_char *) buffer_ptr(&buffer), buffer_len(&buffer));
1.20 markus 385: memset(&ciphercontext, 0, sizeof(ciphercontext));
1.1 deraadt 386: buffer_free(&buffer);
387:
1.8 markus 388: check1 = buffer_get_char(&decrypted);
389: check2 = buffer_get_char(&decrypted);
390: if (check1 != buffer_get_char(&decrypted) ||
391: check2 != buffer_get_char(&decrypted)) {
392: if (strcmp(passphrase, "") != 0)
1.29 ! markus 393: debug("Bad passphrase supplied for key file %.200s.",
! 394: filename);
1.8 markus 395: /* Bad passphrase. */
396: buffer_free(&decrypted);
1.29 ! markus 397: goto fail;
1.8 markus 398: }
399: /* Read the rest of the private key. */
1.29 ! markus 400: buffer_get_bignum(&decrypted, prv->rsa->d);
! 401: buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */
! 402: /* in SSL and SSH v1 p and q are exchanged */
! 403: buffer_get_bignum(&decrypted, prv->rsa->q); /* p */
! 404: buffer_get_bignum(&decrypted, prv->rsa->p); /* q */
1.8 markus 405:
1.29 ! markus 406: /* calculate p-1 and q-1 */
1.8 markus 407: ctx = BN_CTX_new();
408: aux = BN_new();
409:
1.29 ! markus 410: BN_sub(aux, prv->rsa->q, BN_value_one());
! 411: BN_mod(prv->rsa->dmq1, prv->rsa->d, aux, ctx);
! 412:
! 413: BN_sub(aux, prv->rsa->p, BN_value_one());
! 414: BN_mod(prv->rsa->dmp1, prv->rsa->d, aux, ctx);
1.8 markus 415:
416: BN_clear_free(aux);
417: BN_CTX_free(ctx);
418:
419: buffer_free(&decrypted);
1.28 deraadt 420: close(fd);
1.29 ! markus 421: return prv;
! 422:
! 423: fail:
! 424: if (commentp)
! 425: xfree(*commentp);
! 426: close(fd);
! 427: key_free(prv);
! 428: return NULL;
1.15 markus 429: }
430:
1.29 ! markus 431: Key *
! 432: key_load_private_pem(int fd, int type, const char *passphrase,
! 433: char **commentp)
1.15 markus 434: {
435: FILE *fp;
1.21 markus 436: EVP_PKEY *pk = NULL;
1.29 ! markus 437: Key *prv = NULL;
1.21 markus 438: char *name = "<no key>";
1.15 markus 439:
440: fp = fdopen(fd, "r");
441: if (fp == NULL) {
442: error("fdopen failed");
1.28 deraadt 443: close(fd);
1.29 ! markus 444: return NULL;
1.15 markus 445: }
1.21 markus 446: pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase);
447: if (pk == NULL) {
448: debug("PEM_read_PrivateKey failed");
449: (void)ERR_get_error();
1.29 ! markus 450: } else if (pk->type == EVP_PKEY_RSA &&
! 451: (type == KEY_UNSPEC||type==KEY_RSA)) {
! 452: prv = key_new(KEY_UNSPEC);
! 453: prv->rsa = EVP_PKEY_get1_RSA(pk);
! 454: prv->type = KEY_RSA;
! 455: name = "rsa w/o comment";
1.21 markus 456: #ifdef DEBUG_PK
1.29 ! markus 457: RSA_print_fp(stderr, prv->rsa, 8);
1.21 markus 458: #endif
1.29 ! markus 459: } else if (pk->type == EVP_PKEY_DSA &&
! 460: (type == KEY_UNSPEC||type==KEY_DSA)) {
! 461: prv = key_new(KEY_UNSPEC);
! 462: prv->dsa = EVP_PKEY_get1_DSA(pk);
! 463: prv->type = KEY_DSA;
! 464: name = "dsa w/o comment";
1.21 markus 465: #ifdef DEBUG_PK
1.29 ! markus 466: DSA_print_fp(stderr, prv->dsa, 8);
1.21 markus 467: #endif
1.15 markus 468: } else {
1.21 markus 469: error("PEM_read_PrivateKey: mismatch or "
470: "unknown EVP_PKEY save_type %d", pk->save_type);
1.15 markus 471: }
472: fclose(fp);
1.21 markus 473: if (pk != NULL)
474: EVP_PKEY_free(pk);
1.29 ! markus 475: if (prv != NULL && commentp)
! 476: *commentp = xstrdup(name);
! 477: debug("read PEM private key done: type %s",
! 478: prv ? key_type(prv) : "<unknown>");
! 479: return prv;
1.15 markus 480: }
481:
482: int
1.29 ! markus 483: key_perm_ok(int fd, const char *filename)
1.15 markus 484: {
485: struct stat st;
486:
487: /* check owner and modes */
488: if (fstat(fd, &st) < 0 ||
1.24 markus 489: (st.st_uid != 0 && getuid() != 0 && st.st_uid != getuid()) ||
1.15 markus 490: (st.st_mode & 077) != 0) {
491: close(fd);
492: error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
493: error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
494: error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
495: error("Bad ownership or mode(0%3.3o) for '%s'.",
1.28 deraadt 496: st.st_mode & 0777, filename);
1.15 markus 497: error("It is recommended that your private key files are NOT accessible by others.");
1.29 ! markus 498: error("This private key will be ignored.");
1.15 markus 499: return 0;
500: }
1.29 ! markus 501: return 1;
! 502: }
! 503:
! 504: Key *
! 505: key_load_private_type(int type, const char *filename, const char *passphrase,
! 506: char **commentp)
! 507: {
! 508: int fd;
! 509:
! 510: fd = open(filename, O_RDONLY);
! 511: if (fd < 0)
! 512: return NULL;
! 513: if (!key_perm_ok(fd, filename)) {
! 514: debug("bad permissions: ignore key: %s", filename);
! 515: close(fd);
! 516: return NULL;
! 517: }
! 518: switch (type) {
1.21 markus 519: case KEY_RSA1:
1.29 ! markus 520: return key_load_private_rsa1(fd, filename, passphrase,
! 521: commentp);
! 522: /* closes fd */
1.15 markus 523: break;
524: case KEY_DSA:
1.21 markus 525: case KEY_RSA:
526: case KEY_UNSPEC:
1.29 ! markus 527: return key_load_private_pem(fd, type, passphrase, commentp);
! 528: /* closes fd */
1.28 deraadt 529: break;
1.15 markus 530: default:
1.28 deraadt 531: close(fd);
1.15 markus 532: break;
533: }
1.29 ! markus 534: return NULL;
! 535: }
! 536:
! 537: Key *
! 538: key_load_private(const char *filename, const char *passphrase,
! 539: char **commentp)
! 540: {
! 541: Key *pub;
! 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: debug("bad permissions: ignore key: %s", filename);
! 549: close(fd);
! 550: return NULL;
! 551: }
! 552: pub = key_load_public_rsa1(fd, filename, commentp);
! 553: lseek(fd, (off_t) 0, SEEK_SET); /* rewind */
! 554: if (pub == NULL) {
! 555: /* closes fd */
! 556: return key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL);
! 557: } else {
! 558: /* it's a SSH v1 key if the public key part is readable */
! 559: key_free(pub);
! 560: /* closes fd */
! 561: return key_load_private_rsa1(fd, filename, passphrase, NULL);
! 562: }
1.18 markus 563: }
564:
565: int
1.29 ! markus 566: key_try_load_public(Key *k, const char *filename, char **commentp)
1.18 markus 567: {
568: FILE *f;
1.29 ! markus 569: char line[4096];
1.18 markus 570: char *cp;
571:
572: f = fopen(filename, "r");
573: if (f != NULL) {
574: while (fgets(line, sizeof(line), f)) {
575: line[sizeof(line)-1] = '\0';
576: cp = line;
577: switch(*cp){
578: case '#':
579: case '\n':
580: case '\0':
581: continue;
582: }
583: /* Skip leading whitespace. */
584: for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
585: ;
586: if (*cp) {
1.21 markus 587: if (key_read(k, &cp) == 1) {
1.18 markus 588: if (commentp)
589: *commentp=xstrdup(filename);
590: fclose(f);
591: return 1;
592: }
593: }
594: }
595: fclose(f);
596: }
597: return 0;
598: }
599:
1.29 ! markus 600: /* load public key from ssh v1 private or any pubkey file */
! 601: Key *
! 602: key_load_public(const char *filename, char **commentp)
1.18 markus 603: {
1.29 ! markus 604: Key *pub;
! 605: char file[MAXPATHLEN];
1.18 markus 606:
1.29 ! markus 607: pub = key_load_public_type(KEY_RSA1, filename, commentp);
! 608: if (pub != NULL)
! 609: return pub;
! 610: pub = key_new(KEY_UNSPEC);
! 611: if (key_try_load_public(pub, filename, commentp) == 1)
! 612: return pub;
! 613: if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
! 614: (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
! 615: (key_try_load_public(pub, file, commentp) == 1))
! 616: return pub;
! 617: key_free(pub);
! 618: return NULL;
1.1 deraadt 619: }