2024-09-03 15:40:55 -04:00
|
|
|
// Package varsig implements the portion of the [varsig specification]
|
|
|
|
|
// that's needed for the UCAN [Envelope].
|
|
|
|
|
//
|
|
|
|
|
// While the [Envelope] specification has a field that's labelled
|
|
|
|
|
// "VarsigHeader", this field is actually the prefix, header and segments
|
|
|
|
|
// of the body excluding the signature itself (which is a different field
|
|
|
|
|
// in the [Envelope]).
|
|
|
|
|
//
|
|
|
|
|
// Given that [go-ucan] supports a limited number of public key types,
|
|
|
|
|
// and that the signature isn't part of the resulting field, the values
|
|
|
|
|
// that are used are constants. Note that for key types that are fully
|
|
|
|
|
// specified in the [did:key], the [VarsigHeader] field isn't technically
|
|
|
|
|
// needed and could theoretically conflict with the DID.
|
|
|
|
|
//
|
|
|
|
|
// Treating these values as constants has no impact when issuing or
|
|
|
|
|
// delegating tokens. When decoding tokens, simply matching the strings
|
|
|
|
|
// will allow us to detect errors but won't provide as much detail (e.g.
|
|
|
|
|
// we can't indicate that the signature was incorrectly generated from
|
|
|
|
|
// a DAG-JSON encoding.)
|
|
|
|
|
//
|
|
|
|
|
// [varsig specification]: https://github.com/ChainAgnostic/varsig
|
|
|
|
|
// [Envelope]:https://github.com/ucan-wg/spec#envelope
|
|
|
|
|
// [go-ucan]: https://github.com/ucan-wg/go-ucan
|
|
|
|
|
package varsig
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/base64"
|
|
|
|
|
"encoding/binary"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
|
|
"github.com/libp2p/go-libp2p/core/crypto/pb"
|
|
|
|
|
"github.com/multiformats/go-multicodec"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
Prefix = 0x34
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// ErrUnknownHeader is returned when it's not possible to decode the
|
|
|
|
|
// provided string into a libp2p public key type.
|
|
|
|
|
var ErrUnknownHeader = errors.New("could not decode unknown header")
|
|
|
|
|
|
|
|
|
|
// ErrUnknownKeyType is returned when value provided is not a valid
|
|
|
|
|
// libp2p public key type.
|
|
|
|
|
var ErrUnknownKeyType = errors.New("could not encode unsupported key type")
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
decMap = headerToKeyType()
|
|
|
|
|
encMap = keyTypeToHeader()
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Decode returns either the pb.KeyType associated with the provided Header
|
|
|
|
|
// or an error.
|
|
|
|
|
//
|
|
|
|
|
// Currently, only the four key types supported by the [go-libp2p/core/crypto]
|
|
|
|
|
// library are supported.
|
|
|
|
|
//
|
|
|
|
|
// [go-libp2p/core/crypto]: github.com/libp2p/go-libp2p/core/crypto
|
2024-09-04 09:03:03 -04:00
|
|
|
func Decode(header []byte) (pb.KeyType, error) {
|
|
|
|
|
keyType, ok := decMap[string(header)]
|
2024-09-03 15:40:55 -04:00
|
|
|
if !ok {
|
|
|
|
|
return -1, fmt.Errorf("%w: %s", ErrUnknownHeader, header)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return keyType, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Encode returns either the header associated with the provided pb.KeyType
|
|
|
|
|
// or an error indicating the header was unknown.
|
|
|
|
|
//
|
|
|
|
|
// Currently, only the four key types supported by the [go-libp2p/core/crypto]
|
|
|
|
|
// library are supported.
|
|
|
|
|
//
|
|
|
|
|
// [go-libp2p/core/crypto]: github.com/libp2p/go-libp2p/core/crypto
|
2024-09-04 09:03:03 -04:00
|
|
|
func Encode(keyType pb.KeyType) ([]byte, error) {
|
2024-09-03 15:40:55 -04:00
|
|
|
header, ok := encMap[keyType]
|
|
|
|
|
if !ok {
|
2024-09-04 09:03:03 -04:00
|
|
|
return nil, fmt.Errorf("%w: %s", ErrUnknownKeyType, keyType.String())
|
2024-09-03 15:40:55 -04:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 09:03:03 -04:00
|
|
|
return []byte(header), nil
|
2024-09-03 15:40:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func keyTypeToHeader() map[pb.KeyType]string {
|
|
|
|
|
const rsaSigLen = 0x100
|
|
|
|
|
|
|
|
|
|
return map[pb.KeyType]string{
|
|
|
|
|
pb.KeyType_RSA: header(
|
|
|
|
|
Prefix,
|
|
|
|
|
multicodec.RsaPub,
|
|
|
|
|
multicodec.Sha2_256,
|
|
|
|
|
rsaSigLen,
|
|
|
|
|
multicodec.DagCbor,
|
|
|
|
|
),
|
|
|
|
|
pb.KeyType_Ed25519: header(
|
|
|
|
|
Prefix,
|
|
|
|
|
multicodec.Ed25519Pub,
|
|
|
|
|
multicodec.DagCbor,
|
|
|
|
|
),
|
|
|
|
|
pb.KeyType_Secp256k1: header(
|
|
|
|
|
Prefix,
|
|
|
|
|
multicodec.Secp256k1Pub,
|
|
|
|
|
multicodec.Sha2_256,
|
|
|
|
|
multicodec.DagCbor,
|
|
|
|
|
),
|
|
|
|
|
pb.KeyType_ECDSA: header(
|
|
|
|
|
Prefix,
|
|
|
|
|
multicodec.Es256,
|
|
|
|
|
multicodec.Sha2_256,
|
|
|
|
|
multicodec.DagCbor,
|
|
|
|
|
),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func headerToKeyType() map[string]pb.KeyType {
|
|
|
|
|
out := make(map[string]pb.KeyType, len(encMap))
|
|
|
|
|
|
|
|
|
|
for keyType, header := range encMap {
|
|
|
|
|
out[header] = keyType
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func header(vals ...multicodec.Code) string {
|
|
|
|
|
var buf []byte
|
|
|
|
|
|
|
|
|
|
for _, val := range vals {
|
|
|
|
|
buf = binary.AppendUvarint(buf, uint64(val))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return base64.RawStdEncoding.EncodeToString(buf)
|
|
|
|
|
}
|