// 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 acme import ( "crypto" "crypto/rand" "crypto/rsa" "crypto/sha256" "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 *rsa.PrivateKey, nonce string) ([]byte, error) { jwk := jwkEncode(&key.PublicKey) phead := fmt.Sprintf(`{"alg":"RS256","jwk":%s,"nonce":%q}`, jwk, nonce) phead = base64.RawURLEncoding.EncodeToString([]byte(phead)) cs, err := json.Marshal(claimset) if err != nil { return nil, err } payload := base64.RawURLEncoding.EncodeToString(cs) h := sha256.New() h.Write([]byte(phead + "." + payload)) sig, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, h.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 key into a JWK. // The result is also suitable for creating a JWK thumbprint. func jwkEncode(pub *rsa.PublicKey) string { n := pub.N e := big.NewInt(int64(pub.E)) // fields 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()), ) } // JWKThumbprint creates a JWK thumbprint out of pub // as specified in https://tools.ietf.org/html/rfc7638. func JWKThumbprint(pub *rsa.PublicKey) string { jwk := jwkEncode(pub) b := sha256.Sum256([]byte(jwk)) return base64.RawURLEncoding.EncodeToString(b[:]) }