blob: 00bbe4b3caf83daa5ce289d3737d3d6aa2fd383d [file] [log] [blame]
David K. Bainbridge215e0242017-09-05 23:18:24 -07001package libtrust
2
3import (
4 "crypto"
5 "crypto/ecdsa"
6 "crypto/elliptic"
7 "crypto/rand"
8 "crypto/x509"
9 "encoding/json"
10 "encoding/pem"
11 "errors"
12 "fmt"
13 "io"
14 "math/big"
15)
16
17/*
18 * EC DSA PUBLIC KEY
19 */
20
21// ecPublicKey implements a libtrust.PublicKey using elliptic curve digital
22// signature algorithms.
23type ecPublicKey struct {
24 *ecdsa.PublicKey
25 curveName string
26 signatureAlgorithm *signatureAlgorithm
27 extended map[string]interface{}
28}
29
30func fromECPublicKey(cryptoPublicKey *ecdsa.PublicKey) (*ecPublicKey, error) {
31 curve := cryptoPublicKey.Curve
32
33 switch {
34 case curve == elliptic.P256():
35 return &ecPublicKey{cryptoPublicKey, "P-256", es256, map[string]interface{}{}}, nil
36 case curve == elliptic.P384():
37 return &ecPublicKey{cryptoPublicKey, "P-384", es384, map[string]interface{}{}}, nil
38 case curve == elliptic.P521():
39 return &ecPublicKey{cryptoPublicKey, "P-521", es512, map[string]interface{}{}}, nil
40 default:
41 return nil, errors.New("unsupported elliptic curve")
42 }
43}
44
45// KeyType returns the key type for elliptic curve keys, i.e., "EC".
46func (k *ecPublicKey) KeyType() string {
47 return "EC"
48}
49
50// CurveName returns the elliptic curve identifier.
51// Possible values are "P-256", "P-384", and "P-521".
52func (k *ecPublicKey) CurveName() string {
53 return k.curveName
54}
55
56// KeyID returns a distinct identifier which is unique to this Public Key.
57func (k *ecPublicKey) KeyID() string {
58 return keyIDFromCryptoKey(k)
59}
60
61func (k *ecPublicKey) String() string {
62 return fmt.Sprintf("EC Public Key <%s>", k.KeyID())
63}
64
65// Verify verifyies the signature of the data in the io.Reader using this
66// PublicKey. The alg parameter should identify the digital signature
67// algorithm which was used to produce the signature and should be supported
68// by this public key. Returns a nil error if the signature is valid.
69func (k *ecPublicKey) Verify(data io.Reader, alg string, signature []byte) error {
70 // For EC keys there is only one supported signature algorithm depending
71 // on the curve parameters.
72 if k.signatureAlgorithm.HeaderParam() != alg {
73 return fmt.Errorf("unable to verify signature: EC Public Key with curve %q does not support signature algorithm %q", k.curveName, alg)
74 }
75
76 // signature is the concatenation of (r, s), base64Url encoded.
77 sigLength := len(signature)
78 expectedOctetLength := 2 * ((k.Params().BitSize + 7) >> 3)
79 if sigLength != expectedOctetLength {
80 return fmt.Errorf("signature length is %d octets long, should be %d", sigLength, expectedOctetLength)
81 }
82
83 rBytes, sBytes := signature[:sigLength/2], signature[sigLength/2:]
84 r := new(big.Int).SetBytes(rBytes)
85 s := new(big.Int).SetBytes(sBytes)
86
87 hasher := k.signatureAlgorithm.HashID().New()
88 _, err := io.Copy(hasher, data)
89 if err != nil {
90 return fmt.Errorf("error reading data to sign: %s", err)
91 }
92 hash := hasher.Sum(nil)
93
94 if !ecdsa.Verify(k.PublicKey, hash, r, s) {
95 return errors.New("invalid signature")
96 }
97
98 return nil
99}
100
101// CryptoPublicKey returns the internal object which can be used as a
102// crypto.PublicKey for use with other standard library operations. The type
103// is either *rsa.PublicKey or *ecdsa.PublicKey
104func (k *ecPublicKey) CryptoPublicKey() crypto.PublicKey {
105 return k.PublicKey
106}
107
108func (k *ecPublicKey) toMap() map[string]interface{} {
109 jwk := make(map[string]interface{})
110 for k, v := range k.extended {
111 jwk[k] = v
112 }
113 jwk["kty"] = k.KeyType()
114 jwk["kid"] = k.KeyID()
115 jwk["crv"] = k.CurveName()
116
117 xBytes := k.X.Bytes()
118 yBytes := k.Y.Bytes()
119 octetLength := (k.Params().BitSize + 7) >> 3
120 // MUST include leading zeros in the output so that x, y are each
121 // *octetLength* bytes long.
122 xBuf := make([]byte, octetLength-len(xBytes), octetLength)
123 yBuf := make([]byte, octetLength-len(yBytes), octetLength)
124 xBuf = append(xBuf, xBytes...)
125 yBuf = append(yBuf, yBytes...)
126
127 jwk["x"] = joseBase64UrlEncode(xBuf)
128 jwk["y"] = joseBase64UrlEncode(yBuf)
129
130 return jwk
131}
132
133// MarshalJSON serializes this Public Key using the JWK JSON serialization format for
134// elliptic curve keys.
135func (k *ecPublicKey) MarshalJSON() (data []byte, err error) {
136 return json.Marshal(k.toMap())
137}
138
139// PEMBlock serializes this Public Key to DER-encoded PKIX format.
140func (k *ecPublicKey) PEMBlock() (*pem.Block, error) {
141 derBytes, err := x509.MarshalPKIXPublicKey(k.PublicKey)
142 if err != nil {
143 return nil, fmt.Errorf("unable to serialize EC PublicKey to DER-encoded PKIX format: %s", err)
144 }
145 k.extended["kid"] = k.KeyID() // For display purposes.
146 return createPemBlock("PUBLIC KEY", derBytes, k.extended)
147}
148
149func (k *ecPublicKey) AddExtendedField(field string, value interface{}) {
150 k.extended[field] = value
151}
152
153func (k *ecPublicKey) GetExtendedField(field string) interface{} {
154 v, ok := k.extended[field]
155 if !ok {
156 return nil
157 }
158 return v
159}
160
161func ecPublicKeyFromMap(jwk map[string]interface{}) (*ecPublicKey, error) {
162 // JWK key type (kty) has already been determined to be "EC".
163 // Need to extract 'crv', 'x', 'y', and 'kid' and check for
164 // consistency.
165
166 // Get the curve identifier value.
167 crv, err := stringFromMap(jwk, "crv")
168 if err != nil {
169 return nil, fmt.Errorf("JWK EC Public Key curve identifier: %s", err)
170 }
171
172 var (
173 curve elliptic.Curve
174 sigAlg *signatureAlgorithm
175 )
176
177 switch {
178 case crv == "P-256":
179 curve = elliptic.P256()
180 sigAlg = es256
181 case crv == "P-384":
182 curve = elliptic.P384()
183 sigAlg = es384
184 case crv == "P-521":
185 curve = elliptic.P521()
186 sigAlg = es512
187 default:
188 return nil, fmt.Errorf("JWK EC Public Key curve identifier not supported: %q\n", crv)
189 }
190
191 // Get the X and Y coordinates for the public key point.
192 xB64Url, err := stringFromMap(jwk, "x")
193 if err != nil {
194 return nil, fmt.Errorf("JWK EC Public Key x-coordinate: %s", err)
195 }
196 x, err := parseECCoordinate(xB64Url, curve)
197 if err != nil {
198 return nil, fmt.Errorf("JWK EC Public Key x-coordinate: %s", err)
199 }
200
201 yB64Url, err := stringFromMap(jwk, "y")
202 if err != nil {
203 return nil, fmt.Errorf("JWK EC Public Key y-coordinate: %s", err)
204 }
205 y, err := parseECCoordinate(yB64Url, curve)
206 if err != nil {
207 return nil, fmt.Errorf("JWK EC Public Key y-coordinate: %s", err)
208 }
209
210 key := &ecPublicKey{
211 PublicKey: &ecdsa.PublicKey{Curve: curve, X: x, Y: y},
212 curveName: crv, signatureAlgorithm: sigAlg,
213 }
214
215 // Key ID is optional too, but if it exists, it should match the key.
216 _, ok := jwk["kid"]
217 if ok {
218 kid, err := stringFromMap(jwk, "kid")
219 if err != nil {
220 return nil, fmt.Errorf("JWK EC Public Key ID: %s", err)
221 }
222 if kid != key.KeyID() {
223 return nil, fmt.Errorf("JWK EC Public Key ID does not match: %s", kid)
224 }
225 }
226
227 key.extended = jwk
228
229 return key, nil
230}
231
232/*
233 * EC DSA PRIVATE KEY
234 */
235
236// ecPrivateKey implements a JWK Private Key using elliptic curve digital signature
237// algorithms.
238type ecPrivateKey struct {
239 ecPublicKey
240 *ecdsa.PrivateKey
241}
242
243func fromECPrivateKey(cryptoPrivateKey *ecdsa.PrivateKey) (*ecPrivateKey, error) {
244 publicKey, err := fromECPublicKey(&cryptoPrivateKey.PublicKey)
245 if err != nil {
246 return nil, err
247 }
248
249 return &ecPrivateKey{*publicKey, cryptoPrivateKey}, nil
250}
251
252// PublicKey returns the Public Key data associated with this Private Key.
253func (k *ecPrivateKey) PublicKey() PublicKey {
254 return &k.ecPublicKey
255}
256
257func (k *ecPrivateKey) String() string {
258 return fmt.Sprintf("EC Private Key <%s>", k.KeyID())
259}
260
261// Sign signs the data read from the io.Reader using a signature algorithm supported
262// by the elliptic curve private key. If the specified hashing algorithm is
263// supported by this key, that hash function is used to generate the signature
264// otherwise the the default hashing algorithm for this key is used. Returns
265// the signature and the name of the JWK signature algorithm used, e.g.,
266// "ES256", "ES384", "ES512".
267func (k *ecPrivateKey) Sign(data io.Reader, hashID crypto.Hash) (signature []byte, alg string, err error) {
268 // Generate a signature of the data using the internal alg.
269 // The given hashId is only a suggestion, and since EC keys only support
270 // on signature/hash algorithm given the curve name, we disregard it for
271 // the elliptic curve JWK signature implementation.
272 hasher := k.signatureAlgorithm.HashID().New()
273 _, err = io.Copy(hasher, data)
274 if err != nil {
275 return nil, "", fmt.Errorf("error reading data to sign: %s", err)
276 }
277 hash := hasher.Sum(nil)
278
279 r, s, err := ecdsa.Sign(rand.Reader, k.PrivateKey, hash)
280 if err != nil {
281 return nil, "", fmt.Errorf("error producing signature: %s", err)
282 }
283 rBytes, sBytes := r.Bytes(), s.Bytes()
284 octetLength := (k.ecPublicKey.Params().BitSize + 7) >> 3
285 // MUST include leading zeros in the output
286 rBuf := make([]byte, octetLength-len(rBytes), octetLength)
287 sBuf := make([]byte, octetLength-len(sBytes), octetLength)
288
289 rBuf = append(rBuf, rBytes...)
290 sBuf = append(sBuf, sBytes...)
291
292 signature = append(rBuf, sBuf...)
293 alg = k.signatureAlgorithm.HeaderParam()
294
295 return
296}
297
298// CryptoPrivateKey returns the internal object which can be used as a
299// crypto.PublicKey for use with other standard library operations. The type
300// is either *rsa.PublicKey or *ecdsa.PublicKey
301func (k *ecPrivateKey) CryptoPrivateKey() crypto.PrivateKey {
302 return k.PrivateKey
303}
304
305func (k *ecPrivateKey) toMap() map[string]interface{} {
306 jwk := k.ecPublicKey.toMap()
307
308 dBytes := k.D.Bytes()
309 // The length of this octet string MUST be ceiling(log-base-2(n)/8)
310 // octets (where n is the order of the curve). This is because the private
311 // key d must be in the interval [1, n-1] so the bitlength of d should be
312 // no larger than the bitlength of n-1. The easiest way to find the octet
313 // length is to take bitlength(n-1), add 7 to force a carry, and shift this
314 // bit sequence right by 3, which is essentially dividing by 8 and adding
315 // 1 if there is any remainder. Thus, the private key value d should be
316 // output to (bitlength(n-1)+7)>>3 octets.
317 n := k.ecPublicKey.Params().N
318 octetLength := (new(big.Int).Sub(n, big.NewInt(1)).BitLen() + 7) >> 3
319 // Create a buffer with the necessary zero-padding.
320 dBuf := make([]byte, octetLength-len(dBytes), octetLength)
321 dBuf = append(dBuf, dBytes...)
322
323 jwk["d"] = joseBase64UrlEncode(dBuf)
324
325 return jwk
326}
327
328// MarshalJSON serializes this Private Key using the JWK JSON serialization format for
329// elliptic curve keys.
330func (k *ecPrivateKey) MarshalJSON() (data []byte, err error) {
331 return json.Marshal(k.toMap())
332}
333
334// PEMBlock serializes this Private Key to DER-encoded PKIX format.
335func (k *ecPrivateKey) PEMBlock() (*pem.Block, error) {
336 derBytes, err := x509.MarshalECPrivateKey(k.PrivateKey)
337 if err != nil {
338 return nil, fmt.Errorf("unable to serialize EC PrivateKey to DER-encoded PKIX format: %s", err)
339 }
340 k.extended["keyID"] = k.KeyID() // For display purposes.
341 return createPemBlock("EC PRIVATE KEY", derBytes, k.extended)
342}
343
344func ecPrivateKeyFromMap(jwk map[string]interface{}) (*ecPrivateKey, error) {
345 dB64Url, err := stringFromMap(jwk, "d")
346 if err != nil {
347 return nil, fmt.Errorf("JWK EC Private Key: %s", err)
348 }
349
350 // JWK key type (kty) has already been determined to be "EC".
351 // Need to extract the public key information, then extract the private
352 // key value 'd'.
353 publicKey, err := ecPublicKeyFromMap(jwk)
354 if err != nil {
355 return nil, err
356 }
357
358 d, err := parseECPrivateParam(dB64Url, publicKey.Curve)
359 if err != nil {
360 return nil, fmt.Errorf("JWK EC Private Key d-param: %s", err)
361 }
362
363 key := &ecPrivateKey{
364 ecPublicKey: *publicKey,
365 PrivateKey: &ecdsa.PrivateKey{
366 PublicKey: *publicKey.PublicKey,
367 D: d,
368 },
369 }
370
371 return key, nil
372}
373
374/*
375 * Key Generation Functions.
376 */
377
378func generateECPrivateKey(curve elliptic.Curve) (k *ecPrivateKey, err error) {
379 k = new(ecPrivateKey)
380 k.PrivateKey, err = ecdsa.GenerateKey(curve, rand.Reader)
381 if err != nil {
382 return nil, err
383 }
384
385 k.ecPublicKey.PublicKey = &k.PrivateKey.PublicKey
386 k.extended = make(map[string]interface{})
387
388 return
389}
390
391// GenerateECP256PrivateKey generates a key pair using elliptic curve P-256.
392func GenerateECP256PrivateKey() (PrivateKey, error) {
393 k, err := generateECPrivateKey(elliptic.P256())
394 if err != nil {
395 return nil, fmt.Errorf("error generating EC P-256 key: %s", err)
396 }
397
398 k.curveName = "P-256"
399 k.signatureAlgorithm = es256
400
401 return k, nil
402}
403
404// GenerateECP384PrivateKey generates a key pair using elliptic curve P-384.
405func GenerateECP384PrivateKey() (PrivateKey, error) {
406 k, err := generateECPrivateKey(elliptic.P384())
407 if err != nil {
408 return nil, fmt.Errorf("error generating EC P-384 key: %s", err)
409 }
410
411 k.curveName = "P-384"
412 k.signatureAlgorithm = es384
413
414 return k, nil
415}
416
417// GenerateECP521PrivateKey generates aß key pair using elliptic curve P-521.
418func GenerateECP521PrivateKey() (PrivateKey, error) {
419 k, err := generateECPrivateKey(elliptic.P521())
420 if err != nil {
421 return nil, fmt.Errorf("error generating EC P-521 key: %s", err)
422 }
423
424 k.curveName = "P-521"
425 k.signatureAlgorithm = es512
426
427 return k, nil
428}