1. Signature Support

The CBOR library contains support for Creating 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:

a801a3016a53706163652053686f7002663433352e30300363555344026d737061636573686f702e636f6d03781b465237363330303032313131313130303230303530303134333832047468747470733a2f2f62616e6b6e6574322e6f726705683035373638343031067819323032352d30342d32335430393a33343a30382d30353a303007a201fb404371b089a0275202fb405341460aa64c30f863a3012804a401022001215820e812b1a6dcbc708f9ec43cc2921fa0a14e9d5eadcc6dc63471dd4b680c6236b52258209826dcbd4ce6e388f72edd9be413f2425a10f75b5fd83d95fa0cde53159a51d806584005257a10ebea8ec582eef0dc9b0bffb2dfd0a1a0eda6bf0916672a9e53820b8412a465849bb086fbe3da94ae00dc5bf8b271fa0206fdd7c9ec909c4171b0d6b4

The sample was signed using the following COSE private key:

{
  1: 2,
  -1: 1,
  -2: h'e812b1a6dcbc708f9ec43cc2921fa0a14e9d5eadcc6dc63471dd4b680c6236b5',
  -3: h'9826dcbd4ce6e388f72edd9be413f2425a10f75b5fd83d95fa0cde53159a51d8',
  -4: h'e97c4c15785c613e5037dc394c88366922ac6dc8fea63e019d990aed93ade01f'
}
Explanation: Labels 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):
NameLabelValueComment
customData0 anyOptional: data included in the CSF container. Also see Crypto Options.
algorithm1 intSignature algorithm using COSE identifiers.
keyId3 anyOptional: 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.
publicKey4 {} Optional: public key in COSE format. Note that public key objects must not contain additional information like key identifiers or preferred signature algorithms.
certificatePath5 []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.
signatureValue6 bstrSignature value.
To validate a CSF-based signature, apply the following set of rules:
  • Signatures are validated by running the signature validation algorithm, over the CBOR binary representation of the map object holding the application data including the embedded signature object, with the signatureValue label and its associated value as the sole exception (highlighted in the example). Note that the length of the signature object map must be updated to reflect the removal of the signatureValue during validation.
  • Signature validation keys are either implicit, located via keyId attributes, or supplied in publicKey or certificatePath attributes.
  • If publicKey or certificatePath 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'
  }]
}
Validation is performed by validating each signature individually. This is accomplished by removing other signatures (CSF containers), leaving an array holding a single CSF container to the validation process.

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:

1010(["https://example.com/myobject", {
  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'
  }
}])
Note: the sample object features a COTX tag holding an URL based object identifier.

5. Signature Algorithms

Currently supported COSE signature algorithms:
NameIdentifierNotes
HS2565
HS3846
HS5127
Ed25519-501
Ed448-511
ESP256-91
ESP384-481
ESP512-491
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:

package cbor_api_demo;

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:

a301781848656c6c6f205369676e65642043424f5220576f726c64210282f9c480f5f863a201050658207acbf4c14c94ccc6b95d57cdb3750f2c926c61520383f921ac7aecafe3cd0e7c