1. Signature Support
The CBOR library contains support forCreating
and Validating
embedded signatures using a scheme called
"CBOR Signature Format" (CSF).
Unless otherwise noted, CBOR data is shown in
Diagnostic Notation.
Note that unlike COSE [RFC 9052], CSF leverages Deterministic Encoding, enabling constructs like the following:
1: {
1: "Space Shop",
2: "435.00",
3: "USD"
},
2: "spaceshop.com",
3: "FR7630002111110020050014382",
4: "https://banknet2.org",
5: "05768401",
6: "2025-04-23T09:34:08-05:00",
7: {
1: 38.8882,
2: 77.0199
},
/ Embedded signature object /
simple(99): {
/ Signature algorithm = ESP256 /
1: -9,
/ Public key descriptor in COSE format /
4: {
/ kty = EC2 /
1: 2,
/ crv = P-256 /
-1: 1,
/ x /
-2: h'e812b1a6dcbc708f9ec43cc2921fa0a14e9d5eadcc6dc63471dd4b680c6236b5',
/ y /
-3: h'9826dcbd4ce6e388f72edd9be413f2425a10f75b5fd83d95fa0cde53159a51d8'
},
/ Signature value /
6: h'05257a10ebea8ec582eef0dc9b0bffb2dfd0a1a0eda6bf0916672a9e53820b8412a465849bb086fbe3da94ae00dc5bf8b271fa0206fdd7c9ec909c4171b0d6b4'
}
}
The same object expressed as hex-encoded CBOR:
The sample was signed using the following COSE private key:
1: 2,
-1: 1,
-2: h'e812b1a6dcbc708f9ec43cc2921fa0a14e9d5eadcc6dc63471dd4b680c6236b5',
-3: h'9826dcbd4ce6e388f72edd9be413f2425a10f75b5fd83d95fa0cde53159a51d8',
-4: h'e97c4c15785c613e5037dc394c88366922ac6dc8fea63e019d990aed93ade01f'
}
1
-7
represent application data
(which for compatibility with CSF must be supplied in a CBOR map
),
while the reserved label simple(99)
[I-D.draft-rundgren-cbor-simple-4-csf]
holds the embedded signature container.
Note that application labels may be of any type.
2. Signature Validation
Signatures must for compatibility with CSF, be provided as a CBOR map having a fixed set of labels, according to the following table (with map values provided in CDDL [RFC 8610] notation):Name | Label | Value | Comment |
---|---|---|---|
customData | 0 |
any | Optional: data included in the CSF container. Also see Crypto Options. |
algorithm | 1 |
int | Signature algorithm using COSE identifiers. |
keyId | 3 |
any | Optional: key identifier using any valid CBOR object.
Note that keyId must not be used together with
publicKey or certificatePath .
A compliant keyId must uniquely identify a specific signature key.
|
publicKey | 4 |
{} |
Optional: public key in COSE format. Note that public key objects must not contain additional information like key identifiers or preferred signature algorithms. |
certificatePath | 5 |
[] | Optional: certificate path supplied
as an array of byte string objects holding X.509 certificates in DER format,
where the first object must be the signature certificate.
Signature objects must not contain both certificatePath and publicKey elements.
|
signatureValue | 6 |
bstr | Signature value. |
- Signatures are validated by running the signature validation
algorithm
, over the CBOR binary representation of themap
object holding the application data including the embedded signature object, with thesignatureValue
label and its associated value as the sole exception (highlighted in the example). Note that the length of the signature objectmap
must be updated to reflect the removal of thesignatureValue
during validation. - Signature validation keys are either implicit, located via
keyId
attributes, or supplied inpublicKey
orcertificatePath
attributes. - If
publicKey
orcertificatePath
attributes are present, they must be used as signature validation keys. Note though that such keys must also be verified to be known and trusted by the signature-using application. - Signature validation keys must be checked for compatibility with
the
algorithm
attribute.
3. Multiple Signatures
Multiple signatures use the same validation method as single signatures,
but have an enhanced syntax:
the reserved label simple(99)
points to a non-empty array of signature
containers:
1: "Hello signed world!",
2: [4.7, true, h'012345'],
simple(99): [{
1: -50,
4: {
1: 1,
-1: 6,
-2: h'fe49acf5b92b6e923594f2e83368f680ac924be93cf533aecaf802e37757f8c9'
},
6: h'5c2699faa73abc448b1b936e550b4afa9929c4a266a3a394a666577fd90aa9d6cf39a8f0cb771d5ac00b43958a59dc6802a145922ecd6b980839356598d1f70d'
}, {
1: -9,
4: {
1: 2,
-1: 1,
-2: h'e812b1a6dcbc708f9ec43cc2921fa0a14e9d5eadcc6dc63471dd4b680c6236b5',
-3: h'9826dcbd4ce6e388f72edd9be413f2425a10f75b5fd83d95fa0cde53159a51d8'
},
6: h'240861757ecede55cdbc2f0d33785f1e4b1b4e25c9cb5a6411e557ca6898cd083f39431d8e6c22661ff7aa2ee866f95acfc9b6be8510437c183a3c16b0d8cfd3'
}]
}
Also se CBORSigner.setMultiSignatureMode(boolean)
and CBORValidator.setMultiSignatureMode(boolean)
.
4. Tagged and Custom Signature Data
Through Crypto Options, embedded signatures can be further enhanced, like the ability to include a top-level object identifier in the signed data:
1: "Hello signed world!",
2: [4.7, true, h'012345'],
simple(99): {
1: -50,
4: {
1: 1,
-1: 6,
-2: h'fe49acf5b92b6e923594f2e83368f680ac924be93cf533aecaf802e37757f8c9'
},
6: h'5de56d88d5ef3f7052b1e79f323fa585c6a6e5b5bfedb697cd61fe9515bf2578f2af03b149cbf43b5ab7176fa784cf4fbb66ba25943d1879a21ad57bc3c81d0f'
}
}])
5. Signature Algorithms
Name | Identifier | Notes |
---|---|---|
HS256 | 5 | |
HS384 | 6 | |
HS512 | 7 | |
Ed25519 | -50 | 1 |
Ed448 | -51 | 1 |
ESP256 | -9 | 1 |
ESP384 | -48 | 1 |
ESP512 | -49 | 1 |
PS256 | -37 | |
PS384 | -38 | |
PS512 | -39 | |
RS256 | -257 | |
RS384 | -258 | |
RS512 | -259 |
1] Updated for compliance with ID.draft-ietf-jose-fully-specified-algorithms.
6. Test Vectors
An extensive set of test vectors is currently available at: https://github.com/cyberphone/openkeystore/tree/master/testdata/cbor-signatures .
Use CBORPrinter
to list contents in a human-friendly way.
7. Using the Signature API
The following section outlines how the signature API is supposed to be used.Sample program:
import org.webpki.cbor.CBORArray;
import org.webpki.cbor.CBORBoolean;
import org.webpki.cbor.CBORDecoder;
import org.webpki.cbor.CBORFloat;
import org.webpki.cbor.CBORHmacSigner;
import org.webpki.cbor.CBORHmacValidator;
import org.webpki.cbor.CBORInt;
import org.webpki.cbor.CBORMap;
import org.webpki.cbor.CBORString;
import org.webpki.crypto.HmacAlgorithms;
import org.webpki.util.HexaDecimal;
public class SignatureDemo {
static final byte[] HMAC_KEY = HexaDecimal.decode(
"7fdd851a3b9d2dafc5f0d00030e22b9343900cd42ede4948568a4a2ee655291a");
static final CBORInt GREETINGS_LABEL = new CBORInt(1);
static final CBORInt OTHER_DATA_LABEL = new CBORInt(2);
public static void main(String[] args) {
// Create CBOR data to be signed.
CBORMap dataToBeSigned = new CBORMap()
.set(GREETINGS_LABEL, new CBORString("Hello Signed CBOR World!"))
.set(OTHER_DATA_LABEL, new CBORArray()
.add(new CBORFloat(-4.5))
.add(new CBORBoolean(true)));
// Sign data using CSF.
byte[] signatureObject = new CBORHmacSigner(HMAC_KEY, HmacAlgorithms.HMAC_SHA256)
.sign(dataToBeSigned).encode();
// Validate CSF object.
CBORMap decodedCbor = new CBORHmacValidator(HMAC_KEY)
.validate(CBORDecoder.decode(signatureObject)).getMap();
// Fetch a map item.
System.out.println(decodedCbor.get(GREETINGS_LABEL).getString());
}
}
The resulting signed object:
1: "Hello Signed CBOR World!",
2: [-4.5, true],
simple(99): {
1: 5,
6: h'7acbf4c14c94ccc6b95d57cdb3750f2c926c61520383f921ac7aecafe3cd0e7c'
}
}
The resulting signed object expressed in hexadecimal: