blob: 9532c209e2a815ef31fb60abcfe2386826b342a3 [file] [log] [blame]
package cose
import (
"crypto"
"hash"
"strconv"
)
// Algorithms supported by this library.
//
// When using an algorithm which requires hashing,
// make sure the associated hash function is linked to the binary.
const (
// RSASSA-PSS w/ SHA-256 by RFC 8230.
// Requires an available crypto.SHA256.
AlgorithmPS256 Algorithm = -37
// RSASSA-PSS w/ SHA-384 by RFC 8230.
// Requires an available crypto.SHA384.
AlgorithmPS384 Algorithm = -38
// RSASSA-PSS w/ SHA-512 by RFC 8230.
// Requires an available crypto.SHA512.
AlgorithmPS512 Algorithm = -39
// ECDSA w/ SHA-256 by RFC 8152.
// Requires an available crypto.SHA256.
AlgorithmES256 Algorithm = -7
// ECDSA w/ SHA-384 by RFC 8152.
// Requires an available crypto.SHA384.
AlgorithmES384 Algorithm = -35
// ECDSA w/ SHA-512 by RFC 8152.
// Requires an available crypto.SHA512.
AlgorithmES512 Algorithm = -36
// PureEdDSA by RFC 8152.
AlgorithmEd25519 Algorithm = -8
)
// Algorithm represents an IANA algorithm entry in the COSE Algorithms registry.
// Algorithms with string values are not supported.
//
// # See Also
//
// COSE Algorithms: https://www.iana.org/assignments/cose/cose.xhtml#algorithms
//
// RFC 8152 16.4: https://datatracker.ietf.org/doc/html/rfc8152#section-16.4
type Algorithm int64
// extAlgorithm describes an extended algorithm, which is not implemented this
// library.
type extAlgorithm struct {
// Name of the algorithm.
Name string
// Hash is the hash algorithm associated with the algorithm.
// If HashFunc presents, Hash is ignored.
// If HashFunc does not present and Hash is set to 0, no hash is used.
Hash crypto.Hash
// HashFunc is the hash algorithm associated with the algorithm.
// HashFunc is preferred in the case that the hash algorithm is not
// supported by the golang build-in crypto hashes.
// For regular scenarios, use Hash instead.
HashFunc func() hash.Hash
}
// extAlgorithms contains extended algorithms.
var extAlgorithms map[Algorithm]extAlgorithm
// String returns the name of the algorithm
func (a Algorithm) String() string {
switch a {
case AlgorithmPS256:
return "PS256"
case AlgorithmPS384:
return "PS384"
case AlgorithmPS512:
return "PS512"
case AlgorithmES256:
return "ES256"
case AlgorithmES384:
return "ES384"
case AlgorithmES512:
return "ES512"
case AlgorithmEd25519:
// As stated in RFC 8152 8.2, only the pure EdDSA version is used for
// COSE.
return "EdDSA"
}
if alg, ok := extAlgorithms[a]; ok {
return alg.Name
}
return "unknown algorithm value " + strconv.Itoa(int(a))
}
// hashFunc returns the hash associated with the algorithm supported by this
// library.
func (a Algorithm) hashFunc() (crypto.Hash, bool) {
switch a {
case AlgorithmPS256, AlgorithmES256:
return crypto.SHA256, true
case AlgorithmPS384, AlgorithmES384:
return crypto.SHA384, true
case AlgorithmPS512, AlgorithmES512:
return crypto.SHA512, true
case AlgorithmEd25519:
return 0, true
}
return 0, false
}
// newHash returns a new hash instance for computing the digest specified in the
// algorithm.
// Returns nil if no hash is required for the message.
func (a Algorithm) newHash() (hash.Hash, error) {
h, ok := a.hashFunc()
if !ok {
alg, ok := extAlgorithms[a]
if !ok {
return nil, ErrUnknownAlgorithm
}
if alg.HashFunc != nil {
return alg.HashFunc(), nil
}
h = alg.Hash
}
if h == 0 {
// no hash required
return nil, nil
}
if h.Available() {
return h.New(), nil
}
return nil, ErrUnavailableHashFunc
}
// computeHash computing the digest using the hash specified in the algorithm.
// Returns the input data if no hash is required for the message.
func (a Algorithm) computeHash(data []byte) ([]byte, error) {
h, err := a.newHash()
if err != nil {
return nil, err
}
if h == nil {
return data, nil
}
if _, err := h.Write(data); err != nil {
return nil, err
}
return h.Sum(nil), nil
}
// RegisterAlgorithm provides extensibility for the cose library to support
// private algorithms or algorithms not yet registered in IANA.
// The existing algorithms cannot be re-registered.
// The parameter `hash` is the hash algorithm associated with the algorithm. If
// hashFunc presents, hash is ignored. If hashFunc does not present and hash is
// set to 0, no hash is used for this algorithm.
// The parameter `hashFunc` is preferred in the case that the hash algorithm is not
// supported by the golang build-in crypto hashes.
func RegisterAlgorithm(alg Algorithm, name string, hash crypto.Hash, hashFunc func() hash.Hash) error {
if _, ok := alg.hashFunc(); ok {
return ErrAlgorithmRegistered
}
if _, ok := extAlgorithms[alg]; ok {
return ErrAlgorithmRegistered
}
if extAlgorithms == nil {
extAlgorithms = make(map[Algorithm]extAlgorithm)
}
extAlgorithms[alg] = extAlgorithm{
Name: name,
Hash: hash,
HashFunc: hashFunc,
}
return nil
}