github.com/devops-filetransfer/sshego@v7.0.4+incompatible/_vendor/golang.org/x/crypto/acme/jws.go (about) 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 }