Skip to content

Device certificate example

This example shows how to create a product which creates an internal Certificate Authority for issuing Initial Device certificates.

This example uses the reference python client and the UI to perform different actions.

The example is divided to following stages:

  • How to get authentication token
  • Adding certificate profiles
  • Creating product
  • Issuing Initial Device certificates

Authentication

In order to use the reference python client a valid JWT token is needed. How to obtain one is explained in more detail in the authentication chapter. New token must be requested if the current token expires. ( roughly 1 hour of validity)

(venv) $ az login --allow-no-subscriptions --only-show-error
A web browser has been opened at https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize. Please continue the login in the web browser. If no web browser is available or if the web browser fails to open, use device code flow with `az login --use-device-code`.

[1]    N/A(tenant level account)  <redacted>  <redacted>

The default is marked with an *; the default tenant is '<redacted>' and subscription is 'N/A(tenant level account)' (<redacted>).

Select a subscription and tenant (Type a number or Enter for no changes): 1

Tenant: <redacted>
Subscription: N/A(tenant level account) (<redacted>)


(venv) $ az account get-access-token --resource api://<redacted>
{
  "accessToken": "<redacted>",
  "expiresOn": "2025-06-04 15:18:10.000000",
  "expires_on": 1749039490,
  "subscription": "<redacted>",
  "tenant": "<redacted>",
  "tokenType": "Bearer"
}
(venv) $ export TOKEN=<redacted>

Add profiles

In this example a Certificate Authority is created and two profiles are needed. One for the Certificate Authority and one for the issued End Entities.

The example profiles were taken as base and modified for this example

