> Markdown version of https://docs.laavat.io/exampleflows/advancedpki/ from the LAAVAT PKI and Signing Platform documentation. All pages: https://docs.laavat.io/llms.txt

# Advanced PKI hierarchy to issue Device certificates and client certificates

This example shows how to create an advanced setup with root and subordinate CAs for two uses cases:

- Initial Device certificates
- Client certificates for authetication purposes. ( In this example these are used to request the device certificates using mTLS)

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 products
- Issuing client certificates
- Issuing Initial Device certificates using mTLS

***NOTE: If mTLS target environment is LAAVAT Platform maximum chain length is four***

## PKI hierarchy

The following PKI structure will be created:

``` mermaid
graph TD
    A[Root CA<br>• Validity: 200 years<br>] --> B[Device Family Sub CA<br>• Validity: 100 years<br>]
    B --> D[Device CA<br>• Validity: 100 years<br>]
    D --> E[End-Entity certificates for devices<br>• Validity: 100 years<br>]
    A --> C[Client Family CA<br>• Validity: 100 years<br>]
    C --> F[Client CA<br>• Validity: 20 years<br>]
    F --> G[End-Entity certificates for clients<br>• Validity: 2 years<br>]
```

The PKI structure is created with 5 products. See below.

``` mermaid
graph TD
    A[Product for ROOTCA] --> B[Product for Device Family Sub CA]
    A --> C[Product for Client Sub CA]
    B --> D[Product for issuing End-Entity certificates for devices]
    C --> F[Product for issuing End-Entity client 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.](https://docs.laavat.io/api/authentication/)
New token must be requested if the current token expires. ( roughly 1 hour of validity)

```bash
(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> \
    --query accessToken -o tsv > user.token
```

Rather than putting the token on the command line, write it to a file and let `config-init` reference it. This creates
a `test.ini` that stores a `token_file` path (not the token itself):

```bash
(venv) $ config-init -n test.ini -t @user.token -a https://app.laavat.io/<CustomerName>/api/v1
```

The `signing-tool` commands below then run with `-n test.ini`, so no token appears on the command line. See
[Reference Client › Usage](https://docs.laavat.io/democlient/usage/) for the secure token-input forms (`-t @file`, `-t @-`).

## Add profiles

In this example a 5 Certificate Authorities are created and multiple profiles are needed.
Please note that CloudHSM enforces strict compliance with NIST FIPS 140-2 or FIPS 140-3 standards. Therefore the signature algorithm strength cannot be lower that the key size.
In this case the ROOT is using EC P384 key so it must sign the issued certificates with ECDSAWithSHA384.

### ROOT CA

- The [Initial Device Certificate Product Family RootCA EC Profile](https://docs.laavat.io/certtemplates/device-cert-root-ec-profile.yaml) was used as the profile for the ROOT.
- The [Initial Device Certificate Product Family SubCA Profile EC for root issuer](https://docs.laavat.io/certtemplates/device-cert-subca-ecdsa-p384-SHA384-profile.yaml) was used as the profile for the issued certificates under the root.

```bash
(venv) $ signing-tool -n test.ini profile add \
    -F device-cert-root-ec-profile.yaml \
    -N "Initial Device Certificate Product Family RootCA EC Profile" -T ROOT
{
    "id": "4a63eff1-29ae-43fa-baba-c319575291db",
    "profile_name": "Initial Device Certificate Product Family RootCA EC Profile",
    "profile_type": 3,
    "profile_yaml": "IyBDb25maWcg…(3,596 base64 chars elided; text, shown decoded below as value 1 of 2)"
}
Profile added. Profile ID: 4a63eff1-29ae-43fa-baba-c319575291db

(venv) $ signing-tool -n test.ini profile add \
    -F device-cert-subca-ecdsa-p384-SHA384-profile.yaml \
    -N "Initial Device Certificate Product Family SubCA Profile EC for root issuer" \
    -T SUB
{
    "id": "bff08e23-9eaf-427c-a776-1dacbd546311",
    "profile_name": "Initial Device Certificate Product Family SubCA Profile EC for root issuer",
    "profile_type": 2,
    "profile_yaml": "IyBDb25maWcg…(3,628 base64 chars elided; text, shown decoded below as value 2 of 2)"
}
Profile added. Profile ID: bff08e23-9eaf-427c-a776-1dacbd546311
```

Decoded base64 value 1 of 2:

```text
# Config file for the SubCA profile. Do not use TABS
---
Name: ROOT Profile
# Distinguished name of the CA
DN:
  # Organization: 
  Organization: Laavat
  # OrganizationalUnit: R&D
  # Country: FI
  Country: FI
  # Province:
  # Locality:
  # StreetAddress:
  # PostalCode:
  # SerialNumber
  # CommonName: IMX6
# EndEntity is 1, Sub CA profile 2 , Root profile 3
ProfileType: 3
# SignatureAlgorithms
#  SHA1WithRSA = 3
#  SHA256WithRSA = 4
#  SHA384WithRSA = 5
#  SHA512WithRSA = 6
#  DSAWithSHA1 = 7
#  DSAWithSHA256 = 8
#  ECDSAWithSHA1 = 9
#  ECDSAWithSHA256 = 10
#  ECDSAWithSHA384 = 11
#  ECDSAWithSHA512 = 12
#  SHA256WithRSAPSS = 13
#  SHA384WithRSAPSS = 14
#  SHA512WithRSAPSS = 15
SignatureAlgorithm: 11
# KeyAlgorithms
#   RSAAlgorithm = 1
#   ECDSAAlgorithm = 2
KeyAlgorithm: 2
# Validity of the certificate in duration (max 290 years) or with absolute date in RFC3339 e.g. 9999-12-31T23:59:59Z.
# Example in absolute date "9999-12-31T23:59:59Z".
# Example in duration "1h10m10s". Only h, m and/or s are accepted.
ValidityPeriod: "1752000h"
BasicConstraints:
  BasicConstraintsValid: true
  IsCA: true
  MaxPathLen: 3
  # MaxPathLenZero indicates that BasicConstraintsValid==true
  # and MaxPathLen==0 should be interpreted as an actual
  # maximum path length of zero. Otherwise, that combination is
  # interpreted as MaxPathLen not being set.
  # MaxPathLenZero: true
AddSKI: true
AddAKI: true
# KeyUsages
#  KeyUsageDigitalSignature = 1
#  KeyUsageContentCommitment = 2
#  KeyUsageKeyEncipherment = 4
#  KeyUsageDataEncipherment = 8
#  KeyUsageKeyAgreement = 16
#  KeyUsageCertSign = 32 
#  KeyUsageCRLSign = 64
#  KeyUsageEncipherOnly = 128
#  KeyUsageDecipherOnly = 256
KeyUsage:
  - 1
  - 32
  - 64
ExtendedKeyUsage:
  # ExtendedKeyUsages
  #  ExtKeyUsageAny = 0
  #  ExtKeyUsageServerAuth = 1
  #  ExtKeyUsageClientAuth = 2
  #  ExtKeyUsageCodeSigning = 3
  #  ExtKeyUsageEmailProtection = 4
  #  ExtKeyUsageIPSECEndSystem = 5
  #  ExtKeyUsageIPSECTunnel = 6
  #  ExtKeyUsageIPSECUser = 7
  #  ExtKeyUsageTimeStamping = 8
  #  ExtKeyUsageOCSPSigning = 9
  #  ExtKeyUsageMicrosoftServerGatedCrypto = 10
  #  ExtKeyUsageNetscapeServerGatedCrypto = 11
  #  ExtKeyUsageMicrosoftCommercialCodeSigning = 12
  #  ExtKeyUsageMicrosoftKernelCodeSigning = 13
# ExtraExtensions: true
# SANUsage: true
# CRLDistributionPoints. List of URI strings.
#CRLDistributionPoints:
#  - http://crl.laavat.com/products-0/root.crl

# PolicyIdentifiers. List of ASN1 policy OIDS
#PolicyIdentifiers:
#  - 1.10.123.432.4.5
#  - 2.10.123.432.4.65

# EnforceUniqueDN enables the checking if a certificate has been issued with the same subject DN from the CA
# Values true or false
#EnforceUniqueDN: true
```

Decoded base64 value 2 of 2:

```text
# Config file for the SubCA profile. Do not use TABS
---
Name: Family SubCA Profile with ECDSAWithSHA384
# Distinguished name of the CA
DN:
  # Organization: 
  Organization: Laavat
  # OrganizationalUnit: R&D
  # Country: FI
  Country: FI
  # Province:
  # Locality:
  # StreetAddress:
  # PostalCode:
  # SerialNumber
  # CommonName: IMX6
# EndEntity is 1, Sub CA profile 2 , Root profile 3
ProfileType: 2
# SignatureAlgorithms
#  SHA1WithRSA = 3
#  SHA256WithRSA = 4
#  SHA384WithRSA = 5
#  SHA512WithRSA = 6
#  DSAWithSHA1 = 7
#  DSAWithSHA256 = 8
#  ECDSAWithSHA1 = 9
#  ECDSAWithSHA256 = 10
#  ECDSAWithSHA384 = 11
#  ECDSAWithSHA512 = 12
#  SHA256WithRSAPSS = 13
#  SHA384WithRSAPSS = 14
#  SHA512WithRSAPSS = 15
SignatureAlgorithm: 11
# KeyAlgorithms
#   RSAAlgorithm = 1
#   ECDSAAlgorithm = 2
KeyAlgorithm: 2
# Validity of the certificate in duration (max 290 years) or with absolute date in RFC3339 e.g. 9999-12-31T23:59:59Z.
# Example in absolute date "9999-12-31T23:59:59Z".
# Example in duration "1h10m10s". Only h, m and/or s are accepted.
ValidityPeriod: "876000h"
BasicConstraints:
  BasicConstraintsValid: true
  IsCA: true
  MaxPathLen: 0
  # MaxPathLenZero indicates that BasicConstraintsValid==true
  # and MaxPathLen==0 should be interpreted as an actual
  # maximum path length of zero. Otherwise, that combination is
  # interpreted as MaxPathLen not being set.
  MaxPathLenZero: true
AddSKI: true
AddAKI: true
# KeyUsages
#  KeyUsageDigitalSignature = 1
#  KeyUsageContentCommitment = 2
#  KeyUsageKeyEncipherment = 4
#  KeyUsageDataEncipherment = 8
#  KeyUsageKeyAgreement = 16
#  KeyUsageCertSign = 32 
#  KeyUsageCRLSign = 64
#  KeyUsageEncipherOnly = 128
#  KeyUsageDecipherOnly = 256
KeyUsage:
  - 1
  - 32
  - 64
ExtendedKeyUsage:
  # ExtendedKeyUsages
  #  ExtKeyUsageAny = 0
  #  ExtKeyUsageServerAuth = 1
  #  ExtKeyUsageClientAuth = 2
  #  ExtKeyUsageCodeSigning = 3
  #  ExtKeyUsageEmailProtection = 4
  #  ExtKeyUsageIPSECEndSystem = 5
  #  ExtKeyUsageIPSECTunnel = 6
  #  ExtKeyUsageIPSECUser = 7
  #  ExtKeyUsageTimeStamping = 8
  #  ExtKeyUsageOCSPSigning = 9
  #  ExtKeyUsageMicrosoftServerGatedCrypto = 10
  #  ExtKeyUsageNetscapeServerGatedCrypto = 11
  #  ExtKeyUsageMicrosoftCommercialCodeSigning = 12
  #  ExtKeyUsageMicrosoftKernelCodeSigning = 13
# ExtraExtensions: true
# SANUsage: true
# CRLDistributionPoints. List of URI strings.
#CRLDistributionPoints:
#  - http://crl.laavat.com/products-0/root.crl

# PolicyIdentifiers. List of ASN1 policy OIDS
#PolicyIdentifiers:
#  - 1.10.123.432.4.5
#  - 2.10.123.432.4.65

# EnforceUniqueDN enables the checking if a certificate has been issued with the same subject DN from the CA
# Values true or false
#EnforceUniqueDN: true
```

### SUB CA and End-Entity profiles

- The [Initial Device Certificate Product Family SubCA Profile EC](https://docs.laavat.io/certtemplates/device-cert-subca-ecdsa-p256-SHA256-profile.yaml) was used as the profile for the CA.
- The [Initial Device Certificate EndEntity Profile EC](https://docs.laavat.io/certtemplates/device-cert-endentity-ecdsa-p256-SHA256-profile.yaml) was used as the profile for the issued certificates under the CA.
- The [Client Certificate Product Family SubCA Profile EC](https://docs.laavat.io/certtemplates/client-cert-subca-ecdsa-p256-SHA256-profile.yaml) was used as the profile for the CA.
- The [Client Certificate EndEntity Profile EC](https://docs.laavat.io/certtemplates/client-cert-endentity-ecdsa-p256-SHA256-profile.yaml) was used as the profile for the issued certificates under the CA.

```bash
(venv) $ signing-tool -n test.ini profile add \
    -F device-cert-subca-ecdsa-p256-SHA256-profile.yaml \
    -N "Initial Device Certificate Product Family SubCA Profile EC" -T SUB
{
    "id": "3adb4838-10d8-4ad5-b2b2-a711ef4a28db",
    "profile_name": "Initial Device Certificate Product Family SubCA Profile EC",
    "profile_type": 2,
    "profile_yaml": "IyBDb25maWcg…(3,600 base64 chars elided; text, shown decoded below as value 1 of 4)"
}
Profile added. Profile ID: 3adb4838-10d8-4ad5-b2b2-a711ef4a28db

(venv) $ signing-tool -n test.ini profile add \
    -F device-cert-endentity-ecdsa-p256-SHA256-profile.yaml \
    -N "Initial Device Certificate EndEntity Profile EC" -T END
{
    "id": "4d48c275-445a-4e95-9cdb-064688010dc1",
    "profile_name": "Initial Device Certificate EndEntity Profile EC",
    "profile_type": 1,
    "profile_yaml": "IyBDb25maWcg…(3,108 base64 chars elided; text, shown decoded below as value 2 of 4)"
}
Profile added. Profile ID: 4d48c275-445a-4e95-9cdb-064688010dc1

(venv) $ signing-tool -n test.ini profile add \
    -F client-cert-subca-ecdsa-p256-SHA256-profile.yaml \
    -N "Client Certificate Product Family SubCA Profile EC" -T SUB
{
    "id": "73011594-d7b7-428c-b38c-f3ba9213de81",
    "profile_name": "Client Certificate Product Family SubCA Profile EC",
    "profile_type": 2,
    "profile_yaml": "IyBDb25maWcg…(3,636 base64 chars elided; text, shown decoded below as value 3 of 4)"
}
Profile added. Profile ID: 73011594-d7b7-428c-b38c-f3ba9213de81

(venv) $ signing-tool -n test.ini profile add \
    -F client-cert-endentity-ecdsa-p256-SHA256-profile.yaml \
    -N "Client Certificate EndEntity Profile EC" -T END
{
    "id": "292017ef-1987-48f4-a0ca-915991ecf780",
    "profile_name": "Client Certificate EndEntity Profile EC",
    "profile_type": 1,
    "profile_yaml": "IyBDb25maWcg…(3,220 base64 chars elided; text, shown decoded below as value 4 of 4)"
}
Profile added. Profile ID: 292017ef-1987-48f4-a0ca-915991ecf780

(venv) $ signing-tool -n test.ini profile getall
{
    "count": 6,
    "items": [
        {
            "id": "292017ef-1987-48f4-a0ca-915991ecf780",
            "profile_name": "Client Certificate EndEntity Profile EC",
            "profile_type": 1
        },
        {
            "id": "73011594-d7b7-428c-b38c-f3ba9213de81",
            "profile_name": "Client Certificate Product Family SubCA Profile EC",
            "profile_type": 2
        },
        {
            "id": "4d48c275-445a-4e95-9cdb-064688010dc1",
            "profile_name": "Initial Device Certificate EndEntity Profile EC",
            "profile_type": 1
        },
        {
            "id": "4a63eff1-29ae-43fa-baba-c319575291db",
            "profile_name": "Initial Device Certificate Product Family RootCA EC Profile",
            "profile_type": 3
        },
        {
            "id": "3adb4838-10d8-4ad5-b2b2-a711ef4a28db",
            "profile_name": "Initial Device Certificate Product Family SubCA Profile EC",
            "profile_type": 2
        },
        {
            "id": "bff08e23-9eaf-427c-a776-1dacbd546311",
            "profile_name": "Initial Device Certificate Product Family SubCA Profile EC for root issuer",
            "profile_type": 2
        }
    ],
    "next": "/cas/profiles/?page=1",
    "pages": 1,
    "prev": "/cas/profiles/?page=1"
}
```

Decoded base64 value 1 of 4:

```text
# Config file for the SubCA profile. Do not use TABS
---
Name: Family SubCA Profile
# Distinguished name of the CA
DN:
  # Organization: 
  Organization: Laavat
  # OrganizationalUnit: R&D
  # Country: FI
  Country: FI
  # Province:
  # Locality:
  # StreetAddress:
  # PostalCode:
  # SerialNumber
  # CommonName: IMX6
# EndEntity is 1, Sub CA profile 2 , Root profile 3
ProfileType: 2
# SignatureAlgorithms
#  SHA1WithRSA = 3
#  SHA256WithRSA = 4
#  SHA384WithRSA = 5
#  SHA512WithRSA = 6
#  DSAWithSHA1 = 7
#  DSAWithSHA256 = 8
#  ECDSAWithSHA1 = 9
#  ECDSAWithSHA256 = 10
#  ECDSAWithSHA384 = 11
#  ECDSAWithSHA512 = 12
#  SHA256WithRSAPSS = 13
#  SHA384WithRSAPSS = 14
#  SHA512WithRSAPSS = 15
SignatureAlgorithm: 10
# KeyAlgorithms
#   RSAAlgorithm = 1
#   ECDSAAlgorithm = 2
KeyAlgorithm: 2
# Validity of the certificate in duration (max 290 years) or with absolute date in RFC3339 e.g. 9999-12-31T23:59:59Z.
# Example in absolute date "9999-12-31T23:59:59Z".
# Example in duration "1h10m10s". Only h, m and/or s are accepted.
ValidityPeriod: "876000h"
BasicConstraints:
  BasicConstraintsValid: true
  IsCA: true
  MaxPathLen: 0
  # MaxPathLenZero indicates that BasicConstraintsValid==true
  # and MaxPathLen==0 should be interpreted as an actual
  # maximum path length of zero. Otherwise, that combination is
  # interpreted as MaxPathLen not being set.
  MaxPathLenZero: true
AddSKI: true
AddAKI: true
# KeyUsages
#  KeyUsageDigitalSignature = 1
#  KeyUsageContentCommitment = 2
#  KeyUsageKeyEncipherment = 4
#  KeyUsageDataEncipherment = 8
#  KeyUsageKeyAgreement = 16
#  KeyUsageCertSign = 32 
#  KeyUsageCRLSign = 64
#  KeyUsageEncipherOnly = 128
#  KeyUsageDecipherOnly = 256
KeyUsage:
  - 1
  - 32
  - 64
ExtendedKeyUsage:
  # ExtendedKeyUsages
  #  ExtKeyUsageAny = 0
  #  ExtKeyUsageServerAuth = 1
  #  ExtKeyUsageClientAuth = 2
  #  ExtKeyUsageCodeSigning = 3
  #  ExtKeyUsageEmailProtection = 4
  #  ExtKeyUsageIPSECEndSystem = 5
  #  ExtKeyUsageIPSECTunnel = 6
  #  ExtKeyUsageIPSECUser = 7
  #  ExtKeyUsageTimeStamping = 8
  #  ExtKeyUsageOCSPSigning = 9
  #  ExtKeyUsageMicrosoftServerGatedCrypto = 10
  #  ExtKeyUsageNetscapeServerGatedCrypto = 11
  #  ExtKeyUsageMicrosoftCommercialCodeSigning = 12
  #  ExtKeyUsageMicrosoftKernelCodeSigning = 13
# ExtraExtensions: true
# SANUsage: true
# CRLDistributionPoints. List of URI strings.
#CRLDistributionPoints:
#  - http://crl.laavat.com/products-0/root.crl

# PolicyIdentifiers. List of ASN1 policy OIDS
#PolicyIdentifiers:
#  - 1.10.123.432.4.5
#  - 2.10.123.432.4.65

# EnforceUniqueDN enables the checking if a certificate has been issued with the same subject DN from the CA
# Values true or false
#EnforceUniqueDN: true
```

Decoded base64 value 2 of 4:

```text
# Config file for the End entity profile. Do not use TABS
---
Name: EndEntity Profile
DN:
  #Organization: Test Comp
  Organization: Laavat
  #OrganizationalUnit: R&D
  #Country: FI
  Country: FI
  #Province:
  #- Something
  # Locality:
  # StreetAddress:
  # PostalCode:
  # SerialNumber
  # CommonName: 
# EndEntity is 1, Sub CA profile 2 , Root profile 3
ProfileType: 1
# SignatureAlgorithms
#  SHA1WithRSA = 3
#  SHA256WithRSA = 4
#  SHA384WithRSA = 5
#  SHA512WithRSA = 6
#  DSAWithSHA1 = 7
#  DSAWithSHA256 = 8
#  ECDSAWithSHA1 = 9
#  ECDSAWithSHA256 = 10
#  ECDSAWithSHA384 = 11
#  ECDSAWithSHA512 = 12
#  SHA256WithRSAPSS = 13
#  SHA384WithRSAPSS = 14
#  SHA512WithRSAPSS = 15
SignatureAlgorithm: 10
# KeyAlgorithms
#   RSAAlgorithm = 1
#   ECDSAAlgorithm = 2
KeyAlgorithm: 2
# Validity of the certificate in duration (max 290 years) or with absolute date in RFC3339 e.g. 9999-12-31T23:59:59Z.
# Example in absolute date "9999-12-31T23:59:59Z".
# Example in duration "1h10m10s". Only h, m and/or s are accepted.
ValidityPeriod: "876000h"
BasicConstraints:
  Use: true
  IsCA: false
AddSKI: true
AddAKI: true
# KeyUsages
#  KeyUsageDigitalSignature = 1
#  KeyUsageContentCommitment = 2
#  KeyUsageKeyEncipherment = 4
#  KeyUsageDataEncipherment = 8
#  KeyUsageKeyAgreement = 16
#  KeyUsageCertSign = 32 
#  KeyUsageCRLSign = 64
#  KeyUsageEncipherOnly = 128
#  KeyUsageDecipherOnly = 256
KeyUsage:
  - 1
  - 16
ExtendedKeyUsage:
  # ExtendedKeyUsages
  #  ExtKeyUsageAny = 0
  #  ExtKeyUsageServerAuth = 1
  #  ExtKeyUsageClientAuth = 2
  #  ExtKeyUsageCodeSigning = 3
  #  ExtKeyUsageEmailProtection = 4
  #  ExtKeyUsageIPSECEndSystem = 5
  #  ExtKeyUsageIPSECTunnel = 6
  #  ExtKeyUsageIPSECUser = 7
  #  ExtKeyUsageTimeStamping = 8
  #  ExtKeyUsageOCSPSigning = 9
  #  ExtKeyUsageMicrosoftServerGatedCrypto = 10
  #  ExtKeyUsageNetscapeServerGatedCrypto = 11
  #  ExtKeyUsageMicrosoftCommercialCodeSigning = 12
  #  ExtKeyUsageMicrosoftKernelCodeSigning = 13
  - 1
  - 2
ExtraExtensions: true
SANUsage: true
# CRLDistributionPoints. List of URI strings.
CRLDistributionPoints:
  - http://crl.laavat.com/e37f045c.crl
# PolicyIdentifiers. List of ASN1 policy OIDS
# EnforceUniqueDN enables the checking if a certificate has been issued with the same subject DN from the CA
# Values true or false
# EnforceUniqueDN: true
```

Decoded base64 value 3 of 4:

```text
# Config file for the SubCA profile. Do not use TABS
---
Name: Client Certificate Product Family SubCA Profile
# Distinguished name of the CA
DN:
  # Organization: 
  Organization: Laavat
  # OrganizationalUnit: R&D
  # Country: FI
  Country: FI
  # Province:
  # Locality:
  # StreetAddress:
  # PostalCode:
  # SerialNumber
  # CommonName: IMX6
# EndEntity is 1, Sub CA profile 2 , Root profile 3
ProfileType: 2
# SignatureAlgorithms
#  SHA1WithRSA = 3
#  SHA256WithRSA = 4
#  SHA384WithRSA = 5
#  SHA512WithRSA = 6
#  DSAWithSHA1 = 7
#  DSAWithSHA256 = 8
#  ECDSAWithSHA1 = 9
#  ECDSAWithSHA256 = 10
#  ECDSAWithSHA384 = 11
#  ECDSAWithSHA512 = 12
#  SHA256WithRSAPSS = 13
#  SHA384WithRSAPSS = 14
#  SHA512WithRSAPSS = 15
SignatureAlgorithm: 10
# KeyAlgorithms
#   RSAAlgorithm = 1
#   ECDSAAlgorithm = 2
KeyAlgorithm: 2
# Validity of the certificate in duration (max 290 years) or with absolute date in RFC3339 e.g. 9999-12-31T23:59:59Z.
# Example in absolute date "9999-12-31T23:59:59Z".
# Example in duration "1h10m10s". Only h, m and/or s are accepted.
ValidityPeriod: "175200h"
BasicConstraints:
  BasicConstraintsValid: true
  IsCA: true
  MaxPathLen: 0
  # MaxPathLenZero indicates that BasicConstraintsValid==true
  # and MaxPathLen==0 should be interpreted as an actual
  # maximum path length of zero. Otherwise, that combination is
  # interpreted as MaxPathLen not being set.
  MaxPathLenZero: true
AddSKI: true
AddAKI: true
# KeyUsages
#  KeyUsageDigitalSignature = 1
#  KeyUsageContentCommitment = 2
#  KeyUsageKeyEncipherment = 4
#  KeyUsageDataEncipherment = 8
#  KeyUsageKeyAgreement = 16
#  KeyUsageCertSign = 32 
#  KeyUsageCRLSign = 64
#  KeyUsageEncipherOnly = 128
#  KeyUsageDecipherOnly = 256
KeyUsage:
  - 1
  - 32
  - 64
ExtendedKeyUsage:
  # ExtendedKeyUsages
  #  ExtKeyUsageAny = 0
  #  ExtKeyUsageServerAuth = 1
  #  ExtKeyUsageClientAuth = 2
  #  ExtKeyUsageCodeSigning = 3
  #  ExtKeyUsageEmailProtection = 4
  #  ExtKeyUsageIPSECEndSystem = 5
  #  ExtKeyUsageIPSECTunnel = 6
  #  ExtKeyUsageIPSECUser = 7
  #  ExtKeyUsageTimeStamping = 8
  #  ExtKeyUsageOCSPSigning = 9
  #  ExtKeyUsageMicrosoftServerGatedCrypto = 10
  #  ExtKeyUsageNetscapeServerGatedCrypto = 11
  #  ExtKeyUsageMicrosoftCommercialCodeSigning = 12
  #  ExtKeyUsageMicrosoftKernelCodeSigning = 13
# ExtraExtensions: true
# SANUsage: true
# CRLDistributionPoints. List of URI strings.
#CRLDistributionPoints:
#  - http://crl.laavat.com/products-0/root.crl

# PolicyIdentifiers. List of ASN1 policy OIDS
#PolicyIdentifiers:
#  - 1.10.123.432.4.5
#  - 2.10.123.432.4.65

# EnforceUniqueDN enables the checking if a certificate has been issued with the same subject DN from the CA
# Values true or false
#EnforceUniqueDN: true
```

Decoded base64 value 4 of 4:

```text
# Config file for the End entity profile. Do not use TABS
---
Name: Client Certificate EndEntity Profile
DN:
  #Organization: Test Comp
  Organization: Laavat
  #OrganizationalUnit: R&D
  #Country: FI
  Country: FI
  #Province:
  #- Something
  # Locality:
  # StreetAddress:
  # PostalCode:
  # SerialNumber
  # CommonName: 
# EndEntity is 1, Sub CA profile 2 , Root profile 3
ProfileType: 1
# SignatureAlgorithms
#  SHA1WithRSA = 3
#  SHA256WithRSA = 4
#  SHA384WithRSA = 5
#  SHA512WithRSA = 6
#  DSAWithSHA1 = 7
#  DSAWithSHA256 = 8
#  ECDSAWithSHA1 = 9
#  ECDSAWithSHA256 = 10
#  ECDSAWithSHA384 = 11
#  ECDSAWithSHA512 = 12
#  SHA256WithRSAPSS = 13
#  SHA384WithRSAPSS = 14
#  SHA512WithRSAPSS = 15
SignatureAlgorithm: 10
# KeyAlgorithms
#   RSAAlgorithm = 1
#   ECDSAAlgorithm = 2
KeyAlgorithm: 2
# Validity of the certificate in duration (max 290 years) or with absolute date in RFC3339 e.g. 9999-12-31T23:59:59Z.
# Example in absolute date "9999-12-31T23:59:59Z".
# Example in duration "1h10m10s". Only h, m and/or s are accepted.
ValidityPeriod: "17520h"
BasicConstraints:
  Use: true
  IsCA: false
AddSKI: true
AddAKI: true
# KeyUsages
#  KeyUsageDigitalSignature = 1
#  KeyUsageContentCommitment = 2
#  KeyUsageKeyEncipherment = 4
#  KeyUsageDataEncipherment = 8
#  KeyUsageKeyAgreement = 16
#  KeyUsageCertSign = 32 
#  KeyUsageCRLSign = 64
#  KeyUsageEncipherOnly = 128
#  KeyUsageDecipherOnly = 256
KeyUsage:
  - 1
  - 16
ExtendedKeyUsage:
  # ExtendedKeyUsages
  #  ExtKeyUsageAny = 0
  #  ExtKeyUsageServerAuth = 1
  #  ExtKeyUsageClientAuth = 2
  #  ExtKeyUsageCodeSigning = 3
  #  ExtKeyUsageEmailProtection = 4
  #  ExtKeyUsageIPSECEndSystem = 5
  #  ExtKeyUsageIPSECTunnel = 6
  #  ExtKeyUsageIPSECUser = 7
  #  ExtKeyUsageTimeStamping = 8
  #  ExtKeyUsageOCSPSigning = 9
  #  ExtKeyUsageMicrosoftServerGatedCrypto = 10
  #  ExtKeyUsageNetscapeServerGatedCrypto = 11
  #  ExtKeyUsageMicrosoftCommercialCodeSigning = 12
  #  ExtKeyUsageMicrosoftKernelCodeSigning = 13
  - 1
  - 2
ExtraExtensions: true
SANUsage: true
# CRLDistributionPoints. List of URI strings.
CRLDistributionPoints:
  - http://crl.laavat.com/e37f045c.crl
# PolicyIdentifiers. List of ASN1 policy OIDS
# PolicyIdentifiers:
#   - 1.10.123.432.4.5
#   - 2.10.123.432.4.65
# EnforceUniqueDN enables the checking if a certificate has been issued with the same subject DN from the CA
# Values true or false
# EnforceUniqueDN: true
```

## Create products

### Product for ROOT CA

Here is the used [product template](https://docs.laavat.io/producttemplates/product-ecdsa-dev-ca-root.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=4a63eff1-29ae-43fa-baba-c319575291db
- SUBPROFILEID=bff08e23-9eaf-427c-a776-1dacbd546311

In this product there is one operation.

$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.](https://docs.laavat.io/usage/productguide/product/#approval-rules)

Product was created using the python tool

```bash
(venv) $ signing-tool -n test.ini product add \
    -T product-ecdsa-dev-ca-root.template
Product:
{
    "ca_info": [
        {
            "cert_override_payload": null,
            "certificate_type": "ROOT",
            "cn": "Root CA 2025",
            "crl_distribution_points": [
                "http://crl.company.com/e37f045c.crl"
            ],
            "crl_expiry": "24h",
            "crl_issue_interval": "12h",
            "csr": null,
            "description": "ROOT CA to issue SUB CA certificates",
            "external_request_id": null,
            "external_root": false,
            "id": null,
            "issuer_ca_id": null,
            "key_override_id": null,
            "key_type": "ECDSAP384",
            "leafs": [],
            "originating_id": null,
            "policy_identifiers": [],
            "product_id": null,
            "profile_id": "4a63eff1-29ae-43fa-baba-c319575291db",
            "state": null,
            "use_case": "DeviceCA"
        }
    ],
    "description": "Root CA for customer",
    "enabled": true,
    "external_request_id": null,
    "id": null,
    "name": "Product for ROOT 2025",
    "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": "Issuer of Subordinate CAs in ROOT CA",
            "id": null,
            "name": "Issue Subordinate CA",
            "operation_type": "IssueDeviceCertificate",
            "profile_id": "bff08e23-9eaf-427c-a776-1dacbd546311",
            "token": null
        }
    ],
    "product_type": "Production",
    "rnd_keys": [],
    "state": null
}
Is product ok(Y/N): y
{
    "ca_info": [],
    "description": "Root CA for customer",
    "enabled": null,
    "external_request_id": null,
    "id": "1193ecc1-8182-487c-86e4-91857527c1e5",
    "name": "Product for ROOT 2025",
    "product_config_items": null,
    "product_operations": [],
    "product_type": null,
    "rnd_keys": [],
    "state": 2
}
Product Add request sent. Request ID: 1193ecc1-8182-487c-86e4-91857527c1e5 state: ApprovalRequired
```

#### Approve product

The product was approved using the GUI.

- productID = 1193ecc1-8182-487c-86e4-91857527c1e5

### Create product for Device Family Sub CA 

Here is the used [product template](https://docs.laavat.io/producttemplates/product-ecdsa-dev-ca-ext1.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.

- SUBPROFILEID=3adb4838-10d8-4ad5-b2b2-a711ef4a28db
- ENDPROFILEID=3adb4838-10d8-4ad5-b2b2-a711ef4a28db

In this product there is one operation.

$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.](https://docs.laavat.io/usage/productguide/product/#approval-rules)

Product was created using the python tool

```bash
(venv) $ signing-tool -n test.ini product add \
    -T product-ecdsa-dev-ca-ext1.template
Product:
{
    "ca_info": [
        {
            "cert_override_payload": null,
            "certificate_type": "SUBCA",
            "cn": "Device CA Product for Device Family Sub CA",
            "crl_distribution_points": [
                "http://crl.company.com/e37f045c.crl"
            ],
            "crl_expiry": "24h",
            "crl_issue_interval": "12h",
            "csr": null,
            "description": "Ca used for Product for Device Family Sub CA",
            "external_request_id": null,
            "external_root": true,
            "id": null,
            "issuer_ca_id": null,
            "key_override_id": null,
            "key_type": "ECDSAP256",
            "leafs": [],
            "originating_id": null,
            "policy_identifiers": [],
            "product_id": null,
            "profile_id": "3adb4838-10d8-4ad5-b2b2-a711ef4a28db",
            "state": null,
            "use_case": "DeviceCA"
        }
    ],
    "description": "Product testing hierarchy",
    "enabled": false,
    "external_request_id": null,
    "id": null,
    "name": "Product for Device Family Sub CA",
    "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 for Product for Device Family Sub CA",
            "id": null,
            "name": "Issue device certificates",
            "operation_type": "IssueDeviceCertificate",
            "profile_id": "3adb4838-10d8-4ad5-b2b2-a711ef4a28db",
            "token": null
        }
    ],
    "product_type": "RnD",
    "rnd_keys": [],
    "state": null
}
Is product ok(Y/N): y
{
    "ca_info": [],
    "description": "Product testing hierarchy",
    "enabled": null,
    "external_request_id": null,
    "id": "156a10af-325a-4f35-ba96-1e3d28bbe550",
    "name": "Product for Device Family Sub CA",
    "product_config_items": null,
    "product_operations": [],
    "product_type": null,
    "rnd_keys": [],
    "state": 2
}
Product Add request sent. Request ID: 156a10af-325a-4f35-ba96-1e3d28bbe550 state: ApprovalRequired
```

#### Approve product "Product for Device Family Sub CA"

The product was approved using the GUI.

- productID = 156a10af-325a-4f35-ba96-1e3d28bbe550 

#### Issue certificate for the SUB CA from ROOT

We need to get the CA ID from the created product. That datastructure contains the CSR. In this example jq tool is used to extract the id.

```bash
(venv) $ signing-tool -n test.ini product get \
    -I 156a10af-325a-4f35-ba96-1e3d28bbe550 | jq -r .ca_info[0].id
