]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
third_party:heimdal: import lorikeet-heimdal-202508180154
authorGary Lockyer <gary@catalyst.net.nz>
Mon, 18 Aug 2025 01:59:17 +0000 (13:59 +1200)
committerJennifer Sutton <jsutton@samba.org>
Mon, 8 Sep 2025 02:27:53 +0000 (02:27 +0000)
Import lorikeet-heimdal-202508180154 commits:
    beffefde5c6767589603cca98065378250eaae2c
    2073647157adb2791aa8b524e88e1a2d47268e5a
    dedeffb96b24288f6c3387cf48d82c7b9c3bbbf7

Add support for MS Key Trust Authentication

Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
Reviewed-by: Jennifer Sutton <jennifersutton@catalyst.net.nz>
Autobuild-User(master): Jennifer Sutton <jsutton@samba.org>
Autobuild-Date(master): Mon Sep  8 02:27:53 UTC 2025 on atb-devel-224

third_party/heimdal/kdc/kerberos5.c
third_party/heimdal/kdc/pkinit.c
third_party/heimdal/lib/hdb/Makefile.am
third_party/heimdal/lib/hdb/hdb.asn1
third_party/heimdal/lib/hdb/version-script.map
third_party/heimdal/tests/plugin/kdc_test_plugin.c

index 4c0362c8fd560d49ce23b0135bc9c05506258651..d0c646c328ccb56f0f26ccd505c5a587e191ca0e 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 #include "kdc_locl.h"
+#include "krb5_err.h"
 
 #ifdef TIME_T_SIGNED
 #if SIZEOF_TIME_T == 4