(venv) $ ./signing-tool.py -c -t $TOKEN \
    -a https://app.laavat.io/<CustomerName>/api/v1/ profile \
    add -F rootca.yaml -N "Device CA root" -T ROOT
{
    "id": "a80ce30e-d992-4907-90b8-b3da744c89ca",
    "profile_name": "Device CA root",
    "profile_type": 3,
    "profile_yaml": "IyBDb25maWcgZmlsZSBmb3IgdGhlIFN1YkNBIHByb2ZpbGUuIERvIG5vdCB1c2UgVEFCUwotLS0KTmFtZTogSW5pdGlhbCBEZXZpY2UgQ2VydGlmaWNhdGUgUHJvZHVjdCBGYW1pbHkgU3ViQ0EgUHJvZmlsZQojIERpc3Rpbmd1aXNoZWQgbmFtZSBvZiB0aGUgQ0EKRE46CiAgIyBPcmdhbml6YXRpb246IAogIE9yZ2FuaXphdGlvbjogTGFhdmF0CiAgIyBPcmdhbml6YXRpb25hbFVuaXQ6IFImRAogICMgQ291bnRyeTogRkkKICBDb3VudHJ5OiBGSQogICMgUHJvdmluY2U6CiAgIyBMb2NhbGl0eToKICAjIFN0cmVldEFkZHJlc3M6CiAgIyBQb3N0YWxDb2RlOgogICMgU2VyaWFsTnVtYmVyCiAgIyBDb21tb25OYW1lOiBJTVg2CiMgRW5kRW50aXR5IGlzIDEsIFN1YiBDQSBwcm9maWxlIDIgLCBSb290IHByb2ZpbGUgMwpQcm9maWxlVHlwZTogMwojIFNpZ25hdHVyZUFsZ29yaXRobXMKIyAgU0hBMVdpdGhSU0EgPSAzCiMgIFNIQTI1NldpdGhSU0EgPSA0CiMgIFNIQTM4NFdpdGhSU0EgPSA1CiMgIFNIQTUxMldpdGhSU0EgPSA2CiMgIERTQVdpdGhTSEExID0gNwojICBEU0FXaXRoU0hBMjU2ID0gOAojICBFQ0RTQVdpdGhTSEExID0gOQojICBFQ0RTQVdpdGhTSEEyNTYgPSAxMAojICBFQ0RTQVdpdGhTSEEzODQgPSAxMQojICBFQ0RTQVdpdGhTSEE1MTIgPSAxMgojICBTSEEyNTZXaXRoUlNBUFNTID0gMTMKIyAgU0hBMzg0V2l0aFJTQVBTUyA9IDE0CiMgIFNIQTUxMldpdGhSU0FQU1MgPSAxNQpTaWduYXR1cmVBbGdvcml0aG06IDEwCiMgS2V5QWxnb3JpdGhtcwojICAgUlNBQWxnb3JpdGhtID0gMQojICAgRUNEU0FBbGdvcml0aG0gPSAyCktleUFsZ29yaXRobTogMgojIFZhbGlkaXR5IG9mIHRoZSBjZXJ0aWZpY2F0ZSBpbiBkdXJhdGlvbiAobWF4IDI5MCB5ZWFycykgb3Igd2l0aCBhYnNvbHV0ZSBkYXRlIGluIFJGQzMzMzkgZS5nLiA5OTk5LTEyLTMxVDIzOjU5OjU5Wi4KIyBFeGFtcGxlIGluIGFic29sdXRlIGRhdGUgIjk5OTktMTItMzFUMjM6NTk6NTlaIi4KIyBFeGFtcGxlIGluIGR1cmF0aW9uICIxaDEwbTEwcyIuIE9ubHkgaCwgbSBhbmQvb3IgcyBhcmUgYWNjZXB0ZWQuClZhbGlkaXR5UGVyaW9kOiAiOTk5OS0xMi0zMVQyMzo1OTo1OVoiCkJhc2ljQ29uc3RyYWludHM6CiAgQmFzaWNDb25zdHJhaW50c1ZhbGlkOiB0cnVlCiAgSXNDQTogdHJ1ZQogIE1heFBhdGhMZW46IDAKICAjIE1heFBhdGhMZW5aZXJvIGluZGljYXRlcyB0aGF0IEJhc2ljQ29uc3RyYWludHNWYWxpZD09dHJ1ZQogICMgYW5kIE1heFBhdGhMZW49PTAgc2hvdWxkIGJlIGludGVycHJldGVkIGFzIGFuIGFjdHVhbAogICMgbWF4aW11bSBwYXRoIGxlbmd0aCBvZiB6ZXJvLiBPdGhlcndpc2UsIHRoYXQgY29tYmluYXRpb24gaXMKICAjIGludGVycHJldGVkIGFzIE1heFBhdGhMZW4gbm90IGJlaW5nIHNldC4KICBNYXhQYXRoTGVuWmVybzogdHJ1ZQpBZGRTS0k6IHRydWUKQWRkQUtJOiB0cnVlCiMgS2V5VXNhZ2VzCiMgIEtleVVzYWdlRGlnaXRhbFNpZ25hdHVyZSA9IDEKIyAgS2V5VXNhZ2VDb250ZW50Q29tbWl0bWVudCA9IDIKIyAgS2V5VXNhZ2VLZXlFbmNpcGhlcm1lbnQgPSA0CiMgIEtleVVzYWdlRGF0YUVuY2lwaGVybWVudCA9IDgKIyAgS2V5VXNhZ2VLZXlBZ3JlZW1lbnQgPSAxNgojICBLZXlVc2FnZUNlcnRTaWduID0gMzIgCiMgIEtleVVzYWdlQ1JMU2lnbiA9IDY0CiMgIEtleVVzYWdlRW5jaXBoZXJPbmx5ID0gMTI4CiMgIEtleVVzYWdlRGVjaXBoZXJPbmx5ID0gMjU2CktleVVzYWdlOgogIC0gMQogIC0gMzIKICAtIDY0CkV4dGVuZGVkS2V5VXNhZ2U6CiAgIyBFeHRlbmRlZEtleVVzYWdlcwogICMgIEV4dEtleVVzYWdlQW55ID0gMAogICMgIEV4dEtleVVzYWdlU2VydmVyQXV0aCA9IDEKICAjICBFeHRLZXlVc2FnZUNsaWVudEF1dGggPSAyCiAgIyAgRXh0S2V5VXNhZ2VDb2RlU2lnbmluZyA9IDMKICAjICBFeHRLZXlVc2FnZUVtYWlsUHJvdGVjdGlvbiA9IDQKICAjICBFeHRLZXlVc2FnZUlQU0VDRW5kU3lzdGVtID0gNQogICMgIEV4dEtleVVzYWdlSVBTRUNUdW5uZWwgPSA2CiAgIyAgRXh0S2V5VXNhZ2VJUFNFQ1VzZXIgPSA3CiAgIyAgRXh0S2V5VXNhZ2VUaW1lU3RhbXBpbmcgPSA4CiAgIyAgRXh0S2V5VXNhZ2VPQ1NQU2lnbmluZyA9IDkKICAjICBFeHRLZXlVc2FnZU1pY3Jvc29mdFNlcnZlckdhdGVkQ3J5cHRvID0gMTAKICAjICBFeHRLZXlVc2FnZU5ldHNjYXBlU2VydmVyR2F0ZWRDcnlwdG8gPSAxMQogICMgIEV4dEtleVVzYWdlTWljcm9zb2Z0Q29tbWVyY2lhbENvZGVTaWduaW5nID0gMTIKICAjICBFeHRLZXlVc2FnZU1pY3Jvc29mdEtlcm5lbENvZGVTaWduaW5nID0gMTMKIyBFeHRyYUV4dGVuc2lvbnM6IHRydWUKIyBTQU5Vc2FnZTogdHJ1ZQojIENSTERpc3RyaWJ1dGlvblBvaW50cy4gTGlzdCBvZiBVUkkgc3RyaW5ncy4KI0NSTERpc3RyaWJ1dGlvblBvaW50czoKIyAgLSBodHRwOi8vY3JsLmxhYXZhdC5jb20vcHJvZHVjdHMtMC9yb290LmNybAoKIyBQb2xpY3lJZGVudGlmaWVycy4gTGlzdCBvZiBBU04xIHBvbGljeSBPSURTCiNQb2xpY3lJZGVudGlmaWVyczoKIyAgLSAxLjEwLjEyMy40MzIuNC41CiMgIC0gMi4xMC4xMjMuNDMyLjQuNjUKCiMgRW5mb3JjZVVuaXF1ZUROIGVuYWJsZXMgdGhlIGNoZWNraW5nIGlmIGEgY2VydGlmaWNhdGUgaGFzIGJlZW4gaXNzdWVkIHdpdGggdGhlIHNhbWUgc3ViamVjdCBETiBmcm9tIHRoZSBDQQojIFZhbHVlcyB0cnVlIG9yIGZhbHNlCiNFbmZvcmNlVW5pcXVlRE46IHRydWUK"
}
Profile added. Profile ID: a80ce30e-d992-4907-90b8-b3da744c89ca

