cose

package module
v0.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 21, 2021 License: MPL-2.0 Imports: 15 Imported by: 2

README

go-cose

CircleCI Coverage Status

A COSE library for go.

It currently supports signing and verifying the SignMessage type with the ES{256,384,512} and PS256 algorithms.

API docs

Usage

Install
go get -u github.com/PONCI-Berlin/go-cose
Signing a message

See example/sign.go and run it with:

$ go run example/sign.go
Bit lengths of integers r and s (256 and 256) do not match the key length 255
Message signature (ES256): 043685f99421f9e80c7c3c50d0fc8266161d3d614aaa3b63d2cdf581713fca62bb5d2e34d2352dbe41424b31d0b4a11d6b2d4764c18e2af04f4520fbe494d51c
Verifying a message

See example/verify.go and run it with:

$ go run example/verify.go
Bit lengths of integers r and s (256 and 254) do not match the key length 254
Message signature (ES256): 9411dc5200c1cb67ccd76424ade09ce89c4a8d8d2b66f2bbf70edf63beb2dc3cbde83250773e659b635d3715442a1efaa6b0c030ee8a2523c3e37a22ddb055fa
Message signature verified

Development

Running tests:

  1. Install rust and cargo

  2. On OSX: brew install nss nss then in sign_verify_cose_rust_cli_test.go add NSS_LIB_DIR to cmd or -L /usr/local/opt/nss/lib to RUSTFLAGS e.g. cmd.Env = append(os.Environ(), "NSS_LIB_DIR=/usr/local/opt/nss/lib", "RUSTFLAGS=-A dead_code -A unused_imports")

  3. If you already have dep and golint commands installed, run make install-godep install-golint

  4. Run go test

Documentation

Index

Constants

View Source
const ContextSignature = "Signature"

ContextSignature identifies the context of the signature as a COSE_Signature structure per https://tools.ietf.org/html/rfc8152#section-4.4

View Source
const SignMessageCBORTag = 98

SignMessageCBORTag is the CBOR tag for a COSE SignMessage from https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml#tags

Variables

View Source
var (
	// PS256 is RSASSA-PSS w/ SHA-256 from [RFC8230]
	PS256 = getAlgByNameOrPanic("PS256")

	// ES256 is ECDSA w/ SHA-256 from [RFC8152]
	ES256 = getAlgByNameOrPanic("ES256")

	// ES384 is ECDSA w/ SHA-384 from [RFC8152]
	ES384 = getAlgByNameOrPanic("ES384")

	// ES512 is ECDSA w/ SHA-512 from [RFC8152]
	ES512 = getAlgByNameOrPanic("ES512")
)

Supported Algorithms

View Source
var (
	ErrInvalidAlg             = errors.New("Invalid algorithm")
	ErrAlgNotFound            = errors.New("Error fetching alg")
	ErrECDSAVerification      = errors.New("verification failed ecdsa.Verify")
	ErrRSAPSSVerification     = errors.New("verification failed rsa.VerifyPSS err crypto/rsa: verification error")
	ErrMissingCOSETagForLabel = errors.New("No common COSE tag for label")
	ErrMissingCOSETagForTag   = errors.New("No common COSE label for tag")
	ErrNilSigHeader           = errors.New("Signature.headers is nil")
	ErrNilSigProtectedHeaders = errors.New("Signature.headers.protected is nil")
	ErrNilSignatures          = errors.New("SignMessage.signatures is nil. Use AddSignature to add one")
	ErrNoSignatures           = errors.New("No signatures to sign the message. Use AddSignature to add them")
	ErrNoSignerFound          = errors.New("No signer found")
	ErrNoVerifierFound        = errors.New("No verifier found")
	ErrUnavailableHashFunc    = errors.New("hash function is not available")
	ErrUnknownPrivateKeyType  = errors.New("Unrecognized private key type")
	ErrUnknownPublicKeyType   = errors.New("Unrecognized public key type")
)

Functions

func CompressHeaders

func CompressHeaders(headers map[interface{}]interface{}) (compressed map[interface{}]interface{})

CompressHeaders replaces string tags with their int values and alg tags with their IANA int values.

panics when a compressed header tag already exists (e.g. alg and 1) casts int64 keys to int to make looking up common header IDs easier

func DecompressHeaders

func DecompressHeaders(headers map[interface{}]interface{}) (decompressed map[interface{}]interface{})

DecompressHeaders replaces int values with string tags and alg int values with their IANA labels. Is the inverse of CompressHeaders.

func FindDuplicateHeader

func FindDuplicateHeader(headers *Headers) interface{}

FindDuplicateHeader compresses the headers and returns the first duplicate header or nil for none found

func FromBase64Int

func FromBase64Int(data string) *big.Int

FromBase64Int decodes a base64-encoded string into a big.Int or panics

from https://github.com/square/go-jose/blob/789a4c4bd4c118f7564954f441b29c153ccd6a96/utils_test.go#L45 Apache License 2.0

