blob: 73642db2a8b76434166c0c06445afa28bcda3206 [file] [log] [blame]
David K. Bainbridge215e0242017-09-05 23:18:24 -07001package libtrust
2
3import (
4 "crypto"
5 "crypto/ecdsa"
6 "crypto/rsa"
7 "crypto/x509"
8 "encoding/json"
9 "encoding/pem"
10 "errors"
11 "fmt"
12 "io"
13)
14
15// PublicKey is a generic interface for a Public Key.
16type PublicKey interface {
17 // KeyType returns the key type for this key. For elliptic curve keys,
18 // this value should be "EC". For RSA keys, this value should be "RSA".
19 KeyType() string
20 // KeyID returns a distinct identifier which is unique to this Public Key.
21 // The format generated by this library is a base32 encoding of a 240 bit
22 // hash of the public key data divided into 12 groups like so:
23 // ABCD:EFGH:IJKL:MNOP:QRST:UVWX:YZ23:4567:ABCD:EFGH:IJKL:MNOP
24 KeyID() string
25 // Verify verifyies the signature of the data in the io.Reader using this
26 // Public Key. The alg parameter should identify the digital signature
27 // algorithm which was used to produce the signature and should be
28 // supported by this public key. Returns a nil error if the signature
29 // is valid.
30 Verify(data io.Reader, alg string, signature []byte) error
31 // CryptoPublicKey returns the internal object which can be used as a
32 // crypto.PublicKey for use with other standard library operations. The type
33 // is either *rsa.PublicKey or *ecdsa.PublicKey
34 CryptoPublicKey() crypto.PublicKey
35 // These public keys can be serialized to the standard JSON encoding for
36 // JSON Web Keys. See section 6 of the IETF draft RFC for JOSE JSON Web
37 // Algorithms.
38 MarshalJSON() ([]byte, error)
39 // These keys can also be serialized to the standard PEM encoding.
40 PEMBlock() (*pem.Block, error)
41 // The string representation of a key is its key type and ID.
42 String() string
43 AddExtendedField(string, interface{})
44 GetExtendedField(string) interface{}
45}
46
47// PrivateKey is a generic interface for a Private Key.
48type PrivateKey interface {
49 // A PrivateKey contains all fields and methods of a PublicKey of the
50 // same type. The MarshalJSON method also outputs the private key as a
51 // JSON Web Key, and the PEMBlock method outputs the private key as a
52 // PEM block.
53 PublicKey
54 // PublicKey returns the PublicKey associated with this PrivateKey.
55 PublicKey() PublicKey
56 // Sign signs the data read from the io.Reader using a signature algorithm
57 // supported by the private key. If the specified hashing algorithm is
58 // supported by this key, that hash function is used to generate the
59 // signature otherwise the the default hashing algorithm for this key is
60 // used. Returns the signature and identifier of the algorithm used.
61 Sign(data io.Reader, hashID crypto.Hash) (signature []byte, alg string, err error)
62 // CryptoPrivateKey returns the internal object which can be used as a
63 // crypto.PublicKey for use with other standard library operations. The
64 // type is either *rsa.PublicKey or *ecdsa.PublicKey
65 CryptoPrivateKey() crypto.PrivateKey
66}
67
68// FromCryptoPublicKey returns a libtrust PublicKey representation of the given
69// *ecdsa.PublicKey or *rsa.PublicKey. Returns a non-nil error when the given
70// key is of an unsupported type.
71func FromCryptoPublicKey(cryptoPublicKey crypto.PublicKey) (PublicKey, error) {
72 switch cryptoPublicKey := cryptoPublicKey.(type) {
73 case *ecdsa.PublicKey:
74 return fromECPublicKey(cryptoPublicKey)
75 case *rsa.PublicKey:
76 return fromRSAPublicKey(cryptoPublicKey), nil
77 default:
78 return nil, fmt.Errorf("public key type %T is not supported", cryptoPublicKey)
79 }
80}
81
82// FromCryptoPrivateKey returns a libtrust PrivateKey representation of the given
83// *ecdsa.PrivateKey or *rsa.PrivateKey. Returns a non-nil error when the given
84// key is of an unsupported type.
85func FromCryptoPrivateKey(cryptoPrivateKey crypto.PrivateKey) (PrivateKey, error) {
86 switch cryptoPrivateKey := cryptoPrivateKey.(type) {
87 case *ecdsa.PrivateKey:
88 return fromECPrivateKey(cryptoPrivateKey)
89 case *rsa.PrivateKey:
90 return fromRSAPrivateKey(cryptoPrivateKey), nil
91 default:
92 return nil, fmt.Errorf("private key type %T is not supported", cryptoPrivateKey)
93 }
94}
95
96// UnmarshalPublicKeyPEM parses the PEM encoded data and returns a libtrust
97// PublicKey or an error if there is a problem with the encoding.
98func UnmarshalPublicKeyPEM(data []byte) (PublicKey, error) {
99 pemBlock, _ := pem.Decode(data)
100 if pemBlock == nil {
101 return nil, errors.New("unable to find PEM encoded data")
102 } else if pemBlock.Type != "PUBLIC KEY" {
103 return nil, fmt.Errorf("unable to get PublicKey from PEM type: %s", pemBlock.Type)
104 }
105
106 return pubKeyFromPEMBlock(pemBlock)
107}
108
109// UnmarshalPublicKeyPEMBundle parses the PEM encoded data as a bundle of
110// PEM blocks appended one after the other and returns a slice of PublicKey
111// objects that it finds.
112func UnmarshalPublicKeyPEMBundle(data []byte) ([]PublicKey, error) {
113 pubKeys := []PublicKey{}
114
115 for {
116 var pemBlock *pem.Block
117 pemBlock, data = pem.Decode(data)
118 if pemBlock == nil {
119 break
120 } else if pemBlock.Type != "PUBLIC KEY" {
121 return nil, fmt.Errorf("unable to get PublicKey from PEM type: %s", pemBlock.Type)
122 }
123
124 pubKey, err := pubKeyFromPEMBlock(pemBlock)
125 if err != nil {
126 return nil, err
127 }
128
129 pubKeys = append(pubKeys, pubKey)
130 }
131
132 return pubKeys, nil
133}
134
135// UnmarshalPrivateKeyPEM parses the PEM encoded data and returns a libtrust
136// PrivateKey or an error if there is a problem with the encoding.
137func UnmarshalPrivateKeyPEM(data []byte) (PrivateKey, error) {
138 pemBlock, _ := pem.Decode(data)
139 if pemBlock == nil {
140 return nil, errors.New("unable to find PEM encoded data")
141 }
142
143 var key PrivateKey
144
145 switch {
146 case pemBlock.Type == "RSA PRIVATE KEY":
147 rsaPrivateKey, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
148 if err != nil {
149 return nil, fmt.Errorf("unable to decode RSA Private Key PEM data: %s", err)
150 }
151 key = fromRSAPrivateKey(rsaPrivateKey)
152 case pemBlock.Type == "EC PRIVATE KEY":
153 ecPrivateKey, err := x509.ParseECPrivateKey(pemBlock.Bytes)
154 if err != nil {
155 return nil, fmt.Errorf("unable to decode EC Private Key PEM data: %s", err)
156 }
157 key, err = fromECPrivateKey(ecPrivateKey)
158 if err != nil {
159 return nil, err
160 }
161 default:
162 return nil, fmt.Errorf("unable to get PrivateKey from PEM type: %s", pemBlock.Type)
163 }
164
165 addPEMHeadersToKey(pemBlock, key.PublicKey())
166
167 return key, nil
168}
169
170// UnmarshalPublicKeyJWK unmarshals the given JSON Web Key into a generic
171// Public Key to be used with libtrust.
172func UnmarshalPublicKeyJWK(data []byte) (PublicKey, error) {
173 jwk := make(map[string]interface{})
174
175 err := json.Unmarshal(data, &jwk)
176 if err != nil {
177 return nil, fmt.Errorf(
178 "decoding JWK Public Key JSON data: %s\n", err,
179 )
180 }
181
182 // Get the Key Type value.
183 kty, err := stringFromMap(jwk, "kty")
184 if err != nil {
185 return nil, fmt.Errorf("JWK Public Key type: %s", err)
186 }
187
188 switch {
189 case kty == "EC":
190 // Call out to unmarshal EC public key.
191 return ecPublicKeyFromMap(jwk)
192 case kty == "RSA":
193 // Call out to unmarshal RSA public key.
194 return rsaPublicKeyFromMap(jwk)
195 default:
196 return nil, fmt.Errorf(
197 "JWK Public Key type not supported: %q\n", kty,
198 )
199 }
200}
201
202// UnmarshalPublicKeyJWKSet parses the JSON encoded data as a JSON Web Key Set
203// and returns a slice of Public Key objects.
204func UnmarshalPublicKeyJWKSet(data []byte) ([]PublicKey, error) {
205 rawKeys, err := loadJSONKeySetRaw(data)
206 if err != nil {
207 return nil, err
208 }
209
210 pubKeys := make([]PublicKey, 0, len(rawKeys))
211
212 for _, rawKey := range rawKeys {
213 pubKey, err := UnmarshalPublicKeyJWK(rawKey)
214 if err != nil {
215 return nil, err
216 }
217 pubKeys = append(pubKeys, pubKey)
218 }
219
220 return pubKeys, nil
221}
222
223// UnmarshalPrivateKeyJWK unmarshals the given JSON Web Key into a generic
224// Private Key to be used with libtrust.
225func UnmarshalPrivateKeyJWK(data []byte) (PrivateKey, error) {
226 jwk := make(map[string]interface{})
227
228 err := json.Unmarshal(data, &jwk)
229 if err != nil {
230 return nil, fmt.Errorf(
231 "decoding JWK Private Key JSON data: %s\n", err,
232 )
233 }
234
235 // Get the Key Type value.
236 kty, err := stringFromMap(jwk, "kty")
237 if err != nil {
238 return nil, fmt.Errorf("JWK Private Key type: %s", err)
239 }
240
241 switch {
242 case kty == "EC":
243 // Call out to unmarshal EC private key.
244 return ecPrivateKeyFromMap(jwk)
245 case kty == "RSA":
246 // Call out to unmarshal RSA private key.
247 return rsaPrivateKeyFromMap(jwk)
248 default:
249 return nil, fmt.Errorf(
250 "JWK Private Key type not supported: %q\n", kty,
251 )
252 }
253}