diff --git a/Add-a-simple-support-header.patch b/Add-a-simple-DER-support-header.patch similarity index 94% rename from Add-a-simple-support-header.patch rename to Add-a-simple-DER-support-header.patch index d90c866f053b492442872150a2652256bf9eba2e..f87b817366f123a837e1b51fc6d9c226f30fce5c 100644 --- a/Add-a-simple-support-header.patch +++ b/Add-a-simple-DER-support-header.patch @@ -1,11 +1,8 @@ -From 548da160b52b25a106e9f6077d6a42c2c049586c Mon Sep 17 00:00:00 2001 -From: Greg Hudson -Date: Tue, 7 Mar 2023 00:19:33 -0500 +From 77bb00198de40052e1b3eaffd64b411ab19ef920 Mon Sep 17 00:00:00 2001 +From: zhuhongbo +Date: Tue, 19 Nov 2024 17:13:06 Subject: [PATCH] Add a simple DER support header -Reference: https://github.com/krb5/krb5/commit/548da160b52b25a106e9f6077d6a42c2c049586c -Conflict: NA - --- src/include/k5-der.h | 149 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) @@ -13,7 +10,7 @@ Conflict: NA diff --git a/src/include/k5-der.h b/src/include/k5-der.h new file mode 100644 -index 0000000..b8371d9 +index 0000000000..b8371d9b4d --- /dev/null +++ b/src/include/k5-der.h @@ -0,0 +1,149 @@ @@ -167,5 +164,5 @@ index 0000000..b8371d9 + +#endif /* K5_DER_H */ -- -2.33.0 +2.45.1 diff --git a/Fix-CVE-2024-37370-and-CVE-2024-37371.patch b/Fix-vulnerabilities-in-GSS-message-token-handling.patch similarity index 78% rename from Fix-CVE-2024-37370-and-CVE-2024-37371.patch rename to Fix-vulnerabilities-in-GSS-message-token-handling.patch index 15a11a8bf34af215910eaef22fbd033b2da83a52..34a92f0e7fe6f3d0eac0e984b8ba6259581d7d86 100644 --- a/Fix-CVE-2024-37370-and-CVE-2024-37371.patch +++ b/Fix-vulnerabilities-in-GSS-message-token-handling.patch @@ -1,17 +1,26 @@ -From 8713e850abc1b5ac72d267139a344f245f3a6487 Mon Sep 17 00:00:00 2001 -From: root -Date: Tue, 20 Aug 2024 14:21:10 +0800 -Subject: [PATCH] CVE-2024-37370 and CVE-2024-37371 +From 63050c14d364ee9617d3d4db5c20870e72f5f519 Mon Sep 17 00:00:00 2001 +From: zhuhongbo +Date: Fri, 14 Jun 2024 10:56:12 -0400 +Subject: [PATCH] Fix vulnerabilities in GSS message token handling + +CVE-2024-37370: +In MIT krb5 release 1.3 and later, an attacker can modify the +plaintext Extra Count field of a confidential GSS krb5 wrap token, +causing the unwrapped token to appear truncated to the application. + +CVE-2024-37371: +In MIT krb5 release 1.3 and later, an attacker can cause invalid +memory reads by sending message tokens with invalid length fields. --- src/lib/gssapi/krb5/k5sealv3.c | 5 + src/lib/gssapi/krb5/k5sealv3iov.c | 3 +- - src/lib/gssapi/krb5/k5unsealiov.c | 80 ++++++++++-- - src/tests/gssapi/t_invalid.c | 197 ++++++++++++++++++++++++++---- - 4 files changed, 253 insertions(+), 32 deletions(-) + src/lib/gssapi/krb5/k5unsealiov.c | 80 ++++++++++- + src/tests/gssapi/t_invalid.c | 222 ++++++++++++++++++++++++++---- + 4 files changed, 273 insertions(+), 37 deletions(-) diff --git a/src/lib/gssapi/krb5/k5sealv3.c b/src/lib/gssapi/krb5/k5sealv3.c -index 1a5c14c..4bb0ce3 100644 +index 1a5c14c271..4bb0ce34b1 100644 --- a/src/lib/gssapi/krb5/k5sealv3.c +++ b/src/lib/gssapi/krb5/k5sealv3.c @@ -403,10 +403,15 @@ gss_krb5int_unseal_token_v3(krb5_context *contextptr, @@ -31,7 +40,7 @@ index 1a5c14c..4bb0ce3 100644 free(plain.data); goto defective; diff --git a/src/lib/gssapi/krb5/k5sealv3iov.c b/src/lib/gssapi/krb5/k5sealv3iov.c -index a73edb6..b0b0c0f 100644 +index a73edb6a4f..b0b0c0f35a 100644 --- a/src/lib/gssapi/krb5/k5sealv3iov.c +++ b/src/lib/gssapi/krb5/k5sealv3iov.c @@ -403,9 +403,10 @@ gss_krb5int_unseal_v3_iov(krb5_context context, @@ -47,7 +56,7 @@ index a73edb6..b0b0c0f 100644 } else { /* Verify checksum: note EC is checksum size here, not padding */ diff --git a/src/lib/gssapi/krb5/k5unsealiov.c b/src/lib/gssapi/krb5/k5unsealiov.c -index 8b67042..3302c54 100644 +index 8b6704274d..3302c549eb 100644 --- a/src/lib/gssapi/krb5/k5unsealiov.c +++ b/src/lib/gssapi/krb5/k5unsealiov.c @@ -25,6 +25,7 @@ @@ -171,13 +180,55 @@ index 8b67042..3302c54 100644 switch (toktype2) { case KG2_TOK_MIC_MSG: diff --git a/src/tests/gssapi/t_invalid.c b/src/tests/gssapi/t_invalid.c -index 5c8ddac..c92e6e4 100644 +index 5c8ddac8dc..62e39cc2e6 100644 --- a/src/tests/gssapi/t_invalid.c +++ b/src/tests/gssapi/t_invalid.c -@@ -118,16 +118,24 @@ struct test { +@@ -36,20 +36,35 @@ + * + * 1. A pre-CFX wrap or MIC token processed with a CFX-only context causes a + * null pointer dereference. (The token must use SEAL_ALG_NONE or it will +- * be rejected.) ++ * be rejected.) This vulnerability also applies to IOV unwrap. + * +- * 2. A pre-CFX wrap or MIC token with fewer than 24 bytes after the ASN.1 ++ * 2. A CFX wrap token with a different value of EC between the plaintext and ++ * encrypted copies will be erroneously accepted, which allows a message ++ * truncation attack. This vulnerability also applies to IOV unwrap. ++ * ++ * 3. A CFX wrap token with a plaintext length fewer than 16 bytes causes an ++ * access before the beginning of the input buffer, possibly leading to a ++ * crash. ++ * ++ * 4. A CFX wrap token with a plaintext EC value greater than the plaintext ++ * length - 16 causes an integer underflow when computing the result length, ++ * likely causing a crash. ++ * ++ * 5. An IOV unwrap operation will overrun the header buffer if an ASN.1 ++ * wrapper longer than the header buffer is present. ++ * ++ * 6. A pre-CFX wrap or MIC token with fewer than 24 bytes after the ASN.1 + * header causes an input buffer overrun, usually leading to either a segv + * or a GSS_S_DEFECTIVE_TOKEN error due to garbage algorithm, filler, or +- * sequence number values. ++ * sequence number values. This vulnerability also applies to IOV unwrap. + * +- * 3. A pre-CFX wrap token with fewer than 16 + cksumlen bytes after the ASN.1 ++ * 7. A pre-CFX wrap token with fewer than 16 + cksumlen bytes after the ASN.1 + * header causes an integer underflow when computing the ciphertext length, + * leading to an allocation error on 32-bit platforms or a segv on 64-bit + * platforms. A pre-CFX MIC token of this size causes an input buffer + * overrun when comparing the checksum, perhaps leading to a segv. + * +- * 4. A pre-CFX wrap token with fewer than conflen + padlen bytes in the ++ * 8. A pre-CFX wrap token with fewer than conflen + padlen bytes in the + * ciphertext (where padlen is the last byte of the decrypted ciphertext) + * causes an integer underflow when computing the original message length, + * leading to an allocation error. +@@ -117,17 +132,25 @@ struct test { + } }; - /* Fake up enough of a CFX GSS context for gss_unwrap, using an AES key. */ +-/* Fake up enough of a CFX GSS context for gss_unwrap, using an AES key. */ +static void * +ealloc(size_t len) +{ @@ -197,7 +248,7 @@ index 5c8ddac..c92e6e4 100644 gss_union_ctx_id_t uctx; krb5_gss_ctx_id_t kgctx; - krb5_keyblock kb; -- + - kgctx = calloc(1, sizeof(*kgctx)); - if (kgctx == NULL) - abort(); @@ -205,7 +256,7 @@ index 5c8ddac..c92e6e4 100644 kgctx->established = 1; kgctx->proto = 1; if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0) -@@ -136,15 +144,10 @@ make_fake_cfx_context() +@@ -136,15 +159,10 @@ make_fake_cfx_context() kgctx->sealalg = -1; kgctx->signalg = -1; @@ -224,7 +275,7 @@ index 5c8ddac..c92e6e4 100644 uctx->mech_type = &mech_krb5; uctx->internal_ctx_id = (gss_ctx_id_t)kgctx; return (gss_ctx_id_t)uctx; -@@ -160,9 +163,7 @@ make_fake_context(const struct test *test) +@@ -160,9 +178,7 @@ make_fake_context(const struct test *test) unsigned char encbuf[8]; size_t i; @@ -235,18 +286,18 @@ index 5c8ddac..c92e6e4 100644 kgctx->established = 1; if (g_seqstate_init(&kgctx->seqstate, 0, 0, 0, 0) != 0) abort(); -@@ -189,9 +190,7 @@ make_fake_context(const struct test *test) +@@ -189,9 +205,7 @@ make_fake_context(const struct test *test) if (krb5_k_create_key(NULL, &kb, &kgctx->enc) != 0) abort(); - uctx = calloc(1, sizeof(*uctx)); - if (uctx == NULL) - abort(); -+ uctx = ealloc(sizeof(*uctx)); ++ uctx = ealloc(sizeof(*uctx)); uctx->mech_type = &mech_krb5; uctx->internal_ctx_id = (gss_ctx_id_t)kgctx; return (gss_ctx_id_t)uctx; -@@ -221,9 +220,7 @@ make_token(unsigned char *token, size_t len, gss_buffer_t out) +@@ -221,9 +235,7 @@ make_token(unsigned char *token, size_t len, gss_buffer_t out) assert(mech_krb5.length == 9); assert(len + 11 < 128); @@ -257,7 +308,7 @@ index 5c8ddac..c92e6e4 100644 wrapped[0] = 0x60; wrapped[1] = len + 11; wrapped[2] = 0x06; -@@ -234,6 +231,18 @@ make_token(unsigned char *token, size_t len, gss_buffer_t out) +@@ -234,6 +246,18 @@ make_token(unsigned char *token, size_t len, gss_buffer_t out) out->value = wrapped; } @@ -276,7 +327,7 @@ index 5c8ddac..c92e6e4 100644 /* Unwrap a superficially valid RFC 1964 token with a CFX-only context, with * regular and IOV unwrap. */ static void -@@ -265,6 +274,134 @@ test_bogus_1964_token(gss_ctx_id_t ctx) +@@ -265,6 +289,134 @@ test_bogus_1964_token(gss_ctx_id_t ctx) free(in.value); } @@ -411,7 +462,7 @@ index 5c8ddac..c92e6e4 100644 /* Process wrap and MIC tokens with incomplete headers. */ static void test_short_header(gss_ctx_id_t ctx) -@@ -409,11 +546,23 @@ test_bad_pad(gss_ctx_id_t ctx, const struct test *test) +@@ -409,11 +561,23 @@ test_bad_pad(gss_ctx_id_t ctx, const struct test *test) int main(int argc, char **argv) { @@ -437,5 +488,5 @@ index 5c8ddac..c92e6e4 100644 for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) { -- -2.39.3 +2.45.1 diff --git a/Generate-and-verify-message-MACs-in-libkrad.patch b/Generate-and-verify-message-MACs-in-libkrad.patch new file mode 100644 index 0000000000000000000000000000000000000000..1bb1e283c0836d54b430ffef04e48b3ecb30da06 --- /dev/null +++ b/Generate-and-verify-message-MACs-in-libkrad.patch @@ -0,0 +1,604 @@ +From f78c4f2acd1bd8af48d923df381561a17880f9a7 Mon Sep 17 00:00:00 2024 +From: zhuhongbo +Date: Tue, 19 Nov 2024 17:13:06 +Subject: [PATCH] Generate and verify message MACs in libkrad + +--- + src/include/k5-int.h | 5 + + src/lib/crypto/krb/checksum_hmac_md5.c | 28 ++++ + src/lib/crypto/libk5crypto.exports | 1 + + src/lib/krad/attr.c | 17 ++ + src/lib/krad/attrset.c | 59 +++++-- + src/lib/krad/internal.h | 7 +- + src/lib/krad/packet.c | 206 +++++++++++++++++++++++-- + src/lib/krad/t_attrset.c | 2 +- + src/lib/krad/t_daemon.py | 3 +- + src/lib/krad/t_packet.c | 11 ++ + src/tests/t_otp.py | 3 + + 11 files changed, 311 insertions(+), 31 deletions(-) + +diff --git a/src/include/k5-int.h b/src/include/k5-int.h +index 7c549bce2e..ef7993eea4 100644 +--- a/src/include/k5-int.h ++++ b/src/include/k5-int.h +@@ -2429,4 +2429,9 @@ void k5_change_error_message_code(krb5_context ctx, krb5_error_code oldcode, + #define k5_prependmsg krb5_prepend_error_message + #define k5_wrapmsg krb5_wrap_error_message + ++/* Generate an HMAC-MD5 keyed checksum as specified by RFC 2104. */ ++krb5_error_code ++k5_hmac_md5(const krb5_data *key, const krb5_crypto_iov *data, size_t num_data, ++ krb5_data *output); ++ + #endif /* _KRB5_INT_H */ +diff --git a/src/lib/crypto/krb/checksum_hmac_md5.c b/src/lib/crypto/krb/checksum_hmac_md5.c +index ec024f3966..a809388549 100644 +--- a/src/lib/crypto/krb/checksum_hmac_md5.c ++++ b/src/lib/crypto/krb/checksum_hmac_md5.c +@@ -92,3 +92,31 @@ cleanup: + free(hash_iov); + return ret; + } ++ ++krb5_error_code ++k5_hmac_md5(const krb5_data *key, const krb5_crypto_iov *data, size_t num_data, ++ krb5_data *output) ++{ ++ krb5_error_code ret; ++ const struct krb5_hash_provider *hash = &krb5int_hash_md5; ++ krb5_keyblock keyblock = { 0 }; ++ krb5_data hashed_key; ++ uint8_t hkeybuf[16]; ++ krb5_crypto_iov iov; ++ ++ /* Hash the key if it is longer than the block size. */ ++ if (key->length > hash->blocksize) { ++ hashed_key = make_data(hkeybuf, sizeof(hkeybuf)); ++ iov.flags = KRB5_CRYPTO_TYPE_DATA; ++ iov.data = *key; ++ ret = hash->hash(&iov, 1, &hashed_key); ++ if (ret) ++ return ret; ++ key = &hashed_key; ++ } ++ ++ keyblock.magic = KV5M_KEYBLOCK; ++ keyblock.length = key->length; ++ keyblock.contents = (uint8_t *)key->data; ++ return krb5int_hmac_keyblock(hash, &keyblock, data, num_data, output); ++} +diff --git a/src/lib/crypto/libk5crypto.exports b/src/lib/crypto/libk5crypto.exports +index 82eb5f30c0..6a4ba74186 100644 +--- a/src/lib/crypto/libk5crypto.exports ++++ b/src/lib/crypto/libk5crypto.exports +@@ -109,3 +109,4 @@ k5_allow_weak_pbkdf2iter + krb5_c_prfplus + krb5_c_derive_prfplus + k5_enctype_to_ssf ++k5_hmac_md5 +diff --git a/src/lib/krad/attr.c b/src/lib/krad/attr.c +index f96153e2e7..ae1d7d1213 100644 +--- a/src/lib/krad/attr.c ++++ b/src/lib/krad/attr.c +@@ -125,6 +125,23 @@ static const attribute_record attributes[UCHAR_MAX] = { + {"NAS-Port-Type", 4, 4, NULL, NULL}, + {"Port-Limit", 4, 4, NULL, NULL}, + {"Login-LAT-Port", 1, MAX_ATTRSIZE, NULL, NULL}, ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */ ++ {NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */ ++ {NULL, 0, 0, NULL, NULL}, /* Password-Retry */ ++ {NULL, 0, 0, NULL, NULL}, /* Prompt */ ++ {NULL, 0, 0, NULL, NULL}, /* Connect-Info */ ++ {NULL, 0, 0, NULL, NULL}, /* Configuration-Token */ ++ {NULL, 0, 0, NULL, NULL}, /* EAP-Message */ ++ {"Message-Authenticator", MD5_DIGEST_SIZE, MD5_DIGEST_SIZE, NULL, NULL}, + }; + + /* Encode User-Password attribute. */ +diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c +index d89982a131..3e392d5952 100644 +--- a/src/lib/krad/attrset.c ++++ b/src/lib/krad/attrset.c +@@ -164,15 +164,44 @@ krad_attrset_copy(const krad_attrset *set, krad_attrset **copy) + return 0; + } + ++/* Place an encoded attributes into outbuf at position *i. Increment *i by the ++ * length of the encoding. */ ++static krb5_error_code ++append_attr(krb5_context ctx, const char *secret, ++ const uint8_t *auth, krad_attr type, const krb5_data *data, ++ uint8_t outbuf[MAX_ATTRSETSIZE], size_t *i, krb5_boolean *is_fips) ++{ ++ uint8_t buffer[MAX_ATTRSIZE]; ++ size_t attrlen; ++ krb5_error_code retval; ++ ++ retval = kr_attr_encode(ctx, secret, auth, type, data, buffer, &attrlen, ++ is_fips); ++ if (retval) ++ return retval; ++ ++ if (attrlen > MAX_ATTRSETSIZE - *i - 2) ++ return EMSGSIZE; ++ ++ outbuf[(*i)++] = type; ++ outbuf[(*i)++] = attrlen + 2; ++ memcpy(outbuf + *i, buffer, attrlen); ++ *i += attrlen; ++ ++ return 0; ++} ++ + krb5_error_code + kr_attrset_encode(const krad_attrset *set, const char *secret, +- const unsigned char *auth, ++ const uint8_t *auth, krb5_boolean add_msgauth, + unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen, + krb5_boolean *is_fips) + { +- unsigned char buffer[MAX_ATTRSIZE]; + krb5_error_code retval; +- size_t i = 0, attrlen; ++ krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator"); ++ const uint8_t zeroes[MD5_DIGEST_SIZE] = { 0 }; ++ krb5_data zerodata; ++ size_t i = 0; + attr *a; + + if (set == NULL) { +@@ -180,19 +209,21 @@ kr_attrset_encode(const krad_attrset *set, const char *secret, + return 0; + } + +- K5_TAILQ_FOREACH(a, &set->list, list) { +- retval = kr_attr_encode(set->ctx, secret, auth, a->type, &a->attr, +- buffer, &attrlen, is_fips); +- if (retval != 0) ++ if (add_msgauth) { ++ /* Encode Message-Authenticator as the first attribute, per ++ * draft-ietf-radext-deprecating-radius-03 section 5.2. */ ++ zerodata = make_data((uint8_t *)zeroes, MD5_DIGEST_SIZE); ++ retval = append_attr(set->ctx, secret, auth, msgauth_type, &zerodata, ++ outbuf, &i, is_fips); ++ if (retval) + return retval; ++ } + +- if (i + attrlen + 2 > MAX_ATTRSETSIZE) +- return EMSGSIZE; +- +- outbuf[i++] = a->type; +- outbuf[i++] = attrlen + 2; +- memcpy(&outbuf[i], buffer, attrlen); +- i += attrlen; ++ K5_TAILQ_FOREACH(a, &set->list, list) { ++ retval = append_attr(set->ctx, secret, auth, a->type, &a->attr, ++ outbuf, &i, is_fips); ++ if (retval) ++ return retval; + } + + *outlen = i; +diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h +index a53ce31ce5..a8915601bc 100644 +--- a/src/lib/krad/internal.h ++++ b/src/lib/krad/internal.h +@@ -43,6 +43,8 @@ + #define UCHAR_MAX 255 + #endif + ++#define MD5_DIGEST_SIZE 16 ++ + /* RFC 2865 */ + #define MAX_ATTRSIZE (UCHAR_MAX - 2) + #define MAX_ATTRSETSIZE (KRAD_PACKET_SIZE_MAX - 20) +@@ -73,10 +75,11 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth, + krad_attr type, const krb5_data *in, + unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen); + +-/* Encode the attributes into the buffer. */ ++/* Encode set into outbuf. If add_msgauth is true, include a zeroed ++ * Message-Authenticator as the first attribute. */ + krb5_error_code + kr_attrset_encode(const krad_attrset *set, const char *secret, +- const unsigned char *auth, ++ const uint8_t *auth, krb5_boolean add_msgauth, + unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen, + krb5_boolean *is_fips); + +diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c +index 2fbf0ee1e0..84b266882d 100644 +--- a/src/lib/krad/packet.c ++++ b/src/lib/krad/packet.c +@@ -36,6 +36,7 @@ + typedef unsigned char uchar; + + /* RFC 2865 */ ++#define MSGAUTH_SIZE (2 + MD5_DIGEST_SIZE) + #define OFFSET_CODE 0 + #define OFFSET_ID 1 + #define OFFSET_LENGTH 2 +@@ -220,6 +221,106 @@ packet_set_attrset(krb5_context ctx, const char *secret, krad_packet *pkt) + return kr_attrset_decode(ctx, &tmp, secret, pkt_auth(pkt), &pkt->attrset); + } + ++/* Determine if a packet requires a Message-Authenticator attribute. */ ++static inline krb5_boolean ++requires_msgauth(const char *secret, krad_code code) ++{ ++ /* If no secret is provided, assume that the transport is a UNIX socket. ++ * Message-Authenticator is required only on UDP and TCP connections. */ ++ if (*secret == '\0') ++ return FALSE; ++ ++ /* ++ * Per draft-ietf-radext-deprecating-radius-03 sections 5.2.1 and 5.2.4, ++ * Message-Authenticator is required in Access-Request packets and all ++ * potential responses when UDP or TCP transport is used. ++ */ ++ return code == krad_code_name2num("Access-Request") || ++ code == krad_code_name2num("Access-Reject") || ++ code == krad_code_name2num("Access-Accept") || ++ code == krad_code_name2num("Access-Challenge"); ++} ++ ++/* Check if the packet has a Message-Authenticator attribute. */ ++static inline krb5_boolean ++has_pkt_msgauth(const krad_packet *pkt) ++{ ++ krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator"); ++ ++ return krad_attrset_get(pkt->attrset, msgauth_type, 0) != NULL; ++} ++ ++/* Return the beginning of the Message-Authenticator attribute in pkt, or NULL ++ * if no such attribute is present. */ ++static const uint8_t * ++lookup_msgauth_addr(const krad_packet *pkt) ++{ ++ krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator"); ++ size_t i; ++ uint8_t *p; ++ ++ i = OFFSET_ATTR; ++ while (i + 2 < pkt->pkt.length) { ++ p = (uint8_t *)offset(&pkt->pkt, i); ++ if (msgauth_type == *p) ++ return p; ++ i += p[1]; ++ } ++ ++ return NULL; ++} ++ ++/* ++ * Calculate the message authenticator MAC for pkt as specified in RFC 2869 ++ * section 5.14, placing the result in mac_out. Use the provided authenticator ++ * auth, which may be from pkt or from a corresponding request. ++ */ ++static krb5_error_code ++calculate_mac(const char *secret, const krad_packet *pkt, ++ const uint8_t auth[AUTH_FIELD_SIZE], ++ uint8_t mac_out[MD5_DIGEST_SIZE]) ++{ ++ uint8_t zeroed_msgauth[MSGAUTH_SIZE]; ++ krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator"); ++ const uint8_t *msgauth_attr, *msgauth_end, *pkt_end; ++ krb5_crypto_iov input[5]; ++ krb5_data ksecr, mac; ++ ++ msgauth_attr = lookup_msgauth_addr(pkt); ++ if (msgauth_attr == NULL) ++ return EINVAL; ++ msgauth_end = msgauth_attr + MSGAUTH_SIZE; ++ pkt_end = (const uint8_t *)pkt->pkt.data + pkt->pkt.length; ++ ++ /* Read code, id, and length from the packet. */ ++ input[0].flags = KRB5_CRYPTO_TYPE_DATA; ++ input[0].data = make_data(pkt->pkt.data, OFFSET_AUTH); ++ ++ /* Read the provided authenticator. */ ++ input[1].flags = KRB5_CRYPTO_TYPE_DATA; ++ input[1].data = make_data((uint8_t *)auth, AUTH_FIELD_SIZE); ++ ++ /* Read any attributes before Message-Authenticator. */ ++ input[2].flags = KRB5_CRYPTO_TYPE_DATA; ++ input[2].data = make_data(pkt_attr(pkt), msgauth_attr - pkt_attr(pkt)); ++ ++ /* Read Message-Authenticator with the data bytes all set to zero, per RFC ++ * 2869 section 5.14. */ ++ zeroed_msgauth[0] = msgauth_type; ++ zeroed_msgauth[1] = MSGAUTH_SIZE; ++ memset(zeroed_msgauth + 2, 0, MD5_DIGEST_SIZE); ++ input[3].flags = KRB5_CRYPTO_TYPE_DATA; ++ input[3].data = make_data(zeroed_msgauth, MSGAUTH_SIZE); ++ ++ /* Read any attributes after Message-Authenticator. */ ++ input[4].flags = KRB5_CRYPTO_TYPE_DATA; ++ input[4].data = make_data((uint8_t *)msgauth_end, pkt_end - msgauth_end); ++ ++ mac = make_data(mac_out, MD5_DIGEST_SIZE); ++ ksecr = string2data((char *)secret); ++ return k5_hmac_md5(&ksecr, input, 5, &mac); ++} ++ + ssize_t + krad_packet_bytes_needed(const krb5_data *buffer) + { +@@ -253,6 +354,7 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code, + krad_packet *pkt; + uchar id; + size_t attrset_len; ++ krb5_boolean msgauth_required; + + pkt = packet_new(); + if (pkt == NULL) { +@@ -272,9 +374,13 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code, + if (retval != 0) + goto error; + ++ /* Determine if Message-Authenticator is required. */ ++ msgauth_required = (*secret != '\0' && ++ code == krad_code_name2num("Access-Request")); ++ + /* Encode the attributes. */ +- retval = kr_attrset_encode(set, secret, pkt_auth(pkt), pkt_attr(pkt), +- &attrset_len, &pkt->is_fips); ++ retval = kr_attrset_encode(set, secret, pkt_auth(pkt), msgauth_required, ++ pkt_attr(pkt), &attrset_len, &pkt->is_fips); + if (retval != 0) + goto error; + +@@ -283,6 +389,13 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code, + pkt_code_set(pkt, code); + pkt_len_set(pkt, pkt->pkt.length); + ++ if (msgauth_required) { ++ /* Calculate and set the Message-Authenticator MAC. */ ++ retval = calculate_mac(secret, pkt, pkt_auth(pkt), pkt_attr(pkt) + 2); ++ if (retval != 0) ++ goto error; ++ } ++ + /* Copy the attrset for future use. */ + retval = packet_set_attrset(ctx, secret, pkt); + if (retval != 0) +@@ -305,14 +418,19 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code, + krb5_error_code retval; + krad_packet *pkt; + size_t attrset_len; ++ krb5_boolean msgauth_required; + + pkt = packet_new(); + if (pkt == NULL) + return ENOMEM; + ++ /* Determine if Message-Authenticator is required. */ ++ msgauth_required = requires_msgauth(secret, code); ++ + /* Encode the attributes. */ +- retval = kr_attrset_encode(set, secret, pkt_auth(request), pkt_attr(pkt), +- &attrset_len, &pkt->is_fips); ++ retval = kr_attrset_encode(set, secret, pkt_auth(request), ++ msgauth_required, pkt_attr(pkt), &attrset_len, ++ &pkt->is_fips); + if (retval != 0) + goto error; + +@@ -328,6 +446,18 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code, + if (retval != 0) + goto error; + ++ if (msgauth_required) { ++ /* ++ * Calculate and replace the Message-Authenticator MAC. Per RFC 2869 ++ * section 5.14, use the authenticator from the request, not from the ++ * response. ++ */ ++ retval = calculate_mac(secret, pkt, pkt_auth(request), ++ pkt_attr(pkt) + 2); ++ if (retval != 0) ++ goto error; ++ } ++ + /* Copy the attrset for future use. */ + retval = packet_set_attrset(ctx, secret, pkt); + if (retval != 0) +@@ -341,6 +471,34 @@ error: + return retval; + } + ++/* Verify the Message-Authenticator value in pkt, using the provided ++ * authenticator (which may be from pkt or from a corresponding request). */ ++static krb5_error_code ++verify_msgauth(const char *secret, const krad_packet *pkt, ++ const uint8_t auth[AUTH_FIELD_SIZE]) ++{ ++ uint8_t mac[MD5_DIGEST_SIZE]; ++ krad_attr msgauth_type = krad_attr_name2num("Message-Authenticator"); ++ const krb5_data *msgauth; ++ krb5_error_code retval; ++ ++ msgauth = krad_packet_get_attr(pkt, msgauth_type, 0); ++ if (msgauth == NULL) ++ return ENODATA; ++ ++ retval = calculate_mac(secret, pkt, auth, mac); ++ if (retval) ++ return retval; ++ ++ if (msgauth->length != MD5_DIGEST_SIZE) ++ return EMSGSIZE; ++ ++ if (k5_bcmp(mac, msgauth->data, MD5_DIGEST_SIZE) != 0) ++ return EBADMSG; ++ ++ return 0; ++} ++ + /* Decode a packet. */ + static krb5_error_code + decode_packet(krb5_context ctx, const char *secret, const krb5_data *buffer, +@@ -392,21 +550,35 @@ krad_packet_decode_request(krb5_context ctx, const char *secret, + krad_packet **reqpkt) + { + const krad_packet *tmp = NULL; ++ krad_packet *req; + krb5_error_code retval; + +- retval = decode_packet(ctx, secret, buffer, reqpkt); +- if (cb != NULL && retval == 0) { ++ retval = decode_packet(ctx, secret, buffer, &req); ++ if (retval) ++ return retval; ++ ++ /* Verify Message-Authenticator if present. */ ++ if (has_pkt_msgauth(req)) { ++ retval = verify_msgauth(secret, req, pkt_auth(req)); ++ if (retval) { ++ krad_packet_free(req); ++ return retval; ++ } ++ } ++ ++ if (cb != NULL) { + for (tmp = (*cb)(data, FALSE); tmp != NULL; tmp = (*cb)(data, FALSE)) { + if (pkt_id_get(*reqpkt) == pkt_id_get(tmp)) + break; + } +- } + +- if (cb != NULL && (retval != 0 || tmp != NULL)) +- (*cb)(data, TRUE); ++ if (tmp != NULL) ++ (*cb)(data, TRUE); ++ } + ++ *reqpkt = req; + *duppkt = tmp; +- return retval; ++ return 0; + } + + krb5_error_code +@@ -433,9 +605,17 @@ krad_packet_decode_response(krb5_context ctx, const char *secret, + break; + } + +- /* If the authenticator matches, then the response is valid. */ +- if (memcmp(pkt_auth(*rsppkt), auth, sizeof(auth)) == 0) +- break; ++ /* Verify the response authenticator. */ ++ if (k5_bcmp(pkt_auth(*rsppkt), auth, sizeof(auth)) != 0) ++ continue; ++ ++ /* Verify Message-Authenticator if present. */ ++ if (has_pkt_msgauth(*rsppkt)) { ++ if (verify_msgauth(secret, *rsppkt, pkt_auth(tmp)) != 0) ++ continue; ++ } ++ ++ break; + } + } + +diff --git a/src/lib/krad/t_attrset.c b/src/lib/krad/t_attrset.c +index 0f95762534..9a70529dc5 100644 +--- a/src/lib/krad/t_attrset.c ++++ b/src/lib/krad/t_attrset.c +@@ -63,7 +63,7 @@ main() + noerror(krad_attrset_add(set, krad_attr_name2num("User-Password"), &tmp)); + + /* Encode attrset. */ +- noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len, ++ noerror(kr_attrset_encode(set, "foo", auth, FALSE, buffer, &encode_len, + &is_fips)); + krad_attrset_free(set); + +diff --git a/src/lib/krad/t_daemon.py b/src/lib/krad/t_daemon.py +index dcda0050b0..0c178fa92c 100755 +--- a/src/lib/krad/t_daemon.py ++++ b/src/lib/krad/t_daemon.py +@@ -42,6 +42,7 @@ DICTIONARY = """ + ATTRIBUTE\tUser-Name\t1\tstring + ATTRIBUTE\tUser-Password\t2\toctets + ATTRIBUTE\tNAS-Identifier\t32\tstring ++ATTRIBUTE\tMessage-Authenticator\t80\toctets + """ + + class TestServer(server.Server): +@@ -54,7 +55,7 @@ class TestServer(server.Server): + if key == "User-Password": + passwd = map(pkt.PwDecrypt, pkt[key]) + +- reply = self.CreateReplyPacket(pkt) ++ reply = self.CreateReplyPacket(pkt, message_authenticator=True) + if passwd == ['accept']: + reply.code = packet.AccessAccept + else: +diff --git a/src/lib/krad/t_packet.c b/src/lib/krad/t_packet.c +index 0a92e9cc2b..745fb211f1 100644 +--- a/src/lib/krad/t_packet.c ++++ b/src/lib/krad/t_packet.c +@@ -159,6 +159,9 @@ main(int argc, const char **argv) + krb5_data username, password; + krb5_boolean auth = FALSE; + krb5_context ctx; ++ const krad_packet *dupreq; ++ const krb5_data *encpkt; ++ krad_packet *decreq; + + username = string2data("testUser"); + +@@ -171,9 +174,17 @@ main(int argc, const char **argv) + + password = string2data("accept"); + noerror(make_packet(ctx, &username, &password, &packets[ACCEPT_PACKET])); ++ encpkt = krad_packet_encode(packets[ACCEPT_PACKET]); ++ noerror(krad_packet_decode_request(ctx, "foo", encpkt, NULL, NULL, ++ &dupreq, &decreq)); ++ krad_packet_free(decreq); + + password = string2data("reject"); + noerror(make_packet(ctx, &username, &password, &packets[REJECT_PACKET])); ++ encpkt = krad_packet_encode(packets[REJECT_PACKET]); ++ noerror(krad_packet_decode_request(ctx, "foo", encpkt, NULL, NULL, ++ &dupreq, &decreq)); ++ krad_packet_free(decreq); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; +diff --git a/src/tests/t_otp.py b/src/tests/t_otp.py +index f098374f9e..82cdba50eb 100755 +--- a/src/tests/t_otp.py ++++ b/src/tests/t_otp.py +@@ -50,6 +50,7 @@ radius_attributes = ''' + ATTRIBUTE User-Name 1 string + ATTRIBUTE User-Password 2 octets + ATTRIBUTE NAS-Identifier 32 string ++ATTRIBUTE Message-Authenticator 80 octets + ''' + + class RadiusDaemon(Process): +@@ -96,6 +97,8 @@ class RadiusDaemon(Process): + reply.code = packet.AccessReject + replyq['reply'] = False + ++ reply.add_message_authenticator() ++ + outq.put(replyq) + if addr is None: + sock.send(reply.ReplyPacket()) +-- +2.46.0 + diff --git a/Remove-PKINIT-RSA-support.patch b/Remove-PKINIT-RSA-support.patch new file mode 100644 index 0000000000000000000000000000000000000000..2dbb2d51d99ece48b9908b5e0983b1afe9fab349 --- /dev/null +++ b/Remove-PKINIT-RSA-support.patch @@ -0,0 +1,1536 @@ +From d7cf00207500da291b74746ba6050779ba0d3b7c Mon Sep 17 00:00:00 2024 +From: zhuhongbo +Date: Tue, 19 Nov 2024 17:15:06 +Subject: [PATCH] Remove PKINIT RSA support + +--- + doc/user/user_commands/kinit.rst | 4 - + src/plugins/preauth/pkinit/pkinit.h | 2 - + src/plugins/preauth/pkinit/pkinit_clnt.c | 257 +++----- + src/plugins/preauth/pkinit/pkinit_crypto.h | 42 -- + .../preauth/pkinit/pkinit_crypto_openssl.c | 566 ------------------ + src/plugins/preauth/pkinit/pkinit_lib.c | 2 - + src/plugins/preauth/pkinit/pkinit_srv.c | 332 +++------- + src/plugins/preauth/pkinit/pkinit_trace.h | 9 - + src/tests/t_pkinit.py | 6 - + src/windows/leash/htmlhelp/html/KINIT.htm | 3 - + 10 files changed, 164 insertions(+), 1059 deletions(-) + +diff --git a/doc/user/user_commands/kinit.rst b/doc/user/user_commands/kinit.rst +index 33e6aa64ff..b015ee10eb 100644 +--- a/doc/user/user_commands/kinit.rst ++++ b/doc/user/user_commands/kinit.rst +@@ -193,10 +193,6 @@ OPTIONS + **X509_anchors**\ =\ *value* + specify where to find trusted X509 anchor information + +- **flag_RSA_PROTOCOL**\ [**=yes**] +- specify use of RSA, rather than the default Diffie-Hellman +- protocol +- + ENVIRONMENT + ----------- + +diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h +index 430b3f334d..558f75b8d7 100644 +--- a/src/plugins/preauth/pkinit/pkinit.h ++++ b/src/plugins/preauth/pkinit/pkinit.h +@@ -146,7 +146,6 @@ typedef struct _pkinit_plg_opts { + int require_eku; /* require EKU checking (default is true) */ + int accept_secondary_eku;/* accept secondary EKU (default is false) */ + int allow_upn; /* allow UPN-SAN instead of pkinit-SAN */ +- int dh_or_rsa; /* selects DH or RSA based pkinit */ + int require_crl_checking; /* require CRL for a CA (default is false) */ + int dh_min_bits; /* minimum DH modulus size allowed */ + } pkinit_plg_opts; +@@ -158,7 +157,6 @@ typedef struct _pkinit_req_opts { + int require_eku; + int accept_secondary_eku; + int allow_upn; +- int dh_or_rsa; + int require_crl_checking; + int dh_size; /* initial request DH modulus size (default=1024) */ + int require_hostname_match; +diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c +index e73ad53e99..40f930f537 100644 +--- a/src/plugins/preauth/pkinit/pkinit_clnt.c ++++ b/src/plugins/preauth/pkinit/pkinit_clnt.c +@@ -208,7 +208,6 @@ pkinit_as_req_create(krb5_context context, + krb5_auth_pack_draft9 auth_pack9; + krb5_pa_pk_as_req_draft9 *req9 = NULL; + krb5_algorithm_identifier **cmstypes = NULL; +- int protocol = reqctx->opts->dh_or_rsa; + unsigned char *dh_params = NULL, *dh_pubkey = NULL; + unsigned int dh_params_len, dh_pubkey_len; + +@@ -217,7 +216,6 @@ pkinit_as_req_create(krb5_context context, + /* Create the authpack */ + switch((int)reqctx->pa_type) { + case KRB5_PADATA_PK_AS_REQ_OLD: +- protocol = RSA_PROTOCOL; + memset(&auth_pack9, 0, sizeof(auth_pack9)); + auth_pack9.pkAuthenticator.ctime = ctsec; + auth_pack9.pkAuthenticator.cusec = cusec; +@@ -250,42 +248,19 @@ pkinit_as_req_create(krb5_context context, + goto cleanup; + } + +- switch(protocol) { +- case DH_PROTOCOL: +- TRACE_PKINIT_CLIENT_REQ_DH(context); +- pkiDebug("as_req: DH key transport algorithm\n"); +- info.algorithm.algorithm = dh_oid; +- +- /* create client-side DH keys */ +- retval = client_create_dh(context, plgctx->cryptoctx, +- reqctx->cryptoctx, reqctx->idctx, +- reqctx->opts->dh_size, &dh_params, +- &dh_params_len, &dh_pubkey, &dh_pubkey_len); +- if (retval != 0) { +- pkiDebug("failed to create dh parameters\n"); +- goto cleanup; +- } +- info.algorithm.parameters = make_data(dh_params, dh_params_len); +- info.subjectPublicKey = make_data(dh_pubkey, dh_pubkey_len); +- break; +- case RSA_PROTOCOL: +- TRACE_PKINIT_CLIENT_REQ_RSA(context); +- pkiDebug("as_req: RSA key transport algorithm\n"); +- switch((int)reqctx->pa_type) { +- case KRB5_PADATA_PK_AS_REQ_OLD: +- auth_pack9.clientPublicValue = NULL; +- break; +- case KRB5_PADATA_PK_AS_REQ: +- auth_pack.clientPublicValue = NULL; +- break; +- } +- break; +- default: +- pkiDebug("as_req: unknown key transport protocol %d\n", +- protocol); +- retval = -1; ++ TRACE_PKINIT_CLIENT_REQ_DH(context); ++ info.algorithm.algorithm = dh_oid; ++ ++ /* create client-side DH keys */ ++ retval = client_create_dh(context, plgctx->cryptoctx, reqctx->cryptoctx, ++ reqctx->idctx, reqctx->opts->dh_size, &dh_params, ++ &dh_params_len, &dh_pubkey, &dh_pubkey_len); ++ if (retval != 0) { ++ pkiDebug("failed to create dh parameters\n"); + goto cleanup; + } ++ info.algorithm.parameters = make_data(dh_params, dh_params_len); ++ info.subjectPublicKey = make_data(dh_pubkey, dh_pubkey_len); + + /* Encode the authpack */ + switch((int)reqctx->pa_type) { +@@ -662,49 +637,33 @@ pkinit_as_rep_parse(krb5_context context, + return retval; + } + +- switch(kdc_reply->choice) { +- case choice_pa_pk_as_rep_dhInfo: +- pkiDebug("as_rep: DH key transport algorithm\n"); ++ if (kdc_reply->choice != choice_pa_pk_as_rep_dhInfo) { ++ pkiDebug("unknown as_rep type %d\n", kdc_reply->choice); ++ retval = KRB5KDC_ERR_PREAUTH_FAILED; ++ goto cleanup; ++ } ++ + #ifdef DEBUG_ASN1 +- print_buffer_bin(kdc_reply->u.dh_Info.dhSignedData.data, +- kdc_reply->u.dh_Info.dhSignedData.length, "/tmp/client_kdc_signeddata"); ++ print_buffer_bin(kdc_reply->u.dh_Info.dhSignedData.data, ++ kdc_reply->u.dh_Info.dhSignedData.length, ++ "/tmp/client_kdc_signeddata"); + #endif +- if ((retval = cms_signeddata_verify(context, plgctx->cryptoctx, +- reqctx->cryptoctx, reqctx->idctx, CMS_SIGN_SERVER, +- reqctx->opts->require_crl_checking, +- (unsigned char *) +- kdc_reply->u.dh_Info.dhSignedData.data, +- kdc_reply->u.dh_Info.dhSignedData.length, +- (unsigned char **)&dh_data.data, +- &dh_data.length, +- NULL, NULL, NULL)) != 0) { +- pkiDebug("failed to verify pkcs7 signed data\n"); +- TRACE_PKINIT_CLIENT_REP_DH_FAIL(context); +- goto cleanup; +- } +- TRACE_PKINIT_CLIENT_REP_DH(context); +- break; +- case choice_pa_pk_as_rep_encKeyPack: +- pkiDebug("as_rep: RSA key transport algorithm\n"); +- if ((retval = cms_envelopeddata_verify(context, plgctx->cryptoctx, +- reqctx->cryptoctx, reqctx->idctx, pa_type, +- reqctx->opts->require_crl_checking, +- (unsigned char *) +- kdc_reply->u.encKeyPack.data, +- kdc_reply->u.encKeyPack.length, +- (unsigned char **)&dh_data.data, +- &dh_data.length)) != 0) { +- pkiDebug("failed to verify pkcs7 enveloped data\n"); +- TRACE_PKINIT_CLIENT_REP_RSA_FAIL(context); +- goto cleanup; +- } +- TRACE_PKINIT_CLIENT_REP_RSA(context); +- break; +- default: +- pkiDebug("unknown as_rep type %d\n", kdc_reply->choice); +- retval = -1; ++ if ((retval = cms_signeddata_verify(context, plgctx->cryptoctx, ++ reqctx->cryptoctx, reqctx->idctx, ++ CMS_SIGN_SERVER, ++ reqctx->opts->require_crl_checking, ++ (unsigned char *) ++ kdc_reply->u.dh_Info.dhSignedData.data, ++ kdc_reply->u.dh_Info.dhSignedData.length, ++ (unsigned char **)&dh_data.data, ++ &dh_data.length, ++ NULL, NULL, NULL)) != 0) { ++ pkiDebug("failed to verify pkcs7 signed data\n"); ++ TRACE_PKINIT_CLIENT_REP_DH_FAIL(context); + goto cleanup; + } ++ TRACE_PKINIT_CLIENT_REP_DH(context); ++ + retval = krb5_build_principal_ext(context, &kdc_princ, + request->server->realm.length, + request->server->realm.data, +@@ -741,123 +700,55 @@ pkinit_as_rep_parse(krb5_context context, + + OCTETDATA_TO_KRB5DATA(&dh_data, &k5data); + +- switch(kdc_reply->choice) { +- case choice_pa_pk_as_rep_dhInfo: + #ifdef DEBUG_ASN1 +- print_buffer_bin(dh_data.data, dh_data.length, +- "/tmp/client_dh_key"); ++ print_buffer_bin(dh_data.data, dh_data.length, "/tmp/client_dh_key"); + #endif +- if ((retval = k5int_decode_krb5_kdc_dh_key_info(&k5data, +- &kdc_dh)) != 0) { +- pkiDebug("failed to decode kdc_dh_key_info\n"); +- goto cleanup; +- } +- +- /* client after KDC reply */ +- if ((retval = client_process_dh(context, plgctx->cryptoctx, +- reqctx->cryptoctx, reqctx->idctx, +- (unsigned char *) +- kdc_dh->subjectPublicKey.data, +- kdc_dh->subjectPublicKey.length, +- &client_key, &client_key_len)) != 0) { +- pkiDebug("failed to process dh params\n"); +- goto cleanup; +- } ++ if ((retval = k5int_decode_krb5_kdc_dh_key_info(&k5data, &kdc_dh)) != 0) { ++ pkiDebug("failed to decode kdc_dh_key_info\n"); ++ goto cleanup; ++ } + +- /* If we have a KDF algorithm ID, call the algorithm agility KDF... */ +- if (kdc_reply->u.dh_Info.kdfID) { +- secret.length = client_key_len; +- secret.data = (char *)client_key; ++ /* client after KDC reply */ ++ if ((retval = client_process_dh(context, plgctx->cryptoctx, ++ reqctx->cryptoctx, reqctx->idctx, ++ (unsigned char *) ++ kdc_dh->subjectPublicKey.data, ++ kdc_dh->subjectPublicKey.length, ++ &client_key, &client_key_len)) != 0) { ++ pkiDebug("failed to process dh params\n"); ++ goto cleanup; ++ } + +- retval = pkinit_alg_agility_kdf(context, &secret, +- kdc_reply->u.dh_Info.kdfID, +- request->client, request->server, +- etype, encoded_request, +- (krb5_data *)as_rep, key_block); ++ /* If we have a KDF algorithm ID, call the algorithm agility KDF... */ ++ if (kdc_reply->u.dh_Info.kdfID) { ++ secret.length = client_key_len; ++ secret.data = (char *)client_key; + +- if (retval) { +- pkiDebug("failed to create key pkinit_alg_agility_kdf %s\n", +- error_message(retval)); +- goto cleanup; +- } +- TRACE_PKINIT_CLIENT_KDF_ALG(context, kdc_reply->u.dh_Info.kdfID, +- key_block); +- +- /* ...otherwise, use the older octetstring2key function. */ +- } else { ++ retval = pkinit_alg_agility_kdf(context, &secret, ++ kdc_reply->u.dh_Info.kdfID, ++ request->client, request->server, ++ etype, encoded_request, ++ (krb5_data *)as_rep, key_block); + +- retval = pkinit_octetstring2key(context, etype, client_key, +- client_key_len, key_block); +- if (retval) { +- pkiDebug("failed to create key pkinit_octetstring2key %s\n", +- error_message(retval)); +- goto cleanup; +- } +- TRACE_PKINIT_CLIENT_KDF_OS2K(context, key_block); +- } +- +- break; +- case choice_pa_pk_as_rep_encKeyPack: +-#ifdef DEBUG_ASN1 +- print_buffer_bin(dh_data.data, dh_data.length, +- "/tmp/client_key_pack"); +-#endif +- retval = k5int_decode_krb5_reply_key_pack(&k5data, &key_pack); + if (retval) { +- pkiDebug("failed to decode reply_key_pack\n"); ++ pkiDebug("failed to create key pkinit_alg_agility_kdf %s\n", ++ error_message(retval)); + goto cleanup; + } +- /* +- * This is hack but Windows sends back SHA1 checksum +- * with checksum type of 14. There is currently no +- * checksum type of 14 defined. +- */ +- if (key_pack->asChecksum.checksum_type == 14) +- key_pack->asChecksum.checksum_type = CKSUMTYPE_NIST_SHA; +- retval = krb5_c_make_checksum(context, +- key_pack->asChecksum.checksum_type, +- &key_pack->replyKey, +- KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM, +- encoded_request, &cksum); ++ TRACE_PKINIT_CLIENT_KDF_ALG(context, kdc_reply->u.dh_Info.kdfID, ++ key_block); ++ ++ /* ...otherwise, use the older octetstring2key function. */ ++ } else { ++ ++ retval = pkinit_octetstring2key(context, etype, client_key, ++ client_key_len, key_block); + if (retval) { +- pkiDebug("failed to make a checksum\n"); ++ pkiDebug("failed to create key pkinit_octetstring2key %s\n", ++ error_message(retval)); + goto cleanup; + } +- +- if ((cksum.length != key_pack->asChecksum.length) || +- k5_bcmp(cksum.contents, key_pack->asChecksum.contents, +- cksum.length) != 0) { +- TRACE_PKINIT_CLIENT_REP_CHECKSUM_FAIL(context, &cksum, +- &key_pack->asChecksum); +- pkiDebug("failed to match the checksums\n"); +-#ifdef DEBUG_CKSUM +- pkiDebug("calculating checksum on buf size (%d)\n", +- encoded_request->length); +- print_buffer(encoded_request->data, encoded_request->length); +- pkiDebug("encrypting key (%d)\n", key_pack->replyKey.length); +- print_buffer(key_pack->replyKey.contents, +- key_pack->replyKey.length); +- pkiDebug("received checksum type=%d size=%d ", +- key_pack->asChecksum.checksum_type, +- key_pack->asChecksum.length); +- print_buffer(key_pack->asChecksum.contents, +- key_pack->asChecksum.length); +- pkiDebug("expected checksum type=%d size=%d ", +- cksum.checksum_type, cksum.length); +- print_buffer(cksum.contents, cksum.length); +-#endif +- goto cleanup; +- } else +- pkiDebug("checksums match\n"); +- +- krb5_copy_keyblock_contents(context, &key_pack->replyKey, +- key_block); +- TRACE_PKINIT_CLIENT_REP_RSA_KEY(context, key_block, &cksum); +- +- break; +- default: +- pkiDebug("unknow as_rep type %d\n", kdc_reply->choice); +- goto cleanup; ++ TRACE_PKINIT_CLIENT_KDF_OS2K(context, key_block); + } + + retval = 0; +@@ -1400,7 +1291,6 @@ pkinit_client_req_init(krb5_context context, + + reqctx->opts->require_eku = plgctx->opts->require_eku; + reqctx->opts->accept_secondary_eku = plgctx->opts->accept_secondary_eku; +- reqctx->opts->dh_or_rsa = plgctx->opts->dh_or_rsa; + reqctx->opts->allow_upn = plgctx->opts->allow_upn; + reqctx->opts->require_crl_checking = plgctx->opts->require_crl_checking; + +@@ -1568,11 +1458,6 @@ handle_gic_opt(krb5_context context, + retval = add_string_to_array(context, &plgctx->idopts->anchors, value); + if (retval) + return retval; +- } else if (strcmp(attr, "flag_RSA_PROTOCOL") == 0) { +- if (strcmp(value, "yes") == 0) { +- pkiDebug("Setting flag to use RSA_PROTOCOL\n"); +- plgctx->opts->dh_or_rsa = RSA_PROTOCOL; +- } + } + return 0; + } +diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h +index 149923b1d8..b989f61d7e 100644 +--- a/src/plugins/preauth/pkinit/pkinit_crypto.h ++++ b/src/plugins/preauth/pkinit/pkinit_crypto.h +@@ -187,48 +187,6 @@ krb5_error_code cms_signeddata_verify + int *is_signed); /* OUT + receives whether message is signed */ + +-/* +- * this function creates a CMS message where eContentType is EnvelopedData +- */ +-krb5_error_code cms_envelopeddata_create +- (krb5_context context, /* IN */ +- pkinit_plg_crypto_context plg_cryptoctx, /* IN */ +- pkinit_req_crypto_context req_cryptoctx, /* IN */ +- pkinit_identity_crypto_context id_cryptoctx, /* IN */ +- krb5_preauthtype pa_type, /* IN */ +- int include_certchain, /* IN +- specifies whether the certificates field in +- SignedData should contain certificate path */ +- unsigned char *key_pack, /* IN +- contains DER encoded ReplyKeyPack */ +- unsigned int key_pack_len, /* IN +- contains length of key_pack */ +- unsigned char **envel_data, /* OUT +- receives DER encoded encKeyPack */ +- unsigned int *envel_data_len); /* OUT +- receives length of envel_data */ +- +-/* +- * this function creates a CMS message where eContentType is EnvelopedData +- */ +-krb5_error_code cms_envelopeddata_verify +- (krb5_context context, /* IN */ +- pkinit_plg_crypto_context plg_cryptoctx, /* IN */ +- pkinit_req_crypto_context req_cryptoctx, /* IN */ +- pkinit_identity_crypto_context id_cryptoctx, /* IN */ +- krb5_preauthtype pa_type, /* IN */ +- int require_crl_checking, /* IN +- specifies whether CRL checking should be +- strictly enforced */ +- unsigned char *envel_data, /* IN +- contains DER encoded encKeyPack */ +- unsigned int envel_data_len, /* IN +- contains length of envel_data */ +- unsigned char **signed_data, /* OUT +- receives ReplyKeyPack */ +- unsigned int *signed_data_len); /* OUT +- receives length of signed_data */ +- + /* + * This function retrieves the signer's identity, in a form that could + * be passed back in to a future invocation of this module as a candidate +diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +index 9ba3ea89c1..ce41f6d86d 100644 +--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c ++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +@@ -63,30 +63,14 @@ static krb5_error_code create_signature + (unsigned char **, unsigned int *, unsigned char *, unsigned int, + EVP_PKEY *pkey); + +-static krb5_error_code pkinit_decode_data +-(krb5_context context, pkinit_identity_crypto_context cryptoctx, +- const uint8_t *data, unsigned int data_len, uint8_t **decoded, +- unsigned int *decoded_len); +- +-static krb5_error_code decode_data +-(uint8_t **, unsigned int *, const uint8_t *, unsigned int, EVP_PKEY *pkey, +- X509 *cert); +- + #ifdef DEBUG_DH + static void print_dh(DH *, char *); + static void print_pubkey(BIGNUM *, char *); + #endif + +-static int prepare_enc_data +-(const uint8_t *indata, int indata_len, uint8_t **outdata, int *outdata_len); +- + static int openssl_callback (int, X509_STORE_CTX *); + static int openssl_callback_ignore_crls (int, X509_STORE_CTX *); + +-static int pkcs7_decrypt +-(krb5_context context, pkinit_identity_crypto_context id_cryptoctx, PKCS7 *p7, +- unsigned char **data_out, unsigned int *len_out); +- + static ASN1_OBJECT * pkinit_pkcs7type2oid + (pkinit_plg_crypto_context plg_cryptoctx, int pkcs7_type); + +@@ -107,31 +91,17 @@ static krb5_error_code pkinit_open_session + (krb5_context context, pkinit_identity_crypto_context id_cryptoctx); + static void * pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p); + static CK_RV pkinit_C_UnloadModule(void *handle); +-#ifdef SILLYDECRYPT +-CK_RV pkinit_C_Decrypt +-(pkinit_identity_crypto_context id_cryptoctx, +- CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, +- CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen); +-#endif + + static krb5_error_code pkinit_sign_data_pkcs11 + (krb5_context context, pkinit_identity_crypto_context id_cryptoctx, + unsigned char *data, unsigned int data_len, + unsigned char **sig, unsigned int *sig_len); +-static krb5_error_code pkinit_decode_data_pkcs11 +-(krb5_context context, pkinit_identity_crypto_context id_cryptoctx, +- const uint8_t *data, unsigned int data_len, uint8_t **decoded_data, +- unsigned int *decoded_data_len); + #endif /* WITHOUT_PKCS11 */ + + static krb5_error_code pkinit_sign_data_fs + (krb5_context context, pkinit_identity_crypto_context id_cryptoctx, + unsigned char *data, unsigned int data_len, + unsigned char **sig, unsigned int *sig_len); +-static krb5_error_code pkinit_decode_data_fs +-(krb5_context context, pkinit_identity_crypto_context id_cryptoctx, +- const uint8_t *data, unsigned int data_len, uint8_t **decoded_data, +- unsigned int *decoded_data_len); + + static krb5_error_code + create_krb5_invalidCertificates(krb5_context context, +@@ -143,9 +113,6 @@ create_krb5_invalidCertificates(krb5_context context, + static krb5_error_code + create_identifiers_from_stack(STACK_OF(X509) *sk, + krb5_external_principal_identifier *** ids); +-static int +-wrap_signeddata(unsigned char *data, unsigned int data_len, +- unsigned char **out, unsigned int *out_len); + + static char * + pkinit_pkcs11_code_to_text(int err); +@@ -1835,243 +1802,6 @@ cleanup: + return retval; + } + +-krb5_error_code +-cms_envelopeddata_create(krb5_context context, +- pkinit_plg_crypto_context plgctx, +- pkinit_req_crypto_context reqctx, +- pkinit_identity_crypto_context idctx, +- krb5_preauthtype pa_type, +- int include_certchain, +- unsigned char *key_pack, +- unsigned int key_pack_len, +- unsigned char **out, +- unsigned int *out_len) +-{ +- +- krb5_error_code retval = ENOMEM; +- PKCS7 *p7 = NULL; +- BIO *in = NULL; +- unsigned char *p = NULL, *signed_data = NULL, *enc_data = NULL; +- int signed_data_len = 0, enc_data_len = 0, flags = PKCS7_BINARY; +- STACK_OF(X509) *encerts = NULL; +- const EVP_CIPHER *cipher = NULL; +- int cms_msg_type; +- +- /* create the PKCS7 SignedData portion of the PKCS7 EnvelopedData */ +- switch ((int)pa_type) { +- case KRB5_PADATA_PK_AS_REQ_OLD: +- case KRB5_PADATA_PK_AS_REP_OLD: +- cms_msg_type = CMS_SIGN_DRAFT9; +- break; +- case KRB5_PADATA_PK_AS_REQ: +- cms_msg_type = CMS_ENVEL_SERVER; +- break; +- default: +- goto cleanup; +- } +- +- retval = cms_signeddata_create(context, plgctx, reqctx, idctx, +- cms_msg_type, include_certchain, key_pack, key_pack_len, +- &signed_data, (unsigned int *)&signed_data_len); +- if (retval) { +- pkiDebug("failed to create pkcs7 signed data\n"); +- goto cleanup; +- } +- +- /* check we have client's certificate */ +- if (reqctx->received_cert == NULL) { +- retval = KRB5KDC_ERR_PREAUTH_FAILED; +- goto cleanup; +- } +- encerts = sk_X509_new_null(); +- sk_X509_push(encerts, reqctx->received_cert); +- +- cipher = EVP_des_ede3_cbc(); +- in = BIO_new(BIO_s_mem()); +- switch (pa_type) { +- case KRB5_PADATA_PK_AS_REQ: +- prepare_enc_data(signed_data, signed_data_len, &enc_data, +- &enc_data_len); +- retval = BIO_write(in, enc_data, enc_data_len); +- if (retval != enc_data_len) { +- pkiDebug("BIO_write only wrote %d\n", retval); +- goto cleanup; +- } +- break; +- case KRB5_PADATA_PK_AS_REP_OLD: +- case KRB5_PADATA_PK_AS_REQ_OLD: +- retval = BIO_write(in, signed_data, signed_data_len); +- if (retval != signed_data_len) { +- pkiDebug("BIO_write only wrote %d\n", retval); +- goto cleanup; +- } +- break; +- default: +- retval = -1; +- goto cleanup; +- } +- +- p7 = PKCS7_encrypt(encerts, in, cipher, flags); +- if (p7 == NULL) { +- retval = oerr(context, 0, _("Failed to encrypt PKCS7 object")); +- goto cleanup; +- } +- switch (pa_type) { +- case KRB5_PADATA_PK_AS_REQ: +- p7->d.enveloped->enc_data->content_type = +- OBJ_nid2obj(NID_pkcs7_signed); +- break; +- case KRB5_PADATA_PK_AS_REP_OLD: +- case KRB5_PADATA_PK_AS_REQ_OLD: +- p7->d.enveloped->enc_data->content_type = +- OBJ_nid2obj(NID_pkcs7_data); +- break; +- break; +- break; +- break; +- } +- +- *out_len = i2d_PKCS7(p7, NULL); +- if (!*out_len || (p = *out = malloc(*out_len)) == NULL) { +- retval = ENOMEM; +- goto cleanup; +- } +- retval = i2d_PKCS7(p7, &p); +- if (!retval) { +- retval = oerr(context, 0, _("Failed to DER encode PKCS7")); +- goto cleanup; +- } +- retval = 0; +- +-#ifdef DEBUG_ASN1 +- print_buffer_bin(*out, *out_len, "/tmp/kdc_enveloped_data"); +-#endif +- +-cleanup: +- if (p7 != NULL) +- PKCS7_free(p7); +- if (in != NULL) +- BIO_free(in); +- free(signed_data); +- free(enc_data); +- if (encerts != NULL) +- sk_X509_free(encerts); +- +- return retval; +-} +- +-krb5_error_code +-cms_envelopeddata_verify(krb5_context context, +- pkinit_plg_crypto_context plg_cryptoctx, +- pkinit_req_crypto_context req_cryptoctx, +- pkinit_identity_crypto_context id_cryptoctx, +- krb5_preauthtype pa_type, +- int require_crl_checking, +- unsigned char *enveloped_data, +- unsigned int enveloped_data_len, +- unsigned char **data, +- unsigned int *data_len) +-{ +- krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED; +- PKCS7 *p7 = NULL; +- const unsigned char *p = enveloped_data; +- unsigned int tmp_buf_len = 0, tmp_buf2_len = 0, vfy_buf_len = 0; +- unsigned char *tmp_buf = NULL, *tmp_buf2 = NULL, *vfy_buf = NULL; +- int msg_type = 0; +- +-#ifdef DEBUG_ASN1 +- print_buffer_bin(enveloped_data, enveloped_data_len, +- "/tmp/client_envelopeddata"); +-#endif +- /* decode received PKCS7 message */ +- if ((p7 = d2i_PKCS7(NULL, &p, (int)enveloped_data_len)) == NULL) { +- retval = oerr(context, 0, _("Failed to decode PKCS7")); +- goto cleanup; +- } +- +- /* verify that the received message is PKCS7 EnvelopedData message */ +- if (OBJ_obj2nid(p7->type) != NID_pkcs7_enveloped) { +- pkiDebug("Expected id-enveloped PKCS7 msg (received type = %d)\n", +- OBJ_obj2nid(p7->type)); +- krb5_set_error_message(context, retval, "wrong oid\n"); +- goto cleanup; +- } +- +- /* decrypt received PKCS7 message */ +- if (pkcs7_decrypt(context, id_cryptoctx, p7, &tmp_buf, &tmp_buf_len)) { +- pkiDebug("PKCS7 decryption successful\n"); +- } else { +- retval = oerr(context, 0, _("Failed to decrypt PKCS7 message")); +- goto cleanup; +- } +- +-#ifdef DEBUG_ASN1 +- print_buffer_bin(tmp_buf, tmp_buf_len, "/tmp/client_enc_keypack"); +-#endif +- /* verify PKCS7 SignedData message */ +- switch (pa_type) { +- case KRB5_PADATA_PK_AS_REP: +- msg_type = CMS_ENVEL_SERVER; +- +- break; +- case KRB5_PADATA_PK_AS_REP_OLD: +- msg_type = CMS_SIGN_DRAFT9; +- break; +- default: +- pkiDebug("%s: unrecognized pa_type = %d\n", __FUNCTION__, pa_type); +- retval = KRB5KDC_ERR_PREAUTH_FAILED; +- goto cleanup; +- } +- /* +- * If this is the RFC style, wrap the signed data to make +- * decoding easier in the verify routine. +- * For draft9-compatible, we don't do anything because it +- * is already wrapped. +- */ +- if (msg_type == CMS_ENVEL_SERVER) { +- retval = wrap_signeddata(tmp_buf, tmp_buf_len, +- &tmp_buf2, &tmp_buf2_len); +- if (retval) { +- pkiDebug("failed to encode signeddata\n"); +- goto cleanup; +- } +- vfy_buf = tmp_buf2; +- vfy_buf_len = tmp_buf2_len; +- +- } else { +- vfy_buf = tmp_buf; +- vfy_buf_len = tmp_buf_len; +- } +- +-#ifdef DEBUG_ASN1 +- print_buffer_bin(vfy_buf, vfy_buf_len, "/tmp/client_enc_keypack2"); +-#endif +- +- retval = cms_signeddata_verify(context, plg_cryptoctx, req_cryptoctx, +- id_cryptoctx, msg_type, +- require_crl_checking, +- vfy_buf, vfy_buf_len, +- data, data_len, NULL, NULL, NULL); +- +- if (!retval) +- pkiDebug("PKCS7 Verification Success\n"); +- else { +- pkiDebug("PKCS7 Verification Failure\n"); +- goto cleanup; +- } +- +- retval = 0; +- +-cleanup: +- +- if (p7 != NULL) +- PKCS7_free(p7); +- free(tmp_buf); +- free(tmp_buf2); +- +- return retval; +-} +- + static krb5_error_code + crypto_retrieve_X509_sans(krb5_context context, + pkinit_plg_crypto_context plgctx, +@@ -3591,70 +3321,6 @@ pkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx, int pkcs7_type) + + } + +-static int +-wrap_signeddata(unsigned char *data, unsigned int data_len, +- unsigned char **out, unsigned int *out_len) +-{ +- +- unsigned int orig_len = 0, oid_len = 0, tot_len = 0; +- ASN1_OBJECT *oid = NULL; +- unsigned char *p = NULL; +- +- /* Get length to wrap the original data with SEQUENCE tag */ +- tot_len = orig_len = ASN1_object_size(1, (int)data_len, V_ASN1_SEQUENCE); +- +- /* Add the signedData OID and adjust lengths */ +- oid = OBJ_nid2obj(NID_pkcs7_signed); +- oid_len = i2d_ASN1_OBJECT(oid, NULL); +- +- tot_len = ASN1_object_size(1, (int)(orig_len+oid_len), V_ASN1_SEQUENCE); +- +- p = *out = malloc(tot_len); +- if (p == NULL) return -1; +- +- ASN1_put_object(&p, 1, (int)(orig_len+oid_len), +- V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL); +- +- i2d_ASN1_OBJECT(oid, &p); +- +- ASN1_put_object(&p, 1, (int)data_len, 0, V_ASN1_CONTEXT_SPECIFIC); +- memcpy(p, data, data_len); +- +- *out_len = tot_len; +- +- return 0; +-} +- +-static int +-prepare_enc_data(const uint8_t *indata, int indata_len, uint8_t **outdata, +- int *outdata_len) +-{ +- int tag, class; +- long tlen, slen; +- const uint8_t *p = indata, *oldp; +- +- if (ASN1_get_object(&p, &slen, &tag, &class, indata_len) & 0x80) +- return EINVAL; +- if (tag != V_ASN1_SEQUENCE) +- return EINVAL; +- +- oldp = p; +- if (ASN1_get_object(&p, &tlen, &tag, &class, slen) & 0x80) +- return EINVAL; +- p += tlen; +- slen -= (p - oldp); +- +- if (ASN1_get_object(&p, &tlen, &tag, &class, slen) & 0x80) +- return EINVAL; +- +- *outdata = malloc(tlen); +- if (*outdata == NULL) +- return ENOMEM; +- memcpy(*outdata, p, tlen); +- *outdata_len = tlen; +- return 0; +-} +- + #ifndef WITHOUT_PKCS11 + static void * + pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p) +@@ -3946,120 +3612,6 @@ pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx, + } + #endif + +-static krb5_error_code +-pkinit_decode_data_fs(krb5_context context, +- pkinit_identity_crypto_context id_cryptoctx, +- const uint8_t *data, unsigned int data_len, +- uint8_t **decoded_data, unsigned int *decoded_data_len) +-{ +- if (decode_data(decoded_data, decoded_data_len, data, data_len, +- id_cryptoctx->my_key, sk_X509_value(id_cryptoctx->my_certs, +- id_cryptoctx->cert_index)) <= 0) { +- pkiDebug("failed to decode data\n"); +- return KRB5KDC_ERR_PREAUTH_FAILED; +- } +- return 0; +-} +- +-#ifndef WITHOUT_PKCS11 +-/* +- * When using the ActivCard Linux pkcs11 library (v2.0.1), the decrypt function +- * fails. By inserting an extra function call, which serves nothing but to +- * change the stack, we were able to work around the issue. If the ActivCard +- * library is fixed in the future, this function can be inlined back into the +- * caller. +- */ +-static CK_RV +-pkinit_C_Decrypt(pkinit_identity_crypto_context id_cryptoctx, +- CK_BYTE_PTR pEncryptedData, +- CK_ULONG ulEncryptedDataLen, +- CK_BYTE_PTR pData, +- CK_ULONG_PTR pulDataLen) +-{ +- CK_RV rv = CKR_OK; +- +- rv = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, pEncryptedData, +- ulEncryptedDataLen, pData, pulDataLen); +- if (rv == CKR_OK) { +- pkiDebug("pData %p *pulDataLen %d\n", (void *) pData, +- (int) *pulDataLen); +- } +- return rv; +-} +- +-static krb5_error_code +-pkinit_decode_data_pkcs11(krb5_context context, +- pkinit_identity_crypto_context id_cryptoctx, +- const uint8_t *data, unsigned int data_len, +- uint8_t **decoded_data, +- unsigned int *decoded_data_len) +-{ +- CK_OBJECT_HANDLE obj; +- CK_ULONG len; +- CK_MECHANISM mech; +- uint8_t *cp; +- int r; +- +- if (pkinit_open_session(context, id_cryptoctx)) { +- pkiDebug("can't open pkcs11 session\n"); +- return KRB5KDC_ERR_PREAUTH_FAILED; +- } +- +- pkinit_find_private_key(id_cryptoctx, CKA_DECRYPT, &obj); +- +- mech.mechanism = CKM_RSA_PKCS; +- mech.pParameter = NULL; +- mech.ulParameterLen = 0; +- +- if ((r = id_cryptoctx->p11->C_DecryptInit(id_cryptoctx->session, &mech, +- obj)) != CKR_OK) { +- pkiDebug("C_DecryptInit: 0x%x\n", (int) r); +- return KRB5KDC_ERR_PREAUTH_FAILED; +- } +- pkiDebug("data_len = %d\n", data_len); +- cp = malloc((size_t) data_len); +- if (cp == NULL) +- return ENOMEM; +- len = data_len; +- pkiDebug("session %p edata %p edata_len %d data %p datalen @%p %d\n", +- (void *) id_cryptoctx->session, (void *) data, (int) data_len, +- (void *) cp, (void *) &len, (int) len); +- r = pkinit_C_Decrypt(id_cryptoctx, (CK_BYTE_PTR) data, (CK_ULONG) data_len, +- cp, &len); +- if (r != CKR_OK) { +- pkiDebug("C_Decrypt: %s\n", pkinit_pkcs11_code_to_text(r)); +- if (r == CKR_BUFFER_TOO_SMALL) +- pkiDebug("decrypt %d needs %d\n", (int) data_len, (int) len); +- return KRB5KDC_ERR_PREAUTH_FAILED; +- } +- pkiDebug("decrypt %d -> %d\n", (int) data_len, (int) len); +- *decoded_data_len = len; +- *decoded_data = cp; +- +- return 0; +-} +-#endif +- +-krb5_error_code +-pkinit_decode_data(krb5_context context, +- pkinit_identity_crypto_context id_cryptoctx, +- const uint8_t *data, unsigned int data_len, +- uint8_t **decoded_data, unsigned int *decoded_data_len) +-{ +- krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED; +- +- if (id_cryptoctx->pkcs11_method != 1) +- retval = pkinit_decode_data_fs(context, id_cryptoctx, data, data_len, +- decoded_data, decoded_data_len); +-#ifndef WITHOUT_PKCS11 +- else +- retval = pkinit_decode_data_pkcs11(context, id_cryptoctx, data, +- data_len, decoded_data, decoded_data_len); +-#endif +- +- return retval; +-} +- + static krb5_error_code + pkinit_sign_data_fs(krb5_context context, + pkinit_identity_crypto_context id_cryptoctx, +@@ -4160,42 +3712,6 @@ pkinit_sign_data(krb5_context context, + return retval; + } + +- +-static int +-decode_data(uint8_t **out_data, unsigned int *out_data_len, +- const uint8_t *data, unsigned int data_len, EVP_PKEY *pkey, +- X509 *cert) +-{ +- int retval; +- unsigned char *buf = NULL; +- int buf_len = 0; +- +- if (cert && !X509_check_private_key(cert, pkey)) { +- pkiDebug("private key does not match certificate\n"); +- return 0; +- } +- +- buf_len = EVP_PKEY_size(pkey); +- buf = malloc((size_t) buf_len + 10); +- if (buf == NULL) +- return 0; +- +-#if OPENSSL_VERSION_NUMBER >= 0x00909000L +- retval = EVP_PKEY_decrypt_old(buf, data, (int)data_len, pkey); +-#else +- retval = EVP_PKEY_decrypt(buf, data, (int)data_len, pkey); +-#endif +- if (retval <= 0) { +- pkiDebug("unable to decrypt received data (len=%d)\n", data_len); +- free(buf); +- return 0; +- } +- *out_data = buf; +- *out_data_len = retval; +- +- return 1; +-} +- + static krb5_error_code + create_signature(unsigned char **sig, unsigned int *sig_len, + unsigned char *data, unsigned int data_len, EVP_PKEY *pkey) +@@ -5817,88 +5333,6 @@ cleanup: + return retval; + } + +-/* Originally based on OpenSSL's PKCS7_dataDecode(), now modified to remove the +- * use of BIO objects and to fit the PKINIT internal interfaces. */ +-static int +-pkcs7_decrypt(krb5_context context, +- pkinit_identity_crypto_context id_cryptoctx, PKCS7 *p7, +- unsigned char **data_out, unsigned int *len_out) +-{ +- krb5_error_code ret; +- int ok = 0, plaintext_len = 0, final_len; +- unsigned int keylen = 0, eklen = 0, blocksize; +- unsigned char *ek = NULL, *tkey = NULL, *plaintext = NULL, *use_key; +- ASN1_OCTET_STRING *data_body = p7->d.enveloped->enc_data->enc_data; +- const EVP_CIPHER *evp_cipher; +- EVP_CIPHER_CTX *evp_ctx = NULL; +- X509_ALGOR *enc_alg = p7->d.enveloped->enc_data->algorithm; +- STACK_OF(PKCS7_RECIP_INFO) *rsk = p7->d.enveloped->recipientinfo; +- PKCS7_RECIP_INFO *ri = NULL; +- +- *data_out = NULL; +- *len_out = 0; +- +- p7->state = PKCS7_S_HEADER; +- +- /* RFC 4556 section 3.2.3.2 requires that there be exactly one +- * recipientInfo. */ +- if (sk_PKCS7_RECIP_INFO_num(rsk) != 1) { +- pkiDebug("invalid number of EnvelopedData RecipientInfos\n"); +- return 0; +- } +- ri = sk_PKCS7_RECIP_INFO_value(rsk, 0); +- +- evp_cipher = EVP_get_cipherbyobj(enc_alg->algorithm); +- if (evp_cipher == NULL) +- goto cleanup; +- keylen = EVP_CIPHER_key_length(evp_cipher); +- blocksize = EVP_CIPHER_block_size(evp_cipher); +- +- evp_ctx = EVP_CIPHER_CTX_new(); +- if (evp_ctx == NULL) +- goto cleanup; +- if (!EVP_DecryptInit(evp_ctx, evp_cipher, NULL, NULL) || +- EVP_CIPHER_asn1_to_param(evp_ctx, enc_alg->parameter) <= 0) +- goto cleanup; +- +- /* Generate a random symmetric key to avoid exposing timing data if RSA +- * decryption fails the padding check. */ +- tkey = malloc(keylen); +- if (tkey == NULL || !EVP_CIPHER_CTX_rand_key(evp_ctx, tkey)) +- goto cleanup; +- +- /* Decrypt the secret key with the private key. */ +- ret = pkinit_decode_data(context, id_cryptoctx, +- ASN1_STRING_get0_data(ri->enc_key), +- ASN1_STRING_length(ri->enc_key), &ek, &eklen); +- use_key = (ret || eklen != keylen) ? tkey : ek; +- +- /* Allocate a plaintext buffer and decrypt data_body into it. */ +- plaintext = malloc(data_body->length + blocksize); +- if (plaintext == NULL) +- goto cleanup; +- if (!EVP_DecryptInit(evp_ctx, NULL, use_key, NULL)) +- goto cleanup; +- if (!EVP_DecryptUpdate(evp_ctx, plaintext, &plaintext_len, +- data_body->data, data_body->length)) +- goto cleanup; +- if (!EVP_DecryptFinal(evp_ctx, plaintext + plaintext_len, &final_len)) +- goto cleanup; +- plaintext_len += final_len; +- +- *len_out = plaintext_len; +- *data_out = plaintext; +- plaintext = NULL; +- ok = 1; +- +-cleanup: +- EVP_CIPHER_CTX_free(evp_ctx); +- zapfree(plaintext, plaintext_len); +- zapfree(ek, eklen); +- zapfree(tkey, keylen); +- return ok; +-} +- + #ifdef DEBUG_DH + static void + print_dh(DH * dh, char *msg) +diff --git a/src/plugins/preauth/pkinit/pkinit_lib.c b/src/plugins/preauth/pkinit/pkinit_lib.c +index 2f88545da8..118358e086 100644 +--- a/src/plugins/preauth/pkinit/pkinit_lib.c ++++ b/src/plugins/preauth/pkinit/pkinit_lib.c +@@ -50,7 +50,6 @@ pkinit_init_req_opts(pkinit_req_opts **reqopts) + opts->require_eku = 1; + opts->accept_secondary_eku = 0; + opts->allow_upn = 0; +- opts->dh_or_rsa = DH_PROTOCOL; + opts->require_crl_checking = 0; + opts->dh_size = PKINIT_DEFAULT_DH_MIN_BITS; + +@@ -79,7 +78,6 @@ pkinit_init_plg_opts(pkinit_plg_opts **plgopts) + + opts->require_eku = 1; + opts->accept_secondary_eku = 0; +- opts->dh_or_rsa = DH_PROTOCOL; + opts->allow_upn = 0; + opts->require_crl_checking = 0; + +diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c +index 7d86e597e1..3abb9529b7 100644 +--- a/src/plugins/preauth/pkinit/pkinit_srv.c ++++ b/src/plugins/preauth/pkinit/pkinit_srv.c +@@ -874,8 +874,7 @@ pkinit_server_return_padata(krb5_context context, + retval = ENOMEM; + goto cleanup; + } +- /* let's assume it's RSA. we'll reset it to DH if needed */ +- rep->choice = choice_pa_pk_as_rep_encKeyPack; ++ rep->choice = choice_pa_pk_as_rep_dhInfo; + break; + case KRB5_PADATA_PK_AS_REP_OLD: + case KRB5_PADATA_PK_AS_REQ_OLD: +@@ -884,7 +883,7 @@ pkinit_server_return_padata(krb5_context context, + retval = ENOMEM; + goto cleanup; + } +- rep9->choice = choice_pa_pk_as_rep_draft9_encKeyPack; ++ rep9->choice = choice_pa_pk_as_rep_draft9_dhSignedData; + break; + default: + retval = KRB5KDC_ERR_PREAUTH_FAILED; +@@ -905,226 +904,88 @@ pkinit_server_return_padata(krb5_context context, + subjectPublicKey_len = + reqctx->rcv_auth_pack9->clientPublicValue->subjectPublicKey.length; + rep9->choice = choice_pa_pk_as_rep_draft9_dhSignedData; ++ } else { ++ pkiDebug("received RSA key delivery AS REQ\n"); ++ retval = KRB5KDC_ERR_PREAUTH_FAILED; ++ k5_setmsg(context, retval, _("Unsupported PKINIT RSA request")); ++ goto cleanup; + } + +- /* if this DH, then process finish computing DH key */ +- if (rep != NULL && (rep->choice == choice_pa_pk_as_rep_dhInfo || +- rep->choice == choice_pa_pk_as_rep_draft9_dhSignedData)) { +- pkiDebug("received DH key delivery AS REQ\n"); +- retval = server_process_dh(context, plgctx->cryptoctx, +- reqctx->cryptoctx, plgctx->idctx, subjectPublicKey, +- subjectPublicKey_len, &dh_pubkey, &dh_pubkey_len, +- &server_key, &server_key_len); +- if (retval) { +- pkiDebug("failed to process/create dh paramters\n"); +- goto cleanup; +- } ++ /* finish computing DH key */ ++ pkiDebug("received DH key delivery AS REQ\n"); ++ retval = server_process_dh(context, plgctx->cryptoctx, reqctx->cryptoctx, ++ plgctx->idctx, subjectPublicKey, ++ subjectPublicKey_len, &dh_pubkey, &dh_pubkey_len, ++ &server_key, &server_key_len); ++ if (retval) { ++ pkiDebug("failed to process/create dh paramters\n"); ++ goto cleanup; + } +- if ((rep9 != NULL && +- rep9->choice == choice_pa_pk_as_rep_draft9_dhSignedData) || +- (rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo)) { +- +- /* +- * This is DH, so don't generate the key until after we +- * encode the reply, because the encoded reply is needed +- * to generate the key in some cases. +- */ +- +- dhkey_info.subjectPublicKey.length = dh_pubkey_len; +- dhkey_info.subjectPublicKey.data = (char *)dh_pubkey; +- dhkey_info.nonce = request->nonce; +- dhkey_info.dhKeyExpiration = 0; +- +- retval = k5int_encode_krb5_kdc_dh_key_info(&dhkey_info, +- &encoded_dhkey_info); +- if (retval) { +- pkiDebug("encode_krb5_kdc_dh_key_info failed\n"); +- goto cleanup; +- } +-#ifdef DEBUG_ASN1 +- print_buffer_bin((unsigned char *)encoded_dhkey_info->data, +- encoded_dhkey_info->length, +- "/tmp/kdc_dh_key_info"); +-#endif + +- switch ((int)padata->pa_type) { +- case KRB5_PADATA_PK_AS_REQ: +- retval = cms_signeddata_create(context, plgctx->cryptoctx, +- reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_SERVER, 1, +- (unsigned char *) +- encoded_dhkey_info->data, +- encoded_dhkey_info->length, +- (unsigned char **) +- &rep->u.dh_Info.dhSignedData.data, +- &rep->u.dh_Info.dhSignedData.length); +- if (retval) { +- pkiDebug("failed to create pkcs7 signed data\n"); +- goto cleanup; +- } +- break; +- case KRB5_PADATA_PK_AS_REP_OLD: +- case KRB5_PADATA_PK_AS_REQ_OLD: +- retval = cms_signeddata_create(context, plgctx->cryptoctx, +- reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_DRAFT9, 1, +- (unsigned char *) +- encoded_dhkey_info->data, +- encoded_dhkey_info->length, +- (unsigned char **) +- &rep9->u.dhSignedData.data, +- &rep9->u.dhSignedData.length); +- if (retval) { +- pkiDebug("failed to create pkcs7 signed data\n"); +- goto cleanup; +- } +- break; +- } +- +- } else { +- pkiDebug("received RSA key delivery AS REQ\n"); +- +- retval = krb5_c_make_random_key(context, enctype, encrypting_key); +- if (retval) { +- pkiDebug("unable to make a session key\n"); +- goto cleanup; +- } ++ /* ++ * This is DH, so don't generate the key until after we encode the reply, ++ * because the encoded reply is needed to generate the key in some cases. ++ */ + +- /* check if PA_TYPE of KRB5_PADATA_AS_CHECKSUM (132) is present which +- * means the client is requesting that a checksum is send back instead +- * of the nonce. +- */ +- for (i = 0; request->padata[i] != NULL; i++) { +- pkiDebug("%s: Checking pa_type 0x%08x\n", +- __FUNCTION__, request->padata[i]->pa_type); +- if (request->padata[i]->pa_type == KRB5_PADATA_AS_CHECKSUM) +- fixed_keypack = 1; +- } +- pkiDebug("%s: return checksum instead of nonce = %d\n", +- __FUNCTION__, fixed_keypack); +- +- /* if this is an RFC reply or draft9 client requested a checksum +- * in the reply instead of the nonce, create an RFC-style keypack +- */ +- if ((int)padata->pa_type == KRB5_PADATA_PK_AS_REQ || fixed_keypack) { +- init_krb5_reply_key_pack(&key_pack); +- if (key_pack == NULL) { +- retval = ENOMEM; +- goto cleanup; +- } ++ dhkey_info.subjectPublicKey.length = dh_pubkey_len; ++ dhkey_info.subjectPublicKey.data = (char *)dh_pubkey; ++ dhkey_info.nonce = request->nonce; ++ dhkey_info.dhKeyExpiration = 0; + +- retval = krb5_c_make_checksum(context, 0, +- encrypting_key, KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM, +- req_pkt, &key_pack->asChecksum); +- if (retval) { +- pkiDebug("unable to calculate AS REQ checksum\n"); +- goto cleanup; +- } +-#ifdef DEBUG_CKSUM +- pkiDebug("calculating checksum on buf size = %d\n", req_pkt->length); +- print_buffer(req_pkt->data, req_pkt->length); +- pkiDebug("checksum size = %d\n", key_pack->asChecksum.length); +- print_buffer(key_pack->asChecksum.contents, +- key_pack->asChecksum.length); +- pkiDebug("encrypting key (%d)\n", encrypting_key->length); +- print_buffer(encrypting_key->contents, encrypting_key->length); ++ retval = k5int_encode_krb5_kdc_dh_key_info(&dhkey_info, ++ &encoded_dhkey_info); ++ if (retval) { ++ pkiDebug("encode_krb5_kdc_dh_key_info failed\n"); ++ goto cleanup; ++ } ++#ifdef DEBUG_ASN1 ++ print_buffer_bin((unsigned char *)encoded_dhkey_info->data, ++ encoded_dhkey_info->length, "/tmp/kdc_dh_key_info"); + #endif + +- krb5_copy_keyblock_contents(context, encrypting_key, +- &key_pack->replyKey); +- +- retval = k5int_encode_krb5_reply_key_pack(key_pack, +- &encoded_key_pack); +- if (retval) { +- pkiDebug("failed to encode reply_key_pack\n"); +- goto cleanup; +- } +- } +- +- switch ((int)padata->pa_type) { +- case KRB5_PADATA_PK_AS_REQ: +- rep->choice = choice_pa_pk_as_rep_encKeyPack; +- retval = cms_envelopeddata_create(context, plgctx->cryptoctx, +- reqctx->cryptoctx, plgctx->idctx, padata->pa_type, 1, +- (unsigned char *) +- encoded_key_pack->data, +- encoded_key_pack->length, +- (unsigned char **) +- &rep->u.encKeyPack.data, +- &rep->u.encKeyPack.length); +- break; +- case KRB5_PADATA_PK_AS_REP_OLD: +- case KRB5_PADATA_PK_AS_REQ_OLD: +- /* if the request is from the broken draft9 client that +- * expects back a nonce, create it now +- */ +- if (!fixed_keypack) { +- init_krb5_reply_key_pack_draft9(&key_pack9); +- if (key_pack9 == NULL) { +- retval = ENOMEM; +- goto cleanup; +- } +- key_pack9->nonce = reqctx->rcv_auth_pack9->pkAuthenticator.nonce; +- krb5_copy_keyblock_contents(context, encrypting_key, +- &key_pack9->replyKey); +- +- retval = k5int_encode_krb5_reply_key_pack_draft9(key_pack9, +- &encoded_key_pack); +- if (retval) { +- pkiDebug("failed to encode reply_key_pack\n"); +- goto cleanup; +- } +- } +- +- rep9->choice = choice_pa_pk_as_rep_draft9_encKeyPack; +- retval = cms_envelopeddata_create(context, plgctx->cryptoctx, +- reqctx->cryptoctx, plgctx->idctx, padata->pa_type, 1, +- (unsigned char *) +- encoded_key_pack->data, +- encoded_key_pack->length, +- (unsigned char **) +- &rep9->u.encKeyPack.data, &rep9->u.encKeyPack.length); +- break; +- } ++ switch ((int)padata->pa_type) { ++ case KRB5_PADATA_PK_AS_REQ: ++ retval = cms_signeddata_create(context, plgctx->cryptoctx, ++ reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_SERVER, 1, ++ (unsigned char *) ++ encoded_dhkey_info->data, ++ encoded_dhkey_info->length, ++ (unsigned char **) ++ &rep->u.dh_Info.dhSignedData.data, ++ &rep->u.dh_Info.dhSignedData.length); + if (retval) { +- pkiDebug("failed to create pkcs7 enveloped data: %s\n", +- error_message(retval)); ++ pkiDebug("failed to create pkcs7 signed data\n"); + goto cleanup; + } +-#ifdef DEBUG_ASN1 +- print_buffer_bin((unsigned char *)encoded_key_pack->data, +- encoded_key_pack->length, +- "/tmp/kdc_key_pack"); +- switch ((int)padata->pa_type) { +- case KRB5_PADATA_PK_AS_REQ: +- print_buffer_bin(rep->u.encKeyPack.data, +- rep->u.encKeyPack.length, +- "/tmp/kdc_enc_key_pack"); +- break; +- case KRB5_PADATA_PK_AS_REP_OLD: +- case KRB5_PADATA_PK_AS_REQ_OLD: +- print_buffer_bin(rep9->u.encKeyPack.data, +- rep9->u.encKeyPack.length, +- "/tmp/kdc_enc_key_pack"); +- break; ++ break; ++ case KRB5_PADATA_PK_AS_REP_OLD: ++ case KRB5_PADATA_PK_AS_REQ_OLD: ++ retval = cms_signeddata_create(context, plgctx->cryptoctx, ++ reqctx->cryptoctx, plgctx->idctx, CMS_SIGN_DRAFT9, 1, ++ (unsigned char *) ++ encoded_dhkey_info->data, ++ encoded_dhkey_info->length, ++ (unsigned char **) ++ &rep9->u.dhSignedData.data, ++ &rep9->u.dhSignedData.length); ++ if (retval) { ++ pkiDebug("failed to create pkcs7 signed data\n"); ++ goto cleanup; + } +-#endif ++ break; + } + +- if ((rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo) && +- ((reqctx->rcv_auth_pack != NULL && +- reqctx->rcv_auth_pack->supportedKDFs != NULL))) { +- +- /* If using the alg-agility KDF, put the algorithm in the reply +- * before encoding it. +- */ +- if (reqctx->rcv_auth_pack != NULL && +- reqctx->rcv_auth_pack->supportedKDFs != NULL) { +- retval = pkinit_pick_kdf_alg(context, reqctx->rcv_auth_pack->supportedKDFs, +- &(rep->u.dh_Info.kdfID)); +- if (retval) { +- pkiDebug("pkinit_pick_kdf_alg failed: %s\n", +- error_message(retval)); +- goto cleanup; +- } ++ /* If using the alg-agility KDF, put the algorithm in the reply before ++ * encoding it. ++ */ ++ if (reqctx->rcv_auth_pack != NULL && ++ reqctx->rcv_auth_pack->supportedKDFs != NULL) { ++ retval = pkinit_pick_kdf_alg(context, ++ reqctx->rcv_auth_pack->supportedKDFs, ++ &(rep->u.dh_Info.kdfID)); ++ if (retval) { ++ pkiDebug("pkinit_pick_kdf_alg failed: %s\n", error_message(retval)); ++ goto cleanup; + } + } + +@@ -1147,37 +1008,30 @@ pkinit_server_return_padata(krb5_context context, + "/tmp/kdc_as_rep"); + #endif + +- /* If this is DH, we haven't computed the key yet, so do it now. */ +- if ((rep9 != NULL && +- rep9->choice == choice_pa_pk_as_rep_draft9_dhSignedData) || +- (rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo)) { +- +- /* If we're not doing draft 9, and mutually supported KDFs were found, +- * use the algorithm agility KDF. */ +- if (rep != NULL && rep->u.dh_Info.kdfID) { +- secret.data = (char *)server_key; +- secret.length = server_key_len; +- +- retval = pkinit_alg_agility_kdf(context, &secret, +- rep->u.dh_Info.kdfID, +- request->client, request->server, +- enctype, req_pkt, out_data, +- encrypting_key); +- if (retval) { +- pkiDebug("pkinit_alg_agility_kdf failed: %s\n", +- error_message(retval)); +- goto cleanup; +- } ++ /* If we're not doing draft 9, and mutually supported KDFs were found, use ++ * the algorithm agility KDF. */ ++ if (rep != NULL && rep->u.dh_Info.kdfID) { ++ secret.data = (char *)server_key; ++ secret.length = server_key_len; + +- /* Otherwise, use the older octetstring2key() function */ +- } else { +- retval = pkinit_octetstring2key(context, enctype, server_key, +- server_key_len, encrypting_key); +- if (retval) { +- pkiDebug("pkinit_octetstring2key failed: %s\n", +- error_message(retval)); +- goto cleanup; +- } ++ retval = pkinit_alg_agility_kdf(context, &secret, rep->u.dh_Info.kdfID, ++ request->client, request->server, ++ enctype, req_pkt, out_data, ++ encrypting_key); ++ if (retval) { ++ pkiDebug("pkinit_alg_agility_kdf failed: %s\n", ++ error_message(retval)); ++ goto cleanup; ++ } ++ ++ /* Otherwise, use the older octetstring2key() function */ ++ } else { ++ retval = pkinit_octetstring2key(context, enctype, server_key, ++ server_key_len, encrypting_key); ++ if (retval) { ++ pkiDebug("pkinit_octetstring2key failed: %s\n", ++ error_message(retval)); ++ goto cleanup; + } + } + +diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h +index 8d489469fc..607cb7695f 100644 +--- a/src/plugins/preauth/pkinit/pkinit_trace.h ++++ b/src/plugins/preauth/pkinit/pkinit_trace.h +@@ -56,19 +56,10 @@ + 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_REP_RSA(c) \ +- TRACE(c, "PKINIT client verified RSA reply") +-#define TRACE_PKINIT_CLIENT_REP_RSA_KEY(c, keyblock, cksum) \ +- TRACE(c, "PKINIT client retrieved reply key {keyblock} from RSA " \ +- "reply (checksum {cksum})", keyblock, cksum) +-#define TRACE_PKINIT_CLIENT_REP_RSA_FAIL(c) \ +- TRACE(c, "PKINIT client could not verify RSA 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_DH(c) \ + TRACE(c, "PKINIT client making DH request") +-#define TRACE_PKINIT_CLIENT_REQ_RSA(c) \ +- TRACE(c, "PKINIT client making RSA request") + #define TRACE_PKINIT_CLIENT_SAN_CONFIG_DNSNAME(c, host) \ + TRACE(c, "PKINIT client config accepts KDC dNSName SAN {string}", host) + #define TRACE_PKINIT_CLIENT_SAN_MATCH_DNSNAME(c, host) \ +diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py +index 22ab81743f..1fcdd74cee 100755 +--- a/src/tests/t_pkinit.py ++++ b/src/tests/t_pkinit.py +@@ -178,12 +178,6 @@ realm.kinit(realm.user_princ, + realm.klist(realm.user_princ) + realm.run([kvno, realm.host_princ]) + +-# Try again using RSA instead of DH. +-realm.kinit(realm.user_princ, +- flags=['-X', 'X509_user_identity=%s' % file_identity, +- '-X', 'flag_RSA_PROTOCOL=yes']) +-realm.klist(realm.user_princ) +- + # Test a DH parameter renegotiation by temporarily setting a 4096-bit + # minimum on the KDC. (Preauth type 16 is PKINIT PA_PK_AS_REQ; + # 109 is PKINIT TD_DH_PARAMETERS; 133 is FAST PA-FX-COOKIE.) +diff --git a/src/windows/leash/htmlhelp/html/KINIT.htm b/src/windows/leash/htmlhelp/html/KINIT.htm +index eeee211a6e..46cb4a3ad8 100644 +--- a/src/windows/leash/htmlhelp/html/KINIT.htm ++++ b/src/windows/leash/htmlhelp/html/KINIT.htm +@@ -146,9 +146,6 @@ default credentials cache may vary between systems. If the KRB5CCNAME en + -S service_name + specify an alternate service name to use when getting initial + tickets. +- +- flag_RSA_PROTOCOL[=yes] +- specify use of RSA, rather than the default Diffie-Hellman protocol. + + +

