Keychain DID Functions

#include <keychain/keychain_headers.h>

Overview

Keychain DID functions work with keychain-specific DIDs that extend basic DID functionality with keychain-specific fields such as the public-key infrastructure network ID and the keychain type. These DIDs include additional metadata and network information specific to the Keychain ecosystem.

Object Lifecycle Functions

kc_keychain_did_construct_from_serialized_string()

int kc_keychain_did_construct_from_serialized_string(
    kc_keychain_did_t** out_keychain_did_ptr,
    const char* serialized_string,
    const unsigned int serialized_string_size
)

Deserializes a keychain DID from a string representation in W3C format.

Parameters:

  • out_keychain_did_ptr - Pointer to keychain DID pointer (output, caller must free)

  • serialized_string - Serialized DID as a character array

  • serialized_string_size - Number of bytes in the serialized string

Returns: Error code (0 = success)

Example:

kc_keychain_did_t* keychain_did = NULL;
const char* did_string = "did:keychain:mainnet:alice.example.com";
int result = kc_keychain_did_construct_from_serialized_string(&keychain_did,
    did_string, strlen(did_string));
if (result == 0) {
    // Use keychain DID...
    kc_keychain_did_destruct(&keychain_did);
}

kc_keychain_did_construct_from_copy()

int kc_keychain_did_construct_from_copy(
    kc_keychain_did_t** out_keychain_did_ptr,
    const kc_keychain_did_t* rhs_keychain_did_ptr
)

Creates a deep copy of a keychain DID object.

Parameters:

  • out_keychain_did_ptr - Pointer to new keychain DID pointer (output, caller must free)

  • rhs_keychain_did_ptr - Keychain DID object to copy

Returns: Error code (0 = success)

Example:

kc_keychain_did_t* original_did = NULL;
kc_keychain_did_t* copied_did = NULL;

// ... create original_did ...

int result = kc_keychain_did_construct_from_copy(&copied_did, original_did);
if (result == 0) {
    // Use copied keychain DID...
    kc_keychain_did_destruct(&copied_did);
}

kc_keychain_did_destruct()

int kc_keychain_did_destruct(kc_keychain_did_t** keychain_did_ptr)

Destructs a keychain DID object and frees its resources.

Parameters:

  • keychain_did_ptr - Pointer to keychain DID pointer (set to NULL on success)

Returns: Error code (0 = success)

Keychain-Specific Access Functions

kc_keychain_did_keychain_type()

int kc_keychain_did_keychain_type(
    const kc_keychain_did_t* keychain_did_ptr,
    unsigned int* out_keychain_type
)

Gets the keychain type from the keychain DID.

Parameters:

  • keychain_did_ptr - Keychain DID object to query

  • out_keychain_type - Pointer to keychain type (output)

Returns: Error code (0 = success)

Example:

unsigned int keychain_type = 0;
int result = kc_keychain_did_keychain_type(keychain_did, &keychain_type);
if (result == 0) {
    printf("Keychain type: %u\n", keychain_type);
}

kc_keychain_did_network()

int kc_keychain_did_network(
    const kc_keychain_did_t* keychain_did_ptr,
    char** out_network_str,
    unsigned int* out_size
)

Gets the network ID from the keychain DID.

Parameters:

  • keychain_did_ptr - Keychain DID object to query

  • out_network_str - Pointer to network string pointer (output, caller must free)

  • out_size - Pointer to network string size (output)

Returns: Error code (0 = success)

Example:

char* network = NULL;
unsigned int network_size = 0;
int result = kc_keychain_did_network(keychain_did, &network, &network_size);
if (result == 0) {
    printf("Network: %.*s\n", network_size, network);
    kc_common_delete_buffer(&network);
}

kc_keychain_did_network_specific_id()

int kc_keychain_did_network_specific_id(
    const kc_keychain_did_t* keychain_did_ptr,
    char** out_nsid,
    unsigned int* out_size
)

Gets the network-specific identifier from the keychain DID.

Parameters:

  • keychain_did_ptr - Keychain DID object to query

  • out_nsid - Pointer to network-specific ID string pointer (output, caller must free)

  • out_size - Pointer to ID string size (output)

Returns: Error code (0 = success)

Example:

char* nsid = NULL;
unsigned int nsid_size = 0;
int result = kc_keychain_did_network_specific_id(keychain_did, &nsid, &nsid_size);
if (result == 0) {
    printf("Network-specific ID: %.*s\n", nsid_size, nsid);
    kc_common_delete_buffer(&nsid);
}

Standard DID Component Access Functions

kc_keychain_did_scheme()

int kc_keychain_did_scheme(
    const kc_keychain_did_t* keychain_did_ptr,
    char** out_scheme,
    unsigned int* out_size
)

Gets the DID scheme (always "did" for valid DIDs).

