PKCS#11 API för certifikatlagring

Azure Cloud HSM ger robust stöd för certifikatlagring med hjälp av API:et PKCS#11. Den här artikeln beskriver hur du använder PKCS#11 API för att hantera X.509-certifikat, inklusive att skapa, kopiera, ta bort och hämta certifikatattribut. En detaljerad översikt över konfigurationen av certifikatlagring, inklusive krav och konfiguration, finns i Azure Cloud HSM-certifikatlagring.

Använda PKCS#11 API för X.509-certifikatlagring

Följande befintliga API:er i PKCS#11 för Azure Cloud HSM har utökats för att lägga till stöd för X.509 Public Key Certificates.

  • C_CreateObject: Skapar ett nytt certifikatobjekt.
  • C_DestroyObject: Tar bort ett befintligt certifikatobjekt.
  • C_CopyObject: Kopierar ett befintligt certifikatobjekt.
  • C_GetAttributeValue: Hämtar värdet för ett eller flera attribut för ett certifikatobjekt.
  • C_SetAttributeValue: Uppdaterar värdet för ett eller flera attribut för ett certifikatobjekt.
  • C_FindObjectsInit: Startar en sökning efter certifikatobjekt.
  • C_FindObjects: Fortsätter sökningen efter certifikatobjekt.
  • C_FindObjectsFinal: Avslutar en sökning efter certifikatobjekt.

C_CreateObject

C_CREATEOBJECT-API:et fungerar på samma sätt för både nycklar och certifikat. Den förväntar sig en matris med attribut, antalet attribut och en pekare till ett objekthandtag där det genererade handtaget lagras.

Nedan visas ett exempel på hur du använder C_CreateObject.

int create_cert(CK_SESSION_HANDLE session_rw, CK_OBJECT_HANDLE_PTR cert_handle)
{
    // Dummy certificate data
    CK_BYTE certData[] = { 0x30, 0x82, 0x03, 0x08, 0x30, 0x82, 0x02, 0xD0 }; // Sample DER-encoded cert
    CK_ULONG certSize = sizeof(certData);

    CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
    CK_CERTIFICATE_TYPE certType = CKC_X_509;
    CK_BBOOL trueValue = CK_TRUE;
    CK_BYTE id[] = {123};

    // Dummy DER-encoded Subject Name (adjust as needed)
    CK_BYTE subjectData[] = { 0x30, 0x1D, 0x31, 0x1B, 0x30, 0x19, 0x06, 0x03,
                              0x55, 0x04, 0x03, 0x0C, 0x12, 'M', 'y', 'C', 'e',
                              'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e', '-', 'B', 'b', 'j' };
    CK_ULONG subjectSize = sizeof(subjectData);

    CK_ATTRIBUTE certTemplate[] = {
        { CKA_CLASS, &objClass, sizeof(objClass) },
        { CKA_CERTIFICATE_TYPE, &certType, sizeof(certType) },
        { CKA_TOKEN, &trueValue, sizeof(trueValue) },
        { CKA_LABEL, "MyCertificate", 13 },
        { CKA_SUBJECT, subjectData, subjectSize },
        { CKA_ID, id, sizeof(id) },
        { CKA_VALUE, certData, certSize }
    };

    int n_attr = sizeof(certTemplate) / sizeof(CK_ATTRIBUTE);

    if ((func_list->C_CreateObject)(session_rw, certTemplate,
                                    n_attr, cert_handle)) {
        return FAILED;
    }
#ifdef DEBUG
    printf("The cert handle created is : %lu \n", *cert_handle);
#endif

    return CKR_OK;
}

Följande attribut representerar den minsta obligatoriska uppsättningen för att skapa ett X.509-certifikat i PKCS#11.

Skikt Egenskap Datatyp Beskrivning
Vanliga attribut CKA_CLASS CK_OBJEKT_KLASS Objektklass (typ)
Certifikatobjekt CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE Typ av certifikat, CKC_X_509 för X.509-certifikat för offentlig nyckel
X.509 Certifikatobjekt för offentlig nyckel CKA_SUBJEKT Bytematris DER-kodning av certifikatets ämnesnamn
X.509 Certifikatobjekt för offentlig nyckel CKA_VALUE Bytematris BER-kodning av certifikatet

Följande attribut gäller för X.509-certifikat för offentlig nyckel.

Skikt Egenskap Datatyp Beskrivning
Vanliga attribut CKA_CLASS CK_OBJEKT_KLASS Objektklass (typ)
Lagringsobjekt CKA_TOKEN CK_BBOOL CK_TRUE om objektet är ett tokenobjekt. CK_FALSE om objektet är ett sessionsobjekt. Standardvärdet är CK_FALSE.
Lagringsobjekt CKA_PRIVATE CK_BBOOL CK_TRUE om objektet är ett privat objekt. CK_FALSE om objektet är ett offentligt objekt. Standardvärdet är tokenspecifikt och kan bero på värdena för andra attribut i objektet.
Lagringsobjekt CKA_MODIFIABLE CK_BBOOL CK_TRUE om objektet kan ändras; standard är CK_TRUE.
Lagringsobjekt CKA_LABEL RFC2279 sträng Beskrivning av objektet (standard tom).
Lagringsobjekt CKA_COPYABLE CK_BBOOL CK_TRUE om objektet kan kopieras med hjälp av C_CopyObject. Standardinställningen är CK_TRUE. Det kan inte ställas in på SANT när det en gång har ställts in på FALSKT.
Lagringsobjekt CKA_DESTROYABLE CK_BBOOL CK_TRUE om objektet kan förstöras med hjälp av C_DestroyObject. Standardvärdet är CK_TRUE.
Certifikatobjekt CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE Typ av certifikat, CKC_X_509 för X.509-certifikat för offentlig nyckel
Certifikatobjekt CKA_TRUSTED CK_BBOOL Certifikatet kan litas på för den applikation det skapades för.
Certifikatobjekt KKA_CERTIFIKAT_KATEGORI KKA_CERTIFIKAT_KATEGORI (standard CK_CERTIFICATE_CATEGORY_UNSPECIFIED)
Certifikatobjekt CKA_CHECK_VALUE Bytematris Kontrollsumma
Certifikatobjekt CKA_START_DATE CK_DATE Startdatum för certifikatet (standard tom)
Certifikatobjekt CKA_SLUTDATUM CK_DATE Slutdatum för certifikatet (standard tom)
Certifikatobjekt CKA_PUBLIC_KEY_INFO Bytematris DER-kodning av SubjectPublicKeyInfo för den offentliga nyckeln som finns i det här certifikatet (standard tom)
X.509 Certifikatobjekt för offentlig nyckel CKA_SUBJEKT Bytematris DER-kodning av certifikatets ämnesnamn
X.509 Certifikatobjekt för offentlig nyckel CKA_ID Bytematris Nyckelidentifierare för offentligt/privat nyckelpar (standard tom)
X.509 Certifikatobjekt för offentlig nyckel CKA_ISSUER Bytematris DER-kodning av certifikatutfärdarens namn (standard tom)
X.509 Certifikatobjekt för offentlig nyckel CKA_SERIAL_NUMBER Bytematris DER-kodning av certifikatserienumret (standard tom)
X.509 Certifikatobjekt för offentlig nyckel CKA_VALUE Bytematris BER-kodning av certifikatet
X.509 Certifikatobjekt för offentlig nyckel CKA_URL RFC2279 sträng Om det inte är tomt ger det här attributet url:en där det fullständiga certifikatet kan hämtas (standard tom)
X.509 Certifikatobjekt för offentlig nyckel CKA_HASH_OF_SUBJECT_PUBLIC_KEY Bytematris Hash för subjektets offentliga nyckel (som standard tom). Hash-algoritmen definieras av CKA_NAME_HASH_ALGORITHM
X.509 Certifikatobjekt för offentlig nyckel CKA_HASH_OF_ISSUER_PUBLIC_KEY Bytematris Hash för utfärdarens offentliga nyckel (standard tom). Hash-algoritmen definieras av CKA_NAME_HASH_ALGORITHM
X.509 Certifikatobjekt för offentlig nyckel CKA_JAVA_MIDP_SECURITY_DOMAIN CK_JAVA_MIDP_SECURITY_DOMAIN Java MIDP-säkerhetsdomän. (förval CK_SECURITY_DOMAIN_UNSPECIFIED)
X.509 Certifikatobjekt för offentlig nyckel CKA_NAME_HASH_ALGORITHM CK_MECHANISM_TYPE Definierar den mekanism som används för att beräkna CKA_HASH_OF_SUBJECT_PUBLIC_KEY och CKA_HASH_OF_ISSUER_PUBLIC_KEY. Om attributet inte finns är typen SHA-1 som standard.

C_DestroyObject

C_DestroyObject-API:et tar ett sessionshandtag och objekthandtaget som är associerat med certifikatet som du vill ta bort. Om du anropar den här funktionen tas det angivna certifikatet bort från Azure Blob Storage-kontot genom att motsvarande JWS-blob med namnet pkcs11_certificate_<cert-handle>tas bort.

Nedan visas ett kodfragment som visar hur du anropar C_DestroyObject för certifikat (samma metod gäller för nycklar).

int delete_cert(CK_SESSION_HANDLE session_rw, CK_OBJECT_HANDLE cert_handle)
{
    CK_RV rv = 0;

    rv = (func_list->C_DestroyObject)(session_rw, cert_handle);

    if(rv != CKR_OK) {
        printf("Deleting Certificate failed \n");
        return rv;
    }

    return rv;
}

C_CopyObject

C_COPYOBJECT-API:et tar ett sessionshandtag, handtaget för det objekt som ska kopieras och en pekare för att ta emot handtaget för det nyligen skapade objektet. För att upprätthålla paritet med C_CopyObject implementeringen för nyckelobjekt i Azure Cloud HSM stöder certifikatimplementeringen inte att ändra attribut under kopieringsåtgärden.

Nedan visas ett exempelfragment som visar hur du använder C_CopyObject för att lagra certifikat.

int copy_cert(CK_SESSION_HANDLE session_rw, CK_OBJECT_HANDLE cert_handle,
                   CK_OBJECT_HANDLE_PTR copied_cert_handle)
{
    CK_RV rv = 0;

    rv = (func_list->C_CopyObject)(session_rw, cert_handle, NULL, 0, copied_cert_handle);

    if(rv != CKR_OK) {
        printf("Copying Certificate failed \n");
        return rv;
    }

    return rv;
}

C_GetAttributeValue

API:et C_GetAttributeValue tillåter hämtning av alla attribut som anges i avsnittet C_CreateObject API. Det här API:et anropas vanligtvis två gånger. Det första anropet avgör storleken på attribut med okända längder, till exempel CKA_SUBJECT, som innehåller det DER-kodade certifikatämnet.

Nedan visas ett exempel på hur du anropar C_GetAttributeValue för att hämta storlekarna för de angivna attributen.