ENVIRONMENT

+-- +2.46.0 + diff --git a/Simply-OpenSSL-PKCS7-decryption-code.patch b/Simply-OpenSSL-PKCS7-decryption-code.patch new file mode 100644 index 0000000000000000000000000000000000000000..5a1a2f51ae311787d9c54ce88e01d5b90eab4837 --- /dev/null +++ b/Simply-OpenSSL-PKCS7-decryption-code.patch @@ -0,0 +1,296 @@ +From 5686450c4a79b7bf858cf3853039d400676bbf03 Mon Sep 17 00:00:00 2024 +From: zhuhongbo +Date: Tue, 19 Nov 2024 17:13:06 +Subject: [PATCH] Simply OpenSSL PKCS7 decryption code + +--- + .../preauth/pkinit/pkinit_crypto_openssl.c | 211 +++++------------- + 1 file changed, 62 insertions(+), 149 deletions(-) + +diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +index dc7ce7b233..9ba3ea89c1 100644 +--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c ++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +@@ -84,12 +84,8 @@ static int openssl_callback (int, X509_STORE_CTX *); + static int openssl_callback_ignore_crls (int, X509_STORE_CTX *); + + static int pkcs7_decrypt +-(krb5_context context, pkinit_identity_crypto_context id_cryptoctx, +- PKCS7 *p7, BIO *bio); +- +-static BIO * pkcs7_dataDecode +-(krb5_context context, pkinit_identity_crypto_context id_cryptoctx, +- PKCS7 *p7); ++(krb5_context context, pkinit_identity_crypto_context id_cryptoctx, PKCS7 *p7, ++ unsigned char **data_out, unsigned int *len_out); + + static ASN1_OBJECT * pkinit_pkcs7type2oid + (pkinit_plg_crypto_context plg_cryptoctx, int pkcs7_type); +@@ -1978,9 +1974,6 @@ cms_envelopeddata_verify(krb5_context context, + { + krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED; + PKCS7 *p7 = NULL; +- BIO *out = NULL; +- int i = 0; +- unsigned int size = 0; + const unsigned char *p = enveloped_data; + unsigned int tmp_buf_len = 0, tmp_buf2_len = 0, vfy_buf_len = 0; + unsigned char *tmp_buf = NULL, *tmp_buf2 = NULL, *vfy_buf = NULL; +@@ -2005,26 +1998,13 @@ cms_envelopeddata_verify(krb5_context context, + } + + /* decrypt received PKCS7 message */ +- out = BIO_new(BIO_s_mem()); +- if (pkcs7_decrypt(context, id_cryptoctx, p7, out)) { ++ if (pkcs7_decrypt(context, id_cryptoctx, p7, &tmp_buf, &tmp_buf_len)) { + pkiDebug("PKCS7 decryption successful\n"); + } else { + retval = oerr(context, 0, _("Failed to decrypt PKCS7 message")); + goto cleanup; + } + +- /* transfer the decoded PKCS7 SignedData message into a separate buffer */ +- for (;;) { +- if ((tmp_buf = realloc(tmp_buf, size + 1024 * 10)) == NULL) +- goto cleanup; +- i = BIO_read(out, &(tmp_buf[size]), 1024 * 10); +- if (i <= 0) +- break; +- else +- size += i; +- } +- tmp_buf_len = size; +- + #ifdef DEBUG_ASN1 + print_buffer_bin(tmp_buf, tmp_buf_len, "/tmp/client_enc_keypack"); + #endif +@@ -2086,8 +2066,6 @@ cleanup: + + if (p7 != NULL) + PKCS7_free(p7); +- if (out != NULL) +- BIO_free(out); + free(tmp_buf); + free(tmp_buf2); + +@@ -5759,39 +5737,6 @@ cleanup: + return retval; + } + +-static int +-pkcs7_decrypt(krb5_context context, +- pkinit_identity_crypto_context id_cryptoctx, +- PKCS7 *p7, +- BIO *data) +-{ +- BIO *tmpmem = NULL; +- int retval = 0, i = 0; +- char buf[4096]; +- +- if(p7 == NULL) +- return 0; +- +- if(!PKCS7_type_is_enveloped(p7)) { +- pkiDebug("wrong pkcs7 content type\n"); +- return 0; +- } +- +- if(!(tmpmem = pkcs7_dataDecode(context, id_cryptoctx, p7))) { +- pkiDebug("unable to decrypt pkcs7 object\n"); +- return 0; +- } +- +- for(;;) { +- i = BIO_read(tmpmem, buf, sizeof(buf)); +- if (i <= 0) break; +- BIO_write(data, buf, i); +- BIO_free_all(tmpmem); +- return 1; +- } +- return retval; +-} +- + krb5_error_code + pkinit_process_td_trusted_certifiers( + krb5_context context, +@@ -5872,118 +5817,86 @@ cleanup: + return retval; + } + +-static BIO * +-pkcs7_dataDecode(krb5_context context, +- pkinit_identity_crypto_context id_cryptoctx, +- PKCS7 *p7) ++/* Originally based on OpenSSL's PKCS7_dataDecode(), now modified to remove the ++ * use of BIO objects and to fit the PKINIT internal interfaces. */ ++static int ++pkcs7_decrypt(krb5_context context, ++ pkinit_identity_crypto_context id_cryptoctx, PKCS7 *p7, ++ unsigned char **data_out, unsigned int *len_out) + { +- unsigned int eklen=0, tkeylen=0; +- BIO *out=NULL,*etmp=NULL,*bio=NULL; +- unsigned char *ek=NULL, *tkey=NULL; +- ASN1_OCTET_STRING *data_body=NULL; +- const EVP_CIPHER *evp_cipher=NULL; +- EVP_CIPHER_CTX *evp_ctx=NULL; +- X509_ALGOR *enc_alg=NULL; +- STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL; +- PKCS7_RECIP_INFO *ri=NULL; +- +- p7->state=PKCS7_S_HEADER; +- +- rsk=p7->d.enveloped->recipientinfo; +- enc_alg=p7->d.enveloped->enc_data->algorithm; +- data_body=p7->d.enveloped->enc_data->enc_data; +- evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); +- if (evp_cipher == NULL) { +- PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE); +- goto cleanup; +- } ++ krb5_error_code ret; ++ int ok = 0, plaintext_len = 0, final_len; ++ unsigned int keylen = 0, eklen = 0, blocksize; ++ unsigned char *ek = NULL, *tkey = NULL, *plaintext = NULL, *use_key; ++ ASN1_OCTET_STRING *data_body = p7->d.enveloped->enc_data->enc_data; ++ const EVP_CIPHER *evp_cipher; ++ EVP_CIPHER_CTX *evp_ctx = NULL; ++ X509_ALGOR *enc_alg = p7->d.enveloped->enc_data->algorithm; ++ STACK_OF(PKCS7_RECIP_INFO) *rsk = p7->d.enveloped->recipientinfo; ++ PKCS7_RECIP_INFO *ri = NULL; + +- if ((etmp=BIO_new(BIO_f_cipher())) == NULL) { +- PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB); +- goto cleanup; +- } ++ *data_out = NULL; ++ *len_out = 0; + +- /* It was encrypted, we need to decrypt the secret key +- * with the private key */ ++ p7->state = PKCS7_S_HEADER; + + /* RFC 4556 section 3.2.3.2 requires that there be exactly one + * recipientInfo. */ + if (sk_PKCS7_RECIP_INFO_num(rsk) != 1) { + pkiDebug("invalid number of EnvelopedData RecipientInfos\n"); +- goto cleanup; ++ return 0; + } +- + ri = sk_PKCS7_RECIP_INFO_value(rsk, 0); +- (void)pkinit_decode_data(context, id_cryptoctx, +- ASN1_STRING_get0_data(ri->enc_key), +- ASN1_STRING_length(ri->enc_key), &ek, &eklen); + +- evp_ctx=NULL; +- BIO_get_cipher_ctx(etmp,&evp_ctx); +- if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0) ++ evp_cipher = EVP_get_cipherbyobj(enc_alg->algorithm); ++ if (evp_cipher == NULL) ++ goto cleanup; ++ keylen = EVP_CIPHER_key_length(evp_cipher); ++ blocksize = EVP_CIPHER_block_size(evp_cipher); ++ ++ evp_ctx = EVP_CIPHER_CTX_new(); ++ if (evp_ctx == NULL) + goto cleanup; +- if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0) ++ if (!EVP_DecryptInit(evp_ctx, evp_cipher, NULL, NULL) || ++ EVP_CIPHER_asn1_to_param(evp_ctx, enc_alg->parameter) <= 0) + goto cleanup; + + /* Generate a random symmetric key to avoid exposing timing data if RSA + * decryption fails the padding check. */ +- tkeylen = EVP_CIPHER_CTX_key_length(evp_ctx); +- tkey = OPENSSL_malloc(tkeylen); +- if (tkey == NULL) ++ tkey = malloc(keylen); ++ if (tkey == NULL || !EVP_CIPHER_CTX_rand_key(evp_ctx, tkey)) + goto cleanup; +- if (EVP_CIPHER_CTX_rand_key(evp_ctx, tkey) <= 0) +- goto cleanup; +- if (ek == NULL) { +- ek = tkey; +- eklen = tkeylen; +- tkey = NULL; +- } + +- if (eklen != (unsigned)EVP_CIPHER_CTX_key_length(evp_ctx)) { +- /* Some S/MIME clients don't use the same key +- * and effective key length. The key length is +- * determined by the size of the decrypted RSA key. +- */ +- if (!EVP_CIPHER_CTX_set_key_length(evp_ctx, (int)eklen)) { +- ek = tkey; +- eklen = tkeylen; +- tkey = NULL; +- } +- } +- if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,ek,NULL,0) <= 0) +- goto cleanup; ++ /* Decrypt the secret key with the private key. */ ++ ret = pkinit_decode_data(context, id_cryptoctx, ++ ASN1_STRING_get0_data(ri->enc_key), ++ ASN1_STRING_length(ri->enc_key), &ek, &eklen); ++ use_key = (ret || eklen != keylen) ? tkey : ek; + +- if (out == NULL) +- out=etmp; +- else +- BIO_push(out,etmp); +- etmp=NULL; ++ /* Allocate a plaintext buffer and decrypt data_body into it. */ ++ plaintext = malloc(data_body->length + blocksize); ++ if (plaintext == NULL) ++ goto cleanup; ++ if (!EVP_DecryptInit(evp_ctx, NULL, use_key, NULL)) ++ goto cleanup; ++ if (!EVP_DecryptUpdate(evp_ctx, plaintext, &plaintext_len, ++ data_body->data, data_body->length)) ++ goto cleanup; ++ if (!EVP_DecryptFinal(evp_ctx, plaintext + plaintext_len, &final_len)) ++ goto cleanup; ++ plaintext_len += final_len; + +- if (data_body->length > 0) +- bio = BIO_new_mem_buf(data_body->data, data_body->length); +- else { +- bio=BIO_new(BIO_s_mem()); +- BIO_set_mem_eof_return(bio,0); +- } +- BIO_push(out,bio); +- bio=NULL; ++ *len_out = plaintext_len; ++ *data_out = plaintext; ++ plaintext = NULL; ++ ok = 1; + +- if (0) { +- cleanup: +- if (out != NULL) BIO_free_all(out); +- if (etmp != NULL) BIO_free_all(etmp); +- if (bio != NULL) BIO_free_all(bio); +- out=NULL; +- } +- if (ek != NULL) { +- OPENSSL_cleanse(ek, eklen); +- OPENSSL_free(ek); +- } +- if (tkey != NULL) { +- OPENSSL_cleanse(tkey, tkeylen); +- OPENSSL_free(tkey); +- } +- return(out); ++cleanup: ++ EVP_CIPHER_CTX_free(evp_ctx); ++ zapfree(plaintext, plaintext_len); ++ zapfree(ek, eklen); ++ zapfree(tkey, keylen); ++ return ok; + } + + #ifdef DEBUG_DH +-- +2.46.0 + diff --git a/dist b/dist deleted file mode 100644 index ad8eb77ba59be071474988a034571694eaa9db8e..0000000000000000000000000000000000000000 --- a/dist +++ /dev/null @@ -1 +0,0 @@ -an7_9 diff --git a/krb5.spec b/krb5.spec index 89357a7868d503ad0e26bfff2fdcc179cb1820fc..c860900140e4f99fb1076407f363ca29b931f9da 100644 --- a/krb5.spec +++ b/krb5.spec @@ -13,7 +13,7 @@ Summary: The Kerberos network authentication system Name: krb5 Version: 1.15.1 -Release: 55%{anolis_release}%{?dist} +Release: 55%{anolis_release}%{?dist}.3 # - Maybe we should explode from the now-available-to-everybody tarball instead? # http://web.mit.edu/kerberos/dist/krb5/1.13/krb5-1.13.2-signed.tar @@ -145,8 +145,11 @@ Patch231: Fix-KDC-null-deref-on-TGS-inner-body-null-server.patch Patch232: Use-SHA256-instead-of-SHA1-for-PKINIT-CMS-digest.patch Patch233: Try-harder-to-avoid-password-change-replay-errors.patch Patch234: Fix-integer-overflows-in-PAC-parsing.patch -Patch235: Fix-CVE-2024-37370-and-CVE-2024-37371.patch -Patch236: Add-a-simple-support-header.patch +Patch235: Add-a-simple-DER-support-header.patch +Patch236: Fix-vulnerabilities-in-GSS-message-token-handling.patch +Patch237: Simply-OpenSSL-PKCS7-decryption-code.patch +Patch238: Remove-PKINIT-RSA-support.patch +Patch239: Generate-and-verify-message-MACs-in-libkrad.patch License: MIT URL: http://web.mit.edu/kerberos/www/ @@ -424,8 +427,11 @@ ONLY by kerberos itself. Do not depend on this package. %patch232 -p1 -b .Use-SHA256-instead-of-SHA1-for-PKINIT-CMS-digest %patch233 -p1 -b .Try-harder-to-avoid-password-change-replay-errors %patch234 -p1 -b .Fix-integer-overflows-in-PAC-parsing -%patch235 -p1 -b .Fix-CVE-2024-37370-and-CVE-2024-37371 -%patch236 -p1 -b .Add-a-simple-support-header +%patch235 -p1 -b .Add-a-simple-DER-support-header.patch +%patch236 -p1 -b .Fix-vulnerabilities-in-GSS-message-token-handling.patch +%patch237 -p1 -b .Simply-OpenSSL-PKCS7-decryption-code +%patch238 -p1 -b .Remove-PKINIT-RSA-support +%patch239 -p1 -b .Generate-and-verify-message-MACs-in-libkrad ln NOTICE LICENSE @@ -935,6 +941,10 @@ exit 0 %{_libdir}/libkadm5srv_mit.so.* %changelog +* Tue Nov 19 2024 zhuhongbo - 1.15.1-55.0.2.3 +- cve: fix CVE-2024-3596 +- libkrad: implement support for Message-Authenticator + * Tue Aug 20 2024 pangqing - 1.15.1-55.0.2 - Fix CVE-2024-37370 and CVE-2024-37371