PKCS#11-API für den Zertifikatspeicher

Azure Cloud HSM bietet robuste Unterstützung für den Zertifikatspeicher mithilfe der PKCS#11-API. In diesem Artikel wird erläutert, wie Sie die PKCS#11-API zum Verwalten von X.509-Zertifikaten verwenden, einschließlich Erstellen, Kopieren, Löschen und Abrufen von Zertifikatattributen. Eine detaillierte Übersicht über die Zertifikatspeichereinrichtung, einschließlich Voraussetzungen und Konfiguration, finden Sie unter Azure Cloud HSM-Zertifikatspeicher.

Verwenden der PKCS#11-API für X.509-Zertifikatspeicher

Die folgenden vorhandenen APIs in PKCS#11 für Azure Cloud HSM wurden erweitert, um Unterstützung für X.509 Public Key-Zertifikate hinzuzufügen.

  • C_CreateObject: Erstellt ein neues Zertifikatobjekt.
  • C_DestroyObject: Löscht ein vorhandenes Zertifikatobjekt.
  • C_CopyObject: Kopiert ein vorhandenes Zertifikatobjekt.
  • C_GetAttributeValue: Ruft den Wert eines oder mehrerer Attribute eines Zertifikatobjekts ab.
  • C_SetAttributeValue: Aktualisiert den Wert eines oder mehrerer Attribute eines Zertifikatobjekts.
  • C_FindObjectsInit: Startet eine Suche nach Zertifikatobjekten.
  • C_FindObjects: Führt eine Suche nach Zertifikatobjekten aus.
  • C_FindObjectsFinal: Beendet eine Suche nach Zertifikatobjekten.

C_CreateObject

Die C_CreateObject-API funktioniert für Schlüssel und Zertifikate ähnlich. Es erwartet ein Array von Attributen, die Anzahl der Attribute und einen Zeiger auf ein Objekthandle, in dem das erzeugte Handle gespeichert wird.

Im Folgenden finden Sie ein Beispiel für die Verwendung des 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;
}

Die folgenden Attribute stellen den minimal erforderlichen Satz zum Erstellen eines X.509-Zertifikats in PKCS#11 dar.

Ebene Merkmal Datentyp BESCHREIBUNG
Allgemeine Attribute CKA_CLASS CK_OBJECT_CLASS Objektklasse (Typ)
Zertifikatobjekte CKA_ZERTIFIKAT_TYP CK_CERTIFICATE_TYPE Zertifikattyp, CKC_X_509 für X.509-Zertifikate mit öffentlichem Schlüssel
X.509 Öffentliche Schlüsselzertifikatsobjekte CKA_SUBJECT Byte-Array DER-Codierung des Zertifikatantragstellernamens
X.509 Öffentliche Schlüsselzertifikatsobjekte CKA_VALUE Byte-Array BER-Codierung des Zertifikats

Die folgenden Attribute gelten für X.509 Public Key-Zertifikate.

