aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2015-11-28 18:52:49 +0100
committerDimitri Sokolyuk <demon@dim13.org>2015-11-28 18:52:49 +0100
commitc6261c5ce9537296479b621e91a90e4f57a21734 (patch)
treea81f7dfc613bec42437890fedeb9af8b01adf5a5
parentf280d0d011a8dd1fbc582b54a248c9e8459311b0 (diff)
WIP error handler
-rw-r--r--.gitignore1
-rw-r--r--account.go26
-rw-r--r--client.go40
-rw-r--r--cmd/acme/main.go9
-rw-r--r--errors.go25
-rw-r--r--messages.go36
-rw-r--r--nonce.go4
7 files changed, 108 insertions, 33 deletions
diff --git a/.gitignore b/.gitignore
index 1377554..257fc63 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
*.swp
+.acme
diff --git a/account.go b/account.go
index 62d3213..7766893 100644
--- a/account.go
+++ b/account.go
@@ -3,12 +3,16 @@ package acme
import (
"crypto/rand"
"crypto/rsa"
+ "fmt"
"net/mail"
+
+ "github.com/square/go-jose"
)
type Account struct {
Contact []string `json:"contact"`
PrivKey *rsa.PrivateKey `json:"key"`
+ Signer jose.Signer `json:"-"`
}
func NewAccount(email string, bits int) (Account, error) {
@@ -25,3 +29,25 @@ func NewAccount(email string, bits int) (Account, error) {
PrivKey: key,
}, nil
}
+
+func (a *Account) Sign(msg []byte) ([]byte, error) {
+ if a.Signer == nil {
+ signer, err := jose.NewSigner(jose.RS256, a.PrivKey)
+ if err != nil {
+ return nil, err
+ }
+ signer.SetNonceSource(nonces)
+ a.Signer = signer
+ }
+ 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)
+}
diff --git a/client.go b/client.go
index 6e83b5a..06bb907 100644
--- a/client.go
+++ b/client.go
@@ -3,13 +3,16 @@ package acme
import (
"bytes"
"encoding/json"
- "log"
"net/http"
"github.com/square/go-jose"
)
-var nonces = make(nonce, 100) // buffered channel for nonces
+type Signer interface {
+ Sign([]byte) ([]byte, error)
+}
+
+var nonces = newNonce()
func Get(uri string, v interface{}) error {
resp, err := http.Get(uri)
@@ -21,20 +24,28 @@ func Get(uri string, v interface{}) error {
return json.NewDecoder(resp.Body).Decode(v)
}
-func Post(uri string, v interface{}) error {
+func Post(s Signer, uri string, v interface{}) (*http.Response, error) {
body, err := json.Marshal(v)
if err != nil {
- return err
+ return nil, err
}
- log.Println(string(body))
- return nil
- // premature debug abort
- _, err = http.Post(uri, "application/jose+json", bytes.NewReader(body))
+ signed, err := s.Sign(body)
if err != nil {
- return err
+ return nil, err
+ }
+
+ resp, err := http.Post(uri, "application/jose+json", bytes.NewReader(signed))
+ if err != nil {
+ return nil, err
+ }
+ nonces.parse(resp)
+
+ if resp.StatusCode >= http.StatusBadRequest {
+ return nil, handleError(resp)
}
- return nil
+
+ return resp, nil
}
func Sign(acc Account, body []byte) (string, error) {
@@ -49,12 +60,3 @@ func Sign(acc Account, body []byte) (string, error) {
}
return obj.FullSerialize(), nil
}
-
-func ParseSigned(body string) error {
- obj, err := jose.ParseSigned(body)
- if err != nil {
- return err
- }
- log.Printf("%+v\n", obj)
- return nil
-}
diff --git a/cmd/acme/main.go b/cmd/acme/main.go
index 2e35532..c6250e6 100644
--- a/cmd/acme/main.go
+++ b/cmd/acme/main.go
@@ -14,7 +14,7 @@ func must(err error) {
}
const (
- eMail = `Dimitri Sokolyuk <demon@dim13.org>`
+ eMail = `another@example.com`
keySize = 2048
)
@@ -38,8 +38,7 @@ func main() {
must(err)
acme.SaveKey(".acme/priv.pem", acc.PrivKey)
- acme.Post(dir.NewReg, acme.NewRegistration(acc.Contact, acme.NewReg{}))
-
- //s, _ := acme.Sign(acc, []byte("AAA"))
- //acme.ParseSigned(s)
+ resp, err := acme.Post(&acc, dir.NewReg, acme.NewRegistration(acc.Contact, acme.NewReg{}))
+ must(err)
+ log.Println(resp)
}
diff --git a/errors.go b/errors.go
index f23aae3..a321863 100644
--- a/errors.go
+++ b/errors.go
@@ -1,6 +1,12 @@
package acme
-import "errors"
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+)
var (
errBadCSR = errors.New("The CSR is unacceptable (e.g., due to a short key)")
@@ -26,3 +32,20 @@ var Errors = map[string]error{
"urn:acme:error:unauthorized": errUnauthorized,
"urn:acme:error:unknownHost": errUnknownHost,
}
+
+func handleError(r *http.Response) error {
+ defer r.Body.Close()
+ body, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return err
+ }
+ var p Problem
+ err = json.Unmarshal(body, &p)
+ if err != nil {
+ return err
+ }
+ if e, ok := Errors[p.Type]; ok {
+ return fmt.Errorf("%v: %v", e, p.Detail)
+ }
+ return errors.New(p.Detail)
+}
diff --git a/messages.go b/messages.go
index 07c6fe7..511c713 100644
--- a/messages.go
+++ b/messages.go
@@ -1,7 +1,5 @@
package acme
-import jose "github.com/square/go-jose"
-
const (
// LEV1 Let's Encrytpt V1
LEV1 = `https://acme-v01.api.letsencrypt.org/directory`
@@ -20,12 +18,27 @@ type Directory struct {
// Registration Objects
type Registration struct {
- Resource string `json:"resource"`
- Key jose.JsonWebKey `json:"key"`
- Contact []string `json:"contact,omitempty"`
- Agreement string `json:"agreement,omitempty"`
- Authorizations string `json:"authorizations,omitempty"`
- Certificates string `json:"certificates,omitempty"`
+ Resource string `json:"resource"`
+ Contact []string `json:"contact,omitempty"`
+ Agreement string `json:"agreement,omitempty"`
+ Authorizations string `json:"authorizations,omitempty"`
+ Certificates string `json:"certificates,omitempty"`
+}
+
+// RegistrationResp ...
+type RegistrationResp struct {
+ ID int `json:"id"`
+ Key Key `json:"key"`
+ Contact []string `json:"contact"`
+ InitialIP string `json:"initalIp"`
+ CreatedAt string `json:"createdAt"` // 2006-01-02T15:04:05.999999999Z
+}
+
+// Key ...
+type Key struct {
+ Kty string `json:"kty"` // RSA, EC
+ E string `json:"e"`
+ N string `json:"n"`
}
// Authorization Objects
@@ -51,3 +64,10 @@ type Challege struct {
Validated string `json:"validated"` // 2006-01-02T15:04Z
KeyAuthorization string `json:"keyAuthorization"`
}
+
+// Problem description
+type Problem struct {
+ Type string `json:"type"`
+ Detail string `json:"detail"`
+ Instance string `json:"instance"`
+}
diff --git a/nonce.go b/nonce.go
index 95440ab..88e67ca 100644
--- a/nonce.go
+++ b/nonce.go
@@ -9,6 +9,10 @@ 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