daba7613-a99d-4f32-8039-2c4d6792a08d
```

Get the CSR to a file named daba7613-a99d-4f32-8039-2c4d6792a08d.csr

```bash
(venv) $ signing-tool -n test.ini ca getcsr \
    --caid daba7613-a99d-4f32-8039-2c4d6792a08d \
    -O /tmp/daba7613-a99d-4f32-8039-2c4d6792a08d.csr
Payload written to file: /tmp/daba7613-a99d-4f32-8039-2c4d6792a08d.csr
```

The CSR is sent to the ROOT CA product. In this case product with id=1193ecc1-8182-487c-86e4-91857527c1e5

```bash
(venv) $ signing-tool -n test.ini production add \
    -P 1193ecc1-8182-487c-86e4-91857527c1e5 \
    -C /tmp/daba7613-a99d-4f32-8039-2c4d6792a08d.csr 
{
    "certificate": null,
    "chain": [],
    "error_status": null,
    "id": "78335f77-c392-4776-96f6-d9080c30c0f3",
    "state": 1,
    "subject": "CN=Device CA Product for Device Family Sub CA,O=Laavat,C=FI"
}
Certificate signing request sent. Request ID: 78335f77-c392-4776-96f6-d9080c30c0f3 state: Created
```

The created certificate is requested and stored to a file

```bash
(venv) $ signing-tool -n test.ini production get \
    -I 78335f77-c392-4776-96f6-d9080c30c0f3 \
    -O subca1
{
    "certificate": "LS0tLS1CRUdJ…(1,132 base64 chars elided; PEM certificate: CN=Device CA Product for Device Family Sub CA,O=Laavat,C=FI; issuer CN=Root CA 2025,O=Laavat,C=FI; EC secp256r1; valid 2025-06-17 to 2125-05-24)",
    "chain": [
        "LS0tLS1CRUdJ…(1,032 base64 chars elided; PEM certificate: CN=Root CA 2025,O=Laavat,C=FI; issuer CN=Root CA 2025,O=Laavat,C=FI; EC secp384r1; valid 2025-06-17 to 2225-04-30)"
    ],
    "error_status": null,
    "id": "78335f77-c392-4776-96f6-d9080c30c0f3",
    "state": 16,
    "subject": "CN=Device CA Product for Device Family Sub CA,O=Laavat,C=FI"
}
Certificate signing request. Request ID: 78335f77-c392-4776-96f6-d9080c30c0f3 state: Ready
certificate written to: subca1.crt
certificate chain written to: subca1.chain
```

The chain is uploaded to the SUB CA product. After this the CA is ready.

```bash
(venv) $ signing-tool -n test.ini ca patch \
    --caid daba7613-a99d-4f32-8039-2c4d6792a08d \
    -F subca1.chain 
