| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 | // Copyright 2015 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package acmeimport (	"crypto"	"crypto/ecdsa"	"crypto/rand"	"crypto/rsa"	"crypto/sha256"	_ "crypto/sha512" // need for EC keys	"encoding/base64"	"encoding/json"	"fmt"	"math/big")// jwsEncodeJSON signs claimset using provided key and a nonce.// The result is serialized in JSON format.// See https://tools.ietf.org/html/rfc7515#section-7.func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byte, error) {	jwk, err := jwkEncode(key.Public())	if err != nil {		return nil, err	}	alg, sha := jwsHasher(key)	if alg == "" || !sha.Available() {		return nil, ErrUnsupportedKey	}	phead := fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q}`, alg, jwk, nonce)	phead = base64.RawURLEncoding.EncodeToString([]byte(phead))	cs, err := json.Marshal(claimset)	if err != nil {		return nil, err	}	payload := base64.RawURLEncoding.EncodeToString(cs)	hash := sha.New()	hash.Write([]byte(phead + "." + payload))	sig, err := jwsSign(key, sha, hash.Sum(nil))	if err != nil {		return nil, err	}	enc := struct {		Protected string `json:"protected"`		Payload   string `json:"payload"`		Sig       string `json:"signature"`	}{		Protected: phead,		Payload:   payload,		Sig:       base64.RawURLEncoding.EncodeToString(sig),	}	return json.Marshal(&enc)}// jwkEncode encodes public part of an RSA or ECDSA key into a JWK.// The result is also suitable for creating a JWK thumbprint.// https://tools.ietf.org/html/rfc7517func jwkEncode(pub crypto.PublicKey) (string, error) {	switch pub := pub.(type) {	case *rsa.PublicKey:		// https://tools.ietf.org/html/rfc7518#section-6.3.1		n := pub.N		e := big.NewInt(int64(pub.E))		// Field order is important.		// See https://tools.ietf.org/html/rfc7638#section-3.3 for details.		return fmt.Sprintf(`{"e":"%s","kty":"RSA","n":"%s"}`,			base64.RawURLEncoding.EncodeToString(e.Bytes()),			base64.RawURLEncoding.EncodeToString(n.Bytes()),		), nil	case *ecdsa.PublicKey:		// https://tools.ietf.org/html/rfc7518#section-6.2.1		p := pub.Curve.Params()		n := p.BitSize / 8		if p.BitSize%8 != 0 {			n++		}		x := pub.X.Bytes()		if n > len(x) {			x = append(make([]byte, n-len(x)), x...)		}		y := pub.Y.Bytes()		if n > len(y) {			y = append(make([]byte, n-len(y)), y...)		}		// Field order is important.		// See https://tools.ietf.org/html/rfc7638#section-3.3 for details.		return fmt.Sprintf(`{"crv":"%s","kty":"EC","x":"%s","y":"%s"}`,			p.Name,			base64.RawURLEncoding.EncodeToString(x),			base64.RawURLEncoding.EncodeToString(y),		), nil	}	return "", ErrUnsupportedKey}// jwsSign signs the digest using the given key.// It returns ErrUnsupportedKey if the key type is unknown.// The hash is used only for RSA keys.func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) {	switch key := key.(type) {	case *rsa.PrivateKey:		return key.Sign(rand.Reader, digest, hash)	case *ecdsa.PrivateKey:		r, s, err := ecdsa.Sign(rand.Reader, key, digest)		if err != nil {			return nil, err		}		rb, sb := r.Bytes(), s.Bytes()		size := key.Params().BitSize / 8		if size%8 > 0 {			size++		}		sig := make([]byte, size*2)		copy(sig[size-len(rb):], rb)		copy(sig[size*2-len(sb):], sb)		return sig, nil	}	return nil, ErrUnsupportedKey}// jwsHasher indicates suitable JWS algorithm name and a hash function// to use for signing a digest with the provided key.// It returns ("", 0) if the key is not supported.func jwsHasher(key crypto.Signer) (string, crypto.Hash) {	switch key := key.(type) {	case *rsa.PrivateKey:		return "RS256", crypto.SHA256	case *ecdsa.PrivateKey:		switch key.Params().Name {		case "P-256":			return "ES256", crypto.SHA256		case "P-384":			return "ES384", crypto.SHA384		case "P-521":			return "ES512", crypto.SHA512		}	}	return "", 0}// JWKThumbprint creates a JWK thumbprint out of pub// as specified in https://tools.ietf.org/html/rfc7638.func JWKThumbprint(pub crypto.PublicKey) (string, error) {	jwk, err := jwkEncode(pub)	if err != nil {		return "", err	}	b := sha256.Sum256([]byte(jwk))	return base64.RawURLEncoding.EncodeToString(b[:]), nil}
 |