From: Julien Rische Date: Tue, 14 Jan 2025 12:31:11 +0000 (+0100) Subject: Add PKINIT paChecksum2 from MS-PKCA v20230920 X-Git-Tag: krb5-1.22-beta1~20 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F1411%2Fhead;p=thirdparty%2Fkrb5.git Add PKINIT paChecksum2 from MS-PKCA v20230920 In 2023, Microsoft updated MS-PKCA to add the optional paChecksum2 element in the PKAuthenticator sequence. This checksum accepts SHA-1, SHA-256, SHA-384, and SHA-512 digests. In Windows Server 2025, this checksum becomes mandatory when using PKINIT with FFDH (but strangely not with ECDH if SHA-1 is configured as allowed). [ghudson@mit.edu: refactored crypto interfaces to reduce complexity of calling code] ticket: 9166 (new) --- diff --git a/src/include/k5-int-pkinit.h b/src/include/k5-int-pkinit.h index 915904e518..cf6b1f99c5 100644 --- a/src/include/k5-int-pkinit.h +++ b/src/include/k5-int-pkinit.h @@ -36,21 +36,28 @@ * pkinit structures */ -/* PKAuthenticator */ -typedef struct _krb5_pk_authenticator { - krb5_int32 cusec; /* (0..999999) */ - krb5_timestamp ctime; - krb5_int32 nonce; /* (0..4294967295) */ - krb5_checksum paChecksum; - krb5_data *freshnessToken; -} krb5_pk_authenticator; - /* AlgorithmIdentifier */ typedef struct _krb5_algorithm_identifier { krb5_data algorithm; /* OID */ krb5_data parameters; /* Optional */ } krb5_algorithm_identifier; +/* PAChecksum2 */ +typedef struct _krb5_pachecksum2 { + krb5_data checksum; + krb5_algorithm_identifier algorithmIdentifier; +} krb5_pachecksum2; + +/* PKAuthenticator */ +typedef struct _krb5_pk_authenticator { + krb5_int32 cusec; /* (0..999999) */ + krb5_timestamp ctime; + krb5_int32 nonce; /* (0..4294967295) */ + krb5_data paChecksum; + krb5_data *freshnessToken; /* Optional */ + krb5_pachecksum2 *paChecksum2; /* Optional */ +} krb5_pk_authenticator; + /** AuthPack from RFC 4556*/ typedef struct _krb5_auth_pack { krb5_pk_authenticator pkAuthenticator; diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c index 1a250c98c0..f30cbd77c4 100644 --- a/src/lib/krb5/asn.1/asn1_k_encode.c +++ b/src/lib/krb5/asn.1/asn1_k_encode.c @@ -1394,20 +1394,30 @@ DEFSEQTYPE(pkinit_supp_pub_info, krb5_pkinit_supp_pub_info, MAKE_ENCODER(encode_krb5_pkinit_supp_pub_info, pkinit_supp_pub_info); MAKE_ENCODER(encode_krb5_sp80056a_other_info, sp80056a_other_info); -/* A krb5_checksum encoded as an OCTET STRING, for PKAuthenticator. */ -DEFCOUNTEDTYPE(ostring_checksum, krb5_checksum, contents, length, octetstring); +DEFFIELD(pachecksum2_0, krb5_pachecksum2, checksum, 0, ostring_data); +DEFFIELD(pachecksum2_1, krb5_pachecksum2, algorithmIdentifier, 1, + algorithm_identifier); +static const struct atype_info *pachecksum2_fields[] = { + &k5_atype_pachecksum2_0, &k5_atype_pachecksum2_1 +}; +DEFSEQTYPE(pachecksum2, krb5_pachecksum2, pachecksum2_fields); + +DEFPTRTYPE(pachecksum2_ptr, pachecksum2); +DEFOPTIONALZEROTYPE(opt_pachecksum2_ptr, pachecksum2_ptr); DEFFIELD(pk_authenticator_0, krb5_pk_authenticator, cusec, 0, int32); DEFFIELD(pk_authenticator_1, krb5_pk_authenticator, ctime, 1, kerberos_time); DEFFIELD(pk_authenticator_2, krb5_pk_authenticator, nonce, 2, int32); DEFFIELD(pk_authenticator_3, krb5_pk_authenticator, paChecksum, 3, - ostring_checksum); + ostring_data); DEFFIELD(pk_authenticator_4, krb5_pk_authenticator, freshnessToken, 4, opt_ostring_data_ptr); +DEFFIELD(pk_authenticator_5, krb5_pk_authenticator, paChecksum2, 5, + opt_pachecksum2_ptr); static const struct atype_info *pk_authenticator_fields[] = { &k5_atype_pk_authenticator_0, &k5_atype_pk_authenticator_1, &k5_atype_pk_authenticator_2, &k5_atype_pk_authenticator_3, - &k5_atype_pk_authenticator_4 + &k5_atype_pk_authenticator_4, &k5_atype_pk_authenticator_5 }; DEFSEQTYPE(pk_authenticator, krb5_pk_authenticator, pk_authenticator_fields); diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h index 200e75afe7..40e712b24f 100644 --- a/src/plugins/preauth/pkinit/pkinit.h +++ b/src/plugins/preauth/pkinit/pkinit.h @@ -340,6 +340,7 @@ void free_krb5_external_principal_identifier(krb5_external_principal_identifier void free_krb5_algorithm_identifiers(krb5_algorithm_identifier ***in); void free_krb5_algorithm_identifier(krb5_algorithm_identifier *in); void free_krb5_kdc_dh_key_info(krb5_kdc_dh_key_info **in); +void free_pachecksum2(krb5_context context, krb5_pachecksum2 **in); krb5_error_code pkinit_copy_krb5_data(krb5_data *dst, const krb5_data *src); diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c index 9312ff4b1d..94beeb8cf0 100644 --- a/src/plugins/preauth/pkinit/pkinit_clnt.c +++ b/src/plugins/preauth/pkinit/pkinit_clnt.c @@ -55,10 +55,9 @@ use_content_info(krb5_context context, pkinit_req_context req, static krb5_error_code pkinit_as_req_create(krb5_context context, pkinit_context plgctx, pkinit_req_context reqctx, krb5_timestamp ctsec, - krb5_int32 cusec, krb5_ui_4 nonce, - const krb5_checksum *cksum, - krb5_principal client, krb5_principal server, - krb5_data **as_req); + krb5_int32 cusec, krb5_ui_4 nonce, const krb5_data *cksum, + const krb5_pachecksum2 *cksum2, krb5_principal client, + krb5_principal server, krb5_data **as_req); static krb5_error_code pkinit_as_rep_parse(krb5_context context, pkinit_context plgctx, @@ -88,7 +87,8 @@ pa_pkinit_gen_req(krb5_context context, krb5_timestamp ctsec = 0; krb5_int32 cusec = 0; krb5_ui_4 nonce = 0; - krb5_checksum cksum; + krb5_data cksum = empty_data(); + krb5_pachecksum2 *cksum2 = NULL; krb5_data *der_req = NULL; krb5_pa_data **return_pa_data = NULL; @@ -117,15 +117,10 @@ pa_pkinit_gen_req(krb5_context context, goto cleanup; } - retval = krb5_c_make_checksum(context, CKSUMTYPE_SHA1, NULL, 0, der_req, - &cksum); + retval = crypto_generate_checksums(context, der_req, &cksum, &cksum2); if (retval) goto cleanup; - TRACE_PKINIT_CLIENT_REQ_CHECKSUM(context, &cksum); -#ifdef DEBUG_CKSUM - pkiDebug("calculating checksum on buf size (%d)\n", der_req->length); - print_buffer(der_req->data, der_req->length); -#endif + TRACE_PKINIT_CLIENT_REQ_CHECKSUMS(context, &cksum, cksum2); retval = cb->get_preauth_time(context, rock, TRUE, &ctsec, &cusec); if (retval) @@ -139,7 +134,8 @@ pa_pkinit_gen_req(krb5_context context, nonce = request->nonce; retval = pkinit_as_req_create(context, plgctx, reqctx, ctsec, cusec, - nonce, &cksum, request->client, request->server, &out_data); + nonce, &cksum, cksum2, request->client, + request->server, &out_data); if (retval) { pkiDebug("error %d on pkinit_as_req_create; aborting PKINIT\n", (int) retval); @@ -167,23 +163,19 @@ pa_pkinit_gen_req(krb5_context context, cleanup: krb5_free_data(context, der_req); - krb5_free_checksum_contents(context, &cksum); + krb5_free_data_contents(context, &cksum); + free_pachecksum2(context, &cksum2); krb5_free_data(context, out_data); krb5_free_pa_data(context, return_pa_data); return retval; } static krb5_error_code -pkinit_as_req_create(krb5_context context, - pkinit_context plgctx, - pkinit_req_context reqctx, - krb5_timestamp ctsec, - krb5_int32 cusec, - krb5_ui_4 nonce, - const krb5_checksum * cksum, - krb5_principal client, - krb5_principal server, - krb5_data ** as_req) +pkinit_as_req_create(krb5_context context, pkinit_context plgctx, + pkinit_req_context reqctx, krb5_timestamp ctsec, + krb5_int32 cusec, krb5_ui_4 nonce, const krb5_data *cksum, + const krb5_pachecksum2 *cksum2, krb5_principal client, + krb5_principal server, krb5_data **as_req) { krb5_error_code retval = ENOMEM; krb5_data spki = empty_data(), *coded_auth_pack = NULL; @@ -201,6 +193,7 @@ pkinit_as_req_create(krb5_context context, auth_pack.pkAuthenticator.paChecksum = *cksum; if (!reqctx->opts->disable_freshness) auth_pack.pkAuthenticator.freshnessToken = reqctx->freshness_token; + auth_pack.pkAuthenticator.paChecksum2 = (krb5_pachecksum2 *)cksum2; auth_pack.clientDHNonce.length = 0; auth_pack.supportedKDFs = (krb5_data **)supported_kdf_alg_ids; diff --git a/src/plugins/preauth/pkinit/pkinit_constants.c b/src/plugins/preauth/pkinit/pkinit_constants.c index 905e90d29c..a32b373c32 100644 --- a/src/plugins/preauth/pkinit/pkinit_constants.c +++ b/src/plugins/preauth/pkinit/pkinit_constants.c @@ -34,25 +34,49 @@ /* RFC 8636 id-pkinit-kdf-ah-sha1: iso(1) identified-organization(3) dod(6) * internet(1) security(5) kerberosv5(2) pkinit(3) kdf(6) sha1(1) */ -static char sha1_oid[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x01 }; +static char kdf_sha1[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x01 }; /* RFC 8636 id-pkinit-kdf-ah-sha256: iso(1) identified-organization(3) dod(6) * internet(1) security(5) kerberosv5(2) pkinit(3) kdf(6) sha256(2) */ -static char sha256_oid[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x02 }; +static char kdf_sha256[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x02 }; /* RFC 8636 id-pkinit-kdf-ah-sha512: iso(1) identified-organization(3) dod(6) * internet(1) security(5) kerberosv5(2) pkinit(3) kdf(6) sha512(3) */ -static char sha512_oid[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x03 }; +static char kdf_sha512[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x03 }; -const krb5_data sha1_id = { KV5M_DATA, sizeof(sha1_oid), sha1_oid }; -const krb5_data sha256_id = { KV5M_DATA, sizeof(sha256_oid), sha256_oid }; -const krb5_data sha512_id = { KV5M_DATA, sizeof(sha512_oid), sha512_oid }; +const krb5_data kdf_sha1_id = { KV5M_DATA, sizeof(kdf_sha1), kdf_sha1 }; +const krb5_data kdf_sha256_id = { KV5M_DATA, sizeof(kdf_sha256), kdf_sha256 }; +const krb5_data kdf_sha512_id = { KV5M_DATA, sizeof(kdf_sha512), kdf_sha512 }; krb5_data const * const supported_kdf_alg_ids[] = { - &sha256_id, - &sha1_id, - &sha512_id, + &kdf_sha256_id, + &kdf_sha1_id, + &kdf_sha512_id, NULL }; +/* RFC 3370 sha-1: iso(1) identified-organization(3) oiw(14) secsig(3) + * algorithm(2) 26 */ +static char cms_sha1[] = { 0x2b, 0x0e, 0x03, 0x02, 0x1a }; +/* RFC 5754 id-sha256: joint-iso-itu-t(2) country(16) us(840) organization(1) + * gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1 */ +static char cms_sha256[] = { + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 +}; +/* RFC 5754 id-sha384: joint-iso-itu-t(2) country(16) us(840) organization(1) + * gov(101) csor(3) nistalgorithm(4) hashalgs(2) 2 */ +static char cms_sha384[] = { + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 +}; +/* RFC 5754 id-sha512: joint-iso-itu-t(2) country(16) us(840) organization(1) + * gov(101) csor(3) nistalgorithm(4) hashalgs(2) 3 */ +static char cms_sha512[] = { + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 +}; + +const krb5_data cms_sha1_id = { KV5M_DATA, sizeof(cms_sha1), cms_sha1 }; +const krb5_data cms_sha256_id = { KV5M_DATA, sizeof(cms_sha256), cms_sha256 }; +const krb5_data cms_sha384_id = { KV5M_DATA, sizeof(cms_sha384), cms_sha384 }; +const krb5_data cms_sha512_id = { KV5M_DATA, sizeof(cms_sha512), cms_sha512 }; + /* RFC 4055 sha256WithRSAEncryption: iso(1) member-body(2) us(840) * rsadsi(113549) pkcs(1) 1 11 */ static char sha256WithRSAEncr_oid[9] = { diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h index 8e4a813622..57bb3cb840 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto.h +++ b/src/plugins/preauth/pkinit/pkinit_crypto.h @@ -542,9 +542,13 @@ pkinit_kdf(krb5_context context, krb5_data *secret, const krb5_data *alg_oid, const krb5_data *as_req, const krb5_data *pk_as_rep, krb5_keyblock *key_block); -extern const krb5_data sha1_id; -extern const krb5_data sha256_id; -extern const krb5_data sha512_id; +extern const krb5_data kdf_sha1_id; +extern const krb5_data kdf_sha256_id; +extern const krb5_data kdf_sha512_id; +extern const krb5_data cms_sha1_id; +extern const krb5_data cms_sha256_id; +extern const krb5_data cms_sha384_id; +extern const krb5_data cms_sha512_id; extern const krb5_data oakley_1024; extern const krb5_data oakley_2048; extern const krb5_data oakley_4096; @@ -577,4 +581,18 @@ crypto_req_cert_matching_data(krb5_context context, int parse_dh_min_bits(krb5_context context, const char *str); +/* Generate a SHA-1 checksum over body in *cksum1_out and a SHA-256 checksum + * over body in *cksum2_out with appropriate metadata. */ +krb5_error_code +crypto_generate_checksums(krb5_context context, const krb5_data *body, + krb5_data *cksum1_out, + krb5_pachecksum2 **cksum2_out); + +/* Verify the SHA-1 checksum in cksum1 and the tagged checksum in cksum2. + * cksum2 may be NULL, in which case only cksum1 is verified. */ +krb5_error_code +crypto_verify_checksums(krb5_context context, krb5_data *body, + const krb5_data *cksum1, + const krb5_pachecksum2 *cksum2); + #endif /* _PKINIT_CRYPTO_H */ diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c index 8098028eb0..f222dbdf92 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c @@ -2651,11 +2651,11 @@ cleanup: static const EVP_MD * algid_to_md(const krb5_data *alg_id) { - if (data_eq(*alg_id, sha1_id)) + if (data_eq(*alg_id, kdf_sha1_id)) return EVP_sha1(); - if (data_eq(*alg_id, sha256_id)) + if (data_eq(*alg_id, kdf_sha256_id)) return EVP_sha256(); - if (data_eq(*alg_id, sha512_id)) + if (data_eq(*alg_id, kdf_sha512_id)) return EVP_sha512(); return NULL; } @@ -5699,6 +5699,116 @@ parse_dh_min_bits(krb5_context context, const char *str) return PKINIT_DEFAULT_DH_MIN_BITS; } +/* Return the OpenSSL message digest type matching the given CMS OID, or NULL + * if it doesn't match any of the CMS OIDs we know about. */ +static const EVP_MD * +md_from_cms_oid(const krb5_data *alg_id) +{ + if (data_eq(*alg_id, cms_sha1_id)) + return EVP_sha1(); + if (data_eq(*alg_id, cms_sha256_id)) + return EVP_sha256(); + if (data_eq(*alg_id, cms_sha384_id)) + return EVP_sha384(); + if (data_eq(*alg_id, cms_sha512_id)) + return EVP_sha512(); + return NULL; +} + +/* Compute a message digest of the given type over body, placing the result in + * *digest_out in allocated storage. Return true on success. */ +static krb5_boolean +make_digest(const krb5_data *body, const EVP_MD *md, krb5_data *digest_out) +{ + krb5_error_code ret; + krb5_data d; + + if (md == NULL) + return FALSE; + ret = alloc_data(&d, EVP_MD_size(md)); + if (ret) + return FALSE; + if (!EVP_Digest(body->data, body->length, (uint8_t *)d.data, &d.length, md, + NULL)) { + free(d.data); + return FALSE; + } + *digest_out = d; + return TRUE; +} + +/* Return true if digest verifies for the given body and message digest + * type. */ +static krb5_boolean +check_digest(const krb5_data *body, const EVP_MD *md, const krb5_data *digest) +{ + unsigned int digest_len; + uint8_t buf[EVP_MAX_MD_SIZE]; + + if (md == NULL) + return FALSE; + if (!EVP_Digest(body->data, body->length, buf, &digest_len, md, NULL)) + return FALSE; + return (digest->length == digest_len && + CRYPTO_memcmp(digest->data, buf, digest_len) == 0); +} + +krb5_error_code +crypto_generate_checksums(krb5_context context, const krb5_data *body, + krb5_data *cksum1_out, krb5_pachecksum2 **cksum2_out) +{ + krb5_data cksum1 = empty_data(); + krb5_pachecksum2 *cksum2 = NULL; + krb5_error_code ret; + + if (!make_digest(body, EVP_sha1(), &cksum1)) + goto fail; + + cksum2 = k5alloc(sizeof(*cksum2), &ret); + if (cksum2 == NULL) + goto fail; + + if (!make_digest(body, EVP_sha256(), &cksum2->checksum)) + goto fail; + + if (krb5int_copy_data_contents(context, &cms_sha256_id, + &cksum2->algorithmIdentifier.algorithm)) + goto fail; + + cksum2->algorithmIdentifier.parameters = empty_data(); + + *cksum1_out = cksum1; + *cksum2_out = cksum2; + return 0; + +fail: + krb5_free_data_contents(context, &cksum1); + free_pachecksum2(context, &cksum2); + return KRB5_CRYPTO_INTERNAL; +} + +krb5_error_code +crypto_verify_checksums(krb5_context context, krb5_data *body, + const krb5_data *cksum1, + const krb5_pachecksum2 *cksum2) +{ + const EVP_MD *md; + + /* RFC 4556 doesn't say what error to return if the checksum doesn't match. + * Windows returns this one. */ + if (!check_digest(body, EVP_sha1(), cksum1)) + return KRB5KRB_AP_ERR_MODIFIED; + + if (cksum2 == NULL) + return 0; + + md = md_from_cms_oid(&cksum2->algorithmIdentifier.algorithm); + if (!check_digest(body, md, &cksum2->checksum)) + return KRB5KRB_AP_ERR_MODIFIED; + + return 0; +} + #ifdef _WIN32 BOOL WINAPI DllMain(HANDLE hModule, DWORD fdwReason, LPVOID lpvReserved) diff --git a/src/plugins/preauth/pkinit/pkinit_kdf_test.c b/src/plugins/preauth/pkinit/pkinit_kdf_test.c index 0a8a69b2a7..3d0f7198e9 100644 --- a/src/plugins/preauth/pkinit/pkinit_kdf_test.c +++ b/src/plugins/preauth/pkinit/pkinit_kdf_test.c @@ -122,7 +122,7 @@ main(int argc, char **argv) /* TEST 1: SHA-1/AES */ /* set up algorithm id */ - alg_id.algorithm = sha1_id; + alg_id.algorithm = kdf_sha1_id; enctype = enctype_aes; @@ -150,7 +150,7 @@ main(int argc, char **argv) /* TEST 2: SHA-256/AES */ /* set up algorithm id */ - alg_id.algorithm = sha256_id; + alg_id.algorithm = kdf_sha256_id; enctype = enctype_aes; @@ -178,7 +178,7 @@ main(int argc, char **argv) /* TEST 3: SHA-512/DES3 */ /* set up algorithm id */ - alg_id.algorithm = sha512_id; + alg_id.algorithm = kdf_sha512_id; enctype = enctype_des3; diff --git a/src/plugins/preauth/pkinit/pkinit_lib.c b/src/plugins/preauth/pkinit/pkinit_lib.c index 25965eb5d2..891f47fd26 100644 --- a/src/plugins/preauth/pkinit/pkinit_lib.c +++ b/src/plugins/preauth/pkinit/pkinit_lib.c @@ -29,6 +29,7 @@ * SUCH DAMAGES. */ +#include "k5-int.h" #include "pkinit.h" #define FAKECERT @@ -119,8 +120,9 @@ free_krb5_auth_pack(krb5_auth_pack **in) { if ((*in) == NULL) return; krb5_free_data_contents(NULL, &(*in)->clientPublicValue); - free((*in)->pkAuthenticator.paChecksum.contents); + free((*in)->pkAuthenticator.paChecksum.data); krb5_free_data(NULL, (*in)->pkAuthenticator.freshnessToken); + free_pachecksum2(NULL, &(*in)->pkAuthenticator.paChecksum2); if ((*in)->supportedCMSTypes != NULL) free_krb5_algorithm_identifiers(&((*in)->supportedCMSTypes)); if ((*in)->supportedKDFs) { @@ -196,6 +198,18 @@ free_krb5_kdc_dh_key_info(krb5_kdc_dh_key_info **in) free(*in); } +void +free_pachecksum2(krb5_context context, krb5_pachecksum2 **in) +{ + if (*in == NULL) + return; + krb5_free_data_contents(context, &(*in)->checksum); + krb5_free_data_contents(context, &(*in)->algorithmIdentifier.algorithm); + krb5_free_data_contents(context, &(*in)->algorithmIdentifier.parameters); + free(*in); + *in = NULL; +} + void init_krb5_pa_pk_as_req(krb5_pa_pk_as_req **in) { diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c index 1f3db4f271..7a0fa69ee2 100644 --- a/src/plugins/preauth/pkinit/pkinit_srv.c +++ b/src/plugins/preauth/pkinit/pkinit_srv.c @@ -428,11 +428,12 @@ pkinit_server_verify_padata(krb5_context context, krb5_data authp_data = {0, 0, NULL}, krb5_authz = {0, 0, NULL}; krb5_pa_pk_as_req *reqp = NULL; krb5_auth_pack *auth_pack = NULL; + krb5_pk_authenticator *pka; pkinit_kdc_context plgctx = NULL; pkinit_kdc_req_context reqctx = NULL; krb5_checksum cksum = {0, 0, 0, NULL}; krb5_data *der_req = NULL; - krb5_data k5data, *ftoken; + krb5_data k5data; int is_signed = 1; krb5_pa_data **e_data = NULL; krb5_kdcpreauth_modreq modreq = NULL; @@ -524,8 +525,9 @@ pkinit_server_verify_padata(krb5_context context, pkiDebug("failed to decode krb5_auth_pack\n"); goto cleanup; } + pka = &auth_pack->pkAuthenticator; - retval = krb5_check_clockskew(context, auth_pack->pkAuthenticator.ctime); + retval = krb5_check_clockskew(context, pka->ctime); if (retval) goto cleanup; @@ -548,36 +550,14 @@ pkinit_server_verify_padata(krb5_context context, goto cleanup; } der_req = cb->request_body(context, rock); - retval = krb5_c_make_checksum(context, CKSUMTYPE_SHA1, NULL, 0, der_req, - &cksum); - if (retval) { - pkiDebug("unable to calculate AS REQ checksum\n"); - goto cleanup; - } - if (cksum.length != auth_pack->pkAuthenticator.paChecksum.length || - k5_bcmp(cksum.contents, auth_pack->pkAuthenticator.paChecksum.contents, - cksum.length) != 0) { - pkiDebug("failed to match the checksum\n"); -#ifdef DEBUG_CKSUM - pkiDebug("calculating checksum on buf size (%d)\n", req_pkt->length); - print_buffer(req_pkt->data, req_pkt->length); - pkiDebug("received checksum type=%d size=%d ", - auth_pack->pkAuthenticator.paChecksum.checksum_type, - auth_pack->pkAuthenticator.paChecksum.length); - print_buffer(auth_pack->pkAuthenticator.paChecksum.contents, - auth_pack->pkAuthenticator.paChecksum.length); - pkiDebug("expected checksum type=%d size=%d ", - cksum.checksum_type, cksum.length); - print_buffer(cksum.contents, cksum.length); -#endif - retval = KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED; + retval = crypto_verify_checksums(context, der_req, &pka->paChecksum, + pka->paChecksum2); + if (retval) goto cleanup; - } - ftoken = auth_pack->pkAuthenticator.freshnessToken; - if (ftoken != NULL) { - retval = cb->check_freshness_token(context, rock, ftoken); + if (pka->freshnessToken != NULL) { + retval = cb->check_freshness_token(context, rock, pka->freshnessToken); if (retval) goto cleanup; valid_freshness_token = TRUE; diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h index c0b1e2c13f..7d19167eba 100644 --- a/src/plugins/preauth/pkinit/pkinit_trace.h +++ b/src/plugins/preauth/pkinit/pkinit_trace.h @@ -52,8 +52,9 @@ TRACE(c, "PKINIT client verified DH reply") #define TRACE_PKINIT_CLIENT_REP_DH_FAIL(c) \ TRACE(c, "PKINIT client could not verify DH reply") -#define TRACE_PKINIT_CLIENT_REQ_CHECKSUM(c, cksum) \ - TRACE(c, "PKINIT client computed kdc-req-body checksum {cksum}", cksum) +#define TRACE_PKINIT_CLIENT_REQ_CHECKSUMS(c, ck1, ck2) \ + TRACE(c, "PKINIT client computed checksums: {hexdata} {hexdata}", \ + ck1, &(ck2)->checksum) #define TRACE_PKINIT_CLIENT_REQ_DH(c) \ TRACE(c, "PKINIT client making DH request") #define TRACE_PKINIT_CLIENT_SAN_CONFIG_DNSNAME(c, host) \ diff --git a/src/tests/asn.1/krb5_decode_test.c b/src/tests/asn.1/krb5_decode_test.c index 6ead19d5d3..25ed30e422 100644 --- a/src/tests/asn.1/krb5_decode_test.c +++ b/src/tests/asn.1/krb5_decode_test.c @@ -1178,7 +1178,7 @@ main(int argc, char **argv) /* decode_krb5_auth_pack */ { setup(krb5_auth_pack,ktest_make_sample_auth_pack); - decode_run("krb5_auth_pack","","30 81 85 A0 35 30 33 A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 06 04 04 31 32 33 34 A4 0A 04 08 6B 72 62 35 64 61 74 61 A1 08 04 06 70 76 61 6C 75 65 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61", + decode_run("krb5_auth_pack","","30 81 89 A0 39 30 37 A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 0A 04 08 6B 72 62 35 64 61 74 61 A1 08 04 06 70 76 61 6C 75 65 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61", acc.decode_krb5_auth_pack, ktest_equal_auth_pack,ktest_free_auth_pack); ktest_empty_auth_pack(&ref); diff --git a/src/tests/asn.1/ktest.c b/src/tests/asn.1/ktest.c index 02d26c0855..20360c8ffc 100644 --- a/src/tests/asn.1/ktest.c +++ b/src/tests/asn.1/ktest.c @@ -700,9 +700,7 @@ ktest_make_sample_pk_authenticator(krb5_pk_authenticator *p) p->cusec = SAMPLE_USEC; p->ctime = SAMPLE_TIME; p->nonce = SAMPLE_NONCE; - ktest_make_sample_checksum(&p->paChecksum); - /* We don't encode the checksum type, only the contents. */ - p->paChecksum.checksum_type = 0; + ktest_make_sample_data(&p->paChecksum); p->freshnessToken = ealloc(sizeof(krb5_data)); ktest_make_sample_data(p->freshnessToken); } @@ -1604,8 +1602,7 @@ ktest_empty_pa_otp_req(krb5_pa_otp_req *p) static void ktest_empty_pk_authenticator(krb5_pk_authenticator *p) { - ktest_empty_checksum(&p->paChecksum); - p->paChecksum.contents = NULL; + ktest_empty_data(&p->paChecksum); krb5_free_data(NULL, p->freshnessToken); p->freshnessToken = NULL; } diff --git a/src/tests/asn.1/ktest_equal.c b/src/tests/asn.1/ktest_equal.c index b48a0285d2..13786dd1e5 100644 --- a/src/tests/asn.1/ktest_equal.c +++ b/src/tests/asn.1/ktest_equal.c @@ -844,7 +844,7 @@ ktest_equal_pk_authenticator(krb5_pk_authenticator *ref, p = p && scalar_equal(cusec); p = p && scalar_equal(ctime); p = p && scalar_equal(nonce); - p = p && struct_equal(paChecksum, ktest_equal_checksum); + p = p && data_eq(ref->paChecksum, var->paChecksum); return p; } diff --git a/src/tests/asn.1/pkinit_encode.out b/src/tests/asn.1/pkinit_encode.out index 6ec7aaa36a..a764182e15 100644 --- a/src/tests/asn.1/pkinit_encode.out +++ b/src/tests/asn.1/pkinit_encode.out @@ -1,7 +1,7 @@ encode_krb5_pa_pk_as_req: 30 38 80 08 6B 72 62 35 64 61 74 61 A1 22 30 20 30 1E 80 08 6B 72 62 35 64 61 74 61 81 08 6B 72 62 35 64 61 74 61 82 08 6B 72 62 35 64 61 74 61 82 08 6B 72 62 35 64 61 74 61 encode_krb5_pa_pk_as_rep(dhInfo): A0 28 30 26 80 08 6B 72 62 35 64 61 74 61 A1 0A 04 08 6B 72 62 35 64 61 74 61 A2 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61 encode_krb5_pa_pk_as_rep(encKeyPack): 81 08 6B 72 62 35 64 61 74 61 -encode_krb5_auth_pack: 30 81 85 A0 35 30 33 A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 06 04 04 31 32 33 34 A4 0A 04 08 6B 72 62 35 64 61 74 61 A1 08 04 06 70 76 61 6C 75 65 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61 +encode_krb5_auth_pack: 30 81 89 A0 39 30 37 A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 0A 04 08 6B 72 62 35 64 61 74 61 A1 08 04 06 70 76 61 6C 75 65 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61 encode_krb5_kdc_dh_key_info: 30 25 A0 0B 03 09 00 6B 72 62 35 64 61 74 61 A1 03 02 01 2A A2 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A encode_krb5_reply_key_pack: 30 26 A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 encode_krb5_sp80056a_other_info: 30 81 81 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A0 32 04 30 30 2E A0 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A1 32 04 30 30 2E A0 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 0A 04 08 6B 72 62 35 64 61 74 61 diff --git a/src/tests/asn.1/pkinit_trval.out b/src/tests/asn.1/pkinit_trval.out index 46f4a34108..c47bd71f67 100644 --- a/src/tests/asn.1/pkinit_trval.out +++ b/src/tests/asn.1/pkinit_trval.out @@ -38,7 +38,7 @@ encode_krb5_auth_pack: . . [0] [Integer] 123456 . . [1] [Generalized Time] "19940610060317Z" . . [2] [Integer] 42 -. . [3] [Octet String] "1234" +. . [3] [Octet String] "krb5data" . . [4] [Octet String] "krb5data" . [1] [Octet String] "pvalue" . [2] [Sequence/Sequence Of]