(venv) $ ./signing-tool.py -c -t $TOKEN \
    -a https://app.laavat.io/<CustomerName>/api/v1/ profile \
    add -F endentity.yaml -N "Device CA endentity" -T END
{
    "id": "f1d0e083-1cf1-41da-8284-545f57550764",
    "profile_name": "Device CA endentity",
    "profile_type": 1,
    "profile_yaml": "IyBDb25maWcgZmlsZSBmb3IgdGhlIEVuZCBlbnRpdHkgcHJvZmlsZS4gRG8gbm90IHVzZSBUQUJTCi0tLQpOYW1lOiBJbml0aWFsIERldmljZSBDZXJ0aWZpY2F0ZSBFbmRFbnRpdHkgUHJvZmlsZQpETjoKICAjT3JnYW5pemF0aW9uOiBUZXN0IENvbXAKICBPcmdhbml6YXRpb246IExhYXZhdAogICNPcmdhbml6YXRpb25hbFVuaXQ6IFImRAogICNDb3VudHJ5OiBGSQogIENvdW50cnk6IEZJCiAgI1Byb3ZpbmNlOgogICMtIFNvbWV0aGluZwogICMgTG9jYWxpdHk6CiAgIyBTdHJlZXRBZGRyZXNzOgogICMgUG9zdGFsQ29kZToKICAjIFNlcmlhbE51bWJlcgogICMgQ29tbW9uTmFtZTogCiMgRW5kRW50aXR5IGlzIDEsIFN1YiBDQSBwcm9maWxlIDIgLCBSb290IHByb2ZpbGUgMwpQcm9maWxlVHlwZTogMQojIFNpZ25hdHVyZUFsZ29yaXRobXMKIyAgU0hBMVdpdGhSU0EgPSAzCiMgIFNIQTI1NldpdGhSU0EgPSA0CiMgIFNIQTM4NFdpdGhSU0EgPSA1CiMgIFNIQTUxMldpdGhSU0EgPSA2CiMgIERTQVdpdGhTSEExID0gNwojICBEU0FXaXRoU0hBMjU2ID0gOAojICBFQ0RTQVdpdGhTSEExID0gOQojICBFQ0RTQVdpdGhTSEEyNTYgPSAxMAojICBFQ0RTQVdpdGhTSEEzODQgPSAxMQojICBFQ0RTQVdpdGhTSEE1MTIgPSAxMgojICBTSEEyNTZXaXRoUlNBUFNTID0gMTMKIyAgU0hBMzg0V2l0aFJTQVBTUyA9IDE0CiMgIFNIQTUxMldpdGhSU0FQU1MgPSAxNQpTaWduYXR1cmVBbGdvcml0aG06IDEwCiMgS2V5QWxnb3JpdGhtcwojICAgUlNBQWxnb3JpdGhtID0gMQojICAgRUNEU0FBbGdvcml0aG0gPSAyCktleUFsZ29yaXRobTogMgojIFZhbGlkaXR5IG9mIHRoZSBjZXJ0aWZpY2F0ZSBpbiBkdXJhdGlvbiAobWF4IDI5MCB5ZWFycykgb3Igd2l0aCBhYnNvbHV0ZSBkYXRlIGluIFJGQzMzMzkgZS5nLiA5OTk5LTEyLTMxVDIzOjU5OjU5Wi4KIyBFeGFtcGxlIGluIGFic29sdXRlIGRhdGUgIjk5OTktMTItMzFUMjM6NTk6NTlaIi4KIyBFeGFtcGxlIGluIGR1cmF0aW9uICIxaDEwbTEwcyIuIE9ubHkgaCwgbSBhbmQvb3IgcyBhcmUgYWNjZXB0ZWQuClZhbGlkaXR5UGVyaW9kOiAiOTk5OS0xMi0zMVQyMzo1OTo1OVoiCkJhc2ljQ29uc3RyYWludHM6CiAgVXNlOiB0cnVlCiAgSXNDQTogZmFsc2UKQWRkU0tJOiB0cnVlCkFkZEFLSTogdHJ1ZQojIEtleVVzYWdlcwojICBLZXlVc2FnZURpZ2l0YWxTaWduYXR1cmUgPSAxCiMgIEtleVVzYWdlQ29udGVudENvbW1pdG1lbnQgPSAyCiMgIEtleVVzYWdlS2V5RW5jaXBoZXJtZW50ID0gNAojICBLZXlVc2FnZURhdGFFbmNpcGhlcm1lbnQgPSA4CiMgIEtleVVzYWdlS2V5QWdyZWVtZW50ID0gMTYKIyAgS2V5VXNhZ2VDZXJ0U2lnbiA9IDMyIAojICBLZXlVc2FnZUNSTFNpZ24gPSA2NAojICBLZXlVc2FnZUVuY2lwaGVyT25seSA9IDEyOAojICBLZXlVc2FnZURlY2lwaGVyT25seSA9IDI1NgpLZXlVc2FnZToKICAtIDEKICAtIDE2CkV4dGVuZGVkS2V5VXNhZ2U6CiAgIyBFeHRlbmRlZEtleVVzYWdlcwogICMgIEV4dEtleVVzYWdlQW55ID0gMAogICMgIEV4dEtleVVzYWdlU2VydmVyQXV0aCA9IDEKICAjICBFeHRLZXlVc2FnZUNsaWVudEF1dGggPSAyCiAgIyAgRXh0S2V5VXNhZ2VDb2RlU2lnbmluZyA9IDMKICAjICBFeHRLZXlVc2FnZUVtYWlsUHJvdGVjdGlvbiA9IDQKICAjICBFeHRLZXlVc2FnZUlQU0VDRW5kU3lzdGVtID0gNQogICMgIEV4dEtleVVzYWdlSVBTRUNUdW5uZWwgPSA2CiAgIyAgRXh0S2V5VXNhZ2VJUFNFQ1VzZXIgPSA3CiAgIyAgRXh0S2V5VXNhZ2VUaW1lU3RhbXBpbmcgPSA4CiAgIyAgRXh0S2V5VXNhZ2VPQ1NQU2lnbmluZyA9IDkKICAjICBFeHRLZXlVc2FnZU1pY3Jvc29mdFNlcnZlckdhdGVkQ3J5cHRvID0gMTAKICAjICBFeHRLZXlVc2FnZU5ldHNjYXBlU2VydmVyR2F0ZWRDcnlwdG8gPSAxMQogICMgIEV4dEtleVVzYWdlTWljcm9zb2Z0Q29tbWVyY2lhbENvZGVTaWduaW5nID0gMTIKICAjICBFeHRLZXlVc2FnZU1pY3Jvc29mdEtlcm5lbENvZGVTaWduaW5nID0gMTMKICAtIDEKICAtIDIKRXh0cmFFeHRlbnNpb25zOiB0cnVlClNBTlVzYWdlOiB0cnVlCiMgQ1JMRGlzdHJpYnV0aW9uUG9pbnRzLiBMaXN0IG9mIFVSSSBzdHJpbmdzLgpDUkxEaXN0cmlidXRpb25Qb2ludHM6CiAgLSBodHRwOi8vY3JsLmxhYXZhdC5jb20vZTM3ZjA0NWMuY3JsCiMgUG9saWN5SWRlbnRpZmllcnMuIExpc3Qgb2YgQVNOMSBwb2xpY3kgT0lEUwpQb2xpY3lJZGVudGlmaWVyczoKICAtIDEuMTAuMTIzLjQzMi40LjUKICAtIDIuMTAuMTIzLjQzMi40LjY1CiMgRW5mb3JjZVVuaXF1ZUROIGVuYWJsZXMgdGhlIGNoZWNraW5nIGlmIGEgY2VydGlmaWNhdGUgaGFzIGJlZW4gaXNzdWVkIHdpdGggdGhlIHNhbWUgc3ViamVjdCBETiBmcm9tIHRoZSBDQQojIFZhbHVlcyB0cnVlIG9yIGZhbHNlCiMgRW5mb3JjZVVuaXF1ZUROOiB0cnVlCg=="
}
Profile added. Profile ID: f1d0e083-1cf1-41da-8284-545f57550764