Ebene Merkmal Datentyp BESCHREIBUNG
Allgemeine Attribute CKA_CLASS CK_OBJECT_CLASS Objektklasse (Typ)
Speicherobjekte CKA_TOKEN CK_BBOOL CK_TRUE, wenn das Objekt ein Tokenobjekt ist; CK_FALSE, wenn es sich bei dem Objekt um ein Sitzungsobjekt handelt. Der Standardwert ist CK_FALSE.
Speicherobjekte CKA_PRIVATE CK_BBOOL CK_TRUE, wenn es sich bei dem Objekt um ein privates Objekt handelt; CK_FALSE, wenn es sich bei dem Objekt um ein öffentliches Objekt handelt. Der Standardwert ist tokenspezifisch und kann von den Werten anderer Attribute des Objekts abhängen.
Speicherobjekte CKA_MODIFIABLE CK_BBOOL CK_TRUE, wenn das Objekt geändert werden kann. Der Standardwert ist CK_TRUE.
Speicherobjekte CKA_LABEL RFC2279 Zeichenfolge Beschreibung des Objekts (Standard leer).
Speicherobjekte CKA_COPYABLE CK_BBOOL CK_TRUE, ob das Objekt mit C_CopyObject kopiert werden kann. Standardmäßig wird CK_TRUE. Kann nicht auf TRUE festgelegt werden, sobald er auf FALSE festgelegt ist.
Speicherobjekte CKA_DESTROYABLE CK_BBOOL CK_TRUE, wenn das Objekt mit C_DestroyObject zerstört werden kann. Der Standardwert ist CK_TRUE.
Zertifikatobjekte CKA_ZERTIFIKAT_TYP CK_CERTIFICATE_TYPE Zertifikattyp, CKC_X_509 für X.509-Zertifikate mit öffentlichem Schlüssel
Zertifikatobjekte CKA_TRUSTED CK_BBOOL Das Zertifikat kann für die erstellte Anwendung als vertrauenswürdig eingestuft werden.
Zertifikatobjekte CKA_CERTIFICATE_CATEGORY CKA_CERTIFICATE_CATEGORY (Standard-CK_CERTIFICATE_CATEGORY_UNSPECIFIED)
Zertifikatobjekte CKA_CHECK_VALUE Byte-Array Checksum
Zertifikatobjekte CKA_START_DATE CK_DATE Startdatum für das Zertifikat (Standard leer)
Zertifikatobjekte CKA_END_DATE CK_DATE Enddatum für das Zertifikat (Standard leer)
Zertifikatobjekte CKA_PUBLIC_KEY_INFO Byte-Array DER-Codierung der SubjectPublicKeyInfo für den öffentlichen Schlüssel, der in diesem Zertifikat enthalten ist (Standard leer)
X.509 Öffentliche Schlüsselzertifikatsobjekte CKA_SUBJECT Byte-Array DER-Codierung des Zertifikatantragstellernamens
X.509 Öffentliche Schlüsselzertifikatsobjekte CKA_ID Byte-Array Schlüsselbezeichner für öffentliches/privates Schlüsselpaar (Standard leer)
X.509 Öffentliche Schlüsselzertifikatsobjekte CKA_ISSUER Byte-Array DER-Codierung des Zertifikatausstellernamens (Standard leer)
X.509 Öffentliche Schlüsselzertifikatsobjekte CKA_SERIAL_NUMBER Byte-Array DER-Codierung der Seriennummer des Zertifikats (Standard leer)
X.509 Öffentliche Schlüsselzertifikatsobjekte CKA_VALUE Byte-Array BER-Codierung des Zertifikats
X.509 Öffentliche Schlüsselzertifikatsobjekte CKA_URL RFC2279 Zeichenfolge Wenn dieses Attribut nicht leer ist, gibt die URL an, in der das vollständige Zertifikat abgerufen werden kann (Standard leer)
X.509 Öffentliche Schlüsselzertifikatsobjekte CKA_HASH_OF_SUBJECT_PUBLIC_KEY Byte-Array Hash des öffentlichen Schlüssels des Subjekts (Standard leer). Der Hashalgorithmus wird durch CKA_NAME_HASH_ALGORITHM definiert.
X.509 Öffentliche Schlüsselzertifikatsobjekte CKA_HASH_OF_ISSUER_PUBLIC_KEY Byte-Array Hash des öffentlichen Ausstellerschlüssels (Standard leer). Der Hashalgorithmus wird durch CKA_NAME_HASH_ALGORITHM definiert.
X.509 Öffentliche Schlüsselzertifikatsobjekte CKA_JAVA_MIDP_SECURITY_DOMAIN CK_JAVA_MIDP_SECURITY_DOMAIN Java MIDP-Sicherheitsdomäne. (Standard-CK_SECURITY_DOMAIN_UNSPECIFIED)
X.509 Öffentliche Schlüsselzertifikatsobjekte CKA_NAME_HASH_ALGORITHM CK_MECHANISM_TYPE Definiert den Mechanismus zum Berechnen von CKA_HASH_OF_SUBJECT_PUBLIC_KEY und CKA_HASH_OF_ISSUER_PUBLIC_KEY. Wenn das Attribut nicht vorhanden ist, wird der Typ standardmäßig auf SHA-1 festgelegt.

C_DestroyObject

Die C_DestroyObject-API akzeptiert ein Sitzungshandle und das Objekthandle, das dem Zertifikat zugeordnet ist, das Sie löschen möchten. Durch Aufrufen dieser Funktion wird das angegebene Zertifikat aus dem Azure Blob Storage-Konto entfernt, indem das entsprechende JWS-Blob mit dem Namen pkcs11_certificate_<cert-handle>gelöscht wird.

Nachfolgend finden Sie einen Codeausschnitt, der veranschaulicht, wie C_DestroyObject für Zertifikate aufgerufen werden (derselbe Ansatz gilt für Schlüssel).

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

Die C_CopyObject-API verwendet ein Sitzungshandle, das Handle des zu kopierenden Objekts und einen Zeiger, um das Handle des neu erstellten Objekts zu empfangen. Um die Parität mit der C_CopyObject-Implementierung für Schlüsselobjekte in Azure Cloud HSM aufrechtzuerhalten, unterstützt die Zertifikatimplementierung das Ändern von Attributen während des Kopiervorgangs nicht.

Nachfolgend finden Sie einen Beispielausschnitt, der veranschaulicht, wie sie C_CopyObject zum Speichern von Zertifikaten verwenden.

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

Die C_GetAttributeValue-API ermöglicht das Abrufen aller Im Abschnitt C_CreateObject API aufgeführten Attribute. Diese API wird in der Regel zweimal aufgerufen. Der erste Aufruf bestimmt die Größe von Attributen mit unbekannter Länge, z. B. CKA_SUBJECT, die den Der-codierten Zertifikatbetreff enthält.

