diff options
Diffstat (limited to 'sshkey.c')
-rw-r--r-- | sshkey.c | 487 |
1 files changed, 255 insertions, 232 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshkey.c,v 1.99 2020/01/21 05:56:56 djm Exp $ */ | 1 | /* $OpenBSD: sshkey.c,v 1.108 2020/04/11 10:16:11 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2008 Alexander von Gernler. All rights reserved. | 4 | * Copyright (c) 2008 Alexander von Gernler. All rights reserved. |
@@ -1020,10 +1020,8 @@ sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg, | |||
1020 | r = 0; | 1020 | r = 0; |
1021 | out: | 1021 | out: |
1022 | free(ret); | 1022 | free(ret); |
1023 | if (blob != NULL) { | 1023 | if (blob != NULL) |
1024 | explicit_bzero(blob, blob_len); | 1024 | freezero(blob, blob_len); |
1025 | free(blob); | ||
1026 | } | ||
1027 | return r; | 1025 | return r; |
1028 | } | 1026 | } |
1029 | 1027 | ||
@@ -1281,12 +1279,10 @@ sshkey_fingerprint(const struct sshkey *k, int dgst_alg, | |||
1281 | dgst_raw, dgst_raw_len, k); | 1279 | dgst_raw, dgst_raw_len, k); |
1282 | break; | 1280 | break; |
1283 | default: | 1281 | default: |
1284 | explicit_bzero(dgst_raw, dgst_raw_len); | 1282 | freezero(dgst_raw, dgst_raw_len); |
1285 | free(dgst_raw); | ||
1286 | return NULL; | 1283 | return NULL; |
1287 | } | 1284 | } |
1288 | explicit_bzero(dgst_raw, dgst_raw_len); | 1285 | freezero(dgst_raw, dgst_raw_len); |
1289 | free(dgst_raw); | ||
1290 | return retval; | 1286 | return retval; |
1291 | } | 1287 | } |
1292 | 1288 | ||
@@ -3083,8 +3079,8 @@ sshkey_cert_check_authority(const struct sshkey *k, | |||
3083 | u_int i, principal_matches; | 3079 | u_int i, principal_matches; |
3084 | time_t now = time(NULL); | 3080 | time_t now = time(NULL); |
3085 | 3081 | ||
3086 | if (reason != NULL) | 3082 | if (reason == NULL) |
3087 | *reason = NULL; | 3083 | return SSH_ERR_INVALID_ARGUMENT; |
3088 | 3084 | ||
3089 | if (want_host) { | 3085 | if (want_host) { |
3090 | if (k->cert->type != SSH2_CERT_TYPE_HOST) { | 3086 | if (k->cert->type != SSH2_CERT_TYPE_HOST) { |
@@ -3399,38 +3395,52 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) | |||
3399 | if ((r = sshbuf_get_cstring(buf, &tname, NULL)) != 0) | 3395 | if ((r = sshbuf_get_cstring(buf, &tname, NULL)) != 0) |
3400 | goto out; | 3396 | goto out; |
3401 | type = sshkey_type_from_name(tname); | 3397 | type = sshkey_type_from_name(tname); |
3402 | switch (type) { | 3398 | if (sshkey_type_is_cert(type)) { |
3403 | #ifdef WITH_OPENSSL | 3399 | /* |
3404 | case KEY_DSA: | 3400 | * Certificate key private keys begin with the certificate |
3401 | * itself. Make sure this matches the type of the enclosing | ||
3402 | * private key. | ||
3403 | */ | ||
3404 | if ((r = sshkey_froms(buf, &k)) != 0) | ||
3405 | goto out; | ||
3406 | if (k->type != type) { | ||
3407 | r = SSH_ERR_KEY_CERT_MISMATCH; | ||
3408 | goto out; | ||
3409 | } | ||
3410 | /* For ECDSA keys, the group must match too */ | ||
3411 | if (k->type == KEY_ECDSA && | ||
3412 | k->ecdsa_nid != sshkey_ecdsa_nid_from_name(tname)) { | ||
3413 | r = SSH_ERR_KEY_CERT_MISMATCH; | ||
3414 | goto out; | ||
3415 | } | ||
3416 | } else { | ||
3405 | if ((k = sshkey_new(type)) == NULL) { | 3417 | if ((k = sshkey_new(type)) == NULL) { |
3406 | r = SSH_ERR_ALLOC_FAIL; | 3418 | r = SSH_ERR_ALLOC_FAIL; |
3407 | goto out; | 3419 | goto out; |
3408 | } | 3420 | } |
3421 | } | ||
3422 | switch (type) { | ||
3423 | #ifdef WITH_OPENSSL | ||
3424 | case KEY_DSA: | ||
3409 | if ((r = sshbuf_get_bignum2(buf, &dsa_p)) != 0 || | 3425 | if ((r = sshbuf_get_bignum2(buf, &dsa_p)) != 0 || |
3410 | (r = sshbuf_get_bignum2(buf, &dsa_q)) != 0 || | 3426 | (r = sshbuf_get_bignum2(buf, &dsa_q)) != 0 || |
3411 | (r = sshbuf_get_bignum2(buf, &dsa_g)) != 0 || | 3427 | (r = sshbuf_get_bignum2(buf, &dsa_g)) != 0 || |
3412 | (r = sshbuf_get_bignum2(buf, &dsa_pub_key)) != 0 || | 3428 | (r = sshbuf_get_bignum2(buf, &dsa_pub_key)) != 0) |
3413 | (r = sshbuf_get_bignum2(buf, &dsa_priv_key)) != 0) | ||
3414 | goto out; | 3429 | goto out; |
3415 | if (!DSA_set0_pqg(k->dsa, dsa_p, dsa_q, dsa_g)) { | 3430 | if (!DSA_set0_pqg(k->dsa, dsa_p, dsa_q, dsa_g)) { |
3416 | r = SSH_ERR_LIBCRYPTO_ERROR; | 3431 | r = SSH_ERR_LIBCRYPTO_ERROR; |
3417 | goto out; | 3432 | goto out; |
3418 | } | 3433 | } |
3419 | dsa_p = dsa_q = dsa_g = NULL; /* transferred */ | 3434 | dsa_p = dsa_q = dsa_g = NULL; /* transferred */ |
3420 | if (!DSA_set0_key(k->dsa, dsa_pub_key, dsa_priv_key)) { | 3435 | if (!DSA_set0_key(k->dsa, dsa_pub_key, NULL)) { |
3421 | r = SSH_ERR_LIBCRYPTO_ERROR; | 3436 | r = SSH_ERR_LIBCRYPTO_ERROR; |
3422 | goto out; | 3437 | goto out; |
3423 | } | 3438 | } |
3424 | dsa_pub_key = dsa_priv_key = NULL; /* transferred */ | 3439 | dsa_pub_key = NULL; /* transferred */ |
3425 | break; | 3440 | /* FALLTHROUGH */ |
3426 | case KEY_DSA_CERT: | 3441 | case KEY_DSA_CERT: |
3427 | if ((r = sshkey_froms(buf, &k)) != 0 || | 3442 | if ((r = sshbuf_get_bignum2(buf, &dsa_priv_key)) != 0) |
3428 | (r = sshbuf_get_bignum2(buf, &dsa_priv_key)) != 0) | ||
3429 | goto out; | 3443 | goto out; |
3430 | if (k->type != type) { | ||
3431 | r = SSH_ERR_INVALID_FORMAT; | ||
3432 | goto out; | ||
3433 | } | ||
3434 | if (!DSA_set0_key(k->dsa, NULL, dsa_priv_key)) { | 3444 | if (!DSA_set0_key(k->dsa, NULL, dsa_priv_key)) { |
3435 | r = SSH_ERR_LIBCRYPTO_ERROR; | 3445 | r = SSH_ERR_LIBCRYPTO_ERROR; |
3436 | goto out; | 3446 | goto out; |
@@ -3439,10 +3449,6 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) | |||
3439 | break; | 3449 | break; |
3440 | # ifdef OPENSSL_HAS_ECC | 3450 | # ifdef OPENSSL_HAS_ECC |
3441 | case KEY_ECDSA: | 3451 | case KEY_ECDSA: |
3442 | if ((k = sshkey_new(type)) == NULL) { | ||
3443 | r = SSH_ERR_ALLOC_FAIL; | ||
3444 | goto out; | ||
3445 | } | ||
3446 | if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) { | 3452 | if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) { |
3447 | r = SSH_ERR_INVALID_ARGUMENT; | 3453 | r = SSH_ERR_INVALID_ARGUMENT; |
3448 | goto out; | 3454 | goto out; |
@@ -3458,27 +3464,12 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) | |||
3458 | r = SSH_ERR_LIBCRYPTO_ERROR; | 3464 | r = SSH_ERR_LIBCRYPTO_ERROR; |
3459 | goto out; | 3465 | goto out; |
3460 | } | 3466 | } |
3461 | if ((r = sshbuf_get_eckey(buf, k->ecdsa)) != 0 || | 3467 | if ((r = sshbuf_get_eckey(buf, k->ecdsa)) != 0) |
3462 | (r = sshbuf_get_bignum2(buf, &exponent))) | ||
3463 | goto out; | ||
3464 | if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) { | ||
3465 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
3466 | goto out; | ||
3467 | } | ||
3468 | if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa), | ||
3469 | EC_KEY_get0_public_key(k->ecdsa))) != 0 || | ||
3470 | (r = sshkey_ec_validate_private(k->ecdsa)) != 0) | ||
3471 | goto out; | 3468 | goto out; |
3472 | break; | 3469 | /* FALLTHROUGH */ |
3473 | case KEY_ECDSA_CERT: | 3470 | case KEY_ECDSA_CERT: |
3474 | if ((r = sshkey_froms(buf, &k)) != 0 || | 3471 | if ((r = sshbuf_get_bignum2(buf, &exponent)) != 0) |
3475 | (r = sshbuf_get_bignum2(buf, &exponent)) != 0) | ||
3476 | goto out; | ||
3477 | if (k->type != type || | ||
3478 | k->ecdsa_nid != sshkey_ecdsa_nid_from_name(tname)) { | ||
3479 | r = SSH_ERR_INVALID_FORMAT; | ||
3480 | goto out; | 3472 | goto out; |
3481 | } | ||
3482 | if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) { | 3473 | if (EC_KEY_set_private_key(k->ecdsa, exponent) != 1) { |
3483 | r = SSH_ERR_LIBCRYPTO_ERROR; | 3474 | r = SSH_ERR_LIBCRYPTO_ERROR; |
3484 | goto out; | 3475 | goto out; |
@@ -3489,10 +3480,6 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) | |||
3489 | goto out; | 3480 | goto out; |
3490 | break; | 3481 | break; |
3491 | case KEY_ECDSA_SK: | 3482 | case KEY_ECDSA_SK: |
3492 | if ((k = sshkey_new(type)) == NULL) { | ||
3493 | r = SSH_ERR_ALLOC_FAIL; | ||
3494 | goto out; | ||
3495 | } | ||
3496 | if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) { | 3483 | if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) { |
3497 | r = SSH_ERR_INVALID_ARGUMENT; | 3484 | r = SSH_ERR_INVALID_ARGUMENT; |
3498 | goto out; | 3485 | goto out; |
@@ -3525,8 +3512,6 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) | |||
3525 | goto out; | 3512 | goto out; |
3526 | break; | 3513 | break; |
3527 | case KEY_ECDSA_SK_CERT: | 3514 | case KEY_ECDSA_SK_CERT: |
3528 | if ((r = sshkey_froms(buf, &k)) != 0) | ||
3529 | goto out; | ||
3530 | if ((k->sk_key_handle = sshbuf_new()) == NULL || | 3515 | if ((k->sk_key_handle = sshbuf_new()) == NULL || |
3531 | (k->sk_reserved = sshbuf_new()) == NULL) { | 3516 | (k->sk_reserved = sshbuf_new()) == NULL) { |
3532 | r = SSH_ERR_ALLOC_FAIL; | 3517 | r = SSH_ERR_ALLOC_FAIL; |
@@ -3544,43 +3529,21 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) | |||
3544 | break; | 3529 | break; |
3545 | # endif /* OPENSSL_HAS_ECC */ | 3530 | # endif /* OPENSSL_HAS_ECC */ |
3546 | case KEY_RSA: | 3531 | case KEY_RSA: |
3547 | if ((k = sshkey_new(type)) == NULL) { | ||
3548 | r = SSH_ERR_ALLOC_FAIL; | ||
3549 | goto out; | ||
3550 | } | ||
3551 | if ((r = sshbuf_get_bignum2(buf, &rsa_n)) != 0 || | 3532 | if ((r = sshbuf_get_bignum2(buf, &rsa_n)) != 0 || |
3552 | (r = sshbuf_get_bignum2(buf, &rsa_e)) != 0 || | 3533 | (r = sshbuf_get_bignum2(buf, &rsa_e)) != 0) |
3553 | (r = sshbuf_get_bignum2(buf, &rsa_d)) != 0 || | ||
3554 | (r = sshbuf_get_bignum2(buf, &rsa_iqmp)) != 0 || | ||
3555 | (r = sshbuf_get_bignum2(buf, &rsa_p)) != 0 || | ||
3556 | (r = sshbuf_get_bignum2(buf, &rsa_q)) != 0) | ||
3557 | goto out; | 3534 | goto out; |
3558 | if (!RSA_set0_key(k->rsa, rsa_n, rsa_e, rsa_d)) { | 3535 | if (!RSA_set0_key(k->rsa, rsa_n, rsa_e, NULL)) { |
3559 | r = SSH_ERR_LIBCRYPTO_ERROR; | 3536 | r = SSH_ERR_LIBCRYPTO_ERROR; |
3560 | goto out; | 3537 | goto out; |
3561 | } | 3538 | } |
3562 | rsa_n = rsa_e = rsa_d = NULL; /* transferred */ | 3539 | rsa_n = rsa_e = NULL; /* transferred */ |
3563 | if (!RSA_set0_factors(k->rsa, rsa_p, rsa_q)) { | 3540 | /* FALLTHROUGH */ |
3564 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
3565 | goto out; | ||
3566 | } | ||
3567 | rsa_p = rsa_q = NULL; /* transferred */ | ||
3568 | if ((r = check_rsa_length(k->rsa)) != 0) | ||
3569 | goto out; | ||
3570 | if ((r = ssh_rsa_complete_crt_parameters(k, rsa_iqmp)) != 0) | ||
3571 | goto out; | ||
3572 | break; | ||
3573 | case KEY_RSA_CERT: | 3541 | case KEY_RSA_CERT: |
3574 | if ((r = sshkey_froms(buf, &k)) != 0 || | 3542 | if ((r = sshbuf_get_bignum2(buf, &rsa_d)) != 0 || |
3575 | (r = sshbuf_get_bignum2(buf, &rsa_d)) != 0 || | ||
3576 | (r = sshbuf_get_bignum2(buf, &rsa_iqmp)) != 0 || | 3543 | (r = sshbuf_get_bignum2(buf, &rsa_iqmp)) != 0 || |
3577 | (r = sshbuf_get_bignum2(buf, &rsa_p)) != 0 || | 3544 | (r = sshbuf_get_bignum2(buf, &rsa_p)) != 0 || |
3578 | (r = sshbuf_get_bignum2(buf, &rsa_q)) != 0) | 3545 | (r = sshbuf_get_bignum2(buf, &rsa_q)) != 0) |
3579 | goto out; | 3546 | goto out; |
3580 | if (k->type != type) { | ||
3581 | r = SSH_ERR_INVALID_FORMAT; | ||
3582 | goto out; | ||
3583 | } | ||
3584 | if (!RSA_set0_key(k->rsa, NULL, NULL, rsa_d)) { | 3547 | if (!RSA_set0_key(k->rsa, NULL, NULL, rsa_d)) { |
3585 | r = SSH_ERR_LIBCRYPTO_ERROR; | 3548 | r = SSH_ERR_LIBCRYPTO_ERROR; |
3586 | goto out; | 3549 | goto out; |
@@ -3598,30 +3561,10 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) | |||
3598 | break; | 3561 | break; |
3599 | #endif /* WITH_OPENSSL */ | 3562 | #endif /* WITH_OPENSSL */ |
3600 | case KEY_ED25519: | 3563 | case KEY_ED25519: |
3601 | if ((k = sshkey_new(type)) == NULL) { | ||
3602 | r = SSH_ERR_ALLOC_FAIL; | ||
3603 | goto out; | ||
3604 | } | ||
3605 | if ((r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 || | ||
3606 | (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0) | ||
3607 | goto out; | ||
3608 | if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) { | ||
3609 | r = SSH_ERR_INVALID_FORMAT; | ||
3610 | goto out; | ||
3611 | } | ||
3612 | k->ed25519_pk = ed25519_pk; | ||
3613 | k->ed25519_sk = ed25519_sk; | ||
3614 | ed25519_pk = ed25519_sk = NULL; | ||
3615 | break; | ||
3616 | case KEY_ED25519_CERT: | 3564 | case KEY_ED25519_CERT: |
3617 | if ((r = sshkey_froms(buf, &k)) != 0 || | 3565 | if ((r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 || |
3618 | (r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0 || | ||
3619 | (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0) | 3566 | (r = sshbuf_get_string(buf, &ed25519_sk, &sklen)) != 0) |
3620 | goto out; | 3567 | goto out; |
3621 | if (k->type != type) { | ||
3622 | r = SSH_ERR_INVALID_FORMAT; | ||
3623 | goto out; | ||
3624 | } | ||
3625 | if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) { | 3568 | if (pklen != ED25519_PK_SZ || sklen != ED25519_SK_SZ) { |
3626 | r = SSH_ERR_INVALID_FORMAT; | 3569 | r = SSH_ERR_INVALID_FORMAT; |
3627 | goto out; | 3570 | goto out; |
@@ -3631,38 +3574,9 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) | |||
3631 | ed25519_pk = ed25519_sk = NULL; /* transferred */ | 3574 | ed25519_pk = ed25519_sk = NULL; /* transferred */ |
3632 | break; | 3575 | break; |
3633 | case KEY_ED25519_SK: | 3576 | case KEY_ED25519_SK: |
3634 | if ((k = sshkey_new(type)) == NULL) { | ||
3635 | r = SSH_ERR_ALLOC_FAIL; | ||
3636 | goto out; | ||
3637 | } | ||
3638 | if ((r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0) | ||
3639 | goto out; | ||
3640 | if (pklen != ED25519_PK_SZ) { | ||
3641 | r = SSH_ERR_INVALID_FORMAT; | ||
3642 | goto out; | ||
3643 | } | ||
3644 | if ((k->sk_key_handle = sshbuf_new()) == NULL || | ||
3645 | (k->sk_reserved = sshbuf_new()) == NULL) { | ||
3646 | r = SSH_ERR_ALLOC_FAIL; | ||
3647 | goto out; | ||
3648 | } | ||
3649 | if ((r = sshbuf_get_cstring(buf, &k->sk_application, | ||
3650 | NULL)) != 0 || | ||
3651 | (r = sshbuf_get_u8(buf, &k->sk_flags)) != 0 || | ||
3652 | (r = sshbuf_get_stringb(buf, k->sk_key_handle)) != 0 || | ||
3653 | (r = sshbuf_get_stringb(buf, k->sk_reserved)) != 0) | ||
3654 | goto out; | ||
3655 | k->ed25519_pk = ed25519_pk; | ||
3656 | ed25519_pk = NULL; | ||
3657 | break; | ||
3658 | case KEY_ED25519_SK_CERT: | 3577 | case KEY_ED25519_SK_CERT: |
3659 | if ((r = sshkey_froms(buf, &k)) != 0 || | 3578 | if ((r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0) |
3660 | (r = sshbuf_get_string(buf, &ed25519_pk, &pklen)) != 0) | ||
3661 | goto out; | ||
3662 | if (k->type != type) { | ||
3663 | r = SSH_ERR_INVALID_FORMAT; | ||
3664 | goto out; | 3579 | goto out; |
3665 | } | ||
3666 | if (pklen != ED25519_PK_SZ) { | 3580 | if (pklen != ED25519_PK_SZ) { |
3667 | r = SSH_ERR_INVALID_FORMAT; | 3581 | r = SSH_ERR_INVALID_FORMAT; |
3668 | goto out; | 3582 | goto out; |
@@ -3683,10 +3597,7 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) | |||
3683 | break; | 3597 | break; |
3684 | #ifdef WITH_XMSS | 3598 | #ifdef WITH_XMSS |
3685 | case KEY_XMSS: | 3599 | case KEY_XMSS: |
3686 | if ((k = sshkey_new(type)) == NULL) { | 3600 | case KEY_XMSS_CERT: |
3687 | r = SSH_ERR_ALLOC_FAIL; | ||
3688 | goto out; | ||
3689 | } | ||
3690 | if ((r = sshbuf_get_cstring(buf, &xmss_name, NULL)) != 0 || | 3601 | if ((r = sshbuf_get_cstring(buf, &xmss_name, NULL)) != 0 || |
3691 | (r = sshkey_xmss_init(k, xmss_name)) != 0 || | 3602 | (r = sshkey_xmss_init(k, xmss_name)) != 0 || |
3692 | (r = sshbuf_get_string(buf, &xmss_pk, &pklen)) != 0 || | 3603 | (r = sshbuf_get_string(buf, &xmss_pk, &pklen)) != 0 || |
@@ -3704,28 +3615,6 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) | |||
3704 | if ((r = sshkey_xmss_deserialize_state_opt(k, buf)) != 0) | 3615 | if ((r = sshkey_xmss_deserialize_state_opt(k, buf)) != 0) |
3705 | goto out; | 3616 | goto out; |
3706 | break; | 3617 | break; |
3707 | case KEY_XMSS_CERT: | ||
3708 | if ((r = sshkey_froms(buf, &k)) != 0 || | ||
3709 | (r = sshbuf_get_cstring(buf, &xmss_name, NULL)) != 0 || | ||
3710 | (r = sshbuf_get_string(buf, &xmss_pk, &pklen)) != 0 || | ||
3711 | (r = sshbuf_get_string(buf, &xmss_sk, &sklen)) != 0) | ||
3712 | goto out; | ||
3713 | if (k->type != type || strcmp(xmss_name, k->xmss_name) != 0) { | ||
3714 | r = SSH_ERR_INVALID_FORMAT; | ||
3715 | goto out; | ||
3716 | } | ||
3717 | if (pklen != sshkey_xmss_pklen(k) || | ||
3718 | sklen != sshkey_xmss_sklen(k)) { | ||
3719 | r = SSH_ERR_INVALID_FORMAT; | ||
3720 | goto out; | ||
3721 | } | ||
3722 | k->xmss_pk = xmss_pk; | ||
3723 | k->xmss_sk = xmss_sk; | ||
3724 | xmss_pk = xmss_sk = NULL; | ||
3725 | /* optional internal state */ | ||
3726 | if ((r = sshkey_xmss_deserialize_state_opt(k, buf)) != 0) | ||
3727 | goto out; | ||
3728 | break; | ||
3729 | #endif /* WITH_XMSS */ | 3618 | #endif /* WITH_XMSS */ |
3730 | default: | 3619 | default: |
3731 | r = SSH_ERR_KEY_TYPE_UNKNOWN; | 3620 | r = SSH_ERR_KEY_TYPE_UNKNOWN; |
@@ -4055,46 +3944,31 @@ sshkey_private_to_blob2(struct sshkey *prv, struct sshbuf *blob, | |||
4055 | sshbuf_free(encrypted); | 3944 | sshbuf_free(encrypted); |
4056 | cipher_free(ciphercontext); | 3945 | cipher_free(ciphercontext); |
4057 | explicit_bzero(salt, sizeof(salt)); | 3946 | explicit_bzero(salt, sizeof(salt)); |
4058 | if (key != NULL) { | 3947 | if (key != NULL) |
4059 | explicit_bzero(key, keylen + ivlen); | 3948 | freezero(key, keylen + ivlen); |
4060 | free(key); | 3949 | if (pubkeyblob != NULL) |
4061 | } | 3950 | freezero(pubkeyblob, pubkeylen); |
4062 | if (pubkeyblob != NULL) { | 3951 | if (b64 != NULL) |
4063 | explicit_bzero(pubkeyblob, pubkeylen); | 3952 | freezero(b64, strlen(b64)); |
4064 | free(pubkeyblob); | ||
4065 | } | ||
4066 | if (b64 != NULL) { | ||
4067 | explicit_bzero(b64, strlen(b64)); | ||
4068 | free(b64); | ||
4069 | } | ||
4070 | return r; | 3953 | return r; |
4071 | } | 3954 | } |
4072 | 3955 | ||
4073 | static int | 3956 | static int |
4074 | sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase, | 3957 | private2_uudecode(struct sshbuf *blob, struct sshbuf **decodedp) |
4075 | struct sshkey **keyp, char **commentp) | ||
4076 | { | 3958 | { |
4077 | char *comment = NULL, *ciphername = NULL, *kdfname = NULL; | ||
4078 | const struct sshcipher *cipher = NULL; | ||
4079 | const u_char *cp; | 3959 | const u_char *cp; |
4080 | int r = SSH_ERR_INTERNAL_ERROR; | ||
4081 | size_t encoded_len; | 3960 | size_t encoded_len; |
4082 | size_t i, keylen = 0, ivlen = 0, authlen = 0, slen = 0; | 3961 | int r; |
3962 | u_char last; | ||
4083 | struct sshbuf *encoded = NULL, *decoded = NULL; | 3963 | struct sshbuf *encoded = NULL, *decoded = NULL; |
4084 | struct sshbuf *kdf = NULL, *decrypted = NULL; | ||
4085 | struct sshcipher_ctx *ciphercontext = NULL; | ||
4086 | struct sshkey *k = NULL; | ||
4087 | u_char *key = NULL, *salt = NULL, *dp, pad, last; | ||
4088 | u_int blocksize, rounds, nkeys, encrypted_len, check1, check2; | ||
4089 | 3964 | ||
4090 | if (keyp != NULL) | 3965 | if (blob == NULL || decodedp == NULL) |
4091 | *keyp = NULL; | 3966 | return SSH_ERR_INVALID_ARGUMENT; |
4092 | if (commentp != NULL) | 3967 | |
4093 | *commentp = NULL; | 3968 | *decodedp = NULL; |
4094 | 3969 | ||
4095 | if ((encoded = sshbuf_new()) == NULL || | 3970 | if ((encoded = sshbuf_new()) == NULL || |
4096 | (decoded = sshbuf_new()) == NULL || | 3971 | (decoded = sshbuf_new()) == NULL) { |
4097 | (decrypted = sshbuf_new()) == NULL) { | ||
4098 | r = SSH_ERR_ALLOC_FAIL; | 3972 | r = SSH_ERR_ALLOC_FAIL; |
4099 | goto out; | 3973 | goto out; |
4100 | } | 3974 | } |
@@ -4144,13 +4018,56 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase, | |||
4144 | r = SSH_ERR_INVALID_FORMAT; | 4018 | r = SSH_ERR_INVALID_FORMAT; |
4145 | goto out; | 4019 | goto out; |
4146 | } | 4020 | } |
4021 | /* success */ | ||
4022 | *decodedp = decoded; | ||
4023 | decoded = NULL; | ||
4024 | r = 0; | ||
4025 | out: | ||
4026 | sshbuf_free(encoded); | ||
4027 | sshbuf_free(decoded); | ||
4028 | return r; | ||
4029 | } | ||
4030 | |||
4031 | static int | ||
4032 | private2_decrypt(struct sshbuf *decoded, const char *passphrase, | ||
4033 | struct sshbuf **decryptedp, struct sshkey **pubkeyp) | ||
4034 | { | ||
4035 | char *ciphername = NULL, *kdfname = NULL; | ||
4036 | const struct sshcipher *cipher = NULL; | ||
4037 | int r = SSH_ERR_INTERNAL_ERROR; | ||
4038 | size_t keylen = 0, ivlen = 0, authlen = 0, slen = 0; | ||
4039 | struct sshbuf *kdf = NULL, *decrypted = NULL; | ||
4040 | struct sshcipher_ctx *ciphercontext = NULL; | ||
4041 | struct sshkey *pubkey = NULL; | ||
4042 | u_char *key = NULL, *salt = NULL, *dp; | ||
4043 | u_int blocksize, rounds, nkeys, encrypted_len, check1, check2; | ||
4044 | |||
4045 | if (decoded == NULL || decryptedp == NULL || pubkeyp == NULL) | ||
4046 | return SSH_ERR_INVALID_ARGUMENT; | ||
4047 | |||
4048 | *decryptedp = NULL; | ||
4049 | *pubkeyp = NULL; | ||
4050 | |||
4051 | if ((decrypted = sshbuf_new()) == NULL) { | ||
4052 | r = SSH_ERR_ALLOC_FAIL; | ||
4053 | goto out; | ||
4054 | } | ||
4055 | |||
4147 | /* parse public portion of key */ | 4056 | /* parse public portion of key */ |
4148 | if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 || | 4057 | if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 || |
4149 | (r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 || | 4058 | (r = sshbuf_get_cstring(decoded, &ciphername, NULL)) != 0 || |
4150 | (r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 || | 4059 | (r = sshbuf_get_cstring(decoded, &kdfname, NULL)) != 0 || |
4151 | (r = sshbuf_froms(decoded, &kdf)) != 0 || | 4060 | (r = sshbuf_froms(decoded, &kdf)) != 0 || |
4152 | (r = sshbuf_get_u32(decoded, &nkeys)) != 0 || | 4061 | (r = sshbuf_get_u32(decoded, &nkeys)) != 0) |
4153 | (r = sshbuf_skip_string(decoded)) != 0 || /* pubkey */ | 4062 | goto out; |
4063 | |||
4064 | if (nkeys != 1) { | ||
4065 | /* XXX only one key supported at present */ | ||
4066 | r = SSH_ERR_INVALID_FORMAT; | ||
4067 | goto out; | ||
4068 | } | ||
4069 | |||
4070 | if ((r = sshkey_froms(decoded, &pubkey)) != 0 || | ||
4154 | (r = sshbuf_get_u32(decoded, &encrypted_len)) != 0) | 4071 | (r = sshbuf_get_u32(decoded, &encrypted_len)) != 0) |
4155 | goto out; | 4072 | goto out; |
4156 | 4073 | ||
@@ -4158,23 +4075,18 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase, | |||
4158 | r = SSH_ERR_KEY_UNKNOWN_CIPHER; | 4075 | r = SSH_ERR_KEY_UNKNOWN_CIPHER; |
4159 | goto out; | 4076 | goto out; |
4160 | } | 4077 | } |
4161 | if ((passphrase == NULL || strlen(passphrase) == 0) && | ||
4162 | strcmp(ciphername, "none") != 0) { | ||
4163 | /* passphrase required */ | ||
4164 | r = SSH_ERR_KEY_WRONG_PASSPHRASE; | ||
4165 | goto out; | ||
4166 | } | ||
4167 | if (strcmp(kdfname, "none") != 0 && strcmp(kdfname, "bcrypt") != 0) { | 4078 | if (strcmp(kdfname, "none") != 0 && strcmp(kdfname, "bcrypt") != 0) { |
4168 | r = SSH_ERR_KEY_UNKNOWN_CIPHER; | 4079 | r = SSH_ERR_KEY_UNKNOWN_CIPHER; |
4169 | goto out; | 4080 | goto out; |
4170 | } | 4081 | } |
4171 | if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) { | 4082 | if (strcmp(kdfname, "none") == 0 && strcmp(ciphername, "none") != 0) { |
4172 | r = SSH_ERR_INVALID_FORMAT; | 4083 | r = SSH_ERR_INVALID_FORMAT; |
4173 | goto out; | 4084 | goto out; |
4174 | } | 4085 | } |
4175 | if (nkeys != 1) { | 4086 | if ((passphrase == NULL || strlen(passphrase) == 0) && |
4176 | /* XXX only one key supported */ | 4087 | strcmp(kdfname, "none") != 0) { |
4177 | r = SSH_ERR_INVALID_FORMAT; | 4088 | /* passphrase required */ |
4089 | r = SSH_ERR_KEY_WRONG_PASSPHRASE; | ||
4178 | goto out; | 4090 | goto out; |
4179 | } | 4091 | } |
4180 | 4092 | ||
@@ -4239,13 +4151,38 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase, | |||
4239 | r = SSH_ERR_KEY_WRONG_PASSPHRASE; | 4151 | r = SSH_ERR_KEY_WRONG_PASSPHRASE; |
4240 | goto out; | 4152 | goto out; |
4241 | } | 4153 | } |
4154 | /* success */ | ||
4155 | *decryptedp = decrypted; | ||
4156 | decrypted = NULL; | ||
4157 | *pubkeyp = pubkey; | ||
4158 | pubkey = NULL; | ||
4159 | r = 0; | ||
4160 | out: | ||
4161 | cipher_free(ciphercontext); | ||
4162 | free(ciphername); | ||
4163 | free(kdfname); | ||
4164 | sshkey_free(pubkey); | ||
4165 | if (salt != NULL) { | ||
4166 | explicit_bzero(salt, slen); | ||
4167 | free(salt); | ||
4168 | } | ||
4169 | if (key != NULL) { | ||
4170 | explicit_bzero(key, keylen + ivlen); | ||
4171 | free(key); | ||
4172 | } | ||
4173 | sshbuf_free(kdf); | ||
4174 | sshbuf_free(decrypted); | ||
4175 | return r; | ||
4176 | } | ||
4242 | 4177 | ||
4243 | /* Load the private key and comment */ | 4178 | /* Check deterministic padding after private key */ |
4244 | if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 || | 4179 | static int |
4245 | (r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0) | 4180 | private2_check_padding(struct sshbuf *decrypted) |
4246 | goto out; | 4181 | { |
4182 | u_char pad; | ||
4183 | size_t i; | ||
4184 | int r = SSH_ERR_INTERNAL_ERROR; | ||
4247 | 4185 | ||
4248 | /* Check deterministic padding */ | ||
4249 | i = 0; | 4186 | i = 0; |
4250 | while (sshbuf_len(decrypted)) { | 4187 | while (sshbuf_len(decrypted)) { |
4251 | if ((r = sshbuf_get_u8(decrypted, &pad)) != 0) | 4188 | if ((r = sshbuf_get_u8(decrypted, &pad)) != 0) |
@@ -4255,8 +4192,54 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase, | |||
4255 | goto out; | 4192 | goto out; |
4256 | } | 4193 | } |
4257 | } | 4194 | } |
4195 | /* success */ | ||
4196 | r = 0; | ||
4197 | out: | ||
4198 | explicit_bzero(&pad, sizeof(pad)); | ||
4199 | explicit_bzero(&i, sizeof(i)); | ||
4200 | return r; | ||
4201 | } | ||
4258 | 4202 | ||
4259 | /* XXX decode pubkey and check against private */ | 4203 | static int |
4204 | sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase, | ||
4205 | struct sshkey **keyp, char **commentp) | ||
4206 | { | ||
4207 | char *comment = NULL; | ||
4208 | int r = SSH_ERR_INTERNAL_ERROR; | ||
4209 | struct sshbuf *decoded = NULL, *decrypted = NULL; | ||
4210 | struct sshkey *k = NULL, *pubkey = NULL; | ||
4211 | |||
4212 | if (keyp != NULL) | ||
4213 | *keyp = NULL; | ||
4214 | if (commentp != NULL) | ||
4215 | *commentp = NULL; | ||
4216 | |||
4217 | /* Undo base64 encoding and decrypt the private section */ | ||
4218 | if ((r = private2_uudecode(blob, &decoded)) != 0 || | ||
4219 | (r = private2_decrypt(decoded, passphrase, | ||
4220 | &decrypted, &pubkey)) != 0) | ||
4221 | goto out; | ||
4222 | |||
4223 | if (type != KEY_UNSPEC && | ||
4224 | sshkey_type_plain(type) != sshkey_type_plain(pubkey->type)) { | ||
4225 | r = SSH_ERR_KEY_TYPE_MISMATCH; | ||
4226 | goto out; | ||
4227 | } | ||
4228 | |||
4229 | /* Load the private key and comment */ | ||
4230 | if ((r = sshkey_private_deserialize(decrypted, &k)) != 0 || | ||
4231 | (r = sshbuf_get_cstring(decrypted, &comment, NULL)) != 0) | ||
4232 | goto out; | ||
4233 | |||
4234 | /* Check deterministic padding after private section */ | ||
4235 | if ((r = private2_check_padding(decrypted)) != 0) | ||
4236 | goto out; | ||
4237 | |||
4238 | /* Check that the public key in the envelope matches the private key */ | ||
4239 | if (!sshkey_equal(pubkey, k)) { | ||
4240 | r = SSH_ERR_INVALID_FORMAT; | ||
4241 | goto out; | ||
4242 | } | ||
4260 | 4243 | ||
4261 | /* success */ | 4244 | /* success */ |
4262 | r = 0; | 4245 | r = 0; |
@@ -4269,27 +4252,63 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase, | |||
4269 | comment = NULL; | 4252 | comment = NULL; |
4270 | } | 4253 | } |
4271 | out: | 4254 | out: |
4272 | pad = 0; | ||
4273 | cipher_free(ciphercontext); | ||
4274 | free(ciphername); | ||
4275 | free(kdfname); | ||
4276 | free(comment); | 4255 | free(comment); |
4277 | if (salt != NULL) { | ||
4278 | explicit_bzero(salt, slen); | ||
4279 | free(salt); | ||
4280 | } | ||
4281 | if (key != NULL) { | ||
4282 | explicit_bzero(key, keylen + ivlen); | ||
4283 | free(key); | ||
4284 | } | ||
4285 | sshbuf_free(encoded); | ||
4286 | sshbuf_free(decoded); | 4256 | sshbuf_free(decoded); |
4287 | sshbuf_free(kdf); | ||
4288 | sshbuf_free(decrypted); | 4257 | sshbuf_free(decrypted); |
4289 | sshkey_free(k); | 4258 | sshkey_free(k); |
4259 | sshkey_free(pubkey); | ||
4290 | return r; | 4260 | return r; |
4291 | } | 4261 | } |
4292 | 4262 | ||
4263 | static int | ||
4264 | sshkey_parse_private2_pubkey(struct sshbuf *blob, int type, | ||
4265 | struct sshkey **keyp) | ||
4266 | { | ||
4267 | int r = SSH_ERR_INTERNAL_ERROR; | ||
4268 | struct sshbuf *decoded = NULL; | ||
4269 | struct sshkey *pubkey = NULL; | ||
4270 | u_int nkeys = 0; | ||
4271 | |||
4272 | if (keyp != NULL) | ||
4273 | *keyp = NULL; | ||
4274 | |||
4275 | if ((r = private2_uudecode(blob, &decoded)) != 0) | ||
4276 | goto out; | ||
4277 | /* parse public key from unencrypted envelope */ | ||
4278 | if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 || | ||
4279 | (r = sshbuf_skip_string(decoded)) != 0 || /* cipher */ | ||
4280 | (r = sshbuf_skip_string(decoded)) != 0 || /* KDF alg */ | ||
4281 | (r = sshbuf_skip_string(decoded)) != 0 || /* KDF hint */ | ||
4282 | (r = sshbuf_get_u32(decoded, &nkeys)) != 0) | ||
4283 | goto out; | ||
4284 | |||
4285 | if (nkeys != 1) { | ||
4286 | /* XXX only one key supported at present */ | ||
4287 | r = SSH_ERR_INVALID_FORMAT; | ||
4288 | goto out; | ||
4289 | } | ||
4290 | |||
4291 | /* Parse the public key */ | ||
4292 | if ((r = sshkey_froms(decoded, &pubkey)) != 0) | ||
4293 | goto out; | ||
4294 | |||
4295 | if (type != KEY_UNSPEC && | ||
4296 | sshkey_type_plain(type) != sshkey_type_plain(pubkey->type)) { | ||
4297 | r = SSH_ERR_KEY_TYPE_MISMATCH; | ||
4298 | goto out; | ||
4299 | } | ||
4300 | |||
4301 | /* success */ | ||
4302 | r = 0; | ||
4303 | if (keyp != NULL) { | ||
4304 | *keyp = pubkey; | ||
4305 | pubkey = NULL; | ||
4306 | } | ||
4307 | out: | ||
4308 | sshbuf_free(decoded); | ||
4309 | sshkey_free(pubkey); | ||
4310 | return r; | ||
4311 | } | ||
4293 | 4312 | ||
4294 | #ifdef WITH_OPENSSL | 4313 | #ifdef WITH_OPENSSL |
4295 | /* convert SSH v2 key to PEM or PKCS#8 format */ | 4314 | /* convert SSH v2 key to PEM or PKCS#8 format */ |
@@ -4616,24 +4635,16 @@ sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type, | |||
4616 | *commentp = NULL; | 4635 | *commentp = NULL; |
4617 | 4636 | ||
4618 | switch (type) { | 4637 | switch (type) { |
4619 | #ifdef WITH_OPENSSL | ||
4620 | case KEY_DSA: | ||
4621 | case KEY_ECDSA: | ||
4622 | case KEY_RSA: | ||
4623 | return sshkey_parse_private_pem_fileblob(blob, type, | ||
4624 | passphrase, keyp); | ||
4625 | #endif /* WITH_OPENSSL */ | ||
4626 | case KEY_ED25519: | 4638 | case KEY_ED25519: |
4627 | #ifdef WITH_XMSS | ||
4628 | case KEY_XMSS: | 4639 | case KEY_XMSS: |
4629 | #endif /* WITH_XMSS */ | 4640 | /* No fallback for new-format-only keys */ |
4630 | return sshkey_parse_private2(blob, type, passphrase, | 4641 | return sshkey_parse_private2(blob, type, passphrase, |
4631 | keyp, commentp); | 4642 | keyp, commentp); |
4632 | case KEY_UNSPEC: | 4643 | default: |
4633 | r = sshkey_parse_private2(blob, type, passphrase, keyp, | 4644 | r = sshkey_parse_private2(blob, type, passphrase, keyp, |
4634 | commentp); | 4645 | commentp); |
4635 | /* Do not fallback to PEM parser if only passphrase is wrong. */ | 4646 | /* Only fallback to PEM parser if a format error occurred. */ |
4636 | if (r == 0 || r == SSH_ERR_KEY_WRONG_PASSPHRASE) | 4647 | if (r != SSH_ERR_INVALID_FORMAT) |
4637 | return r; | 4648 | return r; |
4638 | #ifdef WITH_OPENSSL | 4649 | #ifdef WITH_OPENSSL |
4639 | return sshkey_parse_private_pem_fileblob(blob, type, | 4650 | return sshkey_parse_private_pem_fileblob(blob, type, |
@@ -4641,8 +4652,6 @@ sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type, | |||
4641 | #else | 4652 | #else |
4642 | return SSH_ERR_INVALID_FORMAT; | 4653 | return SSH_ERR_INVALID_FORMAT; |
4643 | #endif /* WITH_OPENSSL */ | 4654 | #endif /* WITH_OPENSSL */ |
4644 | default: | ||
4645 | return SSH_ERR_KEY_TYPE_UNKNOWN; | ||
4646 | } | 4655 | } |
4647 | } | 4656 | } |
4648 | 4657 | ||
@@ -4665,6 +4674,20 @@ sshkey_sig_details_free(struct sshkey_sig_details *details) | |||
4665 | freezero(details, sizeof(*details)); | 4674 | freezero(details, sizeof(*details)); |
4666 | } | 4675 | } |
4667 | 4676 | ||
4677 | int | ||
4678 | sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob, int type, | ||
4679 | struct sshkey **pubkeyp) | ||
4680 | { | ||
4681 | int r = SSH_ERR_INTERNAL_ERROR; | ||
4682 | |||
4683 | if (pubkeyp != NULL) | ||
4684 | *pubkeyp = NULL; | ||
4685 | /* only new-format private keys bundle a public key inside */ | ||
4686 | if ((r = sshkey_parse_private2_pubkey(blob, type, pubkeyp)) != 0) | ||
4687 | return r; | ||
4688 | return 0; | ||
4689 | } | ||
4690 | |||
4668 | #ifdef WITH_XMSS | 4691 | #ifdef WITH_XMSS |
4669 | /* | 4692 | /* |
4670 | * serialize the key with the current state and forward the state | 4693 | * serialize the key with the current state and forward the state |