diff options
author | Natanael Copa <ncopa@alpinelinux.org> | 2019-07-11 18:05:21 +0200 |
---|---|---|
committer | Natanael Copa <ncopa@alpinelinux.org> | 2019-07-11 18:05:21 +0200 |
commit | abf6ed8fe5ac4d8dac9d7e2f6363a6f728a4bb16 (patch) | |
tree | b815d4250613854c67ec975a3e0bac90a4e69676 | |
parent | 7f6e6b03d2536a389bb79a29915bd3a8fe881517 (diff) |
main/heimdal: add missing patch
-rw-r--r-- | main/heimdal/CVE-2019-12098.patch | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/main/heimdal/CVE-2019-12098.patch b/main/heimdal/CVE-2019-12098.patch new file mode 100644 index 00000000000..af014218614 --- /dev/null +++ b/main/heimdal/CVE-2019-12098.patch @@ -0,0 +1,171 @@ +From 2f7f3d9960aa6ea21358bdf3687cee5149aa35cf Mon Sep 17 00:00:00 2001 +From: Luke Howard <lukeh@padl.com> +Date: Tue, 7 May 2019 13:15:15 +1000 +Subject: [PATCH] CVE-2019-12098: krb5: always confirm PA-PKINIT-KX for anon + PKINIT + +RFC8062 Section 7 requires verification of the PA-PKINIT-KX key excahnge +when anonymous PKINIT is used. Failure to do so can permit an active +attacker to become a man-in-the-middle. + +Introduced by a1ef548600c5bb51cf52a9a9ea12676506ede19f. First tagged +release Heimdal 1.4.0. + +CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N (4.8) + +Change-Id: I6cc1c0c24985936468af08693839ac6c3edda133 +Signed-off-by: Jeffrey Altman <jaltman@auristor.com> +Approved-by: Jeffrey Altman <jaltman@auritor.com> +(cherry picked from commit 38c797e1ae9b9c8f99ae4aa2e73957679031fd2b) +--- + lib/krb5/init_creds_pw.c | 20 +++++++++ + lib/krb5/krb5_locl.h | 1 + + lib/krb5/pkinit.c | 92 ++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 113 insertions(+) + +diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c +index 1eece1760d..9ec07d0609 100644 +--- a/lib/krb5/init_creds_pw.c ++++ b/lib/krb5/init_creds_pw.c +@@ -2267,6 +2267,26 @@ krb5_init_creds_step(krb5_context context, + &ctx->req_buffer, + NULL, + NULL); ++ if (ret == 0 && ctx->pk_init_ctx) { ++ PA_DATA *pa_pkinit_kx; ++ int idx = 0; ++ ++ pa_pkinit_kx = ++ krb5_find_padata(rep.kdc_rep.padata->val, ++ rep.kdc_rep.padata->len, ++ KRB5_PADATA_PKINIT_KX, ++ &idx); ++ ++ ret = _krb5_pk_kx_confirm(context, ctx->pk_init_ctx, ++ ctx->fast_state.reply_key, ++ &ctx->cred.session, ++ pa_pkinit_kx); ++ if (ret) ++ krb5_set_error_message(context, ret, ++ N_("Failed to confirm PA-PKINIT-KX", "")); ++ else if (pa_pkinit_kx != NULL) ++ ctx->ic_flags |= KRB5_INIT_CREDS_PKINIT_KX_VALID; ++ } + if (ret == 0) + ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part); + +diff --git a/lib/krb5/krb5_locl.h b/lib/krb5/krb5_locl.h +index 9d77b9f8a3..f61b66e999 100644 +--- a/lib/krb5/krb5_locl.h ++++ b/lib/krb5/krb5_locl.h +@@ -208,6 +208,7 @@ struct _krb5_get_init_creds_opt_private { + #define KRB5_INIT_CREDS_CANONICALIZE 1 + #define KRB5_INIT_CREDS_NO_C_CANON_CHECK 2 + #define KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK 4 ++#define KRB5_INIT_CREDS_PKINIT_KX_VALID 32 + struct { + krb5_gic_process_last_req func; + void *ctx; +diff --git a/lib/krb5/pkinit.c b/lib/krb5/pkinit.c +index b16ee69d3c..e178242ea3 100644 +--- a/lib/krb5/pkinit.c ++++ b/lib/krb5/pkinit.c +@@ -1220,6 +1220,98 @@ pk_rd_pa_reply_enckey(krb5_context context, + return ret; + } + ++/* ++ * RFC 8062 section 7: ++ * ++ * The client then decrypts the KDC contribution key and verifies that ++ * the ticket session key in the returned ticket is the combined key of ++ * the KDC contribution key and the reply key. ++ */ ++KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL ++_krb5_pk_kx_confirm(krb5_context context, ++ krb5_pk_init_ctx ctx, ++ krb5_keyblock *reply_key, ++ krb5_keyblock *session_key, ++ PA_DATA *pa_pkinit_kx) ++{ ++ krb5_error_code ret; ++ EncryptedData ed; ++ krb5_keyblock ck, sk_verify; ++ krb5_crypto ck_crypto = NULL; ++ krb5_crypto rk_crypto = NULL; ++ size_t len; ++ krb5_data data; ++ krb5_data p1 = { sizeof("PKINIT") - 1, "PKINIT" }; ++ krb5_data p2 = { sizeof("KEYEXCHANGE") - 1, "KEYEXCHANGE" }; ++ ++ heim_assert(ctx != NULL, "PKINIT context is non-NULL"); ++ heim_assert(reply_key != NULL, "reply key is non-NULL"); ++ heim_assert(session_key != NULL, "session key is non-NULL"); ++ ++ /* PA-PKINIT-KX is optional unless anonymous */ ++ if (pa_pkinit_kx == NULL) ++ return ctx->anonymous ? KRB5_KDCREP_MODIFIED : 0; ++ ++ memset(&ed, 0, sizeof(ed)); ++ krb5_keyblock_zero(&ck); ++ krb5_keyblock_zero(&sk_verify); ++ krb5_data_zero(&data); ++ ++ ret = decode_EncryptedData(pa_pkinit_kx->padata_value.data, ++ pa_pkinit_kx->padata_value.length, ++ &ed, &len); ++ if (ret) ++ goto out; ++ ++ if (len != pa_pkinit_kx->padata_value.length) { ++ ret = KRB5_KDCREP_MODIFIED; ++ goto out; ++ } ++ ++ ret = krb5_crypto_init(context, reply_key, 0, &rk_crypto); ++ if (ret) ++ goto out; ++ ++ ret = krb5_decrypt_EncryptedData(context, rk_crypto, ++ KRB5_KU_PA_PKINIT_KX, ++ &ed, &data); ++ if (ret) ++ goto out; ++ ++ ret = decode_EncryptionKey(data.data, data.length, ++ &ck, &len); ++ if (ret) ++ goto out; ++ ++ ret = krb5_crypto_init(context, &ck, 0, &ck_crypto); ++ if (ret) ++ goto out; ++ ++ ret = krb5_crypto_fx_cf2(context, ck_crypto, rk_crypto, ++ &p1, &p2, session_key->keytype, ++ &sk_verify); ++ if (ret) ++ goto out; ++ ++ if (sk_verify.keytype != session_key->keytype || ++ krb5_data_ct_cmp(&sk_verify.keyvalue, &session_key->keyvalue) != 0) { ++ ret = KRB5_KDCREP_MODIFIED; ++ goto out; ++ } ++ ++out: ++ free_EncryptedData(&ed); ++ krb5_free_keyblock_contents(context, &ck); ++ krb5_free_keyblock_contents(context, &sk_verify); ++ if (ck_crypto) ++ krb5_crypto_destroy(context, ck_crypto); ++ if (rk_crypto) ++ krb5_crypto_destroy(context, rk_crypto); ++ krb5_data_free(&data); ++ ++ return ret; ++} ++ + static krb5_error_code + pk_rd_pa_reply_dh(krb5_context context, + const heim_octet_string *indata, |