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