*/
#include "includes.h"
+#include "hdb_asn1.h"
#include <hdb.h>
+#include <krb5.h>
+#include <hx_locl.h>
+#include "rfc2459_asn1.h"
#include "sdb.h"
#include "sdb_hdb.h"
#include "lib/krb5_wrap/krb5_samba.h"
return 0;
}
+
+/**
+* @brief Convert a sdb_pub_key to a HDB_Ext_KeyTrust_val
+*
+* @param s[in] A public key in sdb
+* @param h[in,out] The HDb_Ext_KeyTrust_val to populate
+*
+* @return 0 no error
+* >0 an error occurred
+*/
+static int sdb_pub_key_to_hdb_key_trust_val(const struct sdb_pub_key *s,
+ struct HDB_Ext_KeyTrust_val *h)
+{
+ krb5_error_code ret;
+ SubjectPublicKeyInfo spki = {};
+ RSAPublicKey rsa = {};
+ krb5_data buf = {};
+ AlgorithmIdentifier alg = {};
+ HEIM_ANY parameters = {};
+ uint8_t none[] = {0x05, 0x00};
+ size_t size = 0;
+
+ rsa.publicExponent.length = s->exponent.length;
+ rsa.publicExponent.data = s->exponent.data;
+ rsa.publicExponent.negative = 0;
+
+ rsa.modulus.length = s->modulus.length;
+ rsa.modulus.data = s->modulus.data;
+ rsa.modulus.negative = 0;
+
+ ASN1_MALLOC_ENCODE(
+ RSAPublicKey, buf.data , buf.length, &rsa, &size, ret);
+ if (ret != 0) {
+ goto out;
+ }
+
+ spki.subjectPublicKey.data = buf.data;
+ /*
+ * The public key length is in bits, but the buffer len is in bytes
+ * so need to convert it to bits.
+ */
+ spki.subjectPublicKey.length = buf.length * 8;
+
+ ret = der_copy_oid(ASN1_OID_ID_PKCS1_RSAENCRYPTION, &alg.algorithm);
+ if (ret != 0) {
+ goto out1;
+ }
+ parameters.data = &none;
+ parameters.length = sizeof(none);
+ alg.parameters = ¶meters;
+ spki.algorithm = alg;
+
+ /*
+ * This will be freed when sdb_pub_keys_to_hdb calls
+ * free_HDB_Ext_KeyTrust
+ */
+ ASN1_MALLOC_ENCODE(SubjectPublicKeyInfo,
+ h->pub_key.data,
+ h->pub_key.length,
+ &spki,
+ &size,
+ ret);
+ if (ret != 0) {
+ goto out2;
+ }
+
+out2:
+ der_free_oid(&alg.algorithm);
+out1:
+ der_free_octet_string(&buf);
+out:
+ return ret;
+}
+
+/**
+* @brief Convert any public keys for key trust authentication.
+*
+* @param s[in] The public keys that can be used for authentication
+* @param h[out] The converted public keys
+* @return 0 if there are no errors
+* >0 an error occurred
+*/
+static int sdb_pub_keys_to_hdb_ext(const struct sdb_pub_keys *s,
+ HDB_Ext_KeyTrust *h)
+{
+ int ret, i;
+ *h = (struct HDB_Ext_KeyTrust) {};
+
+ if (s->keys != NULL) {
+ h->val = malloc(s->len * sizeof(heim_octet_string));
+ if (h->val == NULL) {
+ return ENOMEM;
+ }
+ for (i = 0; i < s->len; i++) {
+ ret = sdb_pub_key_to_hdb_key_trust_val(
+ &s->keys[i], &h->val[i]);
+ if (ret != 0) {
+ free_HDB_Ext_KeyTrust(h);
+ return ret;
+ }
+ h->len++;
+ }
+ }
+ return 0;
+}
+
int sdb_entry_to_hdb_entry(krb5_context context,
const struct sdb_entry *s,
hdb_entry *h)
{
struct samba_kdc_entry *ske = s->skdc_entry;
+ struct HDB_Ext_KeyTrust kt = {};
unsigned int i;
int rc;
}
}
+ rc = sdb_pub_keys_to_hdb_ext(&s->pub_keys, &kt);
+ if (rc != 0) {
+ goto error;
+ }
+ if (kt.len > 0) {
+ HDB_extension ext = {};
+ ext.mandatory = FALSE;
+ ext.data.element = choice_HDB_extension_data_key_trust;
+ ext.data.u.key_trust = kt;
+ rc = hdb_replace_extension(context, h, &ext);
+ free_HDB_Ext_KeyTrust(&kt);
+ if (rc != 0) {
+ goto error;
+ }
+ }
+
h->context = ske;
if (ske != NULL) {
ske->kdc_entry = h;
--- /dev/null
+/*
+ * Unit tests for source4/kdc/sdb_to_hdb.c
+ *
+ * Copyright (C) Gary Lockyer 2025
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ *
+ */
+
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+
+#include "../../../third_party/cmocka/cmocka.h"
+
+#include "../sdb_to_hdb.c"
+#include "hdb_asn1.h"
+
+/*
+ * Test that an empty sdb_pub_key is handled without error and that
+ * the expected value is generated
+ */
+static void empty_key(void **state)
+{
+ uint8_t empty_key[] = {
+ 0x30, 0x1a, /* Sequence 26 bytes, 2 elements */
+ 0x30, 0x0d, /* Sequence 13 bytes, 2 elements */
+ 0x06, 0x09, /* OID 9 bytes, 1.2.840.113549.1.1.1 */
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+ 0x05, 0x00, /* Null */
+ 0x03, 0x09, 0x00, /* Bit string 9 bytes, zero unused bits */
+ 0x30, 0x06, /* Sequence 6 bytes, 2 elements */
+ 0x02, 0x01, 0x00, /* Integer 1 byte, value 0, Modulus */
+ 0x02, 0x01, 0x00, /* Integer 1 byte, value 0, Exponent */
+ };
+ struct sdb_pub_key in = {};
+ struct HDB_Ext_KeyTrust_val out = {};
+ int ret = 0;
+
+ ret = sdb_pub_key_to_hdb_key_trust_val(&in, &out);
+
+ assert_int_equal(0, ret);
+ assert_int_equal(sizeof(empty_key), out.pub_key.length);
+ assert_memory_equal(empty_key,
+ out.pub_key.data,
+ sizeof(empty_key));
+
+ free(out.pub_key.data);
+}
+
+/*
+ * Test that modulus and exponent with the leading bit set,
+ * are handled correctly
+ */
+static void test_leading_bit_handling(void **state)
+{
+ uint8_t expected_key[] = {
+ 0x30, 0x1c, /* Sequence 281 bytes, 2 elements */
+ 0x30, 0x0d, /* Sequence 13 bytes, 2 elements */
+ 0x06, 0x09, /* OID 9 bytes, 1.2.840.113549.1.1.1 */
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+ 0x05, 0x00, /* Null */
+ 0x03, 0x0b, 0x00, /* Bit string 11 bytes, zero unused bits */
+ 0x30, 0x08, /* Sequence 8 bytes, 2 elements */
+ 0x02, 0x02, 0x00, 0x80, /* Integer 2 byte, value 0, Modulus */
+ 0x02, 0x02, 0x00, 0x81, /* Integer 2 byte, value 0, Exponent */
+ /*
+ * As the modulus and exponent have the leading bit set
+ * They should get encoded with a leading 0 byte
+ */
+ };
+ uint8_t modulus[] = {0x80};
+ uint8_t exponent[] = {0x81};
+ struct sdb_pub_key in = {};
+ struct HDB_Ext_KeyTrust_val out = {};
+
+ int ret = 0;
+ in.bit_size = 8;
+
+ in.modulus.data = &modulus;
+ in.modulus.length = sizeof(modulus);
+
+ in.exponent.data = &exponent;
+ in.exponent.length = sizeof(exponent);
+
+
+ ret = sdb_pub_key_to_hdb_key_trust_val(&in, &out);
+
+ assert_int_equal(0, ret);
+ assert_int_equal(sizeof(expected_key), out.pub_key.length);
+ assert_memory_equal(expected_key,
+ out.pub_key.data,
+ sizeof(expected_key));
+
+ free(out.pub_key.data);
+}
+/*
+ * Test that modulus and exponent with the leading bit not set,
+ * are handled correctly
+ */
+static void test_no_leading_bit(void **state)
+{
+ uint8_t expected_key[] = {
+ 0x30, 0x1c, /* Sequence 281 bytes, 2 elements */
+ 0x30, 0x0d, /* Sequence 13 bytes, 2 elements */
+ 0x06, 0x09, /* OID 9 bytes, 1.2.840.113549.1.1.1 */
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+ 0x05, 0x00, /* Null */
+ 0x03, 0x0b, 0x00, /* Bit string 11 bytes, zero unused bits */
+ 0x30, 0x08, /* Sequence 8 bytes, 2 elements */
+ 0x02, 0x02, 0x78, 0x9a, /* Integer 2 byte, value 0, Modulus */
+ 0x02, 0x02, 0x65, 0x43, /* Integer 2 byte, value 0, Exponent */
+ };
+ uint8_t modulus[] = {0x78, 0x9a};
+ uint8_t exponent[] = {0x65, 0x43};
+ struct sdb_pub_key in = {};
+ struct HDB_Ext_KeyTrust_val out = {};
+
+ int ret = 0;
+ in.bit_size = 8;
+
+ in.modulus.data = &modulus;
+ in.modulus.length = sizeof(modulus);
+
+ in.exponent.data = &exponent;
+ in.exponent.length = sizeof(exponent);
+
+
+ ret = sdb_pub_key_to_hdb_key_trust_val(&in, &out);
+
+ assert_int_equal(0, ret);
+ assert_int_equal(sizeof(expected_key), out.pub_key.length);
+ assert_memory_equal(expected_key,
+ out.pub_key.data,
+ sizeof(expected_key));
+
+ free(out.pub_key.data);
+}
+
+int main(int argc, const char **argv)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(empty_key),
+ cmocka_unit_test(test_leading_bit_handling),
+ cmocka_unit_test(test_no_leading_bit),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}