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

# Digest signing with detached signature example

> **Tip: Looking for a full design built on digest signing?**
> This page walks through one digest signature. For a complete device design
> that uses digest signing for both the boot image and an update manifest —
> Raspberry Pi 4 signed boot with encrypted updates — see
> [Building CRA-ready Raspberry Pi gateways](https://docs.laavat.io/solutions/cra-ready-raspberry-pi/).

This example shows how to create a product which digest signing with detached signature. Also example signing operation is performed and the result is also verified.

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 profile
- Creating product
- Signing digest
- Verifying digest

## 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)

Here we use the token as an environment variable.
```bash
(venv) $ export TOKEN=<insert here the retrieved token>
```

## Add profiles

> **Note: Token handling in these examples**
> The `signing-tool` commands below use `-n test.ini` — a config file created with `config-init` that references
> a `token_file` rather than embedding a token, so no token appears on the command line. Approver steps use `-n
> approver.ini` (the same config for a user in the approvers group). See [Reference Client ›
> Usage](https://docs.laavat.io/democlient/usage/) for how to create these configs and for the secure token-input forms (`-t
> @file`, `-t @-`).

Digest signing with detached signature is using a Certificate authority which is used to issue signing certificates and a Signing End-Entity issued under that CA.

The [example profile](https://docs.laavat.io/usage/productguide/pki-examples/#example-of-digest-signing-with-detached-signature-profile) were taken as base and modified for this example

```bash
(venv) $ signing-tool -n test.ini profile \
    add -F endentity.yaml -N "Digest signing cert for detached signature" -T END
{
    "id": "41fcea27-d2cb-4400-8c9c-74a5c577e66b",
    "profile_name": "Digest signing cert for detached signature",
    "profile_type": 1,
    "profile_yaml": "IyBDb25maWcg…(3,112 base64 chars elided; text, shown decoded below)"
}
Profile added. Profile ID: 41fcea27-d2cb-4400-8c9c-74a5c577e66b

(venv) $ signing-tool -n test.ini profile getall
{
    "count": 1,
    "items": [
        {
            "id": "41fcea27-d2cb-4400-8c9c-74a5c577e66b",
            "profile_name": "Digest signing cert for detached signature",
            "profile_type": 1
        }
    ],
    "next": "/cas/profiles/?page=1",
    "pages": 1,
    "prev": "/cas/profiles/?page=1"
}
```

Decoded from the base64 value above:

```text
# Config file for the End entity profile. Do not use TABS
---
Name: USB detached signature entity profile
DN:
  # Organization: Test Comp
  # OrganizationalUnit: R&D
  # Country: FI
  # Province:
  #- Something
  # Locality:
  # StreetAddress:
  # PostalCode:
  # SerialNumber
  # CommonName: IMG
# 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: 4
# KeyAlgorithms
#   RSAAlgorithm = 1
#   ECDSAAlgorithm = 2
KeyAlgorithm: 1
# 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" # 100 Years
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:
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:

# 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 product

Here is the used [product template](https://docs.laavat.io/usage/productguide/product/#digest-signing-with-detached-signature). $PRODUCTNAME was changed to "Detached Demo".

The product template was updated with the profile ids obtained from the previous commands. The value ENDSIGPROFILEID were changed with their corresponding profile id.

- ENDSIGPROFILEID=41fcea27-d2cb-4400-8c9c-74a5c577e66b

In the approval rule it was decided that entities in the $WRITERGROUP were able to make signing requests. And entities in the $APPROVERGROUP group would be able to approve those. Autoapproval was not used.

$WRITERGROUP and $APPROVERGROUP were replaced with the corresponding Group Object ID from Microsoft Entra or from Google.

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.json 
Product:
{
    "ca_info": [
        {
            "cert_override_payload": null,
            "certificate_type": "ENDENTITY",
            "cn": "Externally issued End-Entity certificate for Detached demo",
            "crl_distribution_points": null,
            "crl_expiry": null,
            "crl_issue_interval": null,
            "csr": null,
            "description": "End-Entity certificate for signing for Detached demo",
            "external_request_id": null,
            "external_root": true,
            "id": null,
            "issuer_ca_id": null,
            "key_override_id": null,
            "key_type": "RSA2048",
            "leafs": [],
            "originating_id": null,
            "policy_identifiers": null,
            "product_id": null,
            "profile_id": "41fcea27-d2cb-4400-8c9c-74a5c577e66b",
            "state": null,
            "use_case": "CodeSigning"
        }
    ],
    "description": "Product for Digest signing with detached signature based product",
    "enabled": true,
    "external_request_id": null,
    "id": null,
    "name": "Detached demo",
    "product_config_items": null,
    "product_operations": [
        {
            "approval_rule": {
                "allowed_groups": [
                    "writersforsaas@testing.laavat.fi"
                ],
                "approval_groups": [
                    "approversforsaas@testing.laavat.fi"
                ],
                "blanket_groups": [],
                "description": "Rule used for testing for Detached demo",
                "name": "Test rule"
            },
            "ca_use_case": null,
            "description": "Generate detached signature with CodeSigning key for Detached demo",
            "id": null,
            "name": "Generate detached signature with CodeSigning key",
            "operation_type": "DetachedSignature",
            "profile_id": null,
            "token": null
        }
    ],
    "product_type": "RnD",
    "rnd_keys": [],
    "state": null
}
Is product ok(Y/N): y
{
    "ca_info": [],
    "description": "Product for Digest signing with detached signature based product",
    "enabled": null,
    "external_request_id": null,
    "id": "6e1cbe3d-9033-455c-8e38-51d13bf66a9c",
    "name": "Detached demo",
    "product_config_items": null,
    "product_operations": [],
    "product_type": null,
    "rnd_keys": [],
    "state": 2
}
Product Add request sent. Request ID: 6e1cbe3d-9033-455c-8e38-51d13bf66a9c 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 = 6e1cbe3d-9033-455c-8e38-51d13bf66a9c
- operation ID for digest signing with detached signature = 6609abf8-23c8-43cf-9f7b-b3076746b57e

```bash
(venv) $ signing-tool -n test.ini product getall
{
    "count": 1,
    "items": [
        {
            "description": "Product for Digest signing with detached signature based product",
            "id": "6e1cbe3d-9033-455c-8e38-51d13bf66a9c",
            "name": "Detached demo",
            "state": 16
        }
    ],
    "next": "/products/?page=1",
    "pages": 1,
    "prev": "/products/?page=1"
}

(venv) $ signing-tool -n test.ini product \
    get -I 6e1cbe3d-9033-455c-8e38-51d13bf66a9c
{
    "ca_info": [
        {
            "cert_override_payload": null,
            "certificate_type": "ENDENTITY",
            "cn": "Externally issued End-Entity certificate for Detached demo",
            "crl_distribution_points": null,
            "crl_expiry": null,
            "crl_issue_interval": null,
            "csr": "MIICijCCAXIC…(872 base64 chars elided; DER CSR: CN=Externally issued End entity certificate for Detached demo; RSA-2048)",
            "description": "End-Entity certificate for signing for Detached demo",
            "external_request_id": null,
            "external_root": null,
            "id": "09c20a06-f069-4cfe-a413-89c63cf24e98",
            "issuer_ca_id": null,
            "key_override_id": null,
            "key_type": "RSA2048",
            "leafs": [],
            "originating_id": null,
            "policy_identifiers": null,
            "product_id": null,
            "profile_id": "41fcea27-d2cb-4400-8c9c-74a5c577e66b",
            "state": 256,
            "use_case": "CodeSigning"
        }
    ],
    "description": "Product for Digest signing with detached signature based product",
    "enabled": null,
    "external_request_id": "0e89388e-96f6-29b3-d601-0f70a647d610",
    "id": "6e1cbe3d-9033-455c-8e38-51d13bf66a9c",
    "name": "Detached demo",
    "product_config_items": [],
    "product_operations": [
        {
            "approval_rule": {
                "allowed_groups": [
                    "writersforsaas@testing.laavat.fi"
                ],
                "approval_groups": [
                    "approversforsaas@testing.laavat.fi"
                ],
                "blanket_groups": [
                    ""
                ],
                "description": "Rule used for testing for Detached demo",
                "name": "Test rule"
            },
            "ca_use_case": null,
            "description": "Generate detached signature with CodeSigning key for Detached demo",
            "id": "6609abf8-23c8-43cf-9f7b-b3076746b57e",
            "name": "Generate detached signature with CodeSigning key",
            "operation_type": "DetachedSignature",
            "profile_id": "00000000-0000-0000-0000-000000000000",
            "token": null
        }
    ],
    "product_type": "RnD",
    "rnd_keys": [],
    "state": 16
}
```

### Issue certificate using OpenSSL

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 6e1cbe3d-9033-455c-8e38-51d13bf66a9c | jq -r .ca_info[0].id
09c20a06-f069-4cfe-a413-89c63cf24e98
```

Get the CSR to a file named 09c20a06-f069-4cfe-a413-89c63cf24e98.csr

```bash
(venv) $ signing-tool -n test.ini ca getcsr \
    --caid 09c20a06-f069-4cfe-a413-89c63cf24e98 \
    -O /tmp/09c20a06-f069-4cfe-a413-89c63cf24e98.csr
Payload written to file: /tmp/09c20a06-f069-4cfe-a413-89c63cf24e98.csr
```

Then the signing certificate was issued using openssl. The LAAVAT can also be used to create the PKI hierarchy.

```bash
openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 -out rootCA.crt -subj "/C=US/ST=State/L=City/O=Organization/OU=Unit/CN=RootCA"
openssl x509 -req -inform der -in /tmp/09c20a06-f069-4cfe-a413-89c63cf24e98.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out /tmp/09c20a06-f069-4cfe-a413-89c63cf24e98.crt -days 365 -sha256
openssl verify -CAfile rootCA.crt /tmp/09c20a06-f069-4cfe-a413-89c63cf24e98.crt
cat /tmp/09c20a06-f069-4cfe-a413-89c63cf24e98.crt > chain.pem
cat rootCA.crt >> chain.pem
```

The chain is uploaded to the product to complete the configuration. After this the certificate is ready.

```bash
(venv) $ signing-tool -n test.ini ca patch \
    --caid 09c20a06-f069-4cfe-a413-89c63cf24e98 \
    -F chain.pem
None
Chain upload
```

## Digest signing using detached signature

In this example we create a dummy file which we will use. In real life the correct target file is used:

```bash
dd if=/dev/urandom of="/tmp/update.bin" bs="1k" count=1 iflag=fullblock status=none
```

Calculate the s256 digest from the file

```bash
sha256sum < /tmp/update.bin | cut -d" " -f1 | xxd -r -p | base64 -w 0
Hm8KIFv4XZ48PHBjtU4RKphRDRutRsIVVR7df7q6io0=
```

Create an image signing request with the digest in Base64 format and the product id and the operation id.
Hash algorithm SHA256 is used.

- Digest is Hm8KIFv4XZ48PHBjtU4RKphRDRutRsIVVR7df7q6io0=
- ProductID is 6e1cbe3d-9033-455c-8e38-51d13bf66a9c for this example
- OperationID for the detached signature is 6609abf8-23c8-43cf-9f7b-b3076746b57e. This is obtained from the product info

```bash
(venv) $ signing-tool -n test.ini imagesigning add DigestSigning -p Hm8KIFv4XZ48PHBjtU4RKphRDRutRsIVVR7df7q6io0= \
 -P 6e1cbe3d-9033-455c-8e38-51d13bf66a9c --operid 6609abf8-23c8-43cf-9f7b-b3076746b57e -H SHA256
{
    "call_back_url": null,
    "description": "digest signing request",
    "id": "b6a02618-43d4-4d23-8c79-3f571f4e9f3f",
    "id_product": "6e1cbe3d-9033-455c-8e38-51d13bf66a9c",
    "id_product_operation": "6609abf8-23c8-43cf-9f7b-b3076746b57e",
    "name": "Digest signing request",
    "payload": {
        "id": null,
        "metadata": [
            {
                "name": "Version",
                "value": "1.0"
            }
        ],
        "modified_sha256": null,
        "name": "Signing payload",
        "original_sha256": null,
        "s3_url": null,
        "service_provided_parameters": null
    },
    "state": 1
}
Image signing request sent. Request ID: b6a02618-43d4-4d23-8c79-3f571f4e9f3f state: Created
```

The operation created ID "b6a02618-43d4-4d23-8c79-3f571f4e9f3f" which is then used when querying/downloading the signed content.

## Approve signing request

Request was approved from the GUI.

## Download signed content

After approval the request is processed and it can be queried. If the state is 16 then the signing is complete and the content is downloaded.

```bash
(venv) $ signing-tool -n test.ini imagesigning get \
-I b6a02618-43d4-4d23-8c79-3f571f4e9f3f -O /tmp/out.signed 
{
    "call_back_url": null,
    "description": "digest signing request",
    "id": "b6a02618-43d4-4d23-8c79-3f571f4e9f3f",
    "id_product": "6e1cbe3d-9033-455c-8e38-51d13bf66a9c",
    "id_product_operation": "6609abf8-23c8-43cf-9f7b-b3076746b57e",
    "name": "Digest signing request",
    "payload": {
        "id": "13b31717-b640-4ec1-bd4c-0837e5d656c5",
        "metadata": [
            {
                "name": "Version",
                "value": "1.0"
            }
        ],
        "modified_sha256": null,
        "name": "Signing payload",
        "original_sha256": null,
        "s3_url": "redacted",
        "service_provided_parameters": []
    },
    "state": 16
}
Downloading signed binary to: /tmp/out.signed
```

## Verify the digest

Get the public key of the signing certificate which we issued before. It is possible also to get the certificate from the system securely. More info can be found from [client usage](https://docs.laavat.io/usage/clientguide/clients/).

```bash
openssl x509 -in /tmp/09c20a06-f069-4cfe-a413-89c63cf24e98.crt -noout -pubkey > publickey.pem
```

Verify the signature using the Signing certificates public key and signature received against the target binary.

```bash
openssl dgst -sha256 -verify publickey.pem -signature /tmp/out.signed /tmp/update.bin
Verified OK
```
