1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
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,
})
}
|