func GetCommonHeaderLabel

func GetCommonHeaderLabel(tag int) (label string, err error)

GetCommonHeaderLabel returns the CBOR label for the map tag. Is the inverse of GetCommonHeaderTag.

func GetCommonHeaderTag

func GetCommonHeaderTag(label string) (tag int, err error)

GetCommonHeaderTag returns the CBOR tag for the map label

using Common COSE Headers Parameters Table 2 https://tools.ietf.org/html/rfc8152#section-3.1

func GetCommonHeaderTagOrPanic

func GetCommonHeaderTagOrPanic(label string) (tag int)

GetCommonHeaderTagOrPanic returns the CBOR label for a string. Is the inverse of GetCommonHeaderLabel.

func I2OSP

func I2OSP(b *big.Int, n int) []byte

I2OSP "Integer-to-Octet-String" converts a nonnegative integer to an octet string of a specified length

https://tools.ietf.org/html/rfc8017#section-4.1

func IsSignMessage

func IsSignMessage(data []byte) bool

IsSignMessage checks whether the prefix is 0xd8 0x62 for a COSE SignMessage

func Marshal

func Marshal(o interface{}) (b []byte, err error)

Marshal returns the CBOR []byte encoding of param o

func Sign

func Sign(rand io.Reader, digest []byte, signers []ByteSigner) (signatures [][]byte, err error)

Sign returns the SignatureBytes for each Signer in the same order on the digest or the error from the first failing Signer

func Unmarshal

func Unmarshal(b []byte) (o interface{}, err error)

Unmarshal returns the CBOR decoding of a []byte into param o

func Verify

func Verify(digest []byte, signatures [][]byte, verifiers []ByteVerifier) (err error)

Verify returns nil if all Verifier verify the SignatureBytes or the error from the first failing Verifier

Types

type Algorithm

type Algorithm struct {
	Name  string
	Value int

	// optional fields
	HashFunc crypto.Hash // hash function for SignMessages
	// contains filtered or unexported fields
}

Algorithm represents an IANA algorithm's parameters (Name, Value/ID, and optional extra data)

From the spec:

NOTE: The assignment of algorithm identifiers in this document was done so that positive numbers were used for the first layer objects (COSE_Sign, COSE_Sign1, COSE_Encrypt, COSE_Encrypt0, COSE_Mac, and COSE_Mac0). Negative numbers were used for second layer objects (COSE_Signature and COSE_recipient).

https://www.iana.org/assignments/cose/cose.xhtml#header-algorithm-parameters

https://tools.ietf.org/html/rfc8152#section-16.4

type ByteSigner

type ByteSigner interface {
	// Sign returns the COSE signature as a byte slice
	Sign(rand io.Reader, digest []byte) (signature []byte, err error)
}

ByteSigner take a signature digest and returns COSE signature bytes

type ByteVerifier

type ByteVerifier interface {
	// Verify returns nil for a successfully verified signature or an error
	Verify(digest []byte, signature []byte) (err error)
}

ByteVerifier checks COSE signatures

type Headers

type Headers struct {
	Protected   map[interface{}]interface{}
	Unprotected map[interface{}]interface{}
}

Headers represents "two buckets of information that are not considered to be part of the payload itself, but are used for holding information about content, algorithms, keys, or evaluation hints for the processing of the layer."

https://tools.ietf.org/html/rfc8152#section-3

It is represented by CDDL fragments:

Headers = (

protected : empty_or_serialized_map,
unprotected : header_map

)

header_map = {
    Generic_Headers,
    * label => values
}

empty_or_serialized_map = bstr .cbor header_map / bstr .size 0

func (*Headers) Decode

func (h *Headers) Decode(o []interface{}) (err error)

Decode loads a two element interface{} slice into Headers.protected and unprotected respectively

func (*Headers) DecodeProtected

func (h *Headers) DecodeProtected(o interface{}) (err error)

DecodeProtected Unmarshals and sets Headers.protected from an interface{}

func (*Headers) DecodeUnprotected

func (h *Headers) DecodeUnprotected(o interface{}) (err error)

DecodeUnprotected Unmarshals and sets Headers.unprotected from an interface{}

func (*Headers) EncodeProtected

func (h *Headers) EncodeProtected() (bstr []byte)

EncodeProtected compresses and Marshals protected headers to bytes to encode as a CBOR bstr

func (*Headers) EncodeUnprotected

func (h *Headers) EncodeUnprotected() (encoded map[interface{}]interface{})

EncodeUnprotected returns compressed unprotected headers

type KeyType

type KeyType int

KeyType is the type to use in keyOptions to tell MakeDEREndEntity which type of crypto.PrivateKey to generate

const (
	// KeyTypeUnsupported is the type to not generate a key
	KeyTypeUnsupported KeyType = iota

	// KeyTypeRSA is the type to generate an rsa.PrivateKey
	KeyTypeRSA KeyType = iota

	// KeyTypeECDSA is the type to generate an ecdsa.PrivateKey
	KeyTypeECDSA KeyType = iota
)

