diff options
author | Ben Lindstrom <mouring@eviladmin.org> | 2001-03-26 13:44:06 +0000 |
---|---|---|
committer | Ben Lindstrom <mouring@eviladmin.org> | 2001-03-26 13:44:06 +0000 |
commit | d0fca423fcee576f4787d01f8bad3f9c0efd62ab (patch) | |
tree | 696cb73350804862b8e39ccb53dc4edff2f68976 /authfile.c | |
parent | 7bfff36ca3acf469de9fcad98826562ea6c1fbbe (diff) |
- markus@cvs.openbsd.org 2001/03/26 08:07:09
[authfile.c authfile.h ssh-add.c ssh-keygen.c ssh.c sshconnect.c
sshconnect.h sshconnect1.c sshconnect2.c sshd.c]
simpler key load/save interface, see authfile.h
Diffstat (limited to 'authfile.c')
-rw-r--r-- | authfile.c | 343 |
1 files changed, 181 insertions, 162 deletions
diff --git a/authfile.c b/authfile.c index 9f03d5137..c867724db 100644 --- a/authfile.c +++ b/authfile.c | |||
@@ -36,7 +36,7 @@ | |||
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include "includes.h" | 38 | #include "includes.h" |
39 | RCSID("$OpenBSD: authfile.c,v 1.28 2001/02/21 09:05:54 deraadt Exp $"); | 39 | RCSID("$OpenBSD: authfile.c,v 1.29 2001/03/26 08:07:07 markus Exp $"); |
40 | 40 | ||
41 | #include <openssl/err.h> | 41 | #include <openssl/err.h> |
42 | #include <openssl/evp.h> | 42 | #include <openssl/evp.h> |
@@ -51,7 +51,7 @@ RCSID("$OpenBSD: authfile.c,v 1.28 2001/02/21 09:05:54 deraadt Exp $"); | |||
51 | #include "log.h" | 51 | #include "log.h" |
52 | #include "authfile.h" | 52 | #include "authfile.h" |
53 | 53 | ||
54 | /* Version identification string for identity files. */ | 54 | /* Version identification string for SSH v1 identity files. */ |
55 | static const char authfile_id_string[] = | 55 | static const char authfile_id_string[] = |
56 | "SSH PRIVATE KEY FILE FORMAT 1.1\n"; | 56 | "SSH PRIVATE KEY FILE FORMAT 1.1\n"; |
57 | 57 | ||
@@ -63,8 +63,8 @@ static const char authfile_id_string[] = | |||
63 | */ | 63 | */ |
64 | 64 | ||
65 | int | 65 | int |
66 | save_private_key_rsa1(const char *filename, const char *passphrase, | 66 | key_save_private_rsa1(Key *key, const char *filename, const char *passphrase, |
67 | RSA *key, const char *comment) | 67 | const char *comment) |
68 | { | 68 | { |
69 | Buffer buffer, encrypted; | 69 | Buffer buffer, encrypted; |
70 | char buf[100], *cp; | 70 | char buf[100], *cp; |
@@ -100,10 +100,10 @@ save_private_key_rsa1(const char *filename, const char *passphrase, | |||
100 | * will be stored in plain text, and storing them also in encrypted | 100 | * will be stored in plain text, and storing them also in encrypted |
101 | * format would just give known plaintext). | 101 | * format would just give known plaintext). |
102 | */ | 102 | */ |
103 | buffer_put_bignum(&buffer, key->d); | 103 | buffer_put_bignum(&buffer, key->rsa->d); |
104 | buffer_put_bignum(&buffer, key->iqmp); | 104 | buffer_put_bignum(&buffer, key->rsa->iqmp); |
105 | buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */ | 105 | buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */ |
106 | buffer_put_bignum(&buffer, key->p); /* reverse from SSL q */ | 106 | buffer_put_bignum(&buffer, key->rsa->p); /* reverse from SSL q */ |
107 | 107 | ||
108 | /* Pad the part to be encrypted until its size is a multiple of 8. */ | 108 | /* Pad the part to be encrypted until its size is a multiple of 8. */ |
109 | while (buffer_len(&buffer) % 8 != 0) | 109 | while (buffer_len(&buffer) % 8 != 0) |
@@ -122,9 +122,9 @@ save_private_key_rsa1(const char *filename, const char *passphrase, | |||
122 | buffer_put_int(&encrypted, 0); /* For future extension */ | 122 | buffer_put_int(&encrypted, 0); /* For future extension */ |
123 | 123 | ||
124 | /* Store public key. This will be in plain text. */ | 124 | /* Store public key. This will be in plain text. */ |
125 | buffer_put_int(&encrypted, BN_num_bits(key->n)); | 125 | buffer_put_int(&encrypted, BN_num_bits(key->rsa->n)); |
126 | buffer_put_bignum(&encrypted, key->n); | 126 | buffer_put_bignum(&encrypted, key->rsa->n); |
127 | buffer_put_bignum(&encrypted, key->e); | 127 | buffer_put_bignum(&encrypted, key->rsa->e); |
128 | buffer_put_string(&encrypted, comment, strlen(comment)); | 128 | buffer_put_string(&encrypted, comment, strlen(comment)); |
129 | 129 | ||
130 | /* Allocate space for the private part of the key in the buffer. */ | 130 | /* Allocate space for the private part of the key in the buffer. */ |
@@ -156,10 +156,10 @@ save_private_key_rsa1(const char *filename, const char *passphrase, | |||
156 | return 1; | 156 | return 1; |
157 | } | 157 | } |
158 | 158 | ||
159 | /* save SSH2 key in OpenSSL PEM format */ | 159 | /* save SSH v2 key in OpenSSL PEM format */ |
160 | int | 160 | int |
161 | save_private_key_ssh2(const char *filename, const char *_passphrase, | 161 | key_save_private_pem(Key *key, const char *filename, const char *_passphrase, |
162 | Key *key, const char *comment) | 162 | const char *comment) |
163 | { | 163 | { |
164 | FILE *fp; | 164 | FILE *fp; |
165 | int fd; | 165 | int fd; |
@@ -199,16 +199,18 @@ save_private_key_ssh2(const char *filename, const char *_passphrase, | |||
199 | } | 199 | } |
200 | 200 | ||
201 | int | 201 | int |
202 | save_private_key(const char *filename, const char *passphrase, Key *key, | 202 | key_save_private(Key *key, const char *filename, const char *passphrase, |
203 | const char *comment) | 203 | const char *comment) |
204 | { | 204 | { |
205 | switch (key->type) { | 205 | switch (key->type) { |
206 | case KEY_RSA1: | 206 | case KEY_RSA1: |
207 | return save_private_key_rsa1(filename, passphrase, key->rsa, comment); | 207 | return key_save_private_rsa1(key, filename, passphrase, |
208 | comment); | ||
208 | break; | 209 | break; |
209 | case KEY_DSA: | 210 | case KEY_DSA: |
210 | case KEY_RSA: | 211 | case KEY_RSA: |
211 | return save_private_key_ssh2(filename, passphrase, key, comment); | 212 | return key_save_private_pem(key, filename, passphrase, |
213 | comment); | ||
212 | break; | 214 | break; |
213 | default: | 215 | default: |
214 | break; | 216 | break; |
@@ -217,22 +219,20 @@ save_private_key(const char *filename, const char *passphrase, Key *key, | |||
217 | } | 219 | } |
218 | 220 | ||
219 | /* | 221 | /* |
220 | * Loads the public part of the key file. Returns 0 if an error was | 222 | * Loads the public part of the ssh v1 key file. Returns NULL if an error was |
221 | * encountered (the file does not exist or is not readable), and non-zero | 223 | * encountered (the file does not exist or is not readable), and the key |
222 | * otherwise. | 224 | * otherwise. |
223 | */ | 225 | */ |
224 | 226 | ||
225 | int | 227 | Key * |
226 | load_public_key_rsa(const char *filename, RSA * pub, char **comment_return) | 228 | key_load_public_rsa1(int fd, const char *filename, char **commentp) |
227 | { | 229 | { |
228 | int fd, i; | ||
229 | off_t len; | ||
230 | Buffer buffer; | 230 | Buffer buffer; |
231 | Key *pub; | ||
231 | char *cp; | 232 | char *cp; |
233 | int i; | ||
234 | off_t len; | ||
232 | 235 | ||
233 | fd = open(filename, O_RDONLY); | ||
234 | if (fd < 0) | ||
235 | return 0; | ||
236 | len = lseek(fd, (off_t) 0, SEEK_END); | 236 | len = lseek(fd, (off_t) 0, SEEK_END); |
237 | lseek(fd, (off_t) 0, SEEK_SET); | 237 | lseek(fd, (off_t) 0, SEEK_SET); |
238 | 238 | ||
@@ -243,16 +243,14 @@ load_public_key_rsa(const char *filename, RSA * pub, char **comment_return) | |||
243 | debug("Read from key file %.200s failed: %.100s", filename, | 243 | debug("Read from key file %.200s failed: %.100s", filename, |
244 | strerror(errno)); | 244 | strerror(errno)); |
245 | buffer_free(&buffer); | 245 | buffer_free(&buffer); |
246 | close(fd); | 246 | return NULL; |
247 | return 0; | ||
248 | } | 247 | } |
249 | close(fd); | ||
250 | 248 | ||
251 | /* Check that it is at least big enough to contain the ID string. */ | 249 | /* Check that it is at least big enough to contain the ID string. */ |
252 | if (len < sizeof(authfile_id_string)) { | 250 | if (len < sizeof(authfile_id_string)) { |
253 | debug3("Bad RSA1 key file %.200s.", filename); | 251 | debug3("Bad RSA1 key file %.200s.", filename); |
254 | buffer_free(&buffer); | 252 | buffer_free(&buffer); |
255 | return 0; | 253 | return NULL; |
256 | } | 254 | } |
257 | /* | 255 | /* |
258 | * Make sure it begins with the id string. Consume the id string | 256 | * Make sure it begins with the id string. Consume the id string |
@@ -262,7 +260,7 @@ load_public_key_rsa(const char *filename, RSA * pub, char **comment_return) | |||
262 | if (buffer_get_char(&buffer) != authfile_id_string[i]) { | 260 | if (buffer_get_char(&buffer) != authfile_id_string[i]) { |
263 | debug3("Bad RSA1 key file %.200s.", filename); | 261 | debug3("Bad RSA1 key file %.200s.", filename); |
264 | buffer_free(&buffer); | 262 | buffer_free(&buffer); |
265 | return 0; | 263 | return NULL; |
266 | } | 264 | } |
267 | /* Skip cipher type and reserved data. */ | 265 | /* Skip cipher type and reserved data. */ |
268 | (void) buffer_get_char(&buffer); /* cipher type */ | 266 | (void) buffer_get_char(&buffer); /* cipher type */ |
@@ -270,37 +268,33 @@ load_public_key_rsa(const char *filename, RSA * pub, char **comment_return) | |||
270 | 268 | ||
271 | /* Read the public key from the buffer. */ | 269 | /* Read the public key from the buffer. */ |
272 | buffer_get_int(&buffer); | 270 | buffer_get_int(&buffer); |
273 | /* XXX alloc */ | 271 | pub = key_new(KEY_RSA1); |
274 | if (pub->n == NULL) | 272 | buffer_get_bignum(&buffer, pub->rsa->n); |
275 | pub->n = BN_new(); | 273 | buffer_get_bignum(&buffer, pub->rsa->e); |
276 | buffer_get_bignum(&buffer, pub->n); | 274 | if (commentp) |
277 | /* XXX alloc */ | 275 | *commentp = buffer_get_string(&buffer, NULL); |
278 | if (pub->e == NULL) | ||
279 | pub->e = BN_new(); | ||
280 | buffer_get_bignum(&buffer, pub->e); | ||
281 | if (comment_return) | ||
282 | *comment_return = buffer_get_string(&buffer, NULL); | ||
283 | /* The encrypted private part is not parsed by this function. */ | 276 | /* The encrypted private part is not parsed by this function. */ |
284 | 277 | ||
285 | buffer_free(&buffer); | 278 | buffer_free(&buffer); |
286 | 279 | return pub; | |
287 | return 1; | ||
288 | } | 280 | } |
289 | 281 | ||
290 | /* load public key from private-key file */ | 282 | /* load public key from private-key file, works only for SSH v1 */ |
291 | int | 283 | Key * |
292 | load_public_key(const char *filename, Key * key, char **comment_return) | 284 | key_load_public_type(int type, const char *filename, char **commentp) |
293 | { | 285 | { |
294 | switch (key->type) { | 286 | Key *pub; |
295 | case KEY_RSA1: | 287 | int fd; |
296 | return load_public_key_rsa(filename, key->rsa, comment_return); | 288 | |
297 | break; | 289 | if (type == KEY_RSA1) { |
298 | case KEY_DSA: | 290 | fd = open(filename, O_RDONLY); |
299 | case KEY_RSA: | 291 | if (fd < 0) |
300 | default: | 292 | return NULL; |
301 | break; | 293 | pub = key_load_public_rsa1(fd, filename, commentp); |
294 | close(fd); | ||
295 | return pub; | ||
302 | } | 296 | } |
303 | return 0; | 297 | return NULL; |
304 | } | 298 | } |
305 | 299 | ||
306 | /* | 300 | /* |
@@ -310,9 +304,9 @@ load_public_key(const char *filename, Key * key, char **comment_return) | |||
310 | * Assumes we are called under uid of the owner of the file. | 304 | * Assumes we are called under uid of the owner of the file. |
311 | */ | 305 | */ |
312 | 306 | ||
313 | int | 307 | Key * |
314 | load_private_key_rsa1(int fd, const char *filename, | 308 | key_load_private_rsa1(int fd, const char *filename, const char *passphrase, |
315 | const char *passphrase, RSA * prv, char **comment_return) | 309 | char **commentp) |
316 | { | 310 | { |
317 | int i, check1, check2, cipher_type; | 311 | int i, check1, check2, cipher_type; |
318 | off_t len; | 312 | off_t len; |
@@ -322,6 +316,7 @@ load_private_key_rsa1(int fd, const char *filename, | |||
322 | Cipher *cipher; | 316 | Cipher *cipher; |
323 | BN_CTX *ctx; | 317 | BN_CTX *ctx; |
324 | BIGNUM *aux; | 318 | BIGNUM *aux; |
319 | Key *prv = NULL; | ||
325 | 320 | ||
326 | len = lseek(fd, (off_t) 0, SEEK_END); | 321 | len = lseek(fd, (off_t) 0, SEEK_END); |
327 | lseek(fd, (off_t) 0, SEEK_SET); | 322 | lseek(fd, (off_t) 0, SEEK_SET); |
@@ -334,7 +329,7 @@ load_private_key_rsa1(int fd, const char *filename, | |||
334 | strerror(errno)); | 329 | strerror(errno)); |
335 | buffer_free(&buffer); | 330 | buffer_free(&buffer); |
336 | close(fd); | 331 | close(fd); |
337 | return 0; | 332 | return NULL; |
338 | } | 333 | } |
339 | 334 | ||
340 | /* Check that it is at least big enough to contain the ID string. */ | 335 | /* Check that it is at least big enough to contain the ID string. */ |
@@ -342,7 +337,7 @@ load_private_key_rsa1(int fd, const char *filename, | |||
342 | debug3("Bad RSA1 key file %.200s.", filename); | 337 | debug3("Bad RSA1 key file %.200s.", filename); |
343 | buffer_free(&buffer); | 338 | buffer_free(&buffer); |
344 | close(fd); | 339 | close(fd); |
345 | return 0; | 340 | return NULL; |
346 | } | 341 | } |
347 | /* | 342 | /* |
348 | * Make sure it begins with the id string. Consume the id string | 343 | * Make sure it begins with the id string. Consume the id string |
@@ -353,7 +348,7 @@ load_private_key_rsa1(int fd, const char *filename, | |||
353 | debug3("Bad RSA1 key file %.200s.", filename); | 348 | debug3("Bad RSA1 key file %.200s.", filename); |
354 | buffer_free(&buffer); | 349 | buffer_free(&buffer); |
355 | close(fd); | 350 | close(fd); |
356 | return 0; | 351 | return NULL; |
357 | } | 352 | } |
358 | 353 | ||
359 | /* Read cipher type. */ | 354 | /* Read cipher type. */ |
@@ -362,12 +357,12 @@ load_private_key_rsa1(int fd, const char *filename, | |||
362 | 357 | ||
363 | /* Read the public key from the buffer. */ | 358 | /* Read the public key from the buffer. */ |
364 | buffer_get_int(&buffer); | 359 | buffer_get_int(&buffer); |
365 | prv->n = BN_new(); | 360 | prv = key_new_private(KEY_RSA1); |
366 | buffer_get_bignum(&buffer, prv->n); | 361 | |
367 | prv->e = BN_new(); | 362 | buffer_get_bignum(&buffer, prv->rsa->n); |
368 | buffer_get_bignum(&buffer, prv->e); | 363 | buffer_get_bignum(&buffer, prv->rsa->e); |
369 | if (comment_return) | 364 | if (commentp) |
370 | *comment_return = buffer_get_string(&buffer, NULL); | 365 | *commentp = buffer_get_string(&buffer, NULL); |
371 | else | 366 | else |
372 | xfree(buffer_get_string(&buffer, NULL)); | 367 | xfree(buffer_get_string(&buffer, NULL)); |
373 | 368 | ||
@@ -395,93 +390,81 @@ load_private_key_rsa1(int fd, const char *filename, | |||
395 | if (check1 != buffer_get_char(&decrypted) || | 390 | if (check1 != buffer_get_char(&decrypted) || |
396 | check2 != buffer_get_char(&decrypted)) { | 391 | check2 != buffer_get_char(&decrypted)) { |
397 | if (strcmp(passphrase, "") != 0) | 392 | if (strcmp(passphrase, "") != 0) |
398 | debug("Bad passphrase supplied for key file %.200s.", filename); | 393 | debug("Bad passphrase supplied for key file %.200s.", |
394 | filename); | ||
399 | /* Bad passphrase. */ | 395 | /* Bad passphrase. */ |
400 | buffer_free(&decrypted); | 396 | buffer_free(&decrypted); |
401 | fail: | 397 | goto fail; |
402 | BN_clear_free(prv->n); | ||
403 | prv->n = NULL; | ||
404 | BN_clear_free(prv->e); | ||
405 | prv->e = NULL; | ||
406 | if (comment_return) | ||
407 | xfree(*comment_return); | ||
408 | close(fd); | ||
409 | return 0; | ||
410 | } | 398 | } |
411 | /* Read the rest of the private key. */ | 399 | /* Read the rest of the private key. */ |
412 | prv->d = BN_new(); | 400 | buffer_get_bignum(&decrypted, prv->rsa->d); |
413 | buffer_get_bignum(&decrypted, prv->d); | 401 | buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */ |
414 | prv->iqmp = BN_new(); | 402 | /* in SSL and SSH v1 p and q are exchanged */ |
415 | buffer_get_bignum(&decrypted, prv->iqmp); /* u */ | 403 | buffer_get_bignum(&decrypted, prv->rsa->q); /* p */ |
416 | /* in SSL and SSH p and q are exchanged */ | 404 | buffer_get_bignum(&decrypted, prv->rsa->p); /* q */ |
417 | prv->q = BN_new(); | ||
418 | buffer_get_bignum(&decrypted, prv->q); /* p */ | ||
419 | prv->p = BN_new(); | ||
420 | buffer_get_bignum(&decrypted, prv->p); /* q */ | ||
421 | 405 | ||
406 | /* calculate p-1 and q-1 */ | ||
422 | ctx = BN_CTX_new(); | 407 | ctx = BN_CTX_new(); |
423 | aux = BN_new(); | 408 | aux = BN_new(); |
424 | 409 | ||
425 | BN_sub(aux, prv->q, BN_value_one()); | 410 | BN_sub(aux, prv->rsa->q, BN_value_one()); |
426 | prv->dmq1 = BN_new(); | 411 | BN_mod(prv->rsa->dmq1, prv->rsa->d, aux, ctx); |
427 | BN_mod(prv->dmq1, prv->d, aux, ctx); | ||
428 | 412 | ||
429 | BN_sub(aux, prv->p, BN_value_one()); | 413 | BN_sub(aux, prv->rsa->p, BN_value_one()); |
430 | prv->dmp1 = BN_new(); | 414 | BN_mod(prv->rsa->dmp1, prv->rsa->d, aux, ctx); |
431 | BN_mod(prv->dmp1, prv->d, aux, ctx); | ||
432 | 415 | ||
433 | BN_clear_free(aux); | 416 | BN_clear_free(aux); |
434 | BN_CTX_free(ctx); | 417 | BN_CTX_free(ctx); |
435 | 418 | ||
436 | buffer_free(&decrypted); | 419 | buffer_free(&decrypted); |
437 | close(fd); | 420 | close(fd); |
438 | return 1; | 421 | return prv; |
422 | |||
423 | fail: | ||
424 | if (commentp) | ||
425 | xfree(*commentp); | ||
426 | close(fd); | ||
427 | key_free(prv); | ||
428 | return NULL; | ||
439 | } | 429 | } |
440 | 430 | ||
441 | int | 431 | Key * |
442 | load_private_key_ssh2(int fd, const char *passphrase, Key *k, char **comment_return) | 432 | key_load_private_pem(int fd, int type, const char *passphrase, |
433 | char **commentp) | ||
443 | { | 434 | { |
444 | FILE *fp; | 435 | FILE *fp; |
445 | int success = 0; | ||
446 | EVP_PKEY *pk = NULL; | 436 | EVP_PKEY *pk = NULL; |
437 | Key *prv = NULL; | ||
447 | char *name = "<no key>"; | 438 | char *name = "<no key>"; |
448 | 439 | ||
449 | fp = fdopen(fd, "r"); | 440 | fp = fdopen(fd, "r"); |
450 | if (fp == NULL) { | 441 | if (fp == NULL) { |
451 | error("fdopen failed"); | 442 | error("fdopen failed"); |
452 | close(fd); | 443 | close(fd); |
453 | return 0; | 444 | return NULL; |
454 | } | 445 | } |
455 | pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase); | 446 | pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase); |
456 | if (pk == NULL) { | 447 | if (pk == NULL) { |
457 | debug("PEM_read_PrivateKey failed"); | 448 | debug("PEM_read_PrivateKey failed"); |
458 | (void)ERR_get_error(); | 449 | (void)ERR_get_error(); |
459 | } else if (pk->type == EVP_PKEY_RSA) { | 450 | } else if (pk->type == EVP_PKEY_RSA && |
460 | /* replace k->rsa with loaded key */ | 451 | (type == KEY_UNSPEC||type==KEY_RSA)) { |
461 | if (k->type == KEY_RSA || k->type == KEY_UNSPEC) { | 452 | prv = key_new(KEY_UNSPEC); |
462 | if (k->rsa != NULL) | 453 | prv->rsa = EVP_PKEY_get1_RSA(pk); |
463 | RSA_free(k->rsa); | 454 | prv->type = KEY_RSA; |
464 | k->rsa = EVP_PKEY_get1_RSA(pk); | 455 | name = "rsa w/o comment"; |
465 | k->type = KEY_RSA; | ||
466 | name = "rsa w/o comment"; | ||
467 | success = 1; | ||
468 | #ifdef DEBUG_PK | 456 | #ifdef DEBUG_PK |
469 | RSA_print_fp(stderr, k->rsa, 8); | 457 | RSA_print_fp(stderr, prv->rsa, 8); |
470 | #endif | 458 | #endif |
471 | } | 459 | } else if (pk->type == EVP_PKEY_DSA && |
472 | } else if (pk->type == EVP_PKEY_DSA) { | 460 | (type == KEY_UNSPEC||type==KEY_DSA)) { |
473 | /* replace k->dsa with loaded key */ | 461 | prv = key_new(KEY_UNSPEC); |
474 | if (k->type == KEY_DSA || k->type == KEY_UNSPEC) { | 462 | prv->dsa = EVP_PKEY_get1_DSA(pk); |
475 | if (k->dsa != NULL) | 463 | prv->type = KEY_DSA; |
476 | DSA_free(k->dsa); | 464 | name = "dsa w/o comment"; |
477 | k->dsa = EVP_PKEY_get1_DSA(pk); | ||
478 | k->type = KEY_DSA; | ||
479 | name = "dsa w/o comment"; | ||
480 | #ifdef DEBUG_PK | 465 | #ifdef DEBUG_PK |
481 | DSA_print_fp(stderr, k->dsa, 8); | 466 | DSA_print_fp(stderr, prv->dsa, 8); |
482 | #endif | 467 | #endif |
483 | success = 1; | ||
484 | } | ||
485 | } else { | 468 | } else { |
486 | error("PEM_read_PrivateKey: mismatch or " | 469 | error("PEM_read_PrivateKey: mismatch or " |
487 | "unknown EVP_PKEY save_type %d", pk->save_type); | 470 | "unknown EVP_PKEY save_type %d", pk->save_type); |
@@ -489,24 +472,18 @@ load_private_key_ssh2(int fd, const char *passphrase, Key *k, char **comment_ret | |||
489 | fclose(fp); | 472 | fclose(fp); |
490 | if (pk != NULL) | 473 | if (pk != NULL) |
491 | EVP_PKEY_free(pk); | 474 | EVP_PKEY_free(pk); |
492 | if (success && comment_return) | 475 | if (prv != NULL && commentp) |
493 | *comment_return = xstrdup(name); | 476 | *commentp = xstrdup(name); |
494 | debug("read SSH2 private key done: name %s success %d", name, success); | 477 | debug("read PEM private key done: type %s", |
495 | return success; | 478 | prv ? key_type(prv) : "<unknown>"); |
479 | return prv; | ||
496 | } | 480 | } |
497 | 481 | ||
498 | int | 482 | int |
499 | load_private_key(const char *filename, const char *passphrase, Key *key, | 483 | key_perm_ok(int fd, const char *filename) |
500 | char **comment_return) | ||
501 | { | 484 | { |
502 | int fd; | ||
503 | int ret = 0; | ||
504 | struct stat st; | 485 | struct stat st; |
505 | 486 | ||
506 | fd = open(filename, O_RDONLY); | ||
507 | if (fd < 0) | ||
508 | return 0; | ||
509 | |||
510 | /* check owner and modes */ | 487 | /* check owner and modes */ |
511 | #ifdef HAVE_CYGWIN | 488 | #ifdef HAVE_CYGWIN |
512 | if (check_ntsec(filename)) | 489 | if (check_ntsec(filename)) |
@@ -521,40 +498,78 @@ load_private_key(const char *filename, const char *passphrase, Key *key, | |||
521 | error("Bad ownership or mode(0%3.3o) for '%s'.", | 498 | error("Bad ownership or mode(0%3.3o) for '%s'.", |
522 | st.st_mode & 0777, filename); | 499 | st.st_mode & 0777, filename); |
523 | error("It is recommended that your private key files are NOT accessible by others."); | 500 | error("It is recommended that your private key files are NOT accessible by others."); |
501 | error("This private key will be ignored."); | ||
524 | return 0; | 502 | return 0; |
525 | } | 503 | } |
526 | switch (key->type) { | 504 | return 1; |
527 | case KEY_RSA1: | 505 | } |
528 | if (key->rsa->e != NULL) { | ||
529 | BN_clear_free(key->rsa->e); | ||
530 | key->rsa->e = NULL; | ||
531 | } | ||
532 | if (key->rsa->n != NULL) { | ||
533 | BN_clear_free(key->rsa->n); | ||
534 | key->rsa->n = NULL; | ||
535 | } | ||
536 | ret = load_private_key_rsa1(fd, filename, passphrase, | ||
537 | key->rsa, comment_return); /* closes fd */ | ||
538 | 506 | ||
507 | Key * | ||
508 | key_load_private_type(int type, const char *filename, const char *passphrase, | ||
509 | char **commentp) | ||
510 | { | ||
511 | int fd; | ||
512 | |||
513 | fd = open(filename, O_RDONLY); | ||
514 | if (fd < 0) | ||
515 | return NULL; | ||
516 | if (!key_perm_ok(fd, filename)) { | ||
517 | debug("bad permissions: ignore key: %s", filename); | ||
518 | close(fd); | ||
519 | return NULL; | ||
520 | } | ||
521 | switch (type) { | ||
522 | case KEY_RSA1: | ||
523 | return key_load_private_rsa1(fd, filename, passphrase, | ||
524 | commentp); | ||
525 | /* closes fd */ | ||
539 | break; | 526 | break; |
540 | case KEY_DSA: | 527 | case KEY_DSA: |
541 | case KEY_RSA: | 528 | case KEY_RSA: |
542 | case KEY_UNSPEC: | 529 | case KEY_UNSPEC: |
543 | ret = load_private_key_ssh2(fd, passphrase, key, | 530 | return key_load_private_pem(fd, type, passphrase, commentp); |
544 | comment_return); /* closes fd */ | 531 | /* closes fd */ |
545 | break; | 532 | break; |
546 | default: | 533 | default: |
547 | close(fd); | 534 | close(fd); |
548 | break; | 535 | break; |
549 | } | 536 | } |
550 | return ret; | 537 | return NULL; |
538 | } | ||
539 | |||
540 | Key * | ||
541 | key_load_private(const char *filename, const char *passphrase, | ||
542 | char **commentp) | ||
543 | { | ||
544 | Key *pub; | ||
545 | int fd; | ||
546 | |||
547 | fd = open(filename, O_RDONLY); | ||
548 | if (fd < 0) | ||
549 | return NULL; | ||
550 | if (!key_perm_ok(fd, filename)) { | ||
551 | debug("bad permissions: ignore key: %s", filename); | ||
552 | close(fd); | ||
553 | return NULL; | ||
554 | } | ||
555 | pub = key_load_public_rsa1(fd, filename, commentp); | ||
556 | lseek(fd, (off_t) 0, SEEK_SET); /* rewind */ | ||
557 | if (pub == NULL) { | ||
558 | /* closes fd */ | ||
559 | return key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL); | ||
560 | } else { | ||
561 | /* it's a SSH v1 key if the public key part is readable */ | ||
562 | key_free(pub); | ||
563 | /* closes fd */ | ||
564 | return key_load_private_rsa1(fd, filename, passphrase, NULL); | ||
565 | } | ||
551 | } | 566 | } |
552 | 567 | ||
553 | int | 568 | int |
554 | do_load_public_key(const char *filename, Key *k, char **commentp) | 569 | key_try_load_public(Key *k, const char *filename, char **commentp) |
555 | { | 570 | { |
556 | FILE *f; | 571 | FILE *f; |
557 | char line[1024]; | 572 | char line[4096]; |
558 | char *cp; | 573 | char *cp; |
559 | 574 | ||
560 | f = fopen(filename, "r"); | 575 | f = fopen(filename, "r"); |
@@ -585,19 +600,23 @@ do_load_public_key(const char *filename, Key *k, char **commentp) | |||
585 | return 0; | 600 | return 0; |
586 | } | 601 | } |
587 | 602 | ||
588 | /* load public key from pubkey file */ | 603 | /* load public key from ssh v1 private or any pubkey file */ |
589 | int | 604 | Key * |
590 | try_load_public_key(const char *filename, Key *k, char **commentp) | 605 | key_load_public(const char *filename, char **commentp) |
591 | { | 606 | { |
592 | char pub[MAXPATHLEN]; | 607 | Key *pub; |
593 | 608 | char file[MAXPATHLEN]; | |
594 | if (do_load_public_key(filename, k, commentp) == 1) | 609 | |
595 | return 1; | 610 | pub = key_load_public_type(KEY_RSA1, filename, commentp); |
596 | if (strlcpy(pub, filename, sizeof pub) >= MAXPATHLEN) | 611 | if (pub != NULL) |
597 | return 0; | 612 | return pub; |
598 | if (strlcat(pub, ".pub", sizeof pub) >= MAXPATHLEN) | 613 | pub = key_new(KEY_UNSPEC); |
599 | return 0; | 614 | if (key_try_load_public(pub, filename, commentp) == 1) |
600 | if (do_load_public_key(pub, k, commentp) == 1) | 615 | return pub; |
601 | return 1; | 616 | if ((strlcpy(file, filename, sizeof file) < sizeof(file)) && |
602 | return 0; | 617 | (strlcat(file, ".pub", sizeof file) < sizeof(file)) && |
618 | (key_try_load_public(pub, file, commentp) == 1)) | ||
619 | return pub; | ||
620 | key_free(pub); | ||
621 | return NULL; | ||
603 | } | 622 | } |