None
Chain upload
```

### Create product for issuing the device certificates

Here is the used [product template](https://docs.laavat.io/producttemplates/product-ecdsa-dev-ca-ext-sub1.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.

- SUBPROFILEID=3adb4838-10d8-4ad5-b2b2-a711ef4a28db
- ENDPROFILEID=4d48c275-445a-4e95-9cdb-064688010dc1

In this product there is one operation.

$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.](https://docs.laavat.io/usage/productguide/product/#approval-rules)

Product was created using the python tool

```bash
(venv) $ signing-tool -n test.ini product add \
    -T product-ecdsa-dev-ca-ext-sub1.template
Product:
{
    "ca_info": [
        {
            "cert_override_payload": null,
            "certificate_type": "SUBCA",
            "cn": "SUB CA for Device CA",
            "crl_distribution_points": [
                "http://crl.company.com/e37f045c.crl"
            ],
            "crl_expiry": "24h",
            "crl_issue_interval": "12h",
            "csr": null,
            "description": "Ca used for SUBCA1 for Device CA",
            "external_request_id": null,
            "external_root": true,
            "id": null,
            "issuer_ca_id": null,
            "key_override_id": null,
            "key_type": "ECDSAP256",
            "leafs": [],
            "originating_id": null,
            "policy_identifiers": [],
            "product_id": null,
            "profile_id": "3adb4838-10d8-4ad5-b2b2-a711ef4a28db",
            "state": null,
            "use_case": "DeviceCA"
        }
    ],
    "description": "SUB CA for customer",
    "enabled": true,
    "external_request_id": null,
    "id": null,
    "name": "Device CA",
    "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 for Device CA",
            "id": null,
            "name": "Issue Device certificates",
            "operation_type": "IssueDeviceCertificate",
            "profile_id": "4d48c275-445a-4e95-9cdb-064688010dc1",
            "token": null
        }
    ],
    "product_type": "Production",
    "rnd_keys": [],
    "state": null
}
Is product ok(Y/N): y
{
    "ca_info": [],
    "description": "SUB CA for customer",
    "enabled": null,
    "external_request_id": null,
    "id": "842b2c8e-543f-414b-a1a6-89347db38348",
    "name": "Device CA",
    "product_config_items": null,
    "product_operations": [],
    "product_type": null,
    "rnd_keys": [],
    "state": 2
}
Product Add request sent. Request ID: 842b2c8e-543f-414b-a1a6-89347db38348 state: ApprovalRequired
```

#### Approve product "Device CA"

The product was approved using the GUI.

- productID = 842b2c8e-543f-414b-a1a6-89347db38348

#### Issue certificate for the Device CA from Sub CA

We need to get the CA ID from the created product. That datastructure contains the CSR. In this example jq tool is used to extract the id.

```bash
(venv) $ signing-tool -n test.ini product get \
    -I 842b2c8e-543f-414b-a1a6-89347db38348 | jq -r .ca_info[0].id