(venv) $ ./signing-tool.py -c -t $TOKEN \
    -a https://app.laavat.io/<CustomerName>/api/v1/ profile getall
{
    "count": 2,
    "items": [
        {
            "id": "f1d0e083-1cf1-41da-8284-545f57550764",
            "profile_name": "Device CA endentity",
            "profile_type": 1
        },
        {
            "id": "a80ce30e-d992-4907-90b8-b3da744c89ca",
            "profile_name": "Device CA root",
            "profile_type": 3
        }
    ],
    "next": "/cas/profiles/?page=1",
    "pages": 1,
    "prev": "/cas/profiles/?page=1"
}

Create product

Here is the used product template. The product template was updated with the profile ids obtained from the previous commands. The values $ROOTPROFILEID, $ENDPROFILEID were changed with their corresponding profile id.

  • ROOTPROFILEID=a80ce30e-d992-4907-90b8-b3da744c89ca
  • ENDPROFILEID=f1d0e083-1cf1-41da-8284-545f57550764

In this product there is one operation. In the approval rule it was decided that entities in the $WRITERGROUP were able to make issuance requests.

$WRITERGROUP is replaced with the corresponding Group Object ID from Microsoft Entra.

The template was saved as product.json.

More information about rules can be found from approval rules.

Product was created using the python tool