int get_cert_attribute(CK_SESSION_HANDLE session_rw, CK_OBJECT_HANDLE_PTR cert_handle)
{
    CK_RV rv = 0;

    CK_ULONG cka_class = 0;
    CK_CERTIFICATE_TYPE cka_cert_type = 0;
    CK_BBOOL cka_token = 0;
    char* cka_label = NULL;
    char* cka_subject = NULL;
    CK_BYTE* cka_id = NULL;
    CK_BYTE* cka_value = NULL;

    // Determine size needed for each attribute by calling C_GetAttributeValue with NULL pointers
    // and zero as the length.

    CK_ATTRIBUTE cert_template[] = {
        { CKA_CLASS, NULL, 0 },
        { CKA_CERTIFICATE_TYPE, NULL, 0 },
        { CKA_TOKEN, NULL, 0 },
        { CKA_LABEL, NULL, 0 },
        { CKA_ID, NULL, 0 },
    };

    int n_attr = sizeof(cert_template) / sizeof(CK_ATTRIBUTE);

    rv = (func_list->C_GetAttributeValue)(session_rw, *cert_handle, cert_template, n_attr);

    if (rv != CKR_OK) {
        printf("C_GetAttributeValue failed with %ld\n", rv);
        return FAILED;
    }

Once the attribute sizes are known, memory can be allocated accordingly. A second call to the C_GetAttributeValue API is then made to retrieve the attribute values and store them in the allocated memory.

The image below shows a code snippet demonstrating this process based on the previous example:

    cka_label = (char*)malloc(cert_template[3].ulValueLen);
    if (cka_label == NULL) {
        printf("Memory allocation failed for CKA_LABEL.\n");
        rv = FAILED;
        goto end_test_get_cert_attribute;
    }

    cert_template[3].pValue = cka_label;

    if (cert_template[4].ulValueLen <= 0) {
        printf("CKA_ID size must be > 0.\n");
        rv = FAILED;
        goto end_test_get_cert_attribute;
    }

    cka_id = (CK_BYTE*)malloc(cert_template[4].ulValueLen);
    if (cka_id == NULL) {
        printf("Memory allocation failed for CKA_ID.\n");
        rv = FAILED;
        goto end_test_get_cert_attribute;
    }

    cert_template[4].pValue = cka_id;

    rv = (func_list->C_GetAttributeValue)(session_rw, *cert_handle, cert_template, n_attr);
    if (rv != CKR_OK) {
        printf("C_GetAttributeValue failed with %ld\n", rv);
        rv = FAILED;
        goto end_test_get_cert_attribute;
    }

C_SetAttributeValue

C_SetAttributeValue-API:et stöder nu uppdatering av certifikatobjekt. Det kräver att sessionshandtaget, certifikatets handtag uppdateras, en matris med attribut och deras nya värden samt antalet attribut som ska uppdateras. Endast attribut som anges i tabellen C_CreateObject API-användning stöds för uppdateringar. Försök att ändra attribut som inte stöds resulterar i ett misslyckat API-anrop.

Nedan visas ett kodfragment som visar hur C_SetAttributeValue kan användas med certifikatobjekt.

int set_cert_attribute(CK_SESSION_HANDLE session_rw, CK_OBJECT_HANDLE_PTR cert_handle)
{
    CK_RV rv = CKR_OK;
    CK_BBOOL falseValue = CK_FALSE;
    CK_BYTE subjectData[] = { 0x40, 0x41, 0x42, 0x43, 0x44 };
    CK_BYTE id[] = {254};
    CK_BYTE certData[] = { 0x10, 0x20, 0x30, 0x40, 0x50, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };

    CK_ATTRIBUTE certTemplateValid1[] = {
        { CKA_TOKEN, &falseValue, sizeof(falseValue) },
        { CKA_LABEL, "This is a new label", strlen("This is a new label") },
        { CKA_SUBJECT, subjectData, sizeof(subjectData) },
        { CKA_ID, id, sizeof(id) },
        { CKA_VALUE, certData, sizeof(certData) }
    };

    int n_attr = sizeof(certTemplateValid1) / sizeof(CK_ATTRIBUTE);
    rv = (func_list->C_SetAttributeValue)(session_rw, *cert_handle, certTemplateValid1, n_attr);
    if (rv != CKR_OK) {
        printf("test_set_cert_attribute failed when updating attribute values.\n");
        return FAILED;
    }

    return rv;
}

C_FindObjectsInit

API:et C_FindObjects* har nu stöd för att hitta certifikatobjekt utöver nyckelobjekt. En sökåtgärd kan returnera både nyckel- och certifikathandtag om sökmallen innehåller attribut som är gemensamma för båda objekttyperna. API:et C_FindObjectsInit har förbättrats för att stödja alla certifikatrelaterade attribut som anges i tabellen C_CreateObject API-användning.

Nedan visas ett exempel på ett C_FindObjectsInit-anrop som utför en certifikatsökning med hjälp av attributen CKA_CLASS, CKA_CERTIFICATE_TYPE och CKA_LABEL för att hitta alla matchande certifikatobjekt.

int find_cert(CK_SESSION_HANDLE session_rw, CK_OBJECT_HANDLE cert_handle)
{
    CK_RV rv;
    CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
    CK_CERTIFICATE_TYPE certType = CKC_X_509;

    CK_ATTRIBUTE certTemplate[] = {
        { CKA_CLASS, &objClass, sizeof(objClass) },
        { CKA_CERTIFICATE_TYPE, &certType, sizeof(certType) },
        { CKA_LABEL, "MyCertificate", 13 }
    };

    // Step 1: Initialize the search
    rv = (func_list->C_FindObjectsInit)(session_rw, certTemplate, sizeof(certTemplate) / sizeof(CK_ATTRIBUTE));
    if (rv != CKR_OK) {
        printf("C_FindObjectsInit failed: 0x%lX\n", rv);
        return rv;
    }

C_FindObjects

När du har initierat sökparametrarna används C_FindObjects-API:et för att hämta matchande objekthandtag. Den returnerar också antalet objekt som hittades. Det här API:et tar sessionshandtaget, en matris för att lagra de resulterande objekthandtagen, det maximala antalet objekt som ska hämtas och en utdataparameter som anger hur många objekt som hittades.

Kodfragmentet nedan visar ett anrop till C_FindObjects efter konfigurationen av sökmallen i C_FindObjectsInit exemplet ovan.

    // Step 2: Call C_FindObjects
    CK_OBJECT_HANDLE_PTR foundObjects = NULL;
    CK_ULONG maxObjects = 50;

    foundObjects = (CK_OBJECT_HANDLE_PTR)malloc(sizeof(CK_OBJECT_HANDLE) * maxObjects);
    if (!foundObjects) {
        printf("Memory allocation failed\n");
        return CKR_HOST_MEMORY;
    }
    CK_ULONG foundCount = 0;

    rv = (func_list->C_FindObjects)(session_rw, foundObjects, maxObjects, &foundCount);
    if (rv != CKR_OK) {
        printf("C_FindObjects failed: 0x%lX\n", rv);
        (func_list->C_FindObjectsFinal)(session_rw); // Ensure cleanup
        free(foundObjects);
        return rv;
    }

C_FindObjectsFinal

C_FINDOBJECTSFINAL-API:et fungerar på samma sätt för både nyckel- och certifikatobjekt. Den tar den aktuella sessionsreferensen som ett argument och utför rensning av alla sökrelaterade strukturer och minne som allokerats under C_FindObjectsInit-anropet.

Nedan visas ett kodfragment som visar hur du anropar C_FindObjectsFinal för att slutföra och rensa sökprocessen som initieras av api:erna för C_FindObjectsInit och C_FindObjects.

    // Step 3: Finalize the search
    rv = (func_list->C_FindObjectsFinal)(session_rw);
    if (rv != CKR_OK) {
        printf("C_FindObjectsFinal failed: 0x%lX\n", rv);
        free(foundObjects);
        return rv;
    }
}

Konfigurera och köra PKCS#11-programmet med Azure Cloud HSM

Azure Cloud HSM innehåller exempelprogramkod som hjälper dig att verifiera certifikatlagring, som finns i Azure Cloud HSM Certificate Storage-integreringsguiden i Azure Cloud HSM SDK på GitHub.

Certifikatstruktur i datalagring

Verifiera certifikat i lagring

Efter ett lyckat anrop till API:et C_CreateObject() visas det nyligen skapade certifikatobjektet i ditt Azure Blob Storage-konto enligt azcloudhsm_application.cfg-filen. Bloben namnges med formatet pkcs11_certificate_<object-handle>, enligt nedan. Certifikatobjekt tilldelas objektreferenser från 0xFFF00000 till 0xFFFFFFFF (decimalintervall: 4 293 918 720 till 4 294 967 295), vilket ger stöd för upp till 1 048 575 certifikat.

Från både Azure-portalen och från den virtuella Azure-datorn kan du se de certifikat som lagras.

Verifiera från Azure-portalen

Skärmbild som visar certifikatblobar som lagras i Azure-portalen för Azure Cloud HSM.

Verifiera från en virtuell Azure-dator med AZ CLI installerat

chsmVMAdmin@AdminVM:~$ az login --identity
[
  {
    "environmentName": "AzureCloud",
    "homeTenantId": "",
    "id": "",
    "isDefault": true,
    "managedByTenants": [],
    "name": "Test Subscription",
    "state": "Enabled",
    "tenantId": "",
    "user": {
      "assignedIdentityInfo": "MSI",
      "name": "systemAssignedIdentity",
      "type": "servicePrincipal"
    }
  }
]

chsmVMAdmin@AdminVM:~$ az storage blob list \
  --account-name chsmstorage \
  --container-name certificates \
  --auth-mode login \
  --output table

Name                                  Blob Type    Blob Tier    Length    Content Type              Last Modified
-----------------------------------  -----------  -----------  --------  ------------------------  -------------------------
pkcs11_certificate_4293918720        BlockBlob    Hot          1305      application/octet-stream  2025-05-16T22:43:31+00:00
pkcs11_certificate_4293918721        BlockBlob    Hot          1305      application/octet-stream  2025-05-16T22:47:25+00:00
pkcs11_certificate_4293918722        BlockBlob    Hot          1305      application/octet-stream  2025-05-16T22:47:25+00:00
pkcs11_certificate_4293918723        BlockBlob    Hot          3452      application/octet-stream  2025-05-16T22:56:28+00:00

Om du laddar ned bloben eller visar den i Azure-portalen och kontrollerar dess innehåll visas att certifikatet lagras som en JWS-token (JSON-webbsignatur). Token följer JWS-standardstrukturen, som är uppdelad i följande format:

chsmVMAdmin@AdminVM:~$ az storage blob list \
  --account-name chsmstorage \
  --container-name certificates \
  --auth-mode login \
  --output table

Name                                  Blob Type    Blob Tier    Length    Content Type              Last Modified
-----------------------------------  -----------  -----------  --------  ------------------------  -------------------------
pkcs11_certificate_4293918720        BlockBlob    Hot          1305      application/octet-stream  2025-05-16T22:43:31+00:00
pkcs11_certificate_4293918721        BlockBlob    Hot          1305      application/octet-stream  2025-05-16T22:47:25+00:00
pkcs11_certificate_4293918722        BlockBlob    Hot          1305      application/octet-stream  2025-05-16T22:47:25+00:00
pkcs11_certificate_4293918723        BlockBlob    Hot          3452      application/octet-stream  2025-05-16T22:56:28+00:00

chsmVMAdmin@AdminVM:~$ az storage blob download \
  --account-name chsmstorage \
  --container-name certificates \
  --name pkcs11_certificate_4293918723 \
  --file pkcs11_certificate_4293918723.crt \
  --auth-mode login
Finished[########################################] 100.0000%
{
  "container": "certificates",
  "content": ""
}

chsmVMAdmin@AdminVM:~$ cat pkcs11_certificate_4293918723.crt
eyJhbgGciOiJSUzUxMiIsImp... (base64-encoded certificate continues)

Nästa steg