| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- package pki
- import (
- "crypto/x509/pkix"
- "encoding/asn1"
- "encoding/pem"
- "errors"
- "strings"
- "github.com/cloudflare/circl/sign"
- "github.com/cloudflare/circl/sign/schemes"
- )
- var (
- allSchemesByOID map[string]sign.Scheme
- allSchemesByTLS map[uint]sign.Scheme
- )
- type pkixPrivKey struct {
- Version int
- Algorithm pkix.AlgorithmIdentifier
- PrivateKey []byte
- }
- func init() {
- allSchemesByOID = make(map[string]sign.Scheme)
- allSchemesByTLS = make(map[uint]sign.Scheme)
- for _, scheme := range schemes.All() {
- if cert, ok := scheme.(CertificateScheme); ok {
- allSchemesByOID[cert.Oid().String()] = scheme
- }
- if tlsScheme, ok := scheme.(TLSScheme); ok {
- allSchemesByTLS[tlsScheme.TLSIdentifier()] = scheme
- }
- }
- }
- func SchemeByOid(oid asn1.ObjectIdentifier) sign.Scheme { return allSchemesByOID[oid.String()] }
- func SchemeByTLSID(id uint) sign.Scheme { return allSchemesByTLS[id] }
- // Additional methods when the signature scheme is supported in X509.
- type CertificateScheme interface {
- // Return the appropriate OIDs for this instance. It is implicitly
- // assumed that the encoding is simple: e.g. uses the same OID for
- // signature and public key like Ed25519.
- Oid() asn1.ObjectIdentifier
- }
- // Additional methods when the signature scheme is supported in TLS.
- type TLSScheme interface {
- TLSIdentifier() uint
- }
- func UnmarshalPEMPublicKey(data []byte) (sign.PublicKey, error) {
- block, rest := pem.Decode(data)
- if len(rest) != 0 {
- return nil, errors.New("trailing data")
- }
- if !strings.HasSuffix(block.Type, "PUBLIC KEY") {
- return nil, errors.New("pem block type is not public key")
- }
- return UnmarshalPKIXPublicKey(block.Bytes)
- }
- func UnmarshalPKIXPublicKey(data []byte) (sign.PublicKey, error) {
- var pkix struct {
- Raw asn1.RawContent
- Algorithm pkix.AlgorithmIdentifier
- PublicKey asn1.BitString
- }
- if rest, err := asn1.Unmarshal(data, &pkix); err != nil {
- return nil, err
- } else if len(rest) != 0 {
- return nil, errors.New("trailing data")
- }
- scheme := SchemeByOid(pkix.Algorithm.Algorithm)
- if scheme == nil {
- return nil, errors.New("unsupported public key algorithm")
- }
- return scheme.UnmarshalBinaryPublicKey(pkix.PublicKey.RightAlign())
- }
- func UnmarshalPEMPrivateKey(data []byte) (sign.PrivateKey, error) {
- block, rest := pem.Decode(data)
- if len(rest) != 0 {
- return nil, errors.New("trailing")
- }
- if !strings.HasSuffix(block.Type, "PRIVATE KEY") {
- return nil, errors.New("pem block type is not private key")
- }
- return UnmarshalPKIXPrivateKey(block.Bytes)
- }
- func UnmarshalPKIXPrivateKey(data []byte) (sign.PrivateKey, error) {
- var pkix pkixPrivKey
- if rest, err := asn1.Unmarshal(data, &pkix); err != nil {
- return nil, err
- } else if len(rest) != 0 {
- return nil, errors.New("trailing data")
- }
- scheme := SchemeByOid(pkix.Algorithm.Algorithm)
- if scheme == nil {
- return nil, errors.New("unsupported public key algorithm")
- }
- var sk []byte
- if rest, err := asn1.Unmarshal(pkix.PrivateKey, &sk); err != nil {
- return nil, err
- } else if len(rest) > 0 {
- return nil, errors.New("trailing data")
- }
- return scheme.UnmarshalBinaryPrivateKey(sk)
- }
- func MarshalPEMPublicKey(pk sign.PublicKey) ([]byte, error) {
- data, err := MarshalPKIXPublicKey(pk)
- if err != nil {
- return nil, err
- }
- str := pem.EncodeToMemory(&pem.Block{
- Type: "PUBLIC KEY",
- Bytes: data,
- })
- return str, nil
- }
- func MarshalPKIXPublicKey(pk sign.PublicKey) ([]byte, error) {
- data, err := pk.MarshalBinary()
- if err != nil {
- return nil, err
- }
- scheme := pk.Scheme()
- return asn1.Marshal(struct {
- pkix.AlgorithmIdentifier
- asn1.BitString
- }{
- pkix.AlgorithmIdentifier{
- Algorithm: scheme.(CertificateScheme).Oid(),
- },
- asn1.BitString{
- Bytes: data,
- BitLength: len(data) * 8,
- },
- })
- }
- func MarshalPEMPrivateKey(sk sign.PrivateKey) ([]byte, error) {
- data, err := MarshalPKIXPrivateKey(sk)
- if err != nil {
- return nil, err
- }
- str := pem.EncodeToMemory(&pem.Block{
- Type: sk.Scheme().Name() + " PRIVATE KEY",
- Bytes: data,
- },
- )
- return str, nil
- }
- func MarshalPKIXPrivateKey(sk sign.PrivateKey) ([]byte, error) {
- data, err := sk.MarshalBinary()
- if err != nil {
- return nil, err
- }
- data, err = asn1.Marshal(data)
- if err != nil {
- return nil, err
- }
- scheme := sk.Scheme()
- return asn1.Marshal(pkixPrivKey{
- 0,
- pkix.AlgorithmIdentifier{
- Algorithm: scheme.(CertificateScheme).Oid(),
- },
- data,
- })
- }
|