(venv) $ ./signing-tool.py -c -t $TOKEN \
    -a https://app.laavat.io/<CustomerName>/api/v1/ product add -T product.json 
{
    "ca_info": [
        {
            "cert_override_payload": null,
            "certificate_type": "ROOT",
            "cn": "Dummy CA",
            "crl_distribution_points": null,
            "crl_expiry": null,
            "crl_issue_interval": null,
            "csr": null,
            "description": "Device Identity CA for Dummy Device CA issuer",
            "external_request_id": null,
            "external_root": null,
            "id": null,
            "issuer_ca_id": null,
            "key_override_id": null,
            "key_type": "ECDSAP256",
            "leafs": [],
            "originating_id": null,
            "policy_identifiers": null,
            "product_id": null,
            "profile_id": "a80ce30e-d992-4907-90b8-b3da744c89ca",
            "state": null,
            "use_case": "DeviceCA"
        }
    ],
    "description": "Device certificate for Initial Device certificates",
    "enabled": true,
    "external_request_id": null,
    "id": null,
    "name": "Dummy Device CA issuer",
    "product_config_items": null,
    "product_operations": [
        {
            "approval_rule": {
                "allowed_groups": [
                    "b716abb1-2e3b-47a9-bca5-a3669faa50a6"
                ],
                "approval_groups": [],
                "blanket_groups": [],
                "description": "desc",
                "name": "This is rule"
            },
            "ca_use_case": null,
            "description": "Device certificates",
            "id": null,
            "name": "Issue device certificates",
            "operation_type": "IssueDeviceCertificate",
            "profile_id": "f1d0e083-1cf1-41da-8284-545f57550764",
            "token": null
        }
    ],
    "product_type": "Production",
    "rnd_keys": [],
    "state": null
}
Is product ok(Y/N): y
{
    "ca_info": [],
    "description": "Device certificate for Initial Device certificates",
    "enabled": null,
    "external_request_id": null,
    "id": "c57c5925-9a5c-4c57-a70a-74e68a8ddc4f",
    "name": "Dummy Device CA issuer",
    "product_config_items": null,
    "product_operations": [],
    "product_type": null,
    "rnd_keys": [],
    "state": 2
}
Product Add request sent. Request ID: c57c5925-9a5c-4c57-a70a-74e68a8ddc4f state: ApprovalRequired