1b24a868-0b49-4225-a2d5-8a7ced78e439
```

Get the CSR to a file named 1b24a868-0b49-4225-a2d5-8a7ced78e439.csr

```bash
(venv) $ signing-tool -n test.ini ca getcsr \
    --caid 1b24a868-0b49-4225-a2d5-8a7ced78e439 \
    -O /tmp/1b24a868-0b49-4225-a2d5-8a7ced78e439.csr
Payload written to file: /tmp/1b24a868-0b49-4225-a2d5-8a7ced78e439.csr    
```

The CSR is sent to the SUB CA product. In this case product with id=156a10af-325a-4f35-ba96-1e3d28bbe550

```bash
(venv) $ signing-tool -n test.ini production add \
    -P 156a10af-325a-4f35-ba96-1e3d28bbe550 \
    -C /tmp/1b24a868-0b49-4225-a2d5-8a7ced78e439.csr 
{
    "certificate": null,
    "chain": [],
    "error_status": null,
    "id": "f287159f-e826-433c-9c97-fbdeab0949b2",
    "state": 1,
    "subject": "CN=SUB CA for Device CA,O=Laavat,C=FI"
}
Certificate signing request sent. Request ID: f287159f-e826-433c-9c97-fbdeab0949b2 state: Created
```

The created certificate is requested and stored to a file

```bash
(venv) $ signing-tool -n test.ini production get \
    -I f287159f-e826-433c-9c97-fbdeab0949b2 \
    -O deviceca
{
    "certificate": "LS0tLS1CRUdJ…(1,088 base64 chars elided; PEM certificate: CN=SUB CA for Device CA,O=Laavat,C=FI; issuer CN=Device CA Product for Device Family Sub CA,O=Laavat,C=FI; EC secp256r1; valid 2025-06-17 to 2125-05-24)",
    "chain": [
        "LS0tLS1CRUdJ…(1,132 base64 chars elided; PEM certificate: CN=Device CA Product for Device Family Sub CA,O=Laavat,C=FI; issuer CN=Root CA 2025,O=Laavat,C=FI; EC secp256r1; valid 2025-06-17 to 2125-05-24)",
        "LS0tLS1CRUdJ…(1,032 base64 chars elided; PEM certificate: CN=Root CA 2025,O=Laavat,C=FI; issuer CN=Root CA 2025,O=Laavat,C=FI; EC secp384r1; valid 2025-06-17 to 2225-04-30)"
    ],
    "error_status": null,
    "id": "f287159f-e826-433c-9c97-fbdeab0949b2",
    "state": 16,
    "subject": "CN=SUB CA for Device CA,O=Laavat,C=FI"
}
Certificate signing request. Request ID: f287159f-e826-433c-9c97-fbdeab0949b2 state: Ready
certificate written to: deviceca.crt
certificate chain written to: deviceca.chain
```

The chain is uploaded to the SUB CA product. After this the CA is ready.

```bash
(venv) $ signing-tool -n test.ini ca patch \
    --caid 1b24a868-0b49-4225-a2d5-8a7ced78e439  \
    -F deviceca.chain 
