github.com/cloudflare/circl@v1.5.0/pki/pki.go (about) 1 package pki 2 3 import ( 4 "crypto/x509/pkix" 5 "encoding/asn1" 6 "encoding/pem" 7 "errors" 8 "strings" 9 10 "github.com/cloudflare/circl/sign" 11 "github.com/cloudflare/circl/sign/schemes" 12 ) 13 14 var ( 15 allSchemesByOID map[string]sign.Scheme 16 allSchemesByTLS map[uint]sign.Scheme 17 ) 18 19 type pkixPrivKey struct { 20 Version int 21 Algorithm pkix.AlgorithmIdentifier 22 PrivateKey []byte 23 } 24 25 func init() { 26 allSchemesByOID = make(map[string]sign.Scheme) 27 allSchemesByTLS = make(map[uint]sign.Scheme) 28 for _, scheme := range schemes.All() { 29 if cert, ok := scheme.(CertificateScheme); ok { 30 allSchemesByOID[cert.Oid().String()] = scheme 31 } 32 if tlsScheme, ok := scheme.(TLSScheme); ok { 33 allSchemesByTLS[tlsScheme.TLSIdentifier()] = scheme 34 } 35 } 36 } 37 38 func SchemeByOid(oid asn1.ObjectIdentifier) sign.Scheme { return allSchemesByOID[oid.String()] } 39 40 func SchemeByTLSID(id uint) sign.Scheme { return allSchemesByTLS[id] } 41 42 // Additional methods when the signature scheme is supported in X509. 43 type CertificateScheme interface { 44 // Return the appropriate OIDs for this instance. It is implicitly 45 // assumed that the encoding is simple: e.g. uses the same OID for 46 // signature and public key like Ed25519. 47 Oid() asn1.ObjectIdentifier 48 } 49 50 // Additional methods when the signature scheme is supported in TLS. 51 type TLSScheme interface { 52 TLSIdentifier() uint 53 } 54 55 func UnmarshalPEMPublicKey(data []byte) (sign.PublicKey, error) { 56 block, rest := pem.Decode(data) 57 if len(rest) != 0 { 58 return nil, errors.New("trailing data") 59 } 60 if !strings.HasSuffix(block.Type, "PUBLIC KEY") { 61 return nil, errors.New("pem block type is not public key") 62 } 63 64 return UnmarshalPKIXPublicKey(block.Bytes) 65 } 66 67 func UnmarshalPKIXPublicKey(data []byte) (sign.PublicKey, error) { 68 var pkix struct { 69 Raw asn1.RawContent 70 Algorithm pkix.AlgorithmIdentifier 71 PublicKey asn1.BitString 72 } 73 if rest, err := asn1.Unmarshal(data, &pkix); err != nil { 74 return nil, err 75 } else if len(rest) != 0 { 76 return nil, errors.New("trailing data") 77 } 78 scheme := SchemeByOid(pkix.Algorithm.Algorithm) 79 if scheme == nil { 80 return nil, errors.New("unsupported public key algorithm") 81 } 82 return scheme.UnmarshalBinaryPublicKey(pkix.PublicKey.RightAlign()) 83 } 84 85 func UnmarshalPEMPrivateKey(data []byte) (sign.PrivateKey, error) { 86 block, rest := pem.Decode(data) 87 if len(rest) != 0 { 88 return nil, errors.New("trailing") 89 } 90 if !strings.HasSuffix(block.Type, "PRIVATE KEY") { 91 return nil, errors.New("pem block type is not private key") 92 } 93 94 return UnmarshalPKIXPrivateKey(block.Bytes) 95 } 96 97 func UnmarshalPKIXPrivateKey(data []byte) (sign.PrivateKey, error) { 98 var pkix pkixPrivKey 99 if rest, err := asn1.Unmarshal(data, &pkix); err != nil { 100 return nil, err 101 } else if len(rest) != 0 { 102 return nil, errors.New("trailing data") 103 } 104 scheme := SchemeByOid(pkix.Algorithm.Algorithm) 105 if scheme == nil { 106 return nil, errors.New("unsupported public key algorithm") 107 } 108 var sk []byte 109 if rest, err := asn1.Unmarshal(pkix.PrivateKey, &sk); err != nil { 110 return nil, err 111 } else if len(rest) > 0 { 112 return nil, errors.New("trailing data") 113 } 114 return scheme.UnmarshalBinaryPrivateKey(sk) 115 } 116 117 func MarshalPEMPublicKey(pk sign.PublicKey) ([]byte, error) { 118 data, err := MarshalPKIXPublicKey(pk) 119 if err != nil { 120 return nil, err 121 } 122 str := pem.EncodeToMemory(&pem.Block{ 123 Type: "PUBLIC KEY", 124 Bytes: data, 125 }) 126 return str, nil 127 } 128 129 func MarshalPKIXPublicKey(pk sign.PublicKey) ([]byte, error) { 130 data, err := pk.MarshalBinary() 131 if err != nil { 132 return nil, err 133 } 134 135 scheme := pk.Scheme() 136 return asn1.Marshal(struct { 137 pkix.AlgorithmIdentifier 138 asn1.BitString 139 }{ 140 pkix.AlgorithmIdentifier{ 141 Algorithm: scheme.(CertificateScheme).Oid(), 142 }, 143 asn1.BitString{ 144 Bytes: data, 145 BitLength: len(data) * 8, 146 }, 147 }) 148 } 149 150 func MarshalPEMPrivateKey(sk sign.PrivateKey) ([]byte, error) { 151 data, err := MarshalPKIXPrivateKey(sk) 152 if err != nil { 153 return nil, err 154 } 155 str := pem.EncodeToMemory(&pem.Block{ 156 Type: sk.Scheme().Name() + " PRIVATE KEY", 157 Bytes: data, 158 }, 159 ) 160 return str, nil 161 } 162 163 func MarshalPKIXPrivateKey(sk sign.PrivateKey) ([]byte, error) { 164 data, err := sk.MarshalBinary() 165 if err != nil { 166 return nil, err 167 } 168 169 data, err = asn1.Marshal(data) 170 if err != nil { 171 return nil, err 172 } 173 174 scheme := sk.Scheme() 175 return asn1.Marshal(pkixPrivKey{ 176 0, 177 pkix.AlgorithmIdentifier{ 178 Algorithm: scheme.(CertificateScheme).Oid(), 179 }, 180 data, 181 }) 182 }