Approve product

The product was approved using the GUI.

Then with the python tool the state was checked ( state is 16 for ready product) and the product ID and operation ID was obtained.

  • productID = c57c5925-9a5c-4c57-a70a-74e68a8ddc4f
(venv) $ ./signing-tool.py -c -t $TOKEN \
    -a https://app.laavat.io/<CustomerName>/api/v1/ product getall
{
    "count": 1,
    "items": [
        {
            "description": "Device certificate for Initial Device certificates",
            "id": "c57c5925-9a5c-4c57-a70a-74e68a8ddc4f",
            "name": "Dummy Device CA issuer",
            "state": 16
        }
    ],
    "next": "/products/?page=1",
    "pages": 1,
    "prev": "/products/?page=1"
}

(venv) $ ./signing-tool.py -c -t $TOKEN \
    -a https://app.laavat.io/<CustomerName>/api/v1/ product \
    get -I c57c5925-9a5c-4c57-a70a-74e68a8ddc4f 
{
    "ca_info": [
        {
            "cert_override_payload": null,
            "certificate_type": "ROOT",
            "cn": "Dummy CA",
            "crl_distribution_points": null,
            "crl_expiry": null,
            "crl_issue_interval": null,
            "csr": null,
            "description": "Device Identity CA for Dummy Device CA issuer",
            "external_request_id": null,
            "external_root": null,
            "id": "017ba6a9-38f1-4243-adc1-640524095794",
            "issuer_ca_id": null,
            "key_override_id": null,
            "key_type": "ECDSAP256",
            "leafs": [],
            "originating_id": null,
            "policy_identifiers": null,
            "product_id": null,
            "profile_id": "a80ce30e-d992-4907-90b8-b3da744c89ca",
            "state": 16,
            "use_case": "DeviceCA"
        }
    ],
    "description": "Device certificate for Initial Device certificates",
    "enabled": null,
    "external_request_id": "e637820b-7e02-07bc-d067-1e18fcc70d61",
    "id": "c57c5925-9a5c-4c57-a70a-74e68a8ddc4f",
    "name": "Dummy Device CA issuer",
    "product_config_items": [],
    "product_operations": [
        {
            "approval_rule": {
                "allowed_groups": [
                    "b716abb1-2e3b-47a9-bca5-a3669faa50a6"
                ],
                "approval_groups": [
                    ""
                ],
                "blanket_groups": [
                    ""
                ],
                "description": "desc",
                "name": "This is rule"
            },
            "ca_use_case": null,
            "description": "Device certificates",
            "id": "d179e0d0-06b2-4ca4-876f-31c415107337",
            "name": "Issue device certificates",
            "operation_type": "IssueDeviceCertificate",
            "profile_id": "f1d0e083-1cf1-41da-8284-545f57550764",
            "token": null
        }
    ],
    "product_type": "Production",
    "rnd_keys": [],
    "state": 16
}