None
Chain upload
```

### Create product for Client Family Sub CA 

Here is the used [product template](https://docs.laavat.io/producttemplates/product-ecdsa-dev-ca-ext2.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.

- SUBPROFILEID=73011594-d7b7-428c-b38c-f3ba9213de81
- ENDPROFILEID=73011594-d7b7-428c-b38c-f3ba9213de81

In this product there is one operation.

$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.](https://docs.laavat.io/usage/productguide/product/#approval-rules)

Product was created using the python tool

```bash
(venv) $ signing-tool -n test.ini product add \
    -T product-ecdsa-dev-ca-ext2.template 
Product:
{
    "ca_info": [
        {
            "cert_override_payload": null,
            "certificate_type": "SUBCA",
            "cn": "Client CA for Sub CA",
            "crl_distribution_points": [
                "http://crl.company.com/e37f045xxx.crl"
            ],
            "crl_expiry": "24h",
            "crl_issue_interval": "12h",
            "csr": null,
            "description": "Ca used for client authentication for Product for Client Sub CA",
            "external_request_id": null,
            "external_root": true,
            "id": null,
            "issuer_ca_id": null,
            "key_override_id": null,
            "key_type": "ECDSAP256",
            "leafs": [],
            "originating_id": null,
            "policy_identifiers": [],
            "product_id": null,
            "profile_id": "73011594-d7b7-428c-b38c-f3ba9213de81",
            "state": null,
            "use_case": "DeviceCA"
        }
    ],
    "description": "Client certs for authentication",
    "enabled": true,
    "external_request_id": null,
    "id": null,
    "name": "Product for Client Sub CA",
    "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": "Client certificates for Product for Client Sub CA",
            "id": null,
            "name": "Issue client certificates",
            "operation_type": "IssueDeviceCertificate",
            "profile_id": "73011594-d7b7-428c-b38c-f3ba9213de81",
            "token": null
        }
    ],
    "product_type": "Production",
    "rnd_keys": [],
    "state": null
}
Is product ok(Y/N): y
{
    "ca_info": [],
    "description": "Client certs for authentication",
    "enabled": null,
    "external_request_id": null,
    "id": "7f1429b1-8a20-4630-b782-e58a20075f82",
    "name": "Product for Client Sub CA",
    "product_config_items": null,
    "product_operations": [],
    "product_type": null,
    "rnd_keys": [],
    "state": 2
}
Product Add request sent. Request ID: 7f1429b1-8a20-4630-b782-e58a20075f82 state: ApprovalRequired
```

#### Approve product "Product for Client Sub CA"

The product was approved using the GUI.

- productID = 7f1429b1-8a20-4630-b782-e58a20075f82

#### Issue certificate for the product "Product for Client Sub CA" from ROOT

We need to get the CA ID from the created product. That datastructure contains the CSR. In this example jq tool is used to extract the id.

```bash
(venv) $ signing-tool -n test.ini product get \
    -I 7f1429b1-8a20-4630-b782-e58a20075f82 | jq -r .ca_info[0].id
