package acme import ( "crypto/rand" "crypto/rsa" "errors" "fmt" "net/http" "net/mail" "github.com/square/go-jose" ) type Account struct { Contact []string `json:"contact"` PrivKey *rsa.PrivateKey `json:"key"` signer jose.Signer nonce chan string } func NewAccount(email string, bits int) (*Account, error) { m, err := mail.ParseAddress(email) if err != nil { return nil, err } key, err := rsa.GenerateKey(rand.Reader, bits) if err != nil { return nil, err } return &Account{ Contact: []string{"mailto:" + m.Address}, PrivKey: key, nonce: make(chan string, 100), }, nil } func (a *Account) Sign(msg []byte) ([]byte, error) { if a.signer == nil { var err error a.signer, err = jose.NewSigner(jose.RS256, a.PrivKey) if err != nil { return nil, err } a.signer.SetNonceSource(a) } obj, err := a.signer.Sign(msg) return []byte(obj.FullSerialize()), err } func (a *Account) ParseSigned(msg []byte) ([]byte, error) { fmt.Println("MSG", string(msg)) obj, err := jose.ParseSigned(string(msg)) if err != nil { return nil, err } return obj.Verify(&a.PrivKey.PublicKey) } var errNoNonces = errors.New("No nonces available") // Nonce implements jose nonce provider func (a Account) Nonce() (string, error) { if nonce, ok := <-a.nonce; ok { return nonce, nil } return "", errNoNonces } func (a Account) parseNonce(r *http.Response) { if nonce := r.Header.Get("Replay-Nonce"); nonce != "" { a.nonce <- nonce } }