Im Folgenden finden Sie ein Beispiel für das Aufrufen von C_GetAttributeValue zum Abrufen der Größen der angegebenen Attribute.

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

Die C_SetAttributeValue-API unterstützt jetzt das Aktualisieren von Zertifikatobjekten. Es erfordert das Sitzungshandle, das Handle des Zertifikats, das aktualisiert werden soll, ein Array von Attributen und deren neue Werte sowie die Anzahl der zu aktualisierenden Attribute. Nur attribute, die in der tabelle C_CreateObject API Usage aufgeführt sind, werden für Updates unterstützt. Der Versuch, nicht unterstützte Attribute zu ändern, führt zu einem fehlgeschlagenen API-Aufruf.

Unten sehen Sie einen Codeausschnitt, der zeigt, wie C_SetAttributeValue mit Zertifikatobjekten verwendet werden kann.

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

Die C_FindObjects*-API unterstützt jetzt das Auffinden von Zertifikatobjekten zusätzlich zu Schlüsselobjekten. Ein Suchvorgang kann Schlüssel- und Zertifikathandles zurückgeben, wenn die Suchvorlage Attribute enthält, die für beide Objekttypen gemeinsam sind. Die C_FindObjectsInit-API wurde erweitert, um alle zertifikatbezogenen Attribute zu unterstützen, die in der C_CreateObject API-Verwendungstabelle aufgeführt sind.

Nachfolgend finden Sie ein Beispiel für einen C_FindObjectsInit Aufruf, der eine Zertifikatsuche mithilfe der Attribute CKA_CLASS, CKA_CERTIFICATE_TYPE und CKA_LABEL durchführt, um alle übereinstimmenden Zertifikatobjekte zu finden.

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

Nach der Initialisierung der Suchparameter wird die C_FindObjects-API verwendet, um die übereinstimmenden Objekthandles abzurufen. Sie gibt auch die Anzahl der gefundenen Objekte zurück. Diese API verwendet das Sitzungshandle, ein Array zum Speichern der resultierenden Objekthandles, die maximale Anzahl der abzurufenden Objekte und einen Ausgabeparameter, der angibt, wie viele Objekte gefunden wurden.

Der folgende Codeausschnitt zeigt einen Aufruf von C_FindObjects nach der Einrichtung der Suchvorlage im obigen C_FindObjectsInit Beispiel.

    // 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

Die C_FindObjectsFinal-API verhält sich für Schlüssel- und Zertifikatobjekte identisch. Es übernimmt das aktuelle Sitzungshandle als Argument und führt eine Bereinigung aller suchbezogenen Strukturen und des Speichers durch, die während des C_FindObjectsInit-Aufrufs zugewiesen wurden.

Im Folgenden finden Sie einen Codeausschnitt, der zeigt, wie Sie C_FindObjectsFinal aufrufen, um den durch die C_FindObjectsInit und C_FindObjects APIs initiierten Suchvorgang abzuschließen und zu bereinigen.

    // 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;
    }
}

Konfigurieren und Ausführen Ihrer PKCS#11-Anwendung mit Azure Cloud HSM

Azure Cloud HSM enthält Beispielanwendungscode, um den Zertifikatspeicher zu überprüfen, der im Azure Cloud HSM Zertifikatspeicherintegrationshandbuch im Azure Cloud HSM SDK auf GitHub verfügbar ist.

Zertifikatstruktur im Speicher

Überprüfen von Zertifikaten im Speicher

Nach einem erfolgreichen Aufruf der C_CreateObject()-API wird das neu erstellte Zertifikatobjekt in Ihrem Azure Blob Storage-Konto angezeigt, wie in der Datei azcloudhsm_application.cfg angegeben. Das Blob wird mit dem Format pkcs11_certificate_<object-handle>benannt, wie unten dargestellt. Zertifikatobjekte werden Objekthandles zugewiesen, die von 0xFFF00000 bis 0xFFFFFFFF reichen (Dezimalbereich: 4.293.918.720 bis 4.294.967.295), wodurch bis zu 1.048.575 Zertifikate unterstützt werden können.

Sowohl im Azure-Portal als auch auf Ihrem virtuellen Azure-Computer können Sie die gespeicherten Zertifikate sehen.

Überprüfen über das Azure-Portal

Screenshot mit Zertifikatblobs, die im Azure-Portal für Azure Cloud HSM gespeichert sind.

Überprüfen von Azure VM mit installierter AZ CLI

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

Wenn Sie das Blob herunterladen oder im Azure-Portal anzeigen und dessen Inhalt überprüfen, wird angezeigt, dass das Zertifikat als JWS-Token (JSON Web Signature) gespeichert wird. Das Token folgt der standardmäßigen JWS-Struktur, die in das folgende Format unterteilt ist:

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ächste Schritte