f0582789-9e53-49f5-b61e-f185cb18e405
```

Get the CSR to a file named f0582789-9e53-49f5-b61e-f185cb18e405.csr

```bash
(venv) $ signing-tool -n test.ini ca getcsr \
    --caid f0582789-9e53-49f5-b61e-f185cb18e405 \
    -O /tmp/f0582789-9e53-49f5-b61e-f185cb18e405.csr
Payload written to file: /tmp/f0582789-9e53-49f5-b61e-f185cb18e405.csr
```

The CSR is sent to the ROOT CA product. In this case product with id=1193ecc1-8182-487c-86e4-91857527c1e5

```bash
(venv) $ signing-tool -n test.ini production add \
    -P 1193ecc1-8182-487c-86e4-91857527c1e5 \
    -C /tmp/f0582789-9e53-49f5-b61e-f185cb18e405.csr 
{
    "certificate": null,
    "chain": [],
    "error_status": null,
    "id": "b688b2f5-0650-451a-b6df-6dfb2d565d49",
    "state": 1,
    "subject": "CN=Client CA for Sub CA,O=Laavat,C=FI"
}
Certificate signing request sent. Request ID: b688b2f5-0650-451a-b6df-6dfb2d565d49 state: Created

```

The created certificate is requested and stored to a file

```bash
(venv) $ signing-tool -n test.ini production get \
    -I b688b2f5-0650-451a-b6df-6dfb2d565d49 \
    -O subca2
{
    "certificate": "LS0tLS1CRUdJ…(1,092 base64 chars elided; PEM certificate: CN=Client CA for Sub CA,O=Laavat,C=FI; issuer CN=Root CA 2025,O=Laavat,C=FI; EC secp256r1; valid 2025-06-17 to 2125-05-24)",
    "chain": [
        "LS0tLS1CRUdJ…(1,032 base64 chars elided; PEM certificate: CN=Root CA 2025,O=Laavat,C=FI; issuer CN=Root CA 2025,O=Laavat,C=FI; EC secp384r1; valid 2025-06-17 to 2225-04-30)"
    ],
    "error_status": null,
    "id": "b688b2f5-0650-451a-b6df-6dfb2d565d49",
    "state": 16,
    "subject": "CN=Client CA for Sub CA,O=Laavat,C=FI"
}
Certificate signing request. Request ID: b688b2f5-0650-451a-b6df-6dfb2d565d49 state: Ready
certificate written to: subca2.crt
certificate chain written to: subca2.chain
```

The chain is uploaded to the SUB CA product. After this the CA is ready.

```bash
(venv) $ signing-tool -n test.ini ca patch \
    --caid f0582789-9e53-49f5-b61e-f185cb18e405 \
    -F subca2.chain 
None
Chain upload
```

### Create product for issuing the client certificates

Here is the used [product template](https://docs.laavat.io/producttemplates/product-ecdsa-dev-ca-ext-sub2.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.

- SUBPROFILEID=73011594-d7b7-428c-b38c-f3ba9213de81
- ENDPROFILEID=292017ef-1987-48f4-a0ca-915991ecf780

In this product there is one operation.

$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.](https://docs.laavat.io/usage/productguide/product/#approval-rules)

Product was created using the python tool

```bash
(venv) $ signing-tool -n test.ini product add \
    -T product-ecdsa-dev-ca-ext-sub2.template
Product:
{
    "ca_info": [
        {
            "cert_override_payload": null,
            "certificate_type": "SUBCA",
            "cn": "Client CA",
            "crl_distribution_points": [
                "http://crl.company.com/e37f045c.crl"
            ],
            "crl_expiry": "24h",
            "crl_issue_interval": "12h",
            "csr": null,
            "description": "Ca used for SUBCA2 for Product for issuing End-Entity client certificates",
            "external_request_id": null,
            "external_root": true,
            "id": null,
            "issuer_ca_id": null,
            "key_override_id": null,
            "key_type": "ECDSAP256",
            "leafs": [],
            "originating_id": null,
            "policy_identifiers": [],
            "product_id": null,
            "profile_id": "73011594-d7b7-428c-b38c-f3ba9213de81",
            "state": null,
            "use_case": "DeviceCA"
        }
    ],
    "description": "SUB CA for customer",
    "enabled": true,
    "external_request_id": null,
    "id": null,
    "name": "Product for issuing End-Entity client certificates",
    "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": "Client certificates for Product for issuing End-Entity client certificates",
            "id": null,
            "name": "Issue client certificates",
            "operation_type": "IssueDeviceCertificate",
            "profile_id": "292017ef-1987-48f4-a0ca-915991ecf780",
            "token": null
        }
    ],
    "product_type": "Production",
    "rnd_keys": [],
    "state": null
}
Is product ok(Y/N): y
{
    "ca_info": [],
    "description": "SUB CA for customer",
    "enabled": null,
    "external_request_id": null,
    "id": "680bc232-092e-474b-a27a-67767cf2cdad",
    "name": "Product for issuing End-Entity client certificates",
    "product_config_items": null,
    "product_operations": [],
    "product_type": null,
    "rnd_keys": [],
    "state": 2
}
Product Add request sent. Request ID: 680bc232-092e-474b-a27a-67767cf2cdad state: ApprovalRequired
```

#### Approve product "Product for issuing End-Entity client certificates"

The product was approved using the GUI.

- productID = 680bc232-092e-474b-a27a-67767cf2cdad

#### Issue certificate for product "Product for issuing End-Entity client certificates" from Sub CA

We need to get the CA ID from the created product. That datastructure contains the CSR. In this example jq tool is used to extract the id.

```bash
(venv) $ signing-tool -n test.ini product get \
    -I 680bc232-092e-474b-a27a-67767cf2cdad | jq -r .ca_info[0].id
bc4c6917-1b2a-4f21-bbe0-2e4f12e0b6da
```

Get the CSR to a file named bc4c6917-1b2a-4f21-bbe0-2e4f12e0b6da.csr

```bash
(venv) $ signing-tool -n test.ini ca getcsr \
    --caid bc4c6917-1b2a-4f21-bbe0-2e4f12e0b6da \
    -O /tmp/bc4c6917-1b2a-4f21-bbe0-2e4f12e0b6da.csr
Payload written to file: /tmp/bc4c6917-1b2a-4f21-bbe0-2e4f12e0b6da.csr    
```

The CSR is sent to the SUB CA product. In this case product with id=7f1429b1-8a20-4630-b782-e58a20075f82

```bash
(venv) $ signing-tool -n test.ini production add \
    -P 7f1429b1-8a20-4630-b782-e58a20075f82 \
    -C /tmp/bc4c6917-1b2a-4f21-bbe0-2e4f12e0b6da.csr 
{
    "certificate": null,
    "chain": [],
    "error_status": null,
    "id": "02482c85-9423-4abc-b4d0-54cbc2ee9d76",
    "state": 1,
    "subject": "CN=Client CA,O=Laavat,C=FI"
}
Certificate signing request sent. Request ID: 02482c85-9423-4abc-b4d0-54cbc2ee9d76 state: Created