Issuing Device certificates

Create CSR

In real life scenario the device creates the key and the corresponding CSR.

(venv) $ openssl ecparam -name prime256v1 -genkey -noout -conv_form uncompressed -out /tmp/ec.key
(venv) $ openssl req -new -nodes -key /tmp/ec.key -outform DER -subj "/C=FI/O=Customer/CN=device-123" 2>/dev/null > /tmp/csr.bin

Send the CSR for issuance

(venv) $ ./signing-tool.py -c -t $TOKEN \
    -a https://app.laavat.io/<CustomerName>/api/v1/ production add -P c57c5925-9a5c-4c57-a70a-74e68a8ddc4f -C /tmp/csr.bin
{
    "certificate": null,
    "chain": [],
    "error_status": null,
    "id": "dd8c431e-0860-4001-878d-5bf7257d65ef",
    "state": 1,
    "subject": "CN=device-123,O=Customer,C=FI"
}
Certificate signing request sent. Request ID: dd8c431e-0860-4001-878d-5bf7257d65ef state: Created


(venv) $ ./signing-tool.py -c -t $TOKEN \
    -a https://app.laavat.io/<CustomerName>/api/v1/ production \
    get -I dd8c431e-0860-4001-878d-5bf7257d65ef -O /tmp/crt
{
    "certificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNMRENDQWRLZ0F3SUJBZ0lSQUl2VE55Mm1mbHppQmlJQkphN1FaL0l3Q2dZSUtvWkl6ajBFQXdJd01URUwKTUFrR0ExVUVCaE1DUmtreER6QU5CZ05WQkFvVEJreGhZWFpoZERFUk1BOEdBMVVFQXhNSVJIVnRiWGtnUTBFdwpJQmNOTWpVd05qRTJNVEV4TURNMFdoZ1BPVGs1T1RFeU16RXlNelU1TlRsYU1ETXhDekFKQmdOVkJBWVRBa1pKCk1ROHdEUVlEVlFRS0V3Wk1ZV0YyWVhReEV6QVJCZ05WQkFNVENtUmxkbWxqWlMweE1qTXdXVEFUQmdjcWhrak8KUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVJhOFUvRitrTDRNcFBSUHJ5TUR3WjBjNkpMdzZHVFNmY2QvL0NHUkFMUApiNHhTN3dJUzc0Uy8zRTdqcTNBWTZveWwzczB1Yzd1SUlhMWJ1OVNLSnJvNW80SEdNSUhETUE0R0ExVWREd0VCCi93UUVBd0lEaURBZEJnTlZIU1VFRmpBVUJnZ3JCZ0VGQlFjREFRWUlLd1lCQlFVSEF3SXdIUVlEVlIwT0JCWUUKRklacVZZU2xJM0w5YjdYbzJKcmxlNStXakNsZE1COEdBMVVkSXdRWU1CYUFGQ3ppZHJqZ3lkNmFHNlZoVkRoMgpaaHZRMkFIc01CMEdBMVVkSUFRV01CUXdDQVlHTW51RE1BUUZNQWdHQmxwN2d6QUVRVEF6QmdOVkhSOEVMREFxCk1DaWdKcUFraGlKb2RIUndPaTh2WTNKc0xteGhZWFpoZEM1amIyMHZaVE0zWmpBME5XTXVZM0pzTUFvR0NDcUcKU000OUJBTUNBMGdBTUVVQ0lDY1MxSTVpK3MxMXgrUytoaFN6THVPL1ZWTXFWYjBEb0RDd20ydm1kUSt5QWlFQQp3Yjdpb0JJQzlobWhPNDZhdTFzNFlWb0wwbEdNaGM0aU9qM3JUdmJQODZNPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==",
    "chain": [
        "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ4akNDQVd5Z0F3SUJBZ0lSQUwyeG80akpOTEgxcDlzOHY2dHZJRWd3Q2dZSUtvWkl6ajBFQXdJd01URUwKTUFrR0ExVUVCaE1DUmtreER6QU5CZ05WQkFvVEJreGhZWFpoZERFUk1BOEdBMVVFQXhNSVJIVnRiWGtnUTBFdwpJQmNOTWpVd05qRTJNVEExT0RBNVdoZ1BPVGs1T1RFeU16RXlNelU1TlRsYU1ERXhDekFKQmdOVkJBWVRBa1pKCk1ROHdEUVlEVlFRS0V3Wk1ZV0YyWVhReEVUQVBCZ05WQkFNVENFUjFiVzE1SUVOQk1Ga3dFd1lIS29aSXpqMEMKQVFZSUtvWkl6ajBEQVFjRFFnQUVYU0YzQ1B2U1NEcU1TVmROVndxQ0ZUamprcnJuQkZuNkFiUmtTV1JIQTI5eQpzLzNCM1JFU2I4MFQ0aHp1YUhJZnNtdzlZVk81TzFPdDhCZHpFYXhFc3FOak1HRXdEZ1lEVlIwUEFRSC9CQVFECkFnR0dNQThHQTFVZEV3RUIvd1FGTUFNQkFmOHdIUVlEVlIwT0JCWUVGQ3ppZHJqZ3lkNmFHNlZoVkRoMlpodlEKMkFIc01COEdBMVVkSXdRWU1CYUFGQ3ppZHJqZ3lkNmFHNlZoVkRoMlpodlEyQUhzTUFvR0NDcUdTTTQ5QkFNQwpBMGdBTUVVQ0lRQ3NhQWQ1KzBiMmgyREJxQmlWYXUwWllCWnRHT1VScG80dlEydFk0SjVmOVFJZ0puZVpObUF2CnNuZVVRd05HSWptbUZGT01paFpOU0RobE1pOVI2THVHSlVBPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="
    ],
    "error_status": null,
    "id": "dd8c431e-0860-4001-878d-5bf7257d65ef",
    "state": 16,
    "subject": "CN=device-123,O=Customer,C=FI"
}
Certificate signing request. Request ID: dd8c431e-0860-4001-878d-5bf7257d65ef state: Ready
certificate written to: /tmp/crt.crt
certificate chain written to: /tmp/crt.chain