DN: C4A-302-0043
This document covers the design and use of the attestation process implemented by the QASM and the supporting software.
There is a need for a QASM to attest to a remote party about its state and that of other internal objects through a set of claims. This is useful when the remote party engages in secure communications with the QASM or intends to verify the authenticity of an object managed by a QASM.
The following principles guided the design of this protocol.
There are three main parties involved during the attestation process:
There is a trust relationship between the consumer and the claiming authority. Ultimately, the consumer trusts the claims because of the signature associated with the public key that was provided by the claiming authority. Therefore:
An example to support the proposed responsibilities can be found in code signing. In this example, the corporation that distributes software is the claiming authority. It controls a private key used to sign new releases of a software. The servers that accepts this software are the consumers. In this simplified example, the process used to sign a new release (automated or manual) support the policies associated with the use and distribution of the software. The attestation message contains a single implicit claim, which is that the software package is integral and can be trusted. The consumers assume that the policies are supported by verifying the claim via the signature.
This section discusses the general workflow associated with producing attestation messages and consuming them. It introduces a new participant, the Operator, which is the one orchestrating the generation of the attestation message. The operator and consumer could be the same party, specifying both the content of the attestation message and consuming it. It is also important to note that either or both actors, the operator and the consumer, could be automatic processes.
The general information flow is as follows:
Each claim has three components:
For example, to attest that a specific key on the QASM has a given fingerprint, the following claim can be built:
Some claims are not fully defined by the operator. Instead, the operator defines the subject and the predicate. During the attestation process, the QASM inserts the value of the complement. This type of claim is known as a “variable claim”.
For example, if the remote party requests a claim specifying the time at which the attestation was performed, the complement (the time at which the attestation was performed) should be filled by the QASM.
In this section, the claims that are variable in nature are denoted with the designation “variable” in the description.
All claims have a predicate, also known as a type, which is specified using an OID. The type defines the others aspects of the claim such as whether a subject is required or how the complement is represented.
All OIDs introduced in this document fall under the range 1.3.6.1.4.1.39901.6 (reserved under Crypto4A).
id-c4a-claim-type OBJECT IDENTIFIER ::= { id-c4a 6 }
Claim types are broken into three categories; general, system, and object.
General claims are ones that do not relate to the device or any of its associated resources (keys, objects).
The general predicates fall under the range 1.3.6.1.4.1.39901.6.0.
id-c4a-claim-type-general OBJECT IDENTIFIER ::= { id-c4a-claim-type 0 }
The following table explains the defined general predicates. The OID column represents the suffix after ‘id-c4a-claim-type’.
OID | Label | Description | Subject | Complement |
---|---|---|---|---|
.0.0 | false-is-true | Always false. | ||
.0.1 | true-is-true | Always true. | ||
.0.2 | challenge | Attest a challenge. | Octet string containing a challenge (bytes) |
System claims are those that relate to the attesting device or its internal state.
The system predicates fall under the range 1.3.6.1.4.1.39901.6.1.
id-c4a-claim-type-system OBJECT IDENTIFIER ::= { id-c4a-claim-type 1 }
The following table explains the defined system predicates. The OID column represents the suffix after ‘id-c4a-claim-type’.
OID | Label | Description | Subject | Complement |
---|---|---|---|---|
.1.0 | qasm-uuid | Claiming QASM has UUID. (Variable) | Octet string that encodes UUID associated with QASM. (bytes) | |
.1.1 | qasm-serial | Claiming QASM has Platform Serial Number. (Variable) | UTF-8 string that encodes the serial number associated with the platform. (utf8String) | |
.1.2 | attestation-time | Attestation was performed at time.(Variable) | General time structure. (time) | |
.1.3 | qasm-firmware-version | Claiming QASM has firmware version. (Variable) | UTF-8 string that encodes the firmware version associated with the platform. (utf8String) | |
.1.4 | qasm-certified-production | Claiming QASM is a certified production HSM. | ||
.1.5 | qasm-is-in-fips-mode | Claiming QASM is operating in FIPS mode. | ||
.1.6 | audit-logs-state | Claiming the state of the audit log. (Variable) | Octet string that encodes the audit log state structure. (bytes) |
Object claims relate to resources (keys or objects) located on the attesting device.
The object predicates fall under the range 1.3.6.1.4.1.39901.6.2.
id-c4a-claim-type-object OBJECT IDENTIFIER ::= { id-c4a-claim-type 2 }
The following table explains the defined object predicates. The OID column represents the suffix after ‘id-c4a-claim-type’.
OID | Label | Description | Subject | Complement |
---|---|---|---|---|
.2.0 | attestation-keys-are-unique | The attestation keys used for signing this attestation are unique to the QASM. This means that the attestation keys were generated on the claiming QASM and can not be transferred in any way out of the QASM. | ||
.2.1 | key-spki | Key is associated with the subject public key info. (Variable) | Key UUID | Octet string that encodes the SPKI (SubjectPublicKeyInfo) for the key. (bytes) |
.2.2 | key-fingerprint | Key is associated with the fingerprint. (Variable) | Key UUID | Octet string that encodes fingerprint associated with key. (bytes) |
.2.3 | key-spki-sha256 | Key is associated with the SHA-256 of the SPKI. Useful when SPKI is large, like McEliece keys. (Variable) | Key UUID | Octet string that encodes the SHA-256 digest of the SPKI. (bytes) |
.2.4 | object-class | Object is of a specified class. | Object UUID | Integer value that represents the class of the target object. (value) |
.2.5 | object-type | Object is of a specified type. | Object UUID | Integer value that represents the type of the target object. (value) |
.2.6 | object-keystore | Object is in the specified key store type. | Object UUID | Integer value that represents the type of key store where the target object is located. (value) |
.2.7 | key-is-confined | Key is confined to claiming QASM. This means that the subject key was generated on the claiming QASM and can not be transferred in any way out of the QASM. | Key UUID | |
.2.8 | key-is-hardware-generated | Key is hardware generated. Key has the “local” bit set. | Key UUID | |
.2.9 | key-never-extracted | Key has never been extracted. | Key UUID | |
.2.10 | key-is-managed | Key is managed. | Key UUID | |
.2.11 | key-is-not-managed | Key is not managed. | Key UUID | |
.2.13 | key-has-capability | Key has the specified capability. | Key UUID | Integer value that represents a key capability. (value) |
.2.14 | key-does-not-have-capability | Key does not have the specified capability. | Key UUID | Integer value that represents a key capability. (value) |
.2.15 | key-is-related-to-authority | Key is related to authority structure. (Variable) | Key UUID | Octet string that encodes the RelatedAuthorities associated with the key. (bytes) |
.2.16 | key-is-archived-by | Key has archiving key. | Key UUID | Octet string that encodes the UUID of the archiving key. (bytes) |
This section covers the encoding of an attestation message. The definitions are expressed in ASN.1.
The attestation message is the overarching structure to carry attestation information. It is constructed of the following components:
SEQUENCE {
AttestationMessage ::= INTEGER,
version
claims SetOfClaims,SEQUENCE SIZE (1..MAX) OF SignatureBlock,
signatures 0] IMPLICIT SEQUENCE of Certificate OPTIONAL
relatedCertificates [-- As defined in RFC 5280
}
SEQUENCE {
SignatureBlock ::=
sid SignerIdentifier,
signatureAlgorithm AlgorithmIdentifier,STRING
signatureValue BIT
}
SEQUENCE {
SignerIdentifier ::= 0] EXPLICIT OCTET STRING OPTIONAL,
keyId [1] EXPLICIT SubjectPublicKeyInfo OPTIONAL,
subjectKeyIdentifier [-- As defined in RFC 5280
2] EXPLICIT Certificate OPTIONAL
certificate [-- As defined in RFC 5280
}
SEQUENCE {
AlgorithmIdentifier ::=
algorithm OBJECT IDENTIFIER,OPTIONAL
parameters ANY DEFINED BY algorithm }
This section defines the structure containing the claims. This section represents the portion that is signed as part of the attestation message. It contains one or multiple claims. Each claim encodes the subject (if present), predicate, and optional complement. The following sub-sections deal with the encoding of the different types of subjects and complements.
SEQUENCE {
SetOfClaims ::= INTEGER,
version SEQUENCE OF Claim
claims
}
SEQUENCE {
Claim ::=
predicate OBJECT IDENTIFIER,0] EXPLICIT Subject OPTIONAL,
subject [1] EXPLICIT Complement OPTIONAL
complement [ }
This structure is provided for extensibility. Future revisions of this specification may include more subjects.
SEQUENCE {
Subject ::= 0] IMPLICIT OCTET STRING OPTIONAL
uuid [ }
The complement can be specified in many ways, but is constrained by the predicate: the selected choice should match the one indicated by the predicate.
CHOICE {
Complement ::= 0] IMPLICIT OCTET STRING,
bytes [1] IMPLICIT UTF8String,
utf8String [2] IMPLICIT GeneralizedTime,
time [3] IMPLICIT INTEGER
value [ }
There are many types of complement, and the complement encoding varies based on the claim type. Ultimately, each value is converted to one or multiple ASN.1 primitive types. This section deals with the formatting of values into ASN.1.
Within this specification, a UUID is encoded as an Octet String of 16 bytes, with the first byte being the most significant byte of the value for the UUID.
This formatting applies for both subjects, when applicable, and complements.
When a complement contains a general time, then the general time shall be encoded as the standard ASN.1 type: GeneralizedTime. For the purpose of this specification, the representation of time shall be constrained in a manner identical to the way specified in RFC 5280.
For convenience, this is an excerpt from RFC 5280, section 4.1.2.5.2:
For the purposes of this profile, GeneralizedTime values MUST be expressed in Greenwich Mean Time (Zulu) and MUST include seconds (i.e., times are YYYYMMDDHHMMSSZ), even where the number of seconds is zero. GeneralizedTime values MUST NOT include fractional seconds.
#### Subject Public Key Info (SPKI)
For the purpose of this specification, subject public key info (SPKI) is formatted according to RFC 5280 section 4.1.2.7.
The SPKI structure is used to identify public and private keys. In the case of private keys, the associated public key is used for purpose of identification.
If the size of the attestation message is constrained and a subject key is large (McEliece public keys are sizeable in comparison to others), then it is possible to identify a key using the SHA-256 of the SPKI (see claim .2.3).
The formatting of this value is as follows:
When an object class is specified, it should be encoded as an ASN.1 integer. The encoded value shall be represented according to the following table:
Object Class | Integer Value |
---|---|
DATA | 0x01 |
CERTIFICATE | 0x02 |
PUBLIC KEY | 0x03 |
PRIVATE KEY | 0x04 |
SECRET KEY | 0x05 |
AUTHORITY | 0x07 |
ENTITLEMENT | 0x0A |
AUTHORIZATION REQUEST | 0x0B |
POLICY | 0x0C |
When an object type is specified, it should be encoded as an ASN.1 integer. The encoded value shall be represented according to the following table:
Object Type | Integer Value |
---|---|
RSA | 0x01 |
ECC | 0x02 |
HSS | 0x03 |
MCE (McEliece) | 0x04 |
DILITHIUM | 0x06 |
XMSS | 0x07 |
SPHINCS+ | 0x08 |
EDWARDS | 0x09 |
KYBER | 0x0A |
Generic Secret Key | 0x10 |
AES | 0x11 |
User Authorithy | 0x31 |
Quorum Authority | 0x32 |
Counter Entitlement | 0x50 |
X.509 Certificate | 0x60 |
Trust Anchor Certificate | 0x61 |
Encrypted Trust Anchor Certificate | 0x62 |
Generic Data | 0x70 |
Owner Policy | 0x80 |
Access Policy | 0x81 |
When an object keystore is specified, it should be encoded as an ASN.1 integer. The encoded value shall be represented according to the following table:
Object Keystore | Integer Value |
---|---|
IKS | 0x100 |
GLOBAL | 0x101 |
VOLATILE | 0x102 |
PLATFORM | 0x103 |
POST TAMPER | 0x104 |
OWNER | 0x105 |
ACCESS | 0x106 |
When a key capability is specified, it should be encoded as an ASN.1 integer. The encoded value shall be represented according to the following table:
Name | Capability Identifier | Description |
---|---|---|
HSM_KEY_CAPABILITY_ENCRYPT | 0x101 | If set, the associated key can be used in an encrypt function. |
HSM_KEY_CAPABILITY_DECRYPT | 0x102 | If set, the associated key can be used in a decrypt function. |
HSM_KEY_CAPABILITY_WRAP | 0x103 | If set, the associated key can be used in a wrap function. |
HSM_KEY_CAPABILITY_UNWRAP | 0x104 | If set, the associated key can be used in an unwrap function. |
HSM_KEY_CAPABILITY_SIGN | 0x105 | If set, the associated key can be used in a signature function. |
HSM_KEY_CAPABILITY_VERIFY | 0x106 | If set, the associated key can be used in a signature verification. |
HSM_KEY_CAPABILITY_DERIVE | 0x107 | If set, the associated key can be used in a derive function. |
HSM_KEY_CAPABILITY_UNAUTHORIZED | 0x108 | If set, the associated key cannot be used in functions unless authorized. |
HSM_KEY_CAPABILITY_PACK | 0x109 | If set, the associated key can be used in a pack function. |
HSM_KEY_CAPABILITY_UNPACK | 0x10a | If set, the associated key can be used in an unpack function. |
HSM_KEY_CAPABILITY_DBSEC_DPK | 0x10b | If set, the associated key can be used in the role of DPK in DbSec functions. |
HSM_KEY_CAPABILITY_DBSEC_DDK | 0x10c | If set, the associated key can be used in the role of DDK in DbSec functions. |
HSM_KEY_CAPABILITY_ARCHIVE | 0x11d | If set, the associated key is used to archive (back up) other keys via extraction functions. It allows wrap even if a key is not extractable. It allows packing even if a key is not packable. A link “ARCHIVED_BY” is required between the archived key and the associated key. If a key is unpacked or unwrapped using the associated key, the “ARCHIVED_BY” link is added to the recovered key. |
HSM_KEY_CAPABILITY_TAMP_APEX | 0x10e | Not enforced. |
HSM_KEY_CAPABILITY_TAMP_PROCESS | 0x10f | Not enforced. |
HSM_KEY_CAPABILITY_FIRMWARE_SIGN | 0x110 | Not enforced. |
HSM_KEY_CAPABILITY_CODE_SIGN | 0x111 | Not enforced. |
HSM_KEY_CAPABILITY_PROOF_OF_ORIGIN | 0x112 | Not enforced. |
The structure RelatedAuthorities is used to define the set of authorities and keys that are associated with a given object. Some of those keys represent authorities that can approve operations with the key.
For the purpose of this specification, when related authorities are specified, they are first encoded as an ASN.1 structure. Then, the structure is DER encoded and the bytes are used an an octet string.
The remainder of this section explains the ASN.1 encoding of the related authority structure.
SEQUENCE {
PublicKeyInfo ::=
algorithm AlgorithmIdentifier,STRING }
publicKey BIT
SEQUENCE OF PublicKeyInfo
User ::=
SEQUENCE {
QuorumMember ::= INTEGER,
weight
authority Authority }
SEQUENCE OF QuorumMember
QuorumMembers ::=
SEQUENCE {
Quorum ::= INTEGER,
threshold
members QuorumMembers }
CHOICE {
Authority ::= 0] IMPLICIT PublicKeyInfo,
publicKey [1] IMPLICIT User,
user [2] IMPLICIT Quorum }
quorum [
SEQUENCE {
ManagingAuthority ::= INTEGER,
managingLevel
authority Authority }
CHOICE {
RelatedAuthority ::= 0] IMPLICIT ManagingAuthority }
managingAuthority [
SEQUENCE OF RelatedAuthority RelatedAuthorities ::=
The field “managingLevel” is a numerical value that establishes the permissions that the authority has on the key. The following table describes the meaning of the value found in this field.
Name | Value | Description |
---|---|---|
TRUSTEE | 0x01 | The authority can authorize operations that discloses the value of the key. This is the ultimate permission on the key. It allows operations to extract the key. |
OPERATOR | 0x02 | The authority can authorize operations that uses the value of the key. This allows operations such as signature or encryption. |
For a key to participate in the process of attestation, it must first be marked with the capability “attestation”. An attestation key has the following restrictions:
This section describes the functions provided by the QASM to support key attestation.
The Attest function is used to sign a set of claims provided by the caller. It is implemented within the QASM.
The Attest function has the following inputs:
The Attest function has the following outputs:
The Attest function must:
Verify each attestation key:
Verify that the claim version is recognized.
Create a new setOfClaims:
Perform signatures on new setOfClaims.
Create attestation message based on new setOfClaims and generated signatures.
Return attestation message.
The ValidateClaims function is used to verify which claims are deemed valid by the QASM. It is implemented within the QASM. It provides the means to verify why an attestation is failing.
The ValidateClaims function has the following input:
The ValidateClaims function has the following outputs:
This section introduces the concepts of claim templates. To support a specific policy, a number of claim types might be required. With the use of templates, it is possible to specify a pre-defined set of claims instead of specifying individually each one, over and over.
The Certificate Authority / Browser (CA/B) forum has mandated that the private keys for certificates issued after June 2023 must be protected by a signing service that uses an HSM to store the keys.
The CA/B forum requirements only state that a signing service storing private keys must have “use of an HSM”, but do not state any additional requirements. The key could be imported to an HSM, copied to it, or copied out subsequently. The QASM has the ability to prove that additional properties about a key are enforced, but we will not require these for signing service keys, allowing the CAs to make their own judgement. Hence, some of these claims will be optional, allowing us to highlight the QASM’s capability to place stricter controls on the keys and encourage better hygiene.
The following required claims prove that a private key object on the HSM has a corresponding public key, which the validator can check against a CSR (Certificate Signing Request).
The following claims are not required by the CA/B forum requirements, and are only included in the attestation message if true.
The verification tool,
spa-attest verify --require <template>
supports two
variants of this template:
private-key-is-on-hsm
: Requires the presence of the
above required claims, and reports on the presence of the optional
claims.private-key-for-csr-is-on-hsm
: Additionally requires
that a CSR file is provided that has an SPKI that matches the SPKI in
the attestation message.This section describes the pseudo-algorithm employed when attestation templates are requested.
Load the claim template.
Load default attestation keys and certificates, if none provided.
Call QASM’s ValidateClaims on the resulting SetOfClaims.
For each claim in the result:
Using the reduced setOfClaims, call the QASM’s Attest function.
Attach any related certificates to the message.
Bundle the attestation message with the certificates.
This section deals with the Command Line Interface (CLI) applications that are supporting the attestation process.
This command takes some claims and/or claim templates and interacts with the QASM to attest to them, producing an attestation message.
Produce a test claim that is true (–true-is-true), using the default QASM_AA_ECC attestation key and the C4A_ROOT certificate. The message is output to STDOUT if no output file is specified.
$ spa-key-man attest claim --true-is-true
-----BEGIN ATTESTATION MESSAGE-----
MIIHYwIBATAUAgEBMA8wDQYLKwYBBAGCt10GAAEwggK9MIICuTCCAj+gEgQQmrrz
fJKLFkY/a6C9XuxaxqKCAicwggIjMIIBqKADAgECAhRSLwDfIc3tYXTYlyGn2R+k
k61awDAKBggqhkjOPQQDAzAcMRowGAYDVQQDDBFDNEFfU0NBX0Zha2VNYW5DQTAg
Fw0yMzAyMjcyMTQ0MzBaGA85OTk5MTIzMTIzNTk1OVowMzExMC8GA1UEAwwoSFNN
RW11bGF0b3IwMDAwMDAgQXNzZXJ0aW9uIEF1dGhvcml0eSBFQzB2MBAGByqGSM49
AgEGBSuBBAAiA2IABET0UyPDJHQti/es+7HIYZreJyu6axMXEqTCtgJi2/maRTca
yci0JvE8Y+exnB4Pz44aNX17FR1YjDsS5JKQrrVF3kkYn6WqG0z8lgRCMgmYQHyb
4RGqqhcA9NyBR3mL8qOBkTCBjjAdBgNVHQ4EFgQUCTWGWnqviQE/1NC13+YSpjhZ
9AowHwYDVR0jBBgwFoAUzodfGY1cdAYG8VDlV4JwglBv+Q8wDgYDVR0PAQH/BAQD
AgeAMCQGA1UdEQQdMBugGQYJKwYBBAGCt10DoAwGCisGAQQBgrddAwEwFgYDVR0l
BA8wDQYLKwYBBAGCt10EAQEwCgYIKoZIzj0EAwMDaQAwZgIxAIkg2qPXphiJfBUO
rs1u9KlYODeFGNxd1lnhkZQstk4Q7ff7L5AKsdlcX2P5AFWRFQIxAPTkGZi8raxL
9qzAz8/b/aZ4iojp+usWf3dvt2HRx/SLec4VR+Ol5A2v557RSd5XIjAKBggqhkjO
PQQDAwNoADBlAjB9B5ax128DnOg47RKpFIDMJ6chVRHaREmZ6jPUSy1gqqdFLILh
ung7yb1ECqu2+OcCMQD9vQLxiHBURHMHWXNakwsGR8Eh7fn+xQ/aKi0ZO4kU+cgT
wd9BiSwestVqayRIoaOgggSFMIICXjCCAeSgAwIBAgIULVEQ5ZbF4R/s686p0nUT
SDTPhwcwCgYIKoZIzj0EAwMwXjEPMA0GA1UEBgwGQ2FuYWRhMRAwDgYDVQQIDAdP
bnRhcmlvMQ8wDQYDVQQHDAZPdHRhd2ExETAPBgNVBAoMCENyeXB0bzRBMRUwEwYD
VQQDDAxDNEFfUkNBX0ZBS0UwHhcNMjIwOTA2MTk1MTU3WhcNNDcwOTA2MTk1MTU3
WjBeMQ8wDQYDVQQGDAZDYW5hZGExEDAOBgNVBAgMB09udGFyaW8xDzANBgNVBAcM
Bk90dGF3YTERMA8GA1UECgwIQ3J5cHRvNEExFTATBgNVBAMMDEM0QV9SQ0FfRkFL
RTB2MBAGByqGSM49AgEGBSuBBAAiA2IABEEqITyWwvFOD9N7fAPOnO1rnslG1rXK
9BcJMoQEHY0C1LdS1S/5q6bJsxMlg6QmDbuiv7+rUy+eEtBSqQL5L5uVFOApBHHZ
Uabluux8gnM7a93fNMkgAYIS6se9baKiLqNjMGEwDwYDVR0TAQH/BAUwAwEB/zAO
BgNVHQ8BAf8EBAMCAQYwHwYDVR0jBBgwFoAUy/ABUVh4K3dgmrN0YBDgAjx8L2Yw
HQYDVR0OBBYEFMvwAVFYeCt3YJqzdGAQ4AI8fC9mMAoGCCqGSM49BAMDA2gAMGUC
MBJaN/Qi1FgbHdasygkefsX6L7ZgbJ3kbTvFx1kYQlWLbgi6GBwPb0mINcCN/YvW
HQIxAI5QVMrXIZDx9H8u6iWp+dJPVLqD3/vl9ADxlGOZiI1dQ34wZGBTETqGvnhA
NfkV2DCCAh8wggGloAMCAQICFGwULjmrv1u53zBf2OWPqb//9e0OMAoGCCqGSM49
BAMDMF4xDzANBgNVBAYMBkNhbmFkYTEQMA4GA1UECAwHT250YXJpbzEPMA0GA1UE
BwwGT3R0YXdhMREwDwYDVQQKDAhDcnlwdG80QTEVMBMGA1UEAwwMQzRBX1JDQV9G
QUtFMB4XDTIyMDkwNjIwMDAwM1oXDTQyMDkwNjIwMDAwM1owHDEaMBgGA1UEAwwR
QzRBX1NDQV9GYWtlTWFuQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARWZmvXkAFM
serfnptjHYHqlk7fNkT9fa33eIU57IHQOK3uslesQQLw572BUhlyrs3ghwM0aWau
s5iW20fP+dbvM/5Ny9sB+URCM04alBePdD9m8WJOm/JvFI/bPYUARNujZjBkMBIG
A1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMB8GA1UdIwQYMBaAFMvw
AVFYeCt3YJqzdGAQ4AI8fC9mMB0GA1UdDgQWBBTOh18ZjVx0BgbxUOVXgnCCUG/5
DzAKBggqhkjOPQQDAwNoADBlAjBnFK3MOZ3zO4RlvGaM3oncUL12t8/0bW3Qy5vr
+NQ9rJqJLEFlUVQkwh4fC8lcoEECMQDXcnDNUuJLXthZcNQveujIZOC8Jol5f/3k
S+/MSxgZhts1eiAs5uMjvRf8PXqYNBQ=
-----END ATTESTATION MESSAGE-----
The following example shows how to claim that a key with UUID
<uuid>
is managed and has the sign capability,
producing two attestation signatures with the specified keys and
certificates:
$ spa-key-man attest claim --attesting-key <ec-key-uuid> --certificate <ec-cert-uuid> --attesting-key <hss-key-uuid> --certificate <hss-cert-path> ---managed <uuid> --key-has-capability <uuid>=sign --out attestation.pem
In this example, the template private-key-is-on-hsm provides some required and some optional claims. Any valid claims are included in the attestation message.
$ spa-key-man attest claim --private-key-is-on-hsm <private-key-uuid> --out message.pem
This command interacts with the QASM to validate a set of claims. It
takes the same attestation options as attest claim
, and
produces a report explaining which claims are valid, and the reason why
any claim is invalid.
$ spa-key-man attest validate-claims --true-is-true --key-has-capability 92f83f5d-2db6-8c43-73c1-e403e7d1e8be=sign
Claim: TRUE_IS_TRUE
Valid
Subject: 92f83f5d-2db6-8c43-73c1-e403e7d1e8be
Claim: KEY_HAS_CAPABILITY
Subject: 92f83f5d-2db6-8c43-73c1-e403e7d1e8be
Complement: 261
Error: HSM_RET_INVALID_OBJECT_CLASS
JSON format output is also supported, in the same format as
spa-attest verify --format json
, with the addition of the
HSM return code.
$ spa-key-man attest validate-claims --true-is-true --key-has-capability 92f83f5d-2db6-8c43-73c1-e403e7d1e8be=sign --format json
{"claims": {
"global": [{
"predicate": "true-is-true",
"returnCode": 0
}],
"object": {"92f83f5d-2db6-8c43-73c1-e403e7d1e8be": [{
"predicate": "key-has-capability",
"returnCode": 26,
"subject": "92f83f5d-2db6-8c43-73c1-e403e7d1e8be",
"complement": 261
}]}
}}
Spa-attest is a new CLI application to support third parties that wish to consume the claims generated by the attestation process.
This command verifies an attestation message and provides a human-readable explanation of its contents. Without a template option, which adds the display of optional claims, verify only shows claims that actually exist in the bundle. Verify returns a non-zero exit code if any mandatory claims for the template are missing or the signatures are not valid.
The csr option takes a CSR and requires the public key information to match a claim about a public key in the attestation message. For simplicity, in this mode, we only allow the attestation message to contain claims about a single key, which must match the CSR.
Usage:
spa-attest verify <attestation-message-file> [flags]
Flags:
--assume-valid-signer Only do a partial validation, assuming that the certificate or public key provided in the signature identifier is valid. Default: false.
--csr string Path to a CSR to match against this attestation message.
--dev-insecure Use DEV_INSECURE root certificates for verification by default.
--format plaintext|json Output format. (default plaintext)
-h, --help help for verify
--intermediate-cert stringArray Paths to intermediate certificates.
--require string Require that certain claims be present in the attestation.
--root stringArray Paths to accepted root certificates.
Global Flags:
--debug Debug log level
--error Error log level
--info Info log level (default true)
--logDir string Location of the logs directory.
--trace Trace log level
--warning Warning log level
$ spa-attest verify message.att
✔ Attestation was performed at Feb 20, 2023 15:39:29 GMT
✔ QASM is a production certified HSM
eea309ed-c5bc-49d0-9c35-70ecfbe76751
✔ Private key
✔ Has SubjectPublicKeyInfo: ab cd ef
✔ Key is in the independent keystore
✔ Key is hardware generated
✔ Key has the sign capability
If a CSR is provided, then the CSR must match the SPKI of one of the objects in the attestation message.
$ spa-attest verify --csr cert.csr message.att
✔ Attestation was performed at Feb 20, 2023 15:39:29 GMT
✔ QASM is a production certified HSM
Cert.csr == eea309ed-c5bc-49d0-9c35-70ecfbe76751
✔ Private key
✔ Matches the public key in the CSR
✔ Key is in the independent keystore
✔ Key is hardware generated
✔ Key has the sign capability
This example verifies a message and additionally asserts that the attestation message contains the claims needed to verify HSM storage of the private key behind the given CSR.
$ spa-attest verify --require private-key-is-on-hsm --csr cert.csr attestation.pem
✔ Attestation was performed at Feb 20, 2023 15:39:29 GMT
✔ QASM is a production certified HSM
Cert.csr == eea309ed-c5bc-49d0-9c35-70ecfbe76751
✔ Object is a private key
✔ Matches the public key in the CSR
✔ Key is in the independent keystore
✘ Key is confined to the claiming QASM
✔ Key is hardware generated
✘ Key has never been extracted
✔ Key has the sign capability
The verify command takes options to set the root certificate and certificate pool, which allows users to generate their own attestation keys and verify certificates of those keys using their own certificate chain.
$ spa-attest verify --root root.pem --intermediate-cert intermediate.pem <attestation>
Alternatively, the tool may perform a partial validation, which only checks the signature of the certificate or SPKI provided in signerIdentifier.
$ spa-attest verify --assume-valid-signer
For testing against the emulator or on DEV_INSECURE QASMs, use
--dev-insecure
to validate against the C4A_ROOT shipped
with the emulator.
$ spa-key-man attest claim --true-is-true --key-has-capability 979fadd4-7f7c-e744-e9c3-d770507482c4=sign --out test.pem
Output written to test.pem
$ spa-attest verify --dev-insecure test.pem
✔ Claim is true (debug claim)
979fadd4-7f7c-e744-e9c3-d770507482c4
✔ Key has the sign capability
$ spa-attest verify --dev-insecure test.pem --format json
{
"claims": {
"global": [
{
"predicate": "true-is-true"
}
],
"object": {
"979fadd4-7f7c-e744-e9c3-d770507482c4": [
{
"predicate": "key-has-capability",
"subject": "979fadd4-7f7c-e744-e9c3-d770507482c4",
"complement": 261
}
]
}
}
}
This following bullets explain the verification process used by “spa-attest verify”:
If a root certificate and intermediates are provided, load them. Otherwise, load the C4A_RCA root certificate hardcoded in spa-attest.
For each signature block:
Ensure that the certificate in the signature block has the extended key usage C4A_EKU_ATTESTATION(“1.3.6.1.4.1.39901.4.1.1”).
Check that the signature on setOfClaims is valid.
Check that the certificate chain to the provided root is valid.
The preceding bullets explain the full verification. There also
exists an option for partial verification, which is enabled by
--assume-valid-signer
. Partial verification is restricted
to verifying only the signature blocks.