@@ -558,8 +559,10 @@ pa_pkinit_validate(astgs_request_t r, const PA_DATA *pa)
 
     ret = _kdc_pk_rd_padata(r, pa, &pkp);
     if (ret || pkp == NULL) {
-       if (ret == HX509_CERT_REVOKED) {
-           ret = KRB5_KDC_ERR_CLIENT_NOT_TRUSTED;      
+       if (ret == HX509_CERT_REVOKED ||
+           ret == KRB5_KDC_ERR_CLIENT_NOT_TRUSTED) {
+
+           ret = KRB5_KDC_ERR_CLIENT_NOT_TRUSTED;
        } else {
            ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
        }
index 9f1f4b106f0939578098f7600dbef68b9e8d19b9..6fdae939f8c19125aadf3fb6dec5faddf5774366 100644 (file)
@@ -33,6 +33,7 @@
  * SUCH DAMAGE.
  */
 
+#include "hdb_asn1.h"
 #include "kdc_locl.h"
 
 #ifdef PKINIT
@@ -384,6 +385,85 @@ get_dh_param(krb5_context context,
     return ret;
 }
 
+/**
+ * @brief Check to see if the certificate's public key matches any
+ *        of the trusted keys for this client.
+ *
+ * @param context[in] krb5_context
+ * @param client[in]  client hdb record
+ * @param cert[in]    certificate used to sign the request.
+ *
+ * @return 0 no error
+ *         KRB5_KDC_ERR_CLIENT_NOT_TRUSTED certificate public key does not
+ *                                         match any of the trusted keys for
+ *                                         this client
+ *         otherwise an error occurred processing the request.
+ */
+static krb5_error_code
+pk_check_key_trust( krb5_context context, hdb_entry *client, hx509_cert *cert)
+{
+
+    krb5_error_code ret = 0;
+    SubjectPublicKeyInfo spki;
+    HDB_extension *ext = NULL;
+    krb5_data buf;
+    size_t size = 0;
+    HDB_Ext_KeyTrust keys;
+    unsigned int i = 0;
+    krb5_boolean matched = FALSE;
+
+    memset(&spki, 0, sizeof(spki));
+    memset(&buf, 0, sizeof(buf));
+    memset(&keys, 0, sizeof(keys));
+
+    ext = hdb_find_extension(client, choice_HDB_extension_data_key_trust);
+    if (ext == NULL) {
+       ret = KRB5_KDC_ERR_CLIENT_NOT_TRUSTED;
+       krb5_set_error_message(context, ret, "Client has no public keys");
+       goto out;
+    }
+    ret = hx509_cert_get_SPKI(context->hx509ctx, *cert, &spki);
+    if (ret) {
+       ret = KRB5_KDC_ERR_CLIENT_NOT_TRUSTED;
+       krb5_set_error_message(
+           context, ret, "Unable to get certificate public key");
+       goto out1;
+    }
+
+    /*
+     * Does the certificates public key match any of the trusted public
+     * keys for this client?
+     */
+    ASN1_MALLOC_ENCODE(
+       SubjectPublicKeyInfo, buf.data , buf.length, &spki, &size, ret);
+    if (ret) {
+       krb5_set_error_message(
+           context, ret, "Unable to encode certificate public key");
+       goto out2;
+    }
+
+    keys = ext->data.u.key_trust;
+    for (i = 0; i < keys.len; i++) {
+       if (der_heim_octet_string_cmp(&buf, &keys.val[i].pub_key) == 0) {
+           matched = TRUE;
+           break;
+       }
+    }
+    if (!matched) {
+       ret = KRB5_KDC_ERR_CLIENT_NOT_TRUSTED;
+       krb5_set_error_message(
+           context, ret, "Client public keys do not match");
+    }
+    der_free_octet_string(&buf);
+
+out2:
+    free_SubjectPublicKeyInfo(&spki);
+out1:
+    free_HDB_extension(ext);
+out:
+    return ret;
+}
+
 krb5_error_code
 _kdc_pk_rd_padata(astgs_request_t priv,
                  const PA_DATA *pa,
@@ -634,21 +714,64 @@ _kdc_pk_rd_padata(astgs_request_t priv,
                                      &eContentType,
                                      &eContent,
                                      &signer_certs);
-       if (ret) {
+       if (ret == 0) {
+           if (signer_certs) {
+               ret = hx509_get_one_cert(
+                   context->hx509ctx, signer_certs, &cp->cert);
+               hx509_certs_free(&signer_certs);
+           }
+           if (ret) {
+               goto out;
+           }
+       } else if (ret == HX509_CMS_NO_RECIPIENT_CERTIFICATE ||
+                  ret == HX509_ISSUER_NOT_FOUND) {
+           /*
+            * Certificate not in the chain of trust,
+            * however it could be a self signed certificate for key trust
+            * logon.
+           */
+           int f = flags;
+           f |= HX509_CMS_VS_NO_VALIDATE;
+           ret = hx509_cms_verify_signed(context->hx509ctx,
+                                         cp->verify_ctx,
+                                         f,
+                                         signed_content.data,
+                                         signed_content.length,
+                                         NULL,
+                                         kdc_identity->certpool,
+                                         &eContentType,
+                                         &eContent,
+                                         &signer_certs);
+           if (ret != 0) {
+               char *s = hx509_get_error_string(context->hx509ctx, ret);
+               krb5_warnx(context,
+                          "PKINIT: failed to verify signature: %s: %d",
+                          s,
+                          ret);
+               free(s);
+               goto out;
+           }
+           if (signer_certs == NULL) {
+               ret = HX509_CMS_NO_RECIPIENT_CERTIFICATE;
+               goto out;
+           }
+           ret = hx509_get_one_cert(
+               context->hx509ctx, signer_certs, &cp->cert);
+           hx509_certs_free(&signer_certs);
+           if (ret != 0) {
+               goto out;
+           }
+           ret = pk_check_key_trust(context, client, &cp->cert);
+           if (ret) {
+               goto out;
+           }
+       } else {
            char *s = hx509_get_error_string(context->hx509ctx, ret);
            krb5_warnx(context, "PKINIT: failed to verify signature: %s: %d",
                       s, ret);
            free(s);
            goto out;
        }
-
-       if (signer_certs) {
-           ret = hx509_get_one_cert(context->hx509ctx, signer_certs,
-                                    &cp->cert);
-           hx509_certs_free(&signer_certs);
-       }
-       if (ret)
-           goto out;
     }
 
     /* Signature is correct, now verify the signed message */
index 1a6155be40af64ac44dadb5a611136595e9516b5..d36e6faecd3772f5cce5e2e48f078ebaf74e6de7 100644 (file)
@@ -29,6 +29,7 @@ gen_files_hdb = \
        asn1_HDB_Ext_Constrained_delegation_acl.c \
        asn1_HDB_Ext_KeyRotation.c \
        asn1_HDB_Ext_KeySet.c \
+       asn1_HDB_Ext_KeyTrust.c \
        asn1_HDB_Ext_Lan_Manager_OWF.c \
        asn1_HDB_Ext_Password.c \
        asn1_HDB_Ext_PKINIT_acl.c \
index 35b5e29e936934b46ab90d219d70fcb47956bb8a..9102e2b8f94d58a6ff8350824017f2a4f6df14e8 100644 (file)
@@ -192,6 +192,10 @@ KeyRotation ::= SEQUENCE {
 
 HDB-Ext-KeyRotation ::= SEQUENCE SIZE (1..3) OF KeyRotation
 
+HDB-Ext-KeyTrust ::= SEQUENCE OF SEQUENCE {
+       pub_key[0] OCTET STRING
+}
+
 HDB-extension ::= SEQUENCE {
         mandatory[0]    BOOLEAN,        -- kdc MUST understand this extension,
                                         --   if not the whole entry must
@@ -213,6 +217,7 @@ HDB-extension ::= SEQUENCE {
                principal-id[13]                INTEGER(-9223372036854775808..9223372036854775807),
                key-rotation[14]                HDB-Ext-KeyRotation,
                krb5-config[15]                 OCTET STRING,
+               key-trust[16]                   HDB-Ext-KeyTrust,
                ...
        },
        ...
index 058060dae0c1832c8f88fd7a97ecf44c1fa9fa25..6ef67410b2d36c4e703dd4a2c0aadbca7f2d0d0c 100644 (file)
@@ -159,6 +159,7 @@ HEIMDAL_HDB_1.0 {
                free_HDB_extensions;
                free_HDB_Ext_KeyRotation;
                free_HDB_Ext_KeySet;
+               free_HDB_Ext_KeyTrust;
                free_HDB_Ext_PKINIT_acl;
                free_hdb_keyset;
                free_HDB_keyset;
index 45855d7c949038f175bea0006b4e4d04b2a2aac6..33d7b910227a9a5f3b91abfa9c4c44e463e62ee5 100644 (file)
@@ -162,7 +162,7 @@ audit(void *ctx, astgs_request_t r)
 }
 
 static krb5plugin_kdc_ftable kdc_plugin = {
-    KRB5_PLUGIN_KDC_VERSION_11,
+    KRB5_PLUGIN_KDC_VERSION_12,
     init,
     fini,
     pac_generate,