Skip to content

COSE

COSE, RFC 9052, is what JOSE is for JSON: signed, MACed and encrypted messages, written in CBOR. Its six structures and the CWT tag that wraps them are built in and registered by default, so a tagged message decodes to a class that knows its own shape.

use CBOR\Decoder;
use CBOR\StringStream;
use CBOR\Tag\CoseSign1Tag;

$object = Decoder::create()->decode(StringStream::create($binaryData));

if ($object instanceof CoseSign1Tag) {
    $protectedHeader = $object->getProtectedHeaderAsMap(); // the signed header, decoded
    $payload = $object->getPayload();                      // ByteStringObject, or NullObject when detached
    $signature = $object->getSignature();

    $algorithm = $protectedHeader->normalize()[1] ?? null;
}

The protected header travels as a byte string holding an encoded CBOR map, and the payload as a byte string too. That is deliberate: the signature covers those exact bytes. getProtectedHeaderAsMap() decodes a copy for you to read — it does not replace the bytes that were signed, and you should not re-encode them yourself.

A payload that is null is a detached one: the content travelled out of band, and only the signature came with the structure. Check for it before you use the payload.

use CBOR\OtherObject\NullObject;

if ($payload instanceof NullObject) {
    // the content is elsewhere; the verifier has to be given it
}

A token

A CWT is tag 61 around one of those structures, or around a bare claims set:

use CBOR\Tag\CwtTag;

if ($object instanceof CwtTag) {
    $inner = $object->getValue(); // a COSE structure, or the claims as a MapObject
}

What this library does not do

Verifying a signature or a MAC means rebuilding the Sig_structure of the specification, finding the key, and running the algorithm the header names. None of that is CBOR, and none of it is here. web-auth/cose-lib does it, on top of this library, with the algorithm registry of RFC 9053: use it rather than assembling the pieces yourself.