Parameters:

  • keychain_did_ptr - Keychain DID object to query

  • out_scheme - Pointer to scheme string pointer (output, caller must free)

  • out_size - Pointer to scheme string size (output)

Returns: Error code (0 = success)

kc_keychain_did_method()

int kc_keychain_did_method(
    const kc_keychain_did_t* keychain_did_ptr,
    char** out_method,
    unsigned int* out_size
)

Gets the DID method (should be "keychain" for keychain DIDs).

Parameters:

  • keychain_did_ptr - Keychain DID object to query

  • out_method - Pointer to method string pointer (output, caller must free)

  • out_size - Pointer to method string size (output)

Returns: Error code (0 = success)

kc_keychain_did_id()

int kc_keychain_did_id(
    const kc_keychain_did_t* keychain_did_ptr,
    char** out_id,
    unsigned int* out_size
)

Gets the method-specific identifier portion of the DID.

Parameters:

  • keychain_did_ptr - Keychain DID object to query

  • out_id - Pointer to ID string pointer (output, caller must free)

  • out_size - Pointer to ID string size (output)

Returns: Error code (0 = success)

Serialization Functions

kc_keychain_did_serialize()

int kc_keychain_did_serialize(
    const kc_keychain_did_t* keychain_did_ptr,
    char** out_serialized_str,
    unsigned int* out_size
)

Serializes the keychain DID to a string as defined in the W3C specification.

Parameters:

  • keychain_did_ptr - Keychain DID object to serialize

  • out_serialized_str - Pointer to serialized string pointer (output, caller must free)

  • out_size - Pointer to string size (output)

Returns: Error code (0 = success)

Example:

char* serialized = NULL;
unsigned int serialized_size = 0;
int result = kc_keychain_did_serialize(keychain_did, &serialized, &serialized_size);
if (result == 0) {
    printf("Serialized keychain DID: %.*s\n", serialized_size, serialized);
    kc_common_delete_buffer(&serialized);
}

Metadata Functions

kc_keychain_did_data_type()

int kc_keychain_did_data_type(
    const kc_keychain_did_t* keychain_did_ptr,
    unsigned int* out_data_type
)

Gets the data type value indicating this is a keychain DID.

Parameters:

  • keychain_did_ptr - Keychain DID object to query

  • out_data_type - Pointer to data type value (output)

Returns: Error code (0 = success)

Query Functions

kc_keychain_did_equals()

int kc_keychain_did_equals(
    const kc_keychain_did_t* lhs_keychain_did_ptr,
    bool* out_is_equal,
    const kc_keychain_did_t* rhs_keychain_did_ptr
)

Tests equality of two keychain DID objects.

Parameters:

  • lhs_keychain_did_ptr - First keychain DID to compare

  • out_is_equal - Pointer to equality result (output)

  • rhs_keychain_did_ptr - Second keychain DID to compare

Returns: Error code (0 = success)

Example: Keychain DID Analysis

void analyze_keychain_did(const char* did_string) {
    kc_keychain_did_t* keychain_did = NULL;

    printf("Analyzing keychain DID: %s\n", did_string);

    // Parse the keychain DID
    int result = kc_keychain_did_construct_from_serialized_string(&keychain_did,
        did_string, strlen(did_string));

    if (result != 0) {
        printf("Failed to parse keychain DID: %d\n", result);
        return;
    }

    // Get standard DID components
    char* scheme = NULL;
    char* method = NULL;
    char* id = NULL;
    unsigned int scheme_size = 0;
    unsigned int method_size = 0;
    unsigned int id_size = 0;

    kc_keychain_did_scheme(keychain_did, &scheme, &scheme_size);
    kc_keychain_did_method(keychain_did, &method, &method_size);
    kc_keychain_did_id(keychain_did, &id, &id_size);

    printf("\nStandard DID Components:\n");
    printf("  Scheme: %.*s\n", scheme_size, scheme ? scheme : "Unknown");
    printf("  Method: %.*s\n", method_size, method ? method : "Unknown");
    printf("  Method-specific ID: %.*s\n", id_size, id ? id : "Unknown");

    // Get keychain-specific components
    unsigned int keychain_type = 0;
    char* network = NULL;
    char* nsid = NULL;
    unsigned int network_size = 0;
    unsigned int nsid_size = 0;

    kc_keychain_did_keychain_type(keychain_did, &keychain_type);
    kc_keychain_did_network(keychain_did, &network, &network_size);
    kc_keychain_did_network_specific_id(keychain_did, &nsid, &nsid_size);

    printf("\nKeychain-Specific Components:\n");
    printf("  Keychain Type: %u\n", keychain_type);
    printf("  Network: %.*s\n", network_size, network ? network : "Unknown");
    printf("  Network-Specific ID: %.*s\n", nsid_size, nsid ? nsid : "Unknown");

    // Get data type
    unsigned int data_type = 0;
    kc_keychain_did_data_type(keychain_did, &data_type);
    printf("  Data Type: %u\n", data_type);

    // Test serialization
    char* serialized = NULL;
    unsigned int serialized_size = 0;
    result = kc_keychain_did_serialize(keychain_did, &serialized, &serialized_size);

    if (result == 0) {
        printf("\nSerialization Test:\n");
        printf("  Original: %s\n", did_string);
        printf("  Serialized: %.*s\n", serialized_size, serialized);

        if (strlen(did_string) == serialized_size &&
            memcmp(did_string, serialized, serialized_size) == 0) {
            printf("  ✓ Round-trip serialization successful\n");
        } else {
            printf("  ✗ Round-trip serialization failed\n");
        }

        kc_common_delete_buffer(&serialized);
    }

    // Cleanup
    if (scheme) kc_common_delete_buffer(&scheme);
    if (method) kc_common_delete_buffer(&method);
    if (id) kc_common_delete_buffer(&id);
    if (network) kc_common_delete_buffer(&network);
    if (nsid) kc_common_delete_buffer(&nsid);
    kc_keychain_did_destruct(&keychain_did);
}

Example: Network-Based DID Operations

void demonstrate_network_operations() {
    // Test different network configurations
    const char* test_dids[] = {
        "did:keychain:mainnet:alice.company.com",
        "did:keychain:testnet:bob.development.local",
        "did:keychain:private:charlie.internal.corp",
        "did:keychain:staging:diana.staging.example.org"
    };

    printf("Analyzing DIDs by network:\n\n");

    for (size_t i = 0; i < sizeof(test_dids) / sizeof(test_dids[0]); i++) {
        kc_keychain_did_t* did = NULL;
        int result = kc_keychain_did_construct_from_serialized_string(&did,
            test_dids[i], strlen(test_dids[i]));

        if (result == 0) {
            char* network = NULL;
            char* nsid = NULL;
            unsigned int network_size = 0;
            unsigned int nsid_size = 0;
            unsigned int keychain_type = 0;

            kc_keychain_did_network(did, &network, &network_size);
            kc_keychain_did_network_specific_id(did, &nsid, &nsid_size);
            kc_keychain_did_keychain_type(did, &keychain_type);

            printf("DID %zu: %s\n", i + 1, test_dids[i]);
            printf("  Network: %.*s\n", network_size, network ? network : "Unknown");
            printf("  Entity: %.*s\n", nsid_size, nsid ? nsid : "Unknown");
            printf("  Type: %u\n", keychain_type);

            // Determine network characteristics
            if (network && network_size == 7 && memcmp(network, "mainnet", 7) == 0) {
                printf("  Environment: Production\n");
            } else if (network && network_size == 7 && memcmp(network, "testnet", 7) == 0) {
                printf("  Environment: Testing\n");
            } else if (network && network_size == 7 && memcmp(network, "private", 7) == 0) {
                printf("  Environment: Private/Internal\n");
            } else if (network && network_size == 7 && memcmp(network, "staging", 7) == 0) {
                printf("  Environment: Staging\n");
            } else {
                printf("  Environment: Unknown\n");
            }

            printf("\n");

            if (network) kc_common_delete_buffer(&network);
            if (nsid) kc_common_delete_buffer(&nsid);
            kc_keychain_did_destruct(&did);
        } else {
            printf("Failed to parse DID %zu: %s\n", i + 1, test_dids[i]);
        }
    }
}

Example: DID Comparison and Filtering

bool is_same_network(kc_keychain_did_t* did1, kc_keychain_did_t* did2) {
    char* network1 = NULL;
    char* network2 = NULL;
    unsigned int size1 = 0;
    unsigned int size2 = 0;

    int result1 = kc_keychain_did_network(did1, &network1, &size1);
    int result2 = kc_keychain_did_network(did2, &network2, &size2);

    bool same_network = false;
    if (result1 == 0 && result2 == 0 && network1 && network2) {
        if (size1 == size2 && memcmp(network1, network2, size1) == 0) {
            same_network = true;
        }
    }

    if (network1) kc_common_delete_buffer(&network1);
    if (network2) kc_common_delete_buffer(&network2);

    return same_network;
}

void filter_dids_by_network(const char** did_strings, size_t count,
                           const char* target_network) {
    printf("Filtering DIDs for network: %s\n\n", target_network);

    for (size_t i = 0; i < count; i++) {
        kc_keychain_did_t* did = NULL;
        int result = kc_keychain_did_construct_from_serialized_string(&did,
            did_strings[i], strlen(did_strings[i]));

        if (result == 0) {
            char* network = NULL;
            unsigned int network_size = 0;
            kc_keychain_did_network(did, &network, &network_size);

            if (network && strlen(target_network) == network_size &&
                memcmp(network, target_network, network_size) == 0) {

                char* nsid = NULL;
                unsigned int nsid_size = 0;
                kc_keychain_did_network_specific_id(did, &nsid, &nsid_size);

                printf("✓ %s\n", did_strings[i]);
                printf("  Entity: %.*s\n", nsid_size, nsid ? nsid : "Unknown");

                if (nsid) kc_common_delete_buffer(&nsid);
            }

            if (network) kc_common_delete_buffer(&network);
            kc_keychain_did_destruct(&did);
        }
    }
}

void demonstrate_did_filtering() {
    const char* all_dids[] = {
        "did:keychain:mainnet:alice.company.com",
        "did:keychain:testnet:bob.development.local",
        "did:keychain:mainnet:charlie.company.com",
        "did:keychain:private:diana.internal.corp",
        "did:keychain:testnet:eve.development.local",
        "did:keychain:mainnet:frank.company.com"
    };

    size_t count = sizeof(all_dids) / sizeof(all_dids[0]);

    // Filter by different networks
    filter_dids_by_network(all_dids, count, "mainnet");
    printf("\n");
    filter_dids_by_network(all_dids, count, "testnet");
    printf("\n");
    filter_dids_by_network(all_dids, count, "private");
}

Example: DID Type and Configuration Analysis

void analyze_keychain_configuration(kc_keychain_did_t* did) {
    unsigned int keychain_type = 0;
    char* network = NULL;
    unsigned int network_size = 0;

    int result = kc_keychain_did_keychain_type(did, &keychain_type);
    if (result != 0) {
        printf("Failed to get keychain type\n");
        return;
    }

    result = kc_keychain_did_network(did, &network, &network_size);
    if (result != 0) {
        printf("Failed to get network information\n");
        return;
    }

    printf("Keychain Configuration Analysis:\n");
    printf("  Type: %u", keychain_type);

    // Interpret keychain type (assuming some standard values)
    switch (keychain_type) {
        case 1:
            printf(" (Standard)\n");
            break;
        case 2:
            printf(" (Enterprise)\n");
            break;
        case 3:
            printf(" (Development)\n");
            break;
        default:
            printf(" (Unknown)\n");
            break;
    }

    printf("  Network: %.*s", network_size, network);

    // Analyze network security implications
    if (network && network_size == 7 && memcmp(network, "mainnet", 7) == 0) {
        printf(" (Production - High Security)\n");
        printf("  Security Level: Production\n");
        printf("  Certificate Validation: Required\n");
        printf("  Audit Logging: Enabled\n");
    } else if (network && network_size == 7 && memcmp(network, "testnet", 7) == 0) {
        printf(" (Testing - Medium Security)\n");
        printf("  Security Level: Testing\n");
        printf("  Certificate Validation: Optional\n");
        printf("  Audit Logging: Limited\n");
    } else if (network && network_size == 7 && memcmp(network, "private", 7) == 0) {
        printf(" (Private - Custom Security)\n");
        printf("  Security Level: Custom\n");
        printf("  Certificate Validation: Internal CA\n");
        printf("  Audit Logging: Internal\n");
    } else {
        printf(" (Custom Network)\n");
        printf("  Security Level: Unknown\n");
        printf("  Certificate Validation: Unknown\n");
        printf("  Audit Logging: Unknown\n");
    }

    if (network) kc_common_delete_buffer(&network);
}

void demonstrate_configuration_analysis() {
    const char* config_dids[] = {
        "did:keychain:mainnet:prod.enterprise.com",
        "did:keychain:testnet:dev.testing.local",
        "did:keychain:private:internal.company.corp"
    };

    for (size_t i = 0; i < sizeof(config_dids) / sizeof(config_dids[0]); i++) {
        kc_keychain_did_t* did = NULL;
        int result = kc_keychain_did_construct_from_serialized_string(&did,
            config_dids[i], strlen(config_dids[i]));

        if (result == 0) {
            printf("\n=== Configuration %zu ===\n", i + 1);
            printf("DID: %s\n", config_dids[i]);
            analyze_keychain_configuration(did);
            kc_keychain_did_destruct(&did);
        }
    }
}

Memory Management

  • Use kc_keychain_did_destruct() to free keychain DID objects

  • Use kc_common_delete_buffer() for string outputs (scheme, method, ID, network, network-specific ID, serialized data)

  • Always check return codes before using output parameters

  • Keychain DIDs are immutable once created

Best Practices

  • Use appropriate networks for different environments (mainnet for production, testnet for development)

  • Validate network-specific IDs according to your naming conventions

  • Store keychain DIDs in their canonical string form for persistence

  • Use keychain type to categorize different kinds of entities

  • Implement network-based access controls and security policies

See Also