OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / crypto / acme / jws.go
1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package acme
6
7 import (
8         "crypto"
9         "crypto/ecdsa"
10         "crypto/rand"
11         "crypto/rsa"
12         "crypto/sha256"
13         _ "crypto/sha512" // need for EC keys
14         "encoding/base64"
15         "encoding/json"
16         "fmt"
17         "math/big"
18 )
19
20 // jwsEncodeJSON signs claimset using provided key and a nonce.
21 // The result is serialized in JSON format.
22 // See https://tools.ietf.org/html/rfc7515#section-7.
23 func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byte, error) {
24         jwk, err := jwkEncode(key.Public())
25         if err != nil {
26                 return nil, err
27         }
28         alg, sha := jwsHasher(key)
29         if alg == "" || !sha.Available() {
30                 return nil, ErrUnsupportedKey
31         }
32         phead := fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q}`, alg, jwk, nonce)
33         phead = base64.RawURLEncoding.EncodeToString([]byte(phead))
34         cs, err := json.Marshal(claimset)
35         if err != nil {
36                 return nil, err
37         }
38         payload := base64.RawURLEncoding.EncodeToString(cs)
39         hash := sha.New()
40         hash.Write([]byte(phead + "." + payload))
41         sig, err := jwsSign(key, sha, hash.Sum(nil))
42         if err != nil {
43                 return nil, err
44         }
45
46         enc := struct {
47                 Protected string `json:"protected"`
48                 Payload   string `json:"payload"`
49                 Sig       string `json:"signature"`
50         }{
51                 Protected: phead,
52                 Payload:   payload,
53                 Sig:       base64.RawURLEncoding.EncodeToString(sig),
54         }
55         return json.Marshal(&enc)
56 }
57
58 // jwkEncode encodes public part of an RSA or ECDSA key into a JWK.
59 // The result is also suitable for creating a JWK thumbprint.
60 // https://tools.ietf.org/html/rfc7517
61 func jwkEncode(pub crypto.PublicKey) (string, error) {
62         switch pub := pub.(type) {
63         case *rsa.PublicKey:
64                 // https://tools.ietf.org/html/rfc7518#section-6.3.1
65                 n := pub.N
66                 e := big.NewInt(int64(pub.E))
67                 // Field order is important.
68                 // See https://tools.ietf.org/html/rfc7638#section-3.3 for details.
69                 return fmt.Sprintf(`{"e":"%s","kty":"RSA","n":"%s"}`,
70                         base64.RawURLEncoding.EncodeToString(e.Bytes()),
71                         base64.RawURLEncoding.EncodeToString(n.Bytes()),
72                 ), nil
73         case *ecdsa.PublicKey:
74                 // https://tools.ietf.org/html/rfc7518#section-6.2.1
75                 p := pub.Curve.Params()
76                 n := p.BitSize / 8
77                 if p.BitSize%8 != 0 {
78                         n++
79                 }
80                 x := pub.X.Bytes()
81                 if n > len(x) {
82                         x = append(make([]byte, n-len(x)), x...)
83                 }
84                 y := pub.Y.Bytes()
85                 if n > len(y) {
86                         y = append(make([]byte, n-len(y)), y...)
87                 }
88                 // Field order is important.
89                 // See https://tools.ietf.org/html/rfc7638#section-3.3 for details.
90                 return fmt.Sprintf(`{"crv":"%s","kty":"EC","x":"%s","y":"%s"}`,
91                         p.Name,
92                         base64.RawURLEncoding.EncodeToString(x),
93                         base64.RawURLEncoding.EncodeToString(y),
94                 ), nil
95         }
96         return "", ErrUnsupportedKey
97 }
98
99 // jwsSign signs the digest using the given key.
100 // It returns ErrUnsupportedKey if the key type is unknown.
101 // The hash is used only for RSA keys.
102 func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) {
103         switch key := key.(type) {
104         case *rsa.PrivateKey:
105                 return key.Sign(rand.Reader, digest, hash)
106         case *ecdsa.PrivateKey:
107                 r, s, err := ecdsa.Sign(rand.Reader, key, digest)
108                 if err != nil {
109                         return nil, err
110                 }
111                 rb, sb := r.Bytes(), s.Bytes()
112                 size := key.Params().BitSize / 8
113                 if size%8 > 0 {
114                         size++
115                 }
116                 sig := make([]byte, size*2)
117                 copy(sig[size-len(rb):], rb)
118                 copy(sig[size*2-len(sb):], sb)
119                 return sig, nil
120         }
121         return nil, ErrUnsupportedKey
122 }
123
124 // jwsHasher indicates suitable JWS algorithm name and a hash function
125 // to use for signing a digest with the provided key.
126 // It returns ("", 0) if the key is not supported.
127 func jwsHasher(key crypto.Signer) (string, crypto.Hash) {
128         switch key := key.(type) {
129         case *rsa.PrivateKey:
130                 return "RS256", crypto.SHA256
131         case *ecdsa.PrivateKey:
132                 switch key.Params().Name {
133                 case "P-256":
134                         return "ES256", crypto.SHA256
135                 case "P-384":
136                         return "ES384", crypto.SHA384
137                 case "P-521":
138                         return "ES512", crypto.SHA512
139                 }
140         }
141         return "", 0
142 }
143
144 // JWKThumbprint creates a JWK thumbprint out of pub
145 // as specified in https://tools.ietf.org/html/rfc7638.
146 func JWKThumbprint(pub crypto.PublicKey) (string, error) {
147         jwk, err := jwkEncode(pub)
148         if err != nil {
149                 return "", err
150         }
151         b := sha256.Sum256([]byte(jwk))
152         return base64.RawURLEncoding.EncodeToString(b[:]), nil
153 }