```

The created certificate is requested and stored to a file

```bash
(venv) $ signing-tool -n test.ini production get \
    -I 02482c85-9423-4abc-b4d0-54cbc2ee9d76 \
    -O clientca
{
    "certificate": "LS0tLS1CRUdJ…(1,028 base64 chars elided; PEM certificate: CN=Client CA,O=Laavat,C=FI; issuer CN=Client CA for Sub CA,O=Laavat,C=FI; EC secp256r1; valid 2025-06-17 to 2045-06-12)",
    "chain": [
        "LS0tLS1CRUdJ…(1,092 base64 chars elided; PEM certificate: CN=Client CA for Sub CA,O=Laavat,C=FI; issuer CN=Root CA 2025,O=Laavat,C=FI; EC secp256r1; valid 2025-06-17 to 2125-05-24)",
        "LS0tLS1CRUdJ…(1,032 base64 chars elided; PEM certificate: CN=Root CA 2025,O=Laavat,C=FI; issuer CN=Root CA 2025,O=Laavat,C=FI; EC secp384r1; valid 2025-06-17 to 2225-04-30)"
    ],
    "error_status": null,
    "id": "02482c85-9423-4abc-b4d0-54cbc2ee9d76",
    "state": 16,
    "subject": "CN=Client CA,O=Laavat,C=FI"
}
Certificate signing request. Request ID: 02482c85-9423-4abc-b4d0-54cbc2ee9d76 state: Ready
certificate written to: clientca.crt
certificate chain written to: clientca.chain
```

The chain is uploaded to the SUB CA product. After this the CA is ready.

```bash
(venv) $ signing-tool -n test.ini ca patch \
    --caid bc4c6917-1b2a-4f21-bbe0-2e4f12e0b6da \
    -F clientca.chain 
None
Chain upload
```

## Issuing Client certificates

### Create CSR

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

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

### Send the CSR for issuance

```bash
(venv) $ signing-tool -n test.ini production add \
    -P 680bc232-092e-474b-a27a-67767cf2cdad \
    -C /tmp/csr.bin 
{
    "certificate": null,
    "chain": [],
    "error_status": null,
    "id": "7066508a-7238-4db8-bcb3-e896da4dcda1",
    "state": 1,
    "subject": "CN=device-123,O=Customer,C=FI"
}
Certificate signing request sent. Request ID: 7066508a-7238-4db8-bcb3-e896da4dcda1 state: Created

(venv) $ signing-tool -n test.ini production get \
    -I 7066508a-7238-4db8-bcb3-e896da4dcda1 \
    -O client
{
    "certificate": "LS0tLS1CRUdJ…(1,028 base64 chars elided; PEM certificate: CN=device-123,O=Laavat,C=FI; issuer CN=Client CA,O=Laavat,C=FI; EC secp256r1; valid 2025-06-17 to 2027-06-17)",
    "chain": [
        "LS0tLS1CRUdJ…(1,028 base64 chars elided; PEM certificate: CN=Client CA,O=Laavat,C=FI; issuer CN=Client CA for Sub CA,O=Laavat,C=FI; EC secp256r1; valid 2025-06-17 to 2045-06-12)",
        "LS0tLS1CRUdJ…(1,092 base64 chars elided; PEM certificate: CN=Client CA for Sub CA,O=Laavat,C=FI; issuer CN=Root CA 2025,O=Laavat,C=FI; EC secp256r1; valid 2025-06-17 to 2125-05-24)",
        "LS0tLS1CRUdJ…(1,032 base64 chars elided; PEM certificate: CN=Root CA 2025,O=Laavat,C=FI; issuer CN=Root CA 2025,O=Laavat,C=FI; EC secp384r1; valid 2025-06-17 to 2225-04-30)"
    ],
    "error_status": null,
    "id": "7066508a-7238-4db8-bcb3-e896da4dcda1",
    "state": 16,
    "subject": "CN=device-123,O=Customer,C=FI"
}
Certificate signing request. Request ID: 7066508a-7238-4db8-bcb3-e896da4dcda1 state: Ready
certificate written to: client.crt
certificate chain written to: client.chain
```

### Configure the trustpoint

Submit the Client CA chain as a new mTLS truststore request through the GUI. See [Truststore Management](https://docs.laavat.io/gui/admin/truststore/).

### Add a client for accessing the MTLS endpoints

In order to access a specific product with mTLS it needs to be configured. 

In this example the CA certificate for Client certificates used. Type "IssueDeviceCertificateCA" gives access to all certificates issued under the CA in client.crt

```bash
(venv) $ signing-tool -n test.ini \
    client add \
    -N "ClientSUB1" \
    -D "Access device certs" \
    -C clientca.crt \
    -T IssueDeviceCertificateCA \
    -p 842b2c8e-543f-414b-a1a6-89347db38348
{
    "client_type": "IssueDeviceCertificateCA",
    "description": "Access device certs",
    "id": "1c150751-33b4-429b-9845-c9e9598a29c5",
    "id_product": "842b2c8e-543f-414b-a1a6-89347db38348",
    "name": "ClientSUB1",
    "state": 2
}
Client Add request sent. Request ID: 1c150751-33b4-429b-9845-c9e9598a29c5 state: ApprovalRequired
```

### Approve the client request

The client request was approved using the GUI.

## Issuing Device certificates using mTLS

### Create CSR for device certificates

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

```bash
(venv) $ openssl ecparam \
                             -name prime256v1 \
                             -genkey -noout \
                             -conv_form uncompressed \
                             -out device.key
(venv) $ openssl req \
                             -new -nodes \
                             -key device.key \
                             -outform DER \
                             -subj "/C=FI/O=Customer/CN=device-123" \
                             2>/dev/null | base64 -w 0 > /tmp/csr.b64

```

### Create certificate from CSR

Use the csr.b64 file contents as the value for the "csr" field. Certificate is requested from product with id=842b2c8e-543f-414b-a1a6-89347db38348

```bash
curl -sS --cert client.crt --key client.key \
-XPOST https://mtls.app.laavat.io/<CustomerName>/api/v1/certificaterequests \
-H 'Content-Type: application/json' \
-d '{ "csr": "MIHxMIGXAgEA…(328 base64 chars elided; DER CSR: CN=device-123,O=Customer,C=FI; EC secp256r1)", "productId": "842b2c8e-543f-414b-a1a6-89347db38348"}'
{"chain":[],"id":"929aaf03-e60a-4b87-a579-66bc0f2964d5","state":1,"CN=device-123,O=Customer,C=FI"}
```

The certificate request is 929aaf03-e60a-4b87-a579-66bc0f2964d5

```bash
curl -sS -XGET --cert client.crt \
--key /tmp/ec.key \
https://mtls.app.laavat.io/<CustomerName>/api/v1/certificaterequests/929aaf03-e60a-4b87-a579-66bc0f2964d5 \
-H 'Content-Type: application/json' | jq -r
{
  "certificate": "LS0tLS1CRUdJ…(1,056 base64 chars elided; PEM certificate: CN=device-123,O=Laavat,C=FI; issuer CN=SUB CA for Device CA,O=Laavat,C=FI; EC secp256r1; valid 2025-06-17 to 2125-05-24)",
  "chain": [
    "LS0tLS1CRUdJ…(1,088 base64 chars elided; PEM certificate: CN=SUB CA for Device CA,O=Laavat,C=FI; issuer CN=Device CA Product for Device Family Sub CA,O=Laavat,C=FI; EC secp256r1; valid 2025-06-17 to 2125-05-24)",
    "LS0tLS1CRUdJ…(1,132 base64 chars elided; PEM certificate: CN=Device CA Product for Device Family Sub CA,O=Laavat,C=FI; issuer CN=Root CA 2025,O=Laavat,C=FI; EC secp256r1; valid 2025-06-17 to 2125-05-24)",
    "LS0tLS1CRUdJ…(1,032 base64 chars elided; PEM certificate: CN=Root CA 2025,O=Laavat,C=FI; issuer CN=Root CA 2025,O=Laavat,C=FI; EC secp384r1; valid 2025-06-17 to 2225-04-30)"
  ],
  "id": "953b256b-58f6-4e16-8533-9547f9119f86",
  "state": 16,
  "subject": "CN=device-123,O=Customer,C=FI"
}
```
