From 605b1310fb6e1c1fa1382df76a1d52954fc82ba7 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Fri, 4 Dec 2015 17:40:32 +0100 Subject: Update Signer --- account.go | 38 ++++++++++++++++++++++++++++--------- client.go | 57 +++++++++++++++++++++++++++++++++++--------------------- cmd/acme/main.go | 27 +++++++++++++++++++++------ directory.go | 7 ------- messages.go | 19 ++++++++++++------- nonce.go | 28 ---------------------------- 6 files changed, 98 insertions(+), 78 deletions(-) delete mode 100644 directory.go delete mode 100644 nonce.go diff --git a/account.go b/account.go index 7766893..1fd0efd 100644 --- a/account.go +++ b/account.go @@ -3,7 +3,9 @@ package acme import ( "crypto/rand" "crypto/rsa" + "errors" "fmt" + "net/http" "net/mail" "github.com/square/go-jose" @@ -12,34 +14,36 @@ import ( type Account struct { Contact []string `json:"contact"` PrivKey *rsa.PrivateKey `json:"key"` - Signer jose.Signer `json:"-"` + signer jose.Signer + nonce chan string } -func NewAccount(email string, bits int) (Account, error) { +func NewAccount(email string, bits int) (*Account, error) { m, err := mail.ParseAddress(email) if err != nil { - return Account{}, err + return nil, err } key, err := rsa.GenerateKey(rand.Reader, bits) if err != nil { - return Account{}, err + return nil, err } - return Account{ + 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 { + if a.signer == nil { signer, err := jose.NewSigner(jose.RS256, a.PrivKey) if err != nil { return nil, err } - signer.SetNonceSource(nonces) - a.Signer = signer + signer.SetNonceSource(a) + a.signer = signer } - obj, err := a.Signer.Sign(msg) + obj, err := a.signer.Sign(msg) return []byte(obj.FullSerialize()), err } @@ -51,3 +55,19 @@ func (a *Account) ParseSigned(msg []byte) ([]byte, error) { } 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 + } +} diff --git a/client.go b/client.go index b596906..27551ba 100644 --- a/client.go +++ b/client.go @@ -3,27 +3,52 @@ package acme import ( "bytes" "encoding/json" + "errors" "log" "net/http" "net/textproto" "regexp" +) + +type Status int - "github.com/square/go-jose" +const ( + StatusUnknown Status = iota + StatusPending + StatusProcessing + StatusValid + StatusInvalid + StatusRevoked ) +func (s *Status) UnmarshalJSON(b []byte) error { + var status = map[string]Status{ + "unknown": StatusUnknown, + "pending": StatusPending, + "processing": StatusProcessing, + "valid": StatusValid, + "invalid": StatusInvalid, + "revoked": StatusRevoked, + } + if st, ok := status[string(b)]; ok { + *s = st + return nil + } + return errors.New("unknown status") +} + type Signer interface { Sign([]byte) ([]byte, error) + parseNonce(*http.Response) } -var nonces = newNonce() - -func Get(uri string, v interface{}) error { +func Get(s Signer, uri string, v interface{}) error { resp, err := http.Get(uri) if err != nil { return err } defer resp.Body.Close() - nonces.parse(resp) + s.parseNonce(resp) return json.NewDecoder(resp.Body).Decode(v) } @@ -43,31 +68,21 @@ func Post(s Signer, uri string, v interface{}) (*http.Response, error) { return nil, err } - resp, err := http.Post(uri, "application/jose+json", bytes.NewReader(signed)) + resp, err := http.Post(uri, "application/jose+json", + bytes.NewReader(signed)) if err != nil { return nil, err } - nonces.parse(resp) - log.Printf("%+v\n", parseLinks(resp)) + + s.parseNonce(resp) if resp.StatusCode >= http.StatusBadRequest { return nil, handleError(resp) } - return resp, nil -} + log.Printf("%+v\n", parseLinks(resp)) -func Sign(acc Account, body []byte) (string, error) { - signer, err := jose.NewSigner(jose.RS256, acc.PrivKey) - signer.SetNonceSource(nonces) - if err != nil { - return "", err - } - obj, err := signer.Sign(body) - if err != nil { - return "", err - } - return obj.FullSerialize(), nil + return resp, nil } func parseLinks(r *http.Response) map[string]string { diff --git a/cmd/acme/main.go b/cmd/acme/main.go index c6250e6..687fd6f 100644 --- a/cmd/acme/main.go +++ b/cmd/acme/main.go @@ -1,7 +1,9 @@ package main import ( + "encoding/json" "flag" + "io/ioutil" "log" "dim13.org/acme" @@ -23,13 +25,11 @@ var ( port = flag.Int("port", 8443, "port to listen") ) -func main() { +func init() { flag.Parse() +} - dir, err := acme.NewDirectory(*server) - must(err) - acme.Print(dir) - +func main() { acc, err := acme.NewAccount(eMail, keySize) must(err) acme.Print(acc) @@ -38,7 +38,22 @@ func main() { must(err) acme.SaveKey(".acme/priv.pem", acc.PrivKey) - resp, err := acme.Post(&acc, dir.NewReg, acme.NewRegistration(acc.Contact, acme.NewReg{})) + dir := acme.Directory{} + err = acme.Get(acc, *server, &dir) + must(err) + acme.Print(dir) + + resp, err := acme.Post(acc, dir.NewReg, acme.NewRegistration(acc.Contact, acme.NewReg{})) must(err) log.Println(resp) + + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + must(err) + log.Println(string(body)) + + rr := acme.RegistrationResp{} + err = json.Unmarshal(body, &rr) + must(err) + log.Printf("%+v\n", rr) } diff --git a/directory.go b/directory.go deleted file mode 100644 index 44062f5..0000000 --- a/directory.go +++ /dev/null @@ -1,7 +0,0 @@ -package acme - -func NewDirectory(uri string) (Directory, error) { - var dir Directory - err := Get(uri, &dir) - return dir, err -} diff --git a/messages.go b/messages.go index cb10a79..b5a1738 100644 --- a/messages.go +++ b/messages.go @@ -1,5 +1,10 @@ package acme +import ( + "net" + "time" +) + const ( // LEV1 Let's Encrytpt V1 LEV1 = `https://acme-v01.api.letsencrypt.org/directory` @@ -27,11 +32,11 @@ type Registration struct { // RegistrationResp ... type RegistrationResp struct { - ID int `json:"id"` - Key Key `json:"key"` - Contact []string `json:"contact"` - InitialIP string `json:"initalIp"` // not in draft - CreatedAt string `json:"createdAt"` // 2006-01-02T15:04:05.999999999Z + ID int `json:"id"` + Key Key `json:"key"` + Contact []string `json:"contact"` + InitialIP net.IP `json:"initialIp"` // not in draft + CreatedAt time.Time `json:"createdAt"` // 2006-01-02T15:04:05.999999999Z } // Key contains public part of jose.JsonWebKey @@ -50,7 +55,7 @@ type Authorization struct { // AuthorizationResp Objects type AuthorizationResp struct { Identifier Identifier `json:"identifier"` - Status string `json:"status,omitemtpy"` // e.g. valid + Status Status `json:"status,omitemtpy"` // e.g. valid Expires string `json:"expires,omitempty"` // 2006-01-02 Challenges []Challenge `json:"challenges"` Combinations [][]int `json:"combinations,omitemtpy"` @@ -65,7 +70,7 @@ type Identifier struct { // Challege ... type Challege struct { Type string `json:"type"` // http-01 - Status string `json:"status"` // e.g. valid + Status Status `json:"status"` // e.g. valid Validated string `json:"validated"` // 2006-01-02T15:04Z KeyAuthorization string `json:"keyAuthorization"` } diff --git a/nonce.go b/nonce.go deleted file mode 100644 index 88e67ca..0000000 --- a/nonce.go +++ /dev/null @@ -1,28 +0,0 @@ -package acme - -import ( - "errors" - "net/http" -) - -var errNoNonces = errors.New("No nonces available") - -type nonce chan string - -func newNonce() nonce { - return make(nonce, 100) -} - -func (n nonce) parse(r *http.Response) { - if nonce := r.Header.Get("Replay-Nonce"); nonce != "" { - n <- nonce - } -} - -// Nonce implements jose nonce provider -func (n nonce) Nonce() (string, error) { - if nonce, ok := <-n; ok { - return nonce, nil - } - return "", errNoNonces -} -- cgit v1.2.3