Skip to content

go library for CBOR Object Signing and Encryption (COSE)

License

Notifications You must be signed in to change notification settings

veraison/go-cose

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

go-cose

go.dev tests codecov

A golang library for the COSE specification

Project Status

The verasion/go-cose project is actively maintained. See current releases.

The project was initially forked from the upstream mozilla-services/go-cose project, however the Veraison and Mozilla maintainers have agreed to retire the mozilla-services/go-cose project and focus on veraison/go-cose as the active project.

We thank the Mozilla maintainers and contributors for their great work that formed the base of the veraison/go-cose project.

Community

The veraison/go-cose project is an open source community effort.

You can reach the go-cose community via::

Participation in the go-cose community is governed by the Veraison CODE_OF_CONDUCT.md and GOVERNANCE.md

Code of Conduct

This project has adopted the Contributor Covenant Code of Conduct.

Installation

go-cose is compatible with modern Go releases in module mode, with Go installed:

go get github.com/veraison/go-cose

will resolve and add the package to the current development module, along with its dependencies.

Alternatively the same can be achieved if you use import in a package:

import "github.com/veraison/go-cose"

and run go get without parameters.

Finally, to use the top-of-trunk version of this repo, use the following command:

go get github.com/veraison/go-cose@main

Usage

Signing and Verification

import "github.com/veraison/go-cose"

Construct a new COSE_Sign1_Tagged message, then sign it using ECDSA w/ SHA-256 and finally marshal it. For example:

package main

import (
    "crypto/ecdsa"
    "crypto/elliptic"
    "crypto/rand"
    _ "crypto/sha256"

    "github.com/veraison/go-cose"
)

func SignP256(data []byte) ([]byte, error) {
    // create a signer
    privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    if err != nil {
        return nil, err
    }
    signer, err := cose.NewSigner(cose.AlgorithmES256, privateKey)
    if err != nil {
        return nil, err
    }

    // create message header
    headers := cose.Headers{
        Protected: cose.ProtectedHeader{
            cose.HeaderLabelAlgorithm: cose.AlgorithmES256,
        },
    }

    // sign and marshal message
    return cose.Sign1(rand.Reader, signer, headers, data, nil)
}

Verify a raw COSE_Sign1_Tagged message. For example:

package main

import (
    "crypto"
    _ "crypto/sha256"

    "github.com/veraison/go-cose"
)

func VerifyP256(publicKey crypto.PublicKey, sig []byte) error {
    // create a verifier from a trusted private key
    verifier, err := cose.NewVerifier(cose.AlgorithmES256, publicKey)
    if err != nil {
        return err
    }

    // create a sign message from a raw COSE_Sign1 payload
    var msg cose.Sign1Message
    if err = msg.UnmarshalCBOR(sig); err != nil {
        return err
    }
    return msg.Verify(nil, verifier)
}

See example_test.go for more examples.

Untagged Signing and Verification

Untagged COSE_Sign1 messages can be signed and verified as above, using cose.UntaggedSign1Message instead of cose.Sign1Message.

Signing and Verification of payload digest

When cose.NewSigner is used with PS{256,384,512} or ES{256,384,512}, the returned signer can be casted to the cose.DigestSigner interface, whose SignDigest method signs an already digested message.

When cose.NewVerifier is used with PS{256,384,512} or ES{256,384,512}, the returned verifier can be casted to the cose.DigestVerifier interface, whose VerifyDigest method verifies an already digested message.

Please refer to example_test.go for the API usage.

About hashing

go-cose does not import any hash package by its own to avoid linking unnecessary algorithms to the final binary. It is the the responsibility of the go-cose user to make the necessary hash functions available at runtime, i.e., by using a blank import:

import (
    _ "crypto/sha256"
    _ "crypto/sha512"
)

These are the required packages for each built-in cose.Algorithm:

  • cose.AlgorithmPS256, cose.AlgorithmES256: crypto/sha256
  • cose.AlgorithmPS384, cose.AlgorithmPS512, cose.AlgorithmES384, cose.AlgorithmES512: crypto/sha512
  • cose.AlgorithmEdDSA: none

Countersigning

It is possible to countersign cose.Sign1Message, cose.SignMessage, cose.Signature and cose.Countersignature objects and add them as unprotected headers. In order to do so, first create a countersignature holder with cose.NewCountersignature() and call its Sign function passing the parent object which is going to be countersigned. Then assign the countersignature as an unprotected header cose.HeaderLabelCounterSignatureV2 or, if preferred, maintain it as a detached countersignature.

When verifying countersignatures, it is necessary to pass the parent object in the Verify function of the countersignature holder.

See example_test.go for examples.

Features

Signing and Verifying Objects

go-cose supports two different signature structures:

⚠️ The COSE_Sign API is currently EXPERIMENTAL and may be changed or removed in a later release. In addition, the amount of functional and security testing it has received so far is significantly lower than the COSE_Sign1 API.

Countersignatures

go-cose supports COSE_Countersignature, check cose.Countersignature.

⚠️ The COSE_Countersignature API is currently EXPERIMENTAL and may be changed or removed in a later release.

Built-in Algorithms

go-cose has built-in supports the following algorithms:

  • PS{256,384,512}: RSASSA-PSS w/ SHA as defined in RFC 8230.
  • ES{256,384,512}: ECDSA w/ SHA as defined in RFC 8152.
  • Ed25519: PureEdDSA as defined in RFC 8152.

Custom Algorithms

The supported algorithms can be extended at runtime by using cose.RegisterAlgorithm.

API docs

Integer Ranges

CBOR supports integers in the range [-264, -1] ∪ [0, 264 - 1].

This does not map onto a single Go integer type.

go-cose uses int64 to encompass both positive and negative values to keep data sizes smaller and easy to use.

The main effect is that integer label values in the [-264, -263 - 1] and the [263, 264 - 1] ranges, which are nominally valid per RFC 8152, are rejected by the go-cose library.

Conformance Tests

go-cose runs the GlueCOSE test suite on every local go test execution. These are also executed on every CI job.

Fuzz Tests

go-cose implements several fuzz tests using Go's native fuzzing.

Fuzzing requires Go 1.18 or higher, and can be executed as follows:

go test -fuzz=FuzzSign1

Security Reviews

go-cose undergoes periodic security review. The security review reports are located here