#include "lib/messaging/irpc.h"
#include "librpc/gen_ndr/ndr_keycredlink.h"
#include "talloc.h"
+#include "util/data_blob.h"
#include "util/debug.h"
+#include "util/samba_util.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_KERBEROS
return code;
}
+
+
+/**
+ * @brief Copy the contents of a data blob to a krb5_data element
+ *
+ * @param[in] blob The source data blob
+ * @param[out] krb5 The target krb5_data element
+ *
+ * @return 0 No error
+ * ENOMEM memory allocation error
+ *
+ * @note Memory is allocated, with malloc and needs to be freed
+ */
+static krb5_error_code data_blob_to_krb5_data( DATA_BLOB *blob, krb5_data *krb5)
+{
+ krb5->data = malloc(blob->length);
+ if (krb5->data == NULL) {
+ return ENOMEM;
+ }
+ memcpy(krb5->data, blob->data, blob->length);
+ krb5->length = blob->length;
+ return 0;
+}
+
+
+/**
+ * @brief Copy the contents of a hex string data blob to a binary
+ * krb5_data element
+ *
+ * @param[in] blob The source data blob
+ * @param[out] krb5 The target krb5_data element
+ *
+ * @return 0 No error
+ * ENOMEM memory allocation error
+ * EINVAL data blob is not a valid hex string encoding
+ *
+ * @note Memory is allocated, with malloc and needs to be freed
+ */
+static krb5_error_code db_hex_str_to_krb5_data(
+ DATA_BLOB *blob,
+ krb5_data *krb5)
+{
+
+ size_t size = 0;
+
+ if( (blob->length%2) != 0) {
+ DBG_ERR(
+ "Hex string [%*.*s] "
+ "does not have an even length",
+ (int) blob->length,
+ (int) blob->length,
+ (char *) blob->data);
+ return EINVAL;
+ }
+ krb5->length = (blob->length/2);
+ krb5->data = malloc(krb5->length);
+ if (krb5->data == NULL) {
+ krb5->length = 0;
+ return ENOMEM;
+ }
+ size = strhex_to_str(krb5->data,
+ krb5->length,
+ (const char *) blob->data,
+ blob->length);
+ if (size != krb5->length) {
+ krb5->length = 0;
+ SAFE_FREE(krb5->data);
+ return EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * Helper macro to populate the data blob constants used by
+ * populate_certificate_mapping and parse_certificate_mapping
+ */
+#define DATA_BLOB_STRING(str) {\
+ .data = discard_const_p(uint8_t, str), \
+ .length = sizeof(str) - 1 \
+}
+static const DATA_BLOB ISSUER_NAME = DATA_BLOB_STRING("I");
+static const DATA_BLOB SUBJECT_NAME = DATA_BLOB_STRING("S");
+static const DATA_BLOB SERIAL_NUMBER = DATA_BLOB_STRING("SR");
+static const DATA_BLOB SUBJECT_KEY_IDENTIFIER = DATA_BLOB_STRING("SKI");
+static const DATA_BLOB PUBLIC_KEY = DATA_BLOB_STRING("SHA1-PUKEY");
+static const DATA_BLOB RFC822 = DATA_BLOB_STRING("RFC822");
+static const DATA_BLOB X509_HEADER = DATA_BLOB_STRING("X509:");
+#undef DATA_BLOB_STRING
+
+/**
+ * @brief Populate the certificate mapping from the tag and value
+ *
+ * @param[in] tag the tag i.e. I, S, SKI, .....
+ * @param[in] value the value associated with the tag
+ * @param[in,out] mapping the mapping to be updated
+ *
+ * @return 0 No error
+ * EINVAL tag or value are invalid
+ * ENOMEM memory allocation error
+ *
+ * @note Memory is allocated, with malloc and needs to be freed with
+ * sdb_certificate_mapping_free
+ */
+static krb5_error_code populate_certificate_mapping(
+ DATA_BLOB *tag,
+ DATA_BLOB *value,
+ struct sdb_certificate_mapping *mapping)
+{
+ krb5_error_code ret = 0;
+
+ if (tag->length == 0) {
+ DBG_WARNING("altSecurityIdentities empty tag");
+ return EINVAL;
+ }
+ if (value->length == 0) {
+ DBG_WARNING("altSecurityIdentities no value for %*.*s",
+ (int) tag->length,
+ (int) tag->length,
+ tag->data);
+ return EINVAL;
+ }
+
+ if (data_blob_cmp(&ISSUER_NAME, tag) == 0) {
+ /* discard any previous value */
+ if (mapping->issuer_name.data != NULL) {
+ SAFE_FREE(mapping->issuer_name.data);
+ mapping->issuer_name.length = 0;
+ }
+ ret = data_blob_to_krb5_data(value, &mapping->issuer_name);
+
+ } else if (data_blob_cmp(&SUBJECT_NAME, tag) == 0) {
+ /* discard any previous value */
+ if (mapping->subject_name.data != NULL) {
+ SAFE_FREE(mapping->subject_name.data);
+ mapping->subject_name.length = 0;
+ }
+ ret = data_blob_to_krb5_data(value, &mapping->subject_name);
+
+ } else if (data_blob_cmp(&RFC822, tag) == 0) {
+ /* discard any previous value */
+ if (mapping->rfc822.data != NULL) {
+ SAFE_FREE(mapping->rfc822.data);
+ mapping->rfc822.length = 0;
+ }
+ ret = data_blob_to_krb5_data(value, &mapping->rfc822);
+
+ } else if (data_blob_cmp(&SERIAL_NUMBER, tag ) == 0) {
+ /* discard any previous value */
+ if (mapping->serial_number.data != NULL) {
+ SAFE_FREE(mapping->serial_number.data);
+ mapping->serial_number.length = 0;
+ }
+ ret = db_hex_str_to_krb5_data(value, &mapping->serial_number);
+
+ } else if (data_blob_cmp(&SUBJECT_KEY_IDENTIFIER, tag) == 0) {
+ /* discard any previous value */
+ if (mapping->ski.data != NULL) {
+ SAFE_FREE(mapping->ski.data);
+ mapping->ski.length = 0;
+ }
+ ret = db_hex_str_to_krb5_data(value, &mapping->ski);
+
+ } else if (data_blob_cmp(&PUBLIC_KEY, tag) == 0) {
+ /* discard any previous value */
+ if (mapping->public_key.data != NULL) {
+ SAFE_FREE(mapping->public_key.data);
+ mapping->public_key.length = 0;
+ }
+ ret = db_hex_str_to_krb5_data(value, &mapping->public_key);
+
+ } else {
+ DBG_WARNING("altSecurityIdentities invalid tag %*.*s",
+ (int) tag->length,
+ (int) tag->length,
+ tag->data);
+ ret = EINVAL;
+ }
+ return ret;
+}
+
+
+/**
+ * @brief does the krb5 element have a value?
+ *
+ * @param[in] krb5 The target krb5_data element
+ *
+ * @return TRUE krb5 has a value
+ * FALSE krb5 has no value i.e. it's empty
+ */
+static krb5_boolean krb5_data_has_value(krb5_data *krb5)
+{
+ if (krb5->data == NULL || krb5->length == 0) {
+ return FALSE;
+ }
+ return TRUE;
+}
+/**
+ * @brief is the certificate mapping a strong mapping?
+ *
+ * @param[in] mapping the certificate mapping to examine.
+ *
+ * @return TRUE mapping is strong
+ * FALSE mapping is weak
+ */
+static krb5_boolean is_strong_certificate_mapping(
+ struct sdb_certificate_mapping *mapping)
+{
+ /* Subject Key Identifier */
+ if (krb5_data_has_value(&mapping->ski)) {
+ return TRUE;
+ }
+ /* Public Key */
+ if (krb5_data_has_value(&mapping->public_key)) {
+ return TRUE;
+ }
+ /* Issuer Serial Number */
+ if (krb5_data_has_value(&mapping->issuer_name) &&
+ krb5_data_has_value(&mapping->serial_number)
+ ) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ * @brief Parse a certificate mapping string
+ *
+ * The expected format is a header "X509:" and then a series of
+ * tag value pairs "<tag>value"
+ * where tag is one of:
+ * <I> Issuer Name
+ * <S> Subject Name
+ * <SR> Serial Number
+ * <SKI> SKI Subject Key Identifier
+ * <SHA1-PUBKEY> SHA1 checksum of the public key
+ * <RFC822> Email address
+ *
+ *
+ * @param[in] value ldb value containing an altSecurityIdentities entry
+ * @param[out] mapping data parsed from value
+ *
+ * @note it is the callers responsibility to free any memory allocated
+ * in the mapping with a call to sdb_certificate_mapping_free.
+ * EVEN if an error is returned, as mapping may have been partially
+ * updated.
+ *
+ * @return 0 No error
+ * EINVAL altSecurityIdentities entry was invalid
+ * ENOMEM memory allocation error
+ */
+static krb5_error_code parse_certificate_mapping(
+ struct ldb_val *ldb_value,
+ struct sdb_certificate_mapping *mapping)
+{
+ krb5_error_code ret = 0;
+ size_t length = ldb_value->length;
+ uint8_t *data = ldb_value->data;
+ DATA_BLOB tag = data_blob_null;
+ DATA_BLOB value = data_blob_null;
+ enum {
+ start_state,
+ tag_state,
+ value_state
+ } state;
+ size_t i = 0;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ /*
+ * Ensure that there is data, and it starts with X509:
+ * other wise ignore the entry and return ENOENT
+ */
+ if (data == NULL || length == 0) {
+ DBG_DEBUG("altSecurityIdentities, is empty");
+ ret = ENOENT;
+ goto out;
+ }
+ if (length <= X509_HEADER.length ||
+ memcmp(X509_HEADER.data, data, X509_HEADER.length) != 0) {
+ DBG_DEBUG("altSecurityIdentities, entry is not X509 ignoring");
+ ret = ENOENT;
+ goto out;
+ }
+
+ tag = data_blob_talloc(tmp_ctx, NULL, ldb_value->length + 1);
+ if (tag.data == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+ tag.length = 0;
+ value = data_blob_talloc(tmp_ctx, NULL, ldb_value->length + 1);
+ if (value.data == NULL) {
+ ret = ENOMEM;
+ goto out;
+ }
+ value.length = 0;
+
+ state = start_state;
+ /* point to the first byte after the header "X509:" */
+ for( i = 5; i < length; i++) {
+ uint8_t c = data[i];
+ switch (state) {
+ case start_state:
+ /* Ignore characters between the : and the first < */
+ if (c == '<') {
+ state = tag_state;
+ tag.length = 0;
+ }
+ break;
+ case tag_state:
+ if (c == '>') {
+ state = value_state;
+ tag.data[tag.length] = '\0';
+ value.length = 0;
+ } else {
+ tag.data[tag.length] = c;
+ tag.length++;
+ }
+ break;
+ case value_state:
+ if (c == '<') {
+ value.data[value.length] = '\0';
+ ret = populate_certificate_mapping(
+ &tag, &value, mapping);
+ if (ret != 0) {
+ goto out;
+ }
+ state = tag_state;
+ value.length = 0;
+ tag.length = 0;
+ } else {
+ value.data[value.length] = c;
+ value.length++;
+ }
+ break;
+ }
+ }
+ if (state != value_state) {
+ DBG_WARNING("altSecurityIdentities, expected a value");
+ ret = EINVAL;
+ goto out;
+ }
+ value.data[value.length] = '\0';
+ ret = populate_certificate_mapping(
+ &tag, &value, mapping);
+ if (ret != 0) {
+ goto out;
+ }
+ mapping->strong_mapping = is_strong_certificate_mapping(mapping);
+
+out:
+ TALLOC_FREE(tmp_ctx);
+ return ret;
+}
+
+
+/**
+ * @brief extract the certificate mappings for PKINIT from the
+ * ldb message.
+ *
+ * Processes the "X509:" certificate mappings in altSecurityIdentities.
+ *
+ * @param mem_ctx[in] talloc memory context
+ * @param lp_ctx[in] parameter context containing the config options
+ * @param msg[in] ldb message containing the certificate mappings
+ * @param entry[out] entry will be updated with the certificate mappings
+ *
+ * @note Invalid entries will be ignored
+ *
+ * @return 0 No error, and there are zero or more certificate mappings
+ * >0 Errors detected
+ */
+static krb5_error_code get_certificate_mappings(
+ TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx,
+ struct ldb_message *msg,
+ struct sdb_entry *entry)
+{
+ krb5_error_code ret = 0;
+ struct ldb_message_element *el = NULL;
+ size_t i = 0;
+ struct sdb_certificate_mappings mappings = {};
+ unsigned int backdating = 0;
+ time_t created = 0;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ if (tmp_ctx == NULL) {
+ return ENOMEM;
+ }
+
+ mappings.enforcement_mode =
+ lpcfg_strong_certificate_binding_enforcement(lp_ctx);
+
+ backdating = lpcfg_certificate_backdating_compensation(lp_ctx);
+ created = ldb_msg_find_krb5time_ldap_time(msg, "whenCreated", 0);
+ if (created == 0) {
+ DBG_ERR("No whenCreated entry, unable to continue");
+ ret = EINVAL;
+ goto out;
+ }
+ mappings.valid_certificate_start = created - (backdating * 60);
+
+ el = ldb_msg_find_element(msg, "altSecurityIdentities");
+ if (el == NULL || el->num_values == 0) {
+ DBG_DEBUG("No altSecurityIdentities nothing to do");
+ ret = 0;
+ entry->mappings = mappings;
+ goto out;
+ }
+
+ for (i = 0; i < el->num_values; i++) {
+ struct sdb_certificate_mapping mapping = {};
+ ret = parse_certificate_mapping(&el->values[i], &mapping);
+ if (ret != 0) {
+ DBG_DEBUG("Ignoring invalid altSecurityIdentities"
+ " entry [%*.*s]",
+ (int)el->values[i].length,
+ (int)el->values[i].length,
+ (char *)el->values[i].data);
+ sdb_certificate_mapping_free(&mapping);
+ continue;
+ }
+ if (mappings.mappings == NULL) {
+ mappings.len = 0;
+ mappings.mappings = calloc(1, sizeof(mapping));
+ if (mappings.mappings == NULL) {
+ sdb_certificate_mapping_free(&mapping);
+ ret = ENOMEM;
+ goto out;
+ }
+ } else {
+ struct sdb_certificate_mapping *old_mappings =
+ mappings.mappings;
+ mappings.mappings= realloc_p(
+ mappings.mappings,
+ struct sdb_certificate_mapping,
+ mappings.len + 1);
+ if (mappings.mappings == NULL) {
+ mappings.mappings = old_mappings;
+ sdb_certificate_mappings_free(&mappings);
+ sdb_certificate_mapping_free(&mapping);
+ ret = ENOMEM;
+ goto out;
+ }
+ }
+ mappings.mappings[mappings.len] = mapping;
+ mappings.len++;
+ }
+ entry->mappings = mappings;
+ ret = 0;
+
+out:
+ TALLOC_FREE(tmp_ctx);
+ return ret;
+}
+
+
/**
* @brief Extract the KeyMaterial from a KEYCREDENTIALLINK_BLOB
* as a KeyMaterialInternal structure.
}
*pub_key = NULL;
- /* Unpack the binary DN */
dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, value, DSDB_SYNTAX_BINARY_DN);
if (dsdb_dn == NULL) {
DBG_WARNING("Unable to parse KEYCREDENTIALLINK_BLOB, BinaryDn");
if (ret != 0) {
goto out;
}
+ ret = get_certificate_mappings(
+ tmp_ctx, kdc_db_ctx->lp_ctx, msg, entry);
+ if (ret != 0) {
+ goto out;
+ }
talloc_steal(kdc_db_ctx, p);
#include "krb5-protos.h"
#include "ldb.h"
#include "samdb/samdb.h"
+#include "sdb.h"
#include "talloc.h"
#include "util/data_blob.h"
#include "util/debug.h"
return 1;
}
+int certificate_binding_enforcement = 0;
+int lpcfg_strong_certificate_binding_enforcement(
+ struct loadparm_context *lp_ctx)
+{
+ return certificate_binding_enforcement;
+}
+
+int certificate_backdating_compensation = 0;
+int lpcfg_certificate_backdating_compensation(
+ struct loadparm_context *lp_ctx)
+{
+ return certificate_backdating_compensation;
+}
+
/******************************************************************************
* Test helper functions
*****************************************************************************/
-static void add_msDS_KeyCredentialLink(TALLOC_CTX *mem_ctx,
- struct ldb_message *msg,
+static void add_msDS_KeyCredentialLink(struct ldb_message *msg,
size_t size,
uint8_t *data)
{
DATA_BLOB key_cred_val = {.length = size, .data = data};
- char *hex_value = data_blob_hex_string_upper(mem_ctx, &key_cred_val);
+ char *hex_value = data_blob_hex_string_upper(msg, &key_cred_val);
size_t hex_len = strlen(hex_value);
char *binary_dn = talloc_asprintf(
- mem_ctx, "B:%zu:%s:DC=EXAMPLE,DC=COM", hex_len, hex_value);
+ msg, "B:%zu:%s:DC=EXAMPLE,DC=COM", hex_len, hex_value);
TALLOC_FREE(hex_value);
/* Add the data to msDS-KeyCredentialLink */
ldb_msg_add_string(msg, "msDS-KeyCredentialLink", binary_dn);
}
+static struct ldb_val *get_ldb_string(TALLOC_CTX *mem_ctx, const char * str) {
+ char *string = talloc_asprintf(
+ mem_ctx, "%s", str);
+
+ size_t len = strlen(string);
+
+ struct ldb_val *value = talloc_zero(mem_ctx, struct ldb_val);
+
+ value->data = (uint8_t *) string;
+ value->length = len;
+ return value;
+}
+
+static void add_altSecurityIdentities(struct ldb_message *msg,
+ const char *str)
+{
+ /* Add the data to altSecurityIdentities */
+ ldb_msg_add_string(msg, "altSecurityIdentities", str);
+}
+
+static void add_whenCreated(struct ldb_message *msg,
+ time_t created)
+{
+ char* ts = ldb_timestring(msg, created);
+ ldb_msg_add_string(msg, "whenCreated", ts);
+}
+
static void add_empty_msDS_KeyCredentialLink_DN(TALLOC_CTX *mem_ctx,
struct ldb_message *msg)
{
- char *binary_dn = talloc_asprintf(mem_ctx, "B:0::DC=EXAMPLE,DC=COM");
+ char *binary_dn = talloc_asprintf(msg, "B:0::DC=EXAMPLE,DC=COM");
/* Add the data to msDS-KeyCredentialLink */
ldb_msg_add_string(msg, "msDS-KeyCredentialLink", binary_dn);
}
+static void add_empty_altSecurities(
+ TALLOC_CTX *mem_ctx,
+ struct ldb_message *msg)
+{
+ /* Add an empty altSecurityIdentities */
+ ldb_msg_add_string(msg, "altSecurityIdentifiers", "");
+}
+
static struct ldb_message *create_ldb_message(TALLOC_CTX *mem_ctx)
{
DATA_BLOB sid_val = data_blob_null;
"atestuser@test.samba.org");
msg = ldb_msg_new(mem_ctx);
+
err = samba_kdc_message2entry(krb5_ctx,
kdc_db_ctx,
mem_ctx,
struct sdb_entry entry = {};
krb5_error_code err = 0;
+ time_t now = time(NULL);
/* Set up */
smb_krb5_init_context_common(&krb5_ctx);
/* Create the ldb_message */
msg = create_ldb_message(mem_ctx);
+ add_whenCreated(msg, now);
err = samba_kdc_message2entry(krb5_ctx,
kdc_db_ctx,
struct sdb_entry entry = {};
krb5_error_code err = 0;
+ time_t now = time(NULL);
/* Set up */
smb_krb5_init_context_common(&krb5_ctx);
/* Create the ldb_message */
msg = create_ldb_message(mem_ctx);
add_empty_msDS_KeyCredentialLink_DN(mem_ctx, msg);
+ add_whenCreated(msg, now);
err = samba_kdc_message2entry(krb5_ctx,
kdc_db_ctx,
struct sdb_entry entry = {};
krb5_error_code err = 0;
+ time_t now = time(NULL);
/* Set up */
smb_krb5_init_context_common(&krb5_ctx);
/* Create the ldb_message */
msg = create_ldb_message(mem_ctx);
- add_msDS_KeyCredentialLink(mem_ctx,
- msg,
+ add_msDS_KeyCredentialLink(msg,
sizeof(BCRYPT_KEY_CREDENTIAL_LINK),
BCRYPT_KEY_CREDENTIAL_LINK);
+ add_whenCreated(msg, now);
err = samba_kdc_message2entry(krb5_ctx,
kdc_db_ctx,
/* Create the ldb_message */
msg = create_ldb_message(mem_ctx);
- add_msDS_KeyCredentialLink(mem_ctx,
- msg,
+ add_msDS_KeyCredentialLink(msg,
sizeof(KEY_CREDENTIAL_LINK),
KEY_CREDENTIAL_LINK);
/* Create the ldb_message */
msg = create_ldb_message(mem_ctx);
- add_msDS_KeyCredentialLink(mem_ctx,
- msg,
+ add_msDS_KeyCredentialLink(msg,
sizeof(KEY_CREDENTIAL_LINK),
KEY_CREDENTIAL_LINK);
/* Create the ldb_message */
msg = create_ldb_message(mem_ctx);
- add_msDS_KeyCredentialLink(mem_ctx,
- msg,
+ add_msDS_KeyCredentialLink(msg,
sizeof(KEY_CREDENTIAL_LINK),
KEY_CREDENTIAL_LINK);
/* Create the ldb_message */
msg = create_ldb_message(mem_ctx);
- add_msDS_KeyCredentialLink(mem_ctx,
- msg,
+ add_msDS_KeyCredentialLink(msg,
sizeof(KEY_CREDENTIAL_LINK),
KEY_CREDENTIAL_LINK);
/* Create the ldb_message */
msg = ldb_msg_new(mem_ctx);
- add_msDS_KeyCredentialLink(mem_ctx,
- msg,
+ add_msDS_KeyCredentialLink(msg,
sizeof(KEY_CREDENTIAL_LINK),
KEY_CREDENTIAL_LINK);
/* Create the ldb_message */
msg = create_ldb_message(mem_ctx);
- add_msDS_KeyCredentialLink(mem_ctx,
- msg,
+ add_msDS_KeyCredentialLink(msg,
sizeof(BCRYPT_KEY_CREDENTIAL_LINK),
BCRYPT_KEY_CREDENTIAL_LINK);
/* Create the ldb_message */
msg = create_ldb_message(mem_ctx);
- add_msDS_KeyCredentialLink(mem_ctx,
- msg,
+ add_msDS_KeyCredentialLink(msg,
sizeof(TPM_KEY_CREDENTIAL_LINK),
TPM_KEY_CREDENTIAL_LINK);
/* Create the ldb_message */
msg = create_ldb_message(mem_ctx);
- add_msDS_KeyCredentialLink(mem_ctx,
- msg,
+ add_msDS_KeyCredentialLink(msg,
sizeof(DER_KEY_CREDENTIAL_LINK),
DER_KEY_CREDENTIAL_LINK);
/* Create the ldb_message */
msg = create_ldb_message(mem_ctx);
- add_msDS_KeyCredentialLink(mem_ctx,
- msg,
+ add_msDS_KeyCredentialLink(msg,
sizeof(DER_KEY_CREDENTIAL_LINK),
DER_KEY_CREDENTIAL_LINK);
- add_msDS_KeyCredentialLink(mem_ctx,
- msg,
+ add_msDS_KeyCredentialLink(msg,
sizeof(TPM_KEY_CREDENTIAL_LINK),
TPM_KEY_CREDENTIAL_LINK);
- add_msDS_KeyCredentialLink(mem_ctx,
- msg,
+ add_msDS_KeyCredentialLink(msg,
sizeof(BCRYPT_KEY_CREDENTIAL_LINK),
BCRYPT_KEY_CREDENTIAL_LINK);
TALLOC_FREE(mem_ctx);
}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles an empty ldb string value
+ */
+static void empty_string_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ struct ldb_val *value = get_ldb_string(mem_ctx, "");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(ENOENT, err);
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles an ldb string value containing
+ * just the X509: tag
+ */
+static void header_only_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ struct ldb_val *value = get_ldb_string(mem_ctx, "X509:");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(ENOENT, err);
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles an ldb string value containing
+ * a non X509 mapping
+ */
+static void not_x509_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ struct ldb_val *value = get_ldb_string(mem_ctx, "KERBEROS:");
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(ENOENT, err);
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles an ldb string value without
+ * a tag
+ */
+static void no_tag_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ struct ldb_val *value = get_ldb_string(mem_ctx, "X509:No tag here");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(EINVAL, err);
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles an ldb string value without
+ * a tag close character '>'
+ */
+static void no_tag_close_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ struct ldb_val *value = get_ldb_string(mem_ctx, "X509:<No tag close");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(EINVAL, err);
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles an ldb string value with
+ * an empty tag
+ */
+static void empty_tag_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ struct ldb_val *value = get_ldb_string(mem_ctx, "X509:<>Empty tag");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(EINVAL, err);
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles an ldb string value with
+ * no value
+ */
+static void no_value_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ struct ldb_val *value = get_ldb_string(mem_ctx, "X509:<I>");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(EINVAL, err);
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles an issuer name
+ *
+ */
+static void issuer_name_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ struct ldb_val *value = get_ldb_string(mem_ctx, "X509:<I>Issuer");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(0, err);
+ assert_int_equal(6, mapping.issuer_name.length);
+ assert_memory_equal("Issuer", mapping.issuer_name.data, 6);
+ assert_false(mapping.strong_mapping);
+
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles duplicate issuer names
+ *
+ */
+static void duplicate_issuer_name_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ struct ldb_val *value
+ = get_ldb_string(mem_ctx, "X509:<I>Issuer<I>Duplicate");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(0, err);
+
+ /* Only use the last value in the event of duplicate values */
+ assert_int_equal(9, mapping.issuer_name.length);
+ assert_memory_equal("Duplicate", mapping.issuer_name.data, 9);
+ assert_false(mapping.strong_mapping);
+
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles a subject name
+ *
+ */
+static void subject_name_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ struct ldb_val *value = get_ldb_string(mem_ctx, "X509:<S>Subject");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(0, err);
+ assert_int_equal(7, mapping.subject_name.length);
+ assert_memory_equal("Subject", mapping.subject_name.data, 7);
+ assert_false(mapping.strong_mapping);
+
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles duplicate subject names
+ *
+ */
+static void duplicate_subject_name_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ struct ldb_val *value =
+ get_ldb_string(mem_ctx, "X509:<S>Subject<S>A repeat");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(0, err);
+ /* Only use the last value in the event of duplicate values */
+ assert_int_equal(8, mapping.subject_name.length);
+ assert_memory_equal("A repeat", mapping.subject_name.data, 8);
+ assert_false(mapping.strong_mapping);
+
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles an issuer name and subject
+ * name.
+ *
+ */
+static void issuer_and_subject_name_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ struct ldb_val *value = get_ldb_string(
+ mem_ctx, "X509:<S>SubjectsName<I>TheNameOfTheIssuer");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(0, err);
+ assert_int_equal(12, mapping.subject_name.length);
+ assert_memory_equal("SubjectsName", mapping.subject_name.data, 12);
+ assert_int_equal(18, mapping.issuer_name.length);
+ assert_memory_equal("TheNameOfTheIssuer", mapping.issuer_name.data, 18);
+ assert_false(mapping.strong_mapping);
+
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles a serial number
+ *
+ */
+static void serial_number_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ uint8_t sn[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+ struct ldb_val *value
+ = get_ldb_string(mem_ctx, "X509:<SR>0123456789abcdef");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(0, err);
+ assert_int_equal(sizeof(sn), mapping.serial_number.length);
+ assert_memory_equal(sn, mapping.serial_number.data, sizeof(sn));
+ /* The Serial number on it's own is not a strong mapping */
+ assert_false(mapping.strong_mapping);
+
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles multiple serial numbers
+ *
+ */
+static void duplicate_serial_number_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ uint8_t sn[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+ struct ldb_val *value
+ = get_ldb_string(
+ mem_ctx,
+ "X509:<SR>fedcba98765410<SR>0123456789abcdef");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(0, err);
+ assert_int_equal(sizeof(sn), mapping.serial_number.length);
+ assert_memory_equal(sn, mapping.serial_number.data, sizeof(sn));
+ /* The Serial number on it's own is not a strong mapping */
+ assert_false(mapping.strong_mapping);
+
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles a serial number and
+ * issuer name
+ *
+ */
+static void serial_number_and_issuer_name_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ uint8_t sn[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+ struct ldb_val *value = get_ldb_string(
+ mem_ctx, "X509:<SR>0123456789abcdef<I>TheIssuer");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(0, err);
+ assert_int_equal(sizeof(sn), mapping.serial_number.length);
+ assert_memory_equal(sn, mapping.serial_number.data, sizeof(sn));
+ assert_int_equal(9, mapping.issuer_name.length);
+ assert_memory_equal("TheIssuer", mapping.issuer_name.data, 9);
+ assert_true(mapping.strong_mapping);
+
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles an SKI (Subject Key Identifier)
+ */
+static void ski_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ uint8_t ski[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+ struct ldb_val *value = get_ldb_string(
+ mem_ctx, "X509:<SKI>0123456789abcdef");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(0, err);
+ assert_int_equal(sizeof(ski), mapping.ski.length);
+ assert_memory_equal(ski, mapping.ski.data, sizeof(ski));
+ assert_true(mapping.strong_mapping);
+
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles multiple
+ * SKI (Subject Key Identifier) values
+ */
+static void duplicate_ski_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ uint8_t ski[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+ struct ldb_val *value = get_ldb_string(
+ mem_ctx, "X509:<SKI>010203040506<SKI>0123456789abcdef");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(0, err);
+ assert_int_equal(sizeof(ski), mapping.ski.length);
+ assert_memory_equal(ski, mapping.ski.data, sizeof(ski));
+ assert_true(mapping.strong_mapping);
+
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles a public key
+ */
+static void public_key_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ uint8_t pubkey[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+ struct ldb_val *value = get_ldb_string(
+ mem_ctx, "X509:<SHA1-PUKEY>0123456789abcdef");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(0, err);
+ assert_int_equal(sizeof(pubkey), mapping.public_key.length);
+ assert_memory_equal(pubkey, mapping.public_key.data, sizeof(pubkey));
+ assert_true(mapping.strong_mapping);
+
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles multiple public keys
+ */
+static void duplicate_public_key_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ uint8_t pubkey[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+ struct ldb_val *value = get_ldb_string(
+ mem_ctx,
+ "X509:<SHA1-PUKEY>adcdefabcdefabcdef"
+ "<SHA1-PUKEY>0123456789abcdef");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(0, err);
+ assert_int_equal(sizeof(pubkey), mapping.public_key.length);
+ assert_memory_equal(pubkey, mapping.public_key.data, sizeof(pubkey));
+ assert_true(mapping.strong_mapping);
+
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that non hex strings are rejected
+ */
+static void non_hex_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ struct ldb_val *value = get_ldb_string(
+ mem_ctx, "X509:<SHA1-PUKEY>This is not a hex string");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(EINVAL, err);
+ assert_int_equal(0, mapping.public_key.length);
+
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that odd length hex strings are rejected
+ */
+static void odd_length_hex_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ struct ldb_val *value = get_ldb_string(
+ mem_ctx, "X509:<SHA1-PUKEY>abcde");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(EINVAL, err);
+ assert_int_equal(0, mapping.public_key.length);
+
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Ensure that parse_certificate_mapping handles an RFC822 identifier
+ */
+static void RFC822_parse_certificate_mapping(void **state)
+{
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ krb5_error_code err = 0;
+ struct sdb_certificate_mapping mapping = {};
+ struct ldb_val *value = get_ldb_string(
+ mem_ctx, "X509:<RFC822>test@example.com");
+
+ err = parse_certificate_mapping(value, &mapping);
+
+ assert_int_equal(0, err);
+ assert_int_equal(16, mapping.rfc822.length);
+ assert_memory_equal("test@example.com", mapping.rfc822.data, 16);
+ assert_false(mapping.strong_mapping);
+
+ sdb_certificate_mapping_free(&mapping);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Test get_certificate_mapping handles multiple entries
+ *
+ */
+static void multiple_cert_mappings(void **state)
+{
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ struct loadparm_context *lp_ctx = loadparm_init(mem_ctx);
+ struct ldb_message *msg = NULL;
+ krb5_error_code err = 0;
+ struct sdb_entry entry = {};
+ uint8_t ski[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+
+ time_t now = time(NULL);
+ const int backdate = 26280000; /* Fifty years */
+ const int expected_val_cert_start = now - (backdate * 60);
+
+ /* Create the ldb_message */
+ msg = create_ldb_message(mem_ctx);
+ add_altSecurityIdentities(msg,
+ "X509:<SKI>0123456789abcdef");
+ add_altSecurityIdentities(msg,
+ "X509:<RFC822>test@example.com");
+ add_whenCreated(msg, now);
+
+ certificate_binding_enforcement = 1;
+ certificate_backdating_compensation = backdate;
+ err = get_certificate_mappings(mem_ctx, lp_ctx, msg, &entry);
+
+ assert_int_equal(0, err);
+
+ assert_int_equal(2, entry.mappings.len);
+ assert_int_equal(1, entry.mappings.enforcement_mode);
+ assert_int_equal(
+ expected_val_cert_start,
+ entry.mappings.valid_certificate_start);
+
+ assert_int_equal(sizeof(ski), entry.mappings.mappings[0].ski.length);
+ assert_memory_equal(
+ ski, entry.mappings.mappings[0].ski.data, sizeof(ski));
+ assert_true(entry.mappings.mappings[0].strong_mapping);
+
+ assert_int_equal(16, entry.mappings.mappings[1].rfc822.length);
+ assert_memory_equal(
+ "test@example.com", entry.mappings.mappings[1].rfc822.data, 16);
+ assert_false(entry.mappings.mappings[1].strong_mapping);
+
+ sdb_entry_free(&entry);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Test get_certificate_mapping handles a single entry
+ *
+ */
+static void single_cert_mapping(void **state)
+{
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ struct loadparm_context *lp_ctx = loadparm_init(mem_ctx);
+ struct ldb_message *msg = NULL;
+ krb5_error_code err = 0;
+ struct sdb_entry entry = {};
+ uint8_t ski[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+
+ time_t now = time(NULL);
+ const int backdate = 525600; /* One year */
+ const int expected_val_cert_start = now - (backdate * 60);
+
+ /* Create the ldb_message */
+ msg = create_ldb_message(mem_ctx);
+ add_altSecurityIdentities(msg,
+ "X509:<SKI>0123456789abcdef");
+ add_whenCreated(msg, now);
+
+ certificate_binding_enforcement = 2;
+ certificate_backdating_compensation = backdate;
+ err = get_certificate_mappings(mem_ctx, lp_ctx, msg, &entry);
+
+ assert_int_equal(0, err);
+
+ assert_int_equal(1, entry.mappings.len);
+ assert_int_equal(2, entry.mappings.enforcement_mode);
+ assert_int_equal(
+ expected_val_cert_start,
+ entry.mappings.valid_certificate_start);
+
+ assert_int_equal(sizeof(ski), entry.mappings.mappings[0].ski.length);
+ assert_memory_equal(
+ ski, entry.mappings.mappings[0].ski.data, sizeof(ski));
+ assert_true(entry.mappings.mappings[0].strong_mapping);
+
+ sdb_entry_free(&entry);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Test get_certificate_mapping handles an ldb message with no
+ * altSecurityIdentities attribute
+ *
+ */
+static void cert_mapping_no_altSecurityIdentities(void **state)
+{
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ struct loadparm_context *lp_ctx = loadparm_init(mem_ctx);
+ struct ldb_message *msg = NULL;
+ krb5_error_code err = 0;
+ struct sdb_entry entry = {};
+
+ time_t now = time(NULL);
+ const int backdate = 10080; /* 1 week */
+ const int expected_val_cert_start = now - (backdate * 60);
+
+ /* Create the ldb_message */
+ msg = create_ldb_message(mem_ctx);
+ add_whenCreated(msg, now);
+
+ certificate_binding_enforcement = 0;
+ certificate_backdating_compensation = backdate;
+ err = get_certificate_mappings(mem_ctx, lp_ctx, msg, &entry);
+
+ assert_int_equal(0, err);
+
+ assert_int_equal(0, entry.mappings.len);
+ assert_int_equal(0, entry.mappings.enforcement_mode);
+ assert_int_equal(
+ expected_val_cert_start,
+ entry.mappings.valid_certificate_start);
+
+ sdb_entry_free(&entry);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Test get_certificate_mapping handles an ldb message with an
+ * altSecurityIdentities attribute containing no X509 entries
+ *
+ */
+static void no_X509_altSecurityIdentities(void **state)
+{
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ struct loadparm_context *lp_ctx = loadparm_init(mem_ctx);
+ struct ldb_message *msg = NULL;
+ krb5_error_code err = 0;
+ struct sdb_entry entry = {};
+
+ time_t now = time(NULL);
+ const int backdate = 1440; /* 24 hours */
+ const int expected_val_cert_start = now - (backdate * 60);
+
+ /* Create the ldb_message */
+ msg = create_ldb_message(mem_ctx);
+ add_altSecurityIdentities(msg,
+ "KERBEROS:0123456789abcdef");
+ add_altSecurityIdentities(msg,
+ "ANOTHER:0123456789abcdef");
+ add_whenCreated(msg, now);
+
+ certificate_binding_enforcement = 0;
+ certificate_backdating_compensation = backdate;
+ err = get_certificate_mappings(mem_ctx, lp_ctx, msg, &entry);
+
+ assert_int_equal(0, err);
+
+ assert_int_equal(0, entry.mappings.len);
+ assert_int_equal(0, entry.mappings.enforcement_mode);
+ assert_int_equal(
+ expected_val_cert_start,
+ entry.mappings.valid_certificate_start);
+
+
+ sdb_entry_free(&entry);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Test get_certificate_mapping handles an ldb message with an
+ * altSecurityIdentities attribute containing X509,and KERBEROS
+ * entries.
+ *
+ */
+static void mixed_altSecurityIdentities(void **state)
+{
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ struct loadparm_context *lp_ctx = loadparm_init(mem_ctx);
+ struct ldb_message *msg = NULL;
+ krb5_error_code err = 0;
+ struct sdb_entry entry = {};
+ uint8_t ski[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+
+ time_t now = time(NULL);
+ const int backdate = 10;
+ const int expected_val_cert_start = now - (backdate * 60);
+
+ /* Create the ldb_message */
+ msg = create_ldb_message(mem_ctx);
+ add_altSecurityIdentities(msg,
+ "X509:<SKI>0123456789abcdef");
+ add_altSecurityIdentities(msg,
+ "KERBEROS:0123456789abcdef");
+ add_altSecurityIdentities(msg,
+ "X509:<RFC822>test@example.com");
+ add_whenCreated(msg, now);
+
+ certificate_binding_enforcement = 0;
+ certificate_backdating_compensation = backdate;
+ err = get_certificate_mappings(mem_ctx, lp_ctx, msg, &entry);
+
+ assert_int_equal(0, err);
+
+ assert_int_equal(2, entry.mappings.len);
+ assert_int_equal(0, entry.mappings.enforcement_mode);
+ assert_int_equal(
+ expected_val_cert_start,
+ entry.mappings.valid_certificate_start);
+
+ assert_int_equal(sizeof(ski), entry.mappings.mappings[0].ski.length);
+ assert_memory_equal(
+ ski, entry.mappings.mappings[0].ski.data, sizeof(ski));
+ assert_true(entry.mappings.mappings[0].strong_mapping);
+
+ assert_int_equal(16, entry.mappings.mappings[1].rfc822.length);
+ assert_memory_equal(
+ "test@example.com", entry.mappings.mappings[1].rfc822.data, 16);
+ assert_false(entry.mappings.mappings[1].strong_mapping);
+
+ sdb_entry_free(&entry);
+ TALLOC_FREE(mem_ctx);
+}
+
+
+/*
+ * Test get_certificate_mapping handles an empty
+ * altSecurityIdentities attribute
+ *
+ */
+static void cert_mapping_empty_altSecurityIdentities(void **state)
+{
+
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+
+ struct loadparm_context *lp_ctx = loadparm_init(mem_ctx);
+ struct ldb_message *msg = NULL;
+ krb5_error_code err = 0;
+ struct sdb_entry entry = {};
+
+ time_t now = time(NULL);
+ const int backdate = 43800; /* One month */
+ const int expected_val_cert_start = now - (backdate * 60);
+
+ /* Create the ldb_message */
+ msg = create_ldb_message(mem_ctx);
+ add_empty_altSecurities(mem_ctx, msg);
+ add_whenCreated(msg, now);
+
+ certificate_binding_enforcement = 0;
+ certificate_backdating_compensation = backdate;
+ err = get_certificate_mappings(mem_ctx, lp_ctx, msg, &entry);
+
+ assert_int_equal(0, err);
+
+ assert_int_equal(0, entry.mappings.len);
+ assert_int_equal(0, entry.mappings.enforcement_mode);
+ assert_int_equal(
+ expected_val_cert_start,
+ entry.mappings.valid_certificate_start);
+
+ sdb_entry_free(&entry);
+ TALLOC_FREE(mem_ctx);
+}
+
+
int main(int argc, const char **argv)
{
const struct CMUnitTest tests[] = {
cmocka_unit_test(keycred_tpm_key_material),
cmocka_unit_test(keycred_der_key_material),
cmocka_unit_test(keycred_multiple),
+ cmocka_unit_test(empty_string_parse_certificate_mapping),
+ cmocka_unit_test(header_only_parse_certificate_mapping),
+ cmocka_unit_test(not_x509_parse_certificate_mapping),
+ cmocka_unit_test(no_tag_parse_certificate_mapping),
+ cmocka_unit_test(no_tag_close_parse_certificate_mapping),
+ cmocka_unit_test(empty_tag_parse_certificate_mapping),
+ cmocka_unit_test(no_value_parse_certificate_mapping),
+ cmocka_unit_test(issuer_name_parse_certificate_mapping),
+ cmocka_unit_test(
+ duplicate_issuer_name_parse_certificate_mapping),
+ cmocka_unit_test(subject_name_parse_certificate_mapping),
+ cmocka_unit_test(
+ duplicate_subject_name_parse_certificate_mapping),
+ cmocka_unit_test(
+ issuer_and_subject_name_parse_certificate_mapping),
+ cmocka_unit_test(serial_number_parse_certificate_mapping),
+ cmocka_unit_test(
+ duplicate_serial_number_parse_certificate_mapping),
+ cmocka_unit_test(
+ serial_number_and_issuer_name_parse_certificate_mapping
+ ),
+ cmocka_unit_test(ski_parse_certificate_mapping),
+ cmocka_unit_test(duplicate_ski_parse_certificate_mapping),
+ cmocka_unit_test(public_key_parse_certificate_mapping),
+ cmocka_unit_test(
+ duplicate_public_key_parse_certificate_mapping),
+ cmocka_unit_test(non_hex_parse_certificate_mapping),
+ cmocka_unit_test(odd_length_hex_parse_certificate_mapping),
+ cmocka_unit_test(RFC822_parse_certificate_mapping),
+ cmocka_unit_test(multiple_cert_mappings),
+ cmocka_unit_test(single_cert_mapping),
+ cmocka_unit_test(cert_mapping_no_altSecurityIdentities),
+ cmocka_unit_test(cert_mapping_empty_altSecurityIdentities),
+ cmocka_unit_test(no_X509_altSecurityIdentities),
+ cmocka_unit_test(mixed_altSecurityIdentities),
+
};
cmocka_set_message_output(CM_OUTPUT_SUBUNIT);