type RSAOptions

type RSAOptions struct {
	Size int
}

RSAOptions are options for NewSigner currently just the RSA Key size

type SignMessage

type SignMessage struct {
	Headers    *Headers
	Payload    []byte
	Signatures []Signature
}

SignMessage represents a COSESignMessage with CDDL fragment:

COSE_Sign = [

Headers,
payload : bstr / nil,
signatures : [+ COSE_Signature]

]

https://tools.ietf.org/html/rfc8152#section-4.1

func NewSignMessage

func NewSignMessage() *SignMessage

NewSignMessage takes a []byte payload and returns a new pointer to a SignMessage with empty headers and signatures

func (*SignMessage) AddSignature

func (m *SignMessage) AddSignature(s *Signature)

AddSignature adds a signature to the message signatures creating an empty []Signature if necessary

func (*SignMessage) MarshalCBOR

func (message *SignMessage) MarshalCBOR() ([]byte, error)

MarshalCBOR encodes SignMessage.

func (*SignMessage) SigStructure

func (m *SignMessage) SigStructure(external []byte, signature *Signature) (ToBeSigned []byte, err error)

SigStructure returns the byte slice to be signed

func (*SignMessage) Sign

func (m *SignMessage) Sign(rand io.Reader, external []byte, signers []Signer) (err error)

Sign signs a SignMessage i.e. it populates signatures[].SignatureBytes using the provided array of Signers

func (*SignMessage) SignatureDigests

func (m *SignMessage) SignatureDigests(external []byte) (digests [][]byte, err error)

SignatureDigests returns the list of signature digests of a sign message. This is mainly so that we can do the actual signing remotely without sending the message over.

func (*SignMessage) UnmarshalCBOR

func (message *SignMessage) UnmarshalCBOR(data []byte) (err error)

UnmarshalCBOR decodes data into SignMessage.

Unpacks a SignMessage described by CDDL fragments:

COSE_Sign = [

Headers,
payload : bstr / nil,
signatures : [+ COSE_Signature]

]

COSE_Signature = [

Headers,
signature : bstr

]

Headers = (

protected : empty_or_serialized_map,
unprotected : header_map

)

header_map = {
    Generic_Headers,
    * label => values
}

empty_or_serialized_map = bstr .cbor header_map / bstr .size 0

Generic_Headers = (

? 1 => int / tstr,  ; algorithm identifier
? 2 => [+label],    ; criticality
? 3 => tstr / int,  ; content type
? 4 => bstr,        ; key identifier
? 5 => bstr,        ; IV
? 6 => bstr,        ; Partial IV
? 7 => COSE_Signature / [+COSE_Signature] ; Counter signature

)

func (*SignMessage) Verify

func (m *SignMessage) Verify(external []byte, verifiers []Verifier) (err error)

Verify verifies all signatures on the SignMessage returning nil for success or an error from the first failed verification

type Signature

type Signature struct {
	Headers        *Headers
	SignatureBytes []byte
}

Signature represents a COSE signature with CDDL fragment:

COSE_Signature = [

Headers,
signature : bstr

]

https://tools.ietf.org/html/rfc8152#section-4.1

func NewSignature

func NewSignature() (s *Signature)

NewSignature returns a new COSE Signature with empty headers and nil signature bytes

func (*Signature) Decode

func (s *Signature) Decode(o interface{})

Decode updates the signature inplace from its COSE serialization

func (*Signature) Equal

func (s *Signature) Equal(other *Signature) bool

type Signer

type Signer struct {
	PrivateKey crypto.PrivateKey
	// contains filtered or unexported fields
}

Signer holds a COSE Algorithm and private key for signing messages

func NewSigner

func NewSigner(alg *Algorithm, options interface{}) (signer *Signer, err error)

NewSigner returns a Signer with a generated key

func NewSignerFromKey

func NewSignerFromKey(alg *Algorithm, privateKey crypto.PrivateKey) (signer *Signer, err error)

NewSignerFromKey checks whether the privateKey is supported and returns a Signer using the provided key

func (*Signer) Public

func (s *Signer) Public() (publicKey crypto.PublicKey)

Public returns the crypto.PublicKey for the Signer's privateKey

func (*Signer) Sign

func (s *Signer) Sign(rand io.Reader, digest []byte) (signature []byte, err error)

Sign returns the COSE signature as a byte slice

func (*Signer) Verifier

func (s *Signer) Verifier() (verifier *Verifier)

Verifier returns a Verifier using the Signer's public key and Algorithm

type Verifier

type Verifier struct {
	PublicKey crypto.PublicKey
	Alg       *Algorithm
}

Verifier holds a PublicKey and Algorithm to verify signatures

func (*Verifier) Verify

func (v *Verifier) Verify(digest []byte, signature []byte) (err error)

Verify verifies a signature returning nil for success or an error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL