From 0e26bb45ca14fb6befc3cbe710b90c70ebd0f0c4 Mon Sep 17 00:00:00 2001 From: xenolf Date: Wed, 27 Jan 2016 02:01:39 +0100 Subject: [PATCH 1/5] Add support for EC certificates / account keys --- account.go | 16 +++++++------- acme/client.go | 23 +++++++++----------- acme/crypto.go | 44 +++++++++++++++++++++++++++++---------- acme/dns_challenge.go | 2 +- acme/http_challenge.go | 2 +- acme/jws.go | 20 +++++++++++++++--- acme/messages.go | 18 +++++++--------- acme/tls_sni_challenge.go | 4 ++-- cli.go | 8 +++---- cli_handlers.go | 7 ++++++- configuration.go | 20 +++++++++++++++--- crypto.go | 29 ++++++++++++++++++++------ 12 files changed, 130 insertions(+), 63 deletions(-) diff --git a/account.go b/account.go index 13325470..85ac09f1 100644 --- a/account.go +++ b/account.go @@ -1,7 +1,7 @@ package main import ( - "crypto/rsa" + "crypto" "encoding/json" "io/ioutil" "os" @@ -13,7 +13,7 @@ import ( // Account represents a users local saved credentials type Account struct { Email string `json:"email"` - key *rsa.PrivateKey + key crypto.PrivateKey Registration *acme.RegistrationResource `json:"registration"` conf *Configuration @@ -28,16 +28,18 @@ func NewAccount(email string, conf *Configuration) *Account { logger().Fatalf("Could not check/create directory for account %s: %v", email, err) } - var privKey *rsa.PrivateKey + var privKey crypto.PrivateKey if _, err := os.Stat(accKeyPath); os.IsNotExist(err) { - logger().Printf("No key found for account %s. Generating a %v bit key.", email, conf.RsaBits()) - privKey, err = generateRsaKey(conf.RsaBits(), accKeyPath) + + logger().Printf("No key found for account %s. Generating a curve P384 EC key.", email) + privKey, err = generatePrivateKey(accKeyPath) if err != nil { logger().Fatalf("Could not generate RSA private account key for account %s: %v", email, err) } + logger().Printf("Saved key to %s", accKeyPath) } else { - privKey, err = loadRsaKey(accKeyPath) + privKey, err = loadPrivateKey(accKeyPath) if err != nil { logger().Fatalf("Could not load RSA private key from file %s: %v", accKeyPath, err) } @@ -73,7 +75,7 @@ func (a *Account) GetEmail() string { } // GetPrivateKey returns the private RSA account key. -func (a *Account) GetPrivateKey() *rsa.PrivateKey { +func (a *Account) GetPrivateKey() crypto.PrivateKey { return a.key } diff --git a/acme/client.go b/acme/client.go index be9843e2..769b17e0 100644 --- a/acme/client.go +++ b/acme/client.go @@ -3,7 +3,6 @@ package acme import ( "crypto" - "crypto/rsa" "crypto/x509" "encoding/base64" "encoding/json" @@ -38,7 +37,7 @@ func logf(format string, args ...interface{}) { type User interface { GetEmail() string GetRegistration() *RegistrationResource - GetPrivateKey() *rsa.PrivateKey + GetPrivateKey() crypto.PrivateKey } // Interface for all challenge solvers to implement. @@ -53,7 +52,7 @@ type Client struct { directory directory user User jws *jws - keyBits int + keyType KeyType issuerCert []byte solvers map[Challenge]solver } @@ -61,16 +60,12 @@ type Client struct { // NewClient creates a new ACME client on behalf of the user. The client will depend on // the ACME directory located at caDirURL for the rest of its actions. It will // generate private keys for certificates of size keyBits. -func NewClient(caDirURL string, user User, keyBits int) (*Client, error) { +func NewClient(caDirURL string, user User, keyType KeyType) (*Client, error) { privKey := user.GetPrivateKey() if privKey == nil { return nil, errors.New("private key was nil") } - if err := privKey.Validate(); err != nil { - return nil, fmt.Errorf("invalid private key: %v", err) - } - var dir directory if _, err := getJSON(caDirURL, &dir); err != nil { return nil, fmt.Errorf("get directory at '%s': %v", caDirURL, err) @@ -98,7 +93,7 @@ func NewClient(caDirURL string, user User, keyBits int) (*Client, error) { solvers[HTTP01] = &httpChallenge{jws: jws, validate: validate, provider: &HTTPProviderServer{}} solvers[TLSSNI01] = &tlsSNIChallenge{jws: jws, validate: validate, provider: &TLSProviderServer{}} - return &Client{directory: dir, user: user, jws: jws, keyBits: keyBits, solvers: solvers}, nil + return &Client{directory: dir, user: user, jws: jws, keyType: keyType, solvers: solvers}, nil } // SetChallengeProvider specifies a custom provider that will make the solution available @@ -197,8 +192,10 @@ func (c *Client) Register() (*RegistrationResource, error) { // AgreeToTOS updates the Client registration and sends the agreement to // the server. func (c *Client) AgreeToTOS() error { - c.user.GetRegistration().Body.Agreement = c.user.GetRegistration().TosURL - c.user.GetRegistration().Body.Resource = "reg" + reg := c.user.GetRegistration() + + reg.Body.Agreement = c.user.GetRegistration().TosURL + reg.Body.Resource = "reg" _, err := postJSON(c.jws, c.user.GetRegistration().URI, c.user.GetRegistration().Body, nil) return err } @@ -457,7 +454,7 @@ func (c *Client) requestCertificate(authz []authorizationResource, bundle bool, commonName := authz[0] var err error if privKey == nil { - privKey, err = generatePrivateKey(rsakey, c.keyBits) + privKey, err = generatePrivateKey(c.keyType) if err != nil { return CertificateResource{}, err } @@ -471,7 +468,7 @@ func (c *Client) requestCertificate(authz []authorizationResource, bundle bool, } // TODO: should the CSR be customizable? - csr, err := generateCsr(privKey.(*rsa.PrivateKey), commonName.Domain, san) + csr, err := generateCsr(privKey, commonName.Domain, san) if err != nil { return CertificateResource{}, err } diff --git a/acme/crypto.go b/acme/crypto.go index 5ce5ea5f..78a87847 100644 --- a/acme/crypto.go +++ b/acme/crypto.go @@ -25,12 +25,16 @@ import ( "golang.org/x/crypto/sha3" ) -type keyType int +// KeyType represents the key algo as well as the key size or curve to use. +type KeyType string type derCertificateBytes []byte const ( - eckey keyType = iota - rsakey + EC256 = KeyType("P256") + EC384 = KeyType("P348") + RSA2048 = KeyType("2048") + RSA4096 = KeyType("4096") + RSA8192 = KeyType("8192") ) const ( @@ -123,8 +127,16 @@ func GetOCSPForCert(bundle []byte) ([]byte, *ocsp.Response, error) { } func getKeyAuthorization(token string, key interface{}) (string, error) { + var publicKey crypto.PublicKey + switch k := key.(type) { + case *ecdsa.PrivateKey: + publicKey = k.Public() + case *rsa.PrivateKey: + publicKey = k.Public() + } + // Generate the Key Authorization for the challenge - jwk := keyAsJWK(key) + jwk := keyAsJWK(publicKey) if jwk == nil { return "", errors.New("Could not generate JWK from key.") } @@ -217,18 +229,25 @@ func parsePEMPrivateKey(key []byte) (crypto.PrivateKey, error) { } } -func generatePrivateKey(t keyType, keyLength int) (crypto.PrivateKey, error) { - switch t { - case eckey: +func generatePrivateKey(keyType KeyType) (crypto.PrivateKey, error) { + + switch keyType { + case EC256: + return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + case EC384: return ecdsa.GenerateKey(elliptic.P384(), rand.Reader) - case rsakey: - return rsa.GenerateKey(rand.Reader, keyLength) + case RSA2048: + return rsa.GenerateKey(rand.Reader, 2048) + case RSA4096: + return rsa.GenerateKey(rand.Reader, 4096) + case RSA8192: + return rsa.GenerateKey(rand.Reader, 8192) } - return nil, fmt.Errorf("Invalid keytype: %d", t) + return nil, fmt.Errorf("Invalid KeyType: %s", keyType) } -func generateCsr(privateKey *rsa.PrivateKey, domain string, san []string) ([]byte, error) { +func generateCsr(privateKey crypto.PrivateKey, domain string, san []string) ([]byte, error) { template := x509.CertificateRequest{ Subject: pkix.Name{ CommonName: domain, @@ -245,6 +264,9 @@ func generateCsr(privateKey *rsa.PrivateKey, domain string, san []string) ([]byt func pemEncode(data interface{}) []byte { var pemBlock *pem.Block switch key := data.(type) { + case *ecdsa.PrivateKey: + keyBytes, _ := x509.MarshalECPrivateKey(key) + pemBlock = &pem.Block{Type: "EC PRIVATE KEY", Bytes: keyBytes} case *rsa.PrivateKey: pemBlock = &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)} break diff --git a/acme/dns_challenge.go b/acme/dns_challenge.go index 4cd58f50..d187f63b 100644 --- a/acme/dns_challenge.go +++ b/acme/dns_challenge.go @@ -45,7 +45,7 @@ func (s *dnsChallenge) Solve(chlng challenge, domain string) error { } // Generate the Key Authorization for the challenge - keyAuth, err := getKeyAuthorization(chlng.Token, &s.jws.privKey.PublicKey) + keyAuth, err := getKeyAuthorization(chlng.Token, s.jws.privKey) if err != nil { return err } diff --git a/acme/http_challenge.go b/acme/http_challenge.go index 1cc1f6e1..95cb1fd8 100644 --- a/acme/http_challenge.go +++ b/acme/http_challenge.go @@ -21,7 +21,7 @@ func (s *httpChallenge) Solve(chlng challenge, domain string) error { logf("[INFO][%s] acme: Trying to solve HTTP-01", domain) // Generate the Key Authorization for the challenge - keyAuth, err := getKeyAuthorization(chlng.Token, &s.jws.privKey.PublicKey) + keyAuth, err := getKeyAuthorization(chlng.Token, s.jws.privKey) if err != nil { return err } diff --git a/acme/jws.go b/acme/jws.go index b676fe39..78d82724 100644 --- a/acme/jws.go +++ b/acme/jws.go @@ -2,7 +2,9 @@ package acme import ( "bytes" + "crypto" "crypto/ecdsa" + "crypto/elliptic" "crypto/rsa" "fmt" "net/http" @@ -12,7 +14,7 @@ import ( type jws struct { directoryURL string - privKey *rsa.PrivateKey + privKey crypto.PrivateKey nonces []string } @@ -46,8 +48,20 @@ func (j *jws) post(url string, content []byte) (*http.Response, error) { } func (j *jws) signContent(content []byte) (*jose.JsonWebSignature, error) { - // TODO: support other algorithms - RS512 - signer, err := jose.NewSigner(jose.RS256, j.privKey) + + var alg jose.SignatureAlgorithm + switch k := j.privKey.(type) { + case *rsa.PrivateKey: + alg = jose.RS256 + case *ecdsa.PrivateKey: + if k.Curve == elliptic.P256() { + alg = jose.ES256 + } else if k.Curve == elliptic.P384() { + alg = jose.ES384 + } + } + + signer, err := jose.NewSigner(alg, j.privKey) if err != nil { return nil, err } diff --git a/acme/messages.go b/acme/messages.go index 55e54321..d238df81 100644 --- a/acme/messages.go +++ b/acme/messages.go @@ -28,17 +28,13 @@ type registrationMessage struct { // Registration is returned by the ACME server after the registration // The client implementation should save this registration somewhere. type Registration struct { - Resource string `json:"resource,omitempty"` - ID int `json:"id"` - Key struct { - Kty string `json:"kty"` - N string `json:"n"` - E string `json:"e"` - } `json:"key"` - Contact []string `json:"contact"` - Agreement string `json:"agreement,omitempty"` - Authorizations string `json:"authorizations,omitempty"` - Certificates string `json:"certificates,omitempty"` + Resource string `json:"resource,omitempty"` + ID int `json:"id"` + Key jose.JsonWebKey `json:"key"` + Contact []string `json:"contact"` + Agreement string `json:"agreement,omitempty"` + Authorizations string `json:"authorizations,omitempty"` + Certificates string `json:"certificates,omitempty"` // RecoveryKey recoveryKeyMessage `json:"recoveryKey,omitempty"` } diff --git a/acme/tls_sni_challenge.go b/acme/tls_sni_challenge.go index dca886bd..c36f6acc 100644 --- a/acme/tls_sni_challenge.go +++ b/acme/tls_sni_challenge.go @@ -22,7 +22,7 @@ func (t *tlsSNIChallenge) Solve(chlng challenge, domain string) error { logf("[INFO][%s] acme: Trying to solve TLS-SNI-01", domain) // Generate the Key Authorization for the challenge - keyAuth, err := getKeyAuthorization(chlng.Token, &t.jws.privKey.PublicKey) + keyAuth, err := getKeyAuthorization(chlng.Token, t.jws.privKey) if err != nil { return err } @@ -43,7 +43,7 @@ func (t *tlsSNIChallenge) Solve(chlng challenge, domain string) error { // TLSSNI01ChallengeCert returns a certificate for the `tls-sni-01` challenge func TLSSNI01ChallengeCert(keyAuth string) (tls.Certificate, error) { // generate a new RSA key for the certificates - tempPrivKey, err := generatePrivateKey(rsakey, 2048) + tempPrivKey, err := generatePrivateKey(RSA2048) if err != nil { return tls.Certificate{}, err } diff --git a/cli.go b/cli.go index 97d3a816..893d1cda 100644 --- a/cli.go +++ b/cli.go @@ -92,10 +92,10 @@ func main() { Name: "accept-tos, a", Usage: "By setting this flag to true you indicate that you accept the current Let's Encrypt terms of service.", }, - cli.IntFlag{ - Name: "rsa-key-size, B", - Value: 2048, - Usage: "Size of the RSA key.", + cli.StringFlag{ + Name: "key-type, k", + Value: "rsa2048", + Usage: "Key type to use for private keys. Supported: rsa2048, rsa4096, rsa8192, ec256, ec384", }, cli.StringFlag{ Name: "path", diff --git a/cli_handlers.go b/cli_handlers.go index e6e71cbe..cdf4dca8 100644 --- a/cli_handlers.go +++ b/cli_handlers.go @@ -34,7 +34,12 @@ func setup(c *cli.Context) (*Configuration, *Account, *acme.Client) { //TODO: move to account struct? Currently MUST pass email. acc := NewAccount(c.GlobalString("email"), conf) - client, err := acme.NewClient(c.GlobalString("server"), acc, conf.RsaBits()) + keyType, err := conf.KeyType() + if err != nil { + logger().Fatal(err.Error()) + } + + client, err := acme.NewClient(c.GlobalString("server"), acc, keyType) if err != nil { logger().Fatalf("Could not create client: %s", err.Error()) } diff --git a/configuration.go b/configuration.go index cbb157f3..a437fd56 100644 --- a/configuration.go +++ b/configuration.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "net/url" "os" "path" @@ -20,9 +21,22 @@ func NewConfiguration(c *cli.Context) *Configuration { return &Configuration{context: c} } -// RsaBits returns the current set RSA bit length for private keys -func (c *Configuration) RsaBits() int { - return c.context.GlobalInt("rsa-key-size") +// KeyType the type from which private keys should be generated +func (c *Configuration) KeyType() (acme.KeyType, error) { + switch strings.ToUpper(c.context.GlobalString("key-type")) { + case "RSA2048": + return acme.RSA2048, nil + case "RSA4096": + return acme.RSA4096, nil + case "RSA8192": + return acme.RSA8192, nil + case "EC256": + return acme.EC256, nil + case "EC384": + return acme.EC384, nil + } + + return "", fmt.Errorf("Unsupported KeyType: %s", c.context.GlobalString("key-type")) } // ExcludedSolvers is a list of solvers that are to be excluded. diff --git a/crypto.go b/crypto.go index 3644ed99..684b1100 100644 --- a/crypto.go +++ b/crypto.go @@ -1,21 +1,30 @@ package main import ( + "crypto" + "crypto/ecdsa" + "crypto/elliptic" "crypto/rand" - "crypto/rsa" "crypto/x509" "encoding/pem" + "errors" "io/ioutil" "os" ) -func generateRsaKey(length int, file string) (*rsa.PrivateKey, error) { - privateKey, err := rsa.GenerateKey(rand.Reader, length) +func generatePrivateKey(file string) (crypto.PrivateKey, error) { + + privateKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader) if err != nil { return nil, err } - pemKey := pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)} + keyBytes, err := x509.MarshalECPrivateKey(privateKey) + if err != nil { + return nil, err + } + + pemKey := pem.Block{Type: "EC PRIVATE KEY", Bytes: keyBytes} certOut, err := os.Create(file) if err != nil { @@ -28,12 +37,20 @@ func generateRsaKey(length int, file string) (*rsa.PrivateKey, error) { return privateKey, nil } -func loadRsaKey(file string) (*rsa.PrivateKey, error) { +func loadPrivateKey(file string) (crypto.PrivateKey, error) { keyBytes, err := ioutil.ReadFile(file) if err != nil { return nil, err } keyBlock, _ := pem.Decode(keyBytes) - return x509.ParsePKCS1PrivateKey(keyBlock.Bytes) + + switch keyBlock.Type { + case "RSA PRIVATE KEY": + x509.ParsePKCS1PrivateKey(keyBlock.Bytes) + case "EC PRIVATE KEY": + return x509.ParseECPrivateKey(keyBlock.Bytes) + } + + return nil, errors.New("Unknown private key type.") } From 1f777a0d774894b29681a44317bbd7d608d1ed2a Mon Sep 17 00:00:00 2001 From: xenolf Date: Wed, 27 Jan 2016 02:01:58 +0100 Subject: [PATCH 2/5] Adapt tests to EC changes --- acme/client_test.go | 16 +++++++++------- acme/crypto_test.go | 9 +++++---- acme/dns_challenge_test.go | 5 +++-- acme/http_challenge_test.go | 9 +++++---- acme/tls_sni_challenge_test.go | 9 +++++---- 5 files changed, 27 insertions(+), 21 deletions(-) diff --git a/acme/client_test.go b/acme/client_test.go index 9ba165ed..49824735 100644 --- a/acme/client_test.go +++ b/acme/client_test.go @@ -1,6 +1,7 @@ package acme import ( + "crypto" "crypto/rand" "crypto/rsa" "encoding/json" @@ -13,6 +14,7 @@ import ( func TestNewClient(t *testing.T) { keyBits := 32 // small value keeps test fast + keyType := RSA2048 key, err := rsa.GenerateKey(rand.Reader, keyBits) if err != nil { t.Fatal("Could not generate test key:", err) @@ -28,7 +30,7 @@ func TestNewClient(t *testing.T) { w.Write(data) })) - client, err := NewClient(ts.URL, user, keyBits) + client, err := NewClient(ts.URL, user, keyType) if err != nil { t.Fatalf("Could not create client: %v", err) } @@ -40,8 +42,8 @@ func TestNewClient(t *testing.T) { t.Errorf("Expected jws.privKey to be %p but was %p", expected, actual) } - if client.keyBits != keyBits { - t.Errorf("Expected keyBits to be %d but was %d", keyBits, client.keyBits) + if client.keyType != keyType { + t.Errorf("Expected keyBits to be %d but was %d", keyType, client.keyType) } if expected, actual := 2, len(client.solvers); actual != expected { @@ -68,7 +70,7 @@ func TestClientOptPort(t *testing.T) { optPort := "1234" optHost := "" - client, err := NewClient(ts.URL, user, keyBits) + client, err := NewClient(ts.URL, user, RSA2048) if err != nil { t.Fatalf("Could not create client: %v", err) } @@ -140,8 +142,8 @@ func TestValidate(t *testing.T) { })) defer ts.Close() - privKey, _ := generatePrivateKey(rsakey, 512) - j := &jws{privKey: privKey.(*rsa.PrivateKey), directoryURL: ts.URL} + privKey, _ := rsa.GenerateKey(rand.Reader, 512) + j := &jws{privKey: privKey, directoryURL: ts.URL} tsts := []struct { name string @@ -193,4 +195,4 @@ type mockUser struct { func (u mockUser) GetEmail() string { return u.email } func (u mockUser) GetRegistration() *RegistrationResource { return u.regres } -func (u mockUser) GetPrivateKey() *rsa.PrivateKey { return u.privatekey } +func (u mockUser) GetPrivateKey() crypto.PrivateKey { return u.privatekey } diff --git a/acme/crypto_test.go b/acme/crypto_test.go index 81ab287e..d2fc5088 100644 --- a/acme/crypto_test.go +++ b/acme/crypto_test.go @@ -2,13 +2,14 @@ package acme import ( "bytes" + "crypto/rand" "crypto/rsa" "testing" "time" ) func TestGeneratePrivateKey(t *testing.T) { - key, err := generatePrivateKey(rsakey, 32) + key, err := generatePrivateKey(RSA2048) if err != nil { t.Error("Error generating private key:", err) } @@ -18,12 +19,12 @@ func TestGeneratePrivateKey(t *testing.T) { } func TestGenerateCSR(t *testing.T) { - key, err := generatePrivateKey(rsakey, 512) + key, err := rsa.GenerateKey(rand.Reader, 512) if err != nil { t.Fatal("Error generating private key:", err) } - csr, err := generateCsr(key.(*rsa.PrivateKey), "fizz.buzz", nil) + csr, err := generateCsr(key, "fizz.buzz", nil) if err != nil { t.Error("Error generating CSR:", err) } @@ -52,7 +53,7 @@ func TestPEMEncode(t *testing.T) { } func TestPEMCertExpiration(t *testing.T) { - privKey, err := generatePrivateKey(rsakey, 2048) + privKey, err := generatePrivateKey(RSA2048) if err != nil { t.Fatal("Error generating private key:", err) } diff --git a/acme/dns_challenge_test.go b/acme/dns_challenge_test.go index e1e67efe..850a0f59 100644 --- a/acme/dns_challenge_test.go +++ b/acme/dns_challenge_test.go @@ -2,6 +2,7 @@ package acme import ( "bufio" + "crypto/rand" "crypto/rsa" "net/http" "net/http/httptest" @@ -76,7 +77,7 @@ func TestDNSValidServerResponse(t *testing.T) { preCheckDNS = func(fqdn, value string) (bool, error) { return true, nil } - privKey, _ := generatePrivateKey(rsakey, 512) + privKey, _ := rsa.GenerateKey(rand.Reader, 512) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Replay-Nonce", "12345") @@ -84,7 +85,7 @@ func TestDNSValidServerResponse(t *testing.T) { })) manualProvider, _ := NewDNSProviderManual() - jws := &jws{privKey: privKey.(*rsa.PrivateKey), directoryURL: ts.URL} + jws := &jws{privKey: privKey, directoryURL: ts.URL} solver := &dnsChallenge{jws: jws, validate: validate, provider: manualProvider} clientChallenge := challenge{Type: "dns01", Status: "pending", URI: ts.URL, Token: "http8"} diff --git a/acme/http_challenge_test.go b/acme/http_challenge_test.go index 79b8b545..fdd8f4d2 100644 --- a/acme/http_challenge_test.go +++ b/acme/http_challenge_test.go @@ -1,6 +1,7 @@ package acme import ( + "crypto/rand" "crypto/rsa" "io/ioutil" "strings" @@ -8,8 +9,8 @@ import ( ) func TestHTTPChallenge(t *testing.T) { - privKey, _ := generatePrivateKey(rsakey, 512) - j := &jws{privKey: privKey.(*rsa.PrivateKey)} + privKey, _ := rsa.GenerateKey(rand.Reader, 512) + j := &jws{privKey: privKey} clientChallenge := challenge{Type: HTTP01, Token: "http1"} mockValidate := func(_ *jws, _, _ string, chlng challenge) error { uri := "http://localhost:23457/.well-known/acme-challenge/" + chlng.Token @@ -43,8 +44,8 @@ func TestHTTPChallenge(t *testing.T) { } func TestHTTPChallengeInvalidPort(t *testing.T) { - privKey, _ := generatePrivateKey(rsakey, 128) - j := &jws{privKey: privKey.(*rsa.PrivateKey)} + privKey, _ := rsa.GenerateKey(rand.Reader, 128) + j := &jws{privKey: privKey} clientChallenge := challenge{Type: HTTP01, Token: "http2"} solver := &httpChallenge{jws: j, validate: stubValidate, provider: &HTTPProviderServer{port: "123456"}} diff --git a/acme/tls_sni_challenge_test.go b/acme/tls_sni_challenge_test.go index 60f1498b..3aec7456 100644 --- a/acme/tls_sni_challenge_test.go +++ b/acme/tls_sni_challenge_test.go @@ -1,6 +1,7 @@ package acme import ( + "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/tls" @@ -11,8 +12,8 @@ import ( ) func TestTLSSNIChallenge(t *testing.T) { - privKey, _ := generatePrivateKey(rsakey, 512) - j := &jws{privKey: privKey.(*rsa.PrivateKey)} + privKey, _ := rsa.GenerateKey(rand.Reader, 512) + j := &jws{privKey: privKey} clientChallenge := challenge{Type: TLSSNI01, Token: "tlssni1"} mockValidate := func(_ *jws, _, _ string, chlng challenge) error { conn, err := tls.Dial("tcp", "localhost:23457", &tls.Config{ @@ -51,8 +52,8 @@ func TestTLSSNIChallenge(t *testing.T) { } func TestTLSSNIChallengeInvalidPort(t *testing.T) { - privKey, _ := generatePrivateKey(rsakey, 128) - j := &jws{privKey: privKey.(*rsa.PrivateKey)} + privKey, _ := rsa.GenerateKey(rand.Reader, 128) + j := &jws{privKey: privKey} clientChallenge := challenge{Type: TLSSNI01, Token: "tlssni2"} solver := &tlsSNIChallenge{jws: j, validate: stubValidate, provider: &TLSProviderServer{port: "123456"}} From d46b0db199079c884fbca77f5928c0e7c3f2ab0c Mon Sep 17 00:00:00 2001 From: xenolf Date: Sat, 6 Feb 2016 22:41:29 +0100 Subject: [PATCH 3/5] Fix missing return in loadPrivateKey --- crypto.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto.go b/crypto.go index 684b1100..8b23e2fc 100644 --- a/crypto.go +++ b/crypto.go @@ -47,7 +47,7 @@ func loadPrivateKey(file string) (crypto.PrivateKey, error) { switch keyBlock.Type { case "RSA PRIVATE KEY": - x509.ParsePKCS1PrivateKey(keyBlock.Bytes) + return x509.ParsePKCS1PrivateKey(keyBlock.Bytes) case "EC PRIVATE KEY": return x509.ParseECPrivateKey(keyBlock.Bytes) } From a61e41c90e4f062c39647784908661c4b631f2b4 Mon Sep 17 00:00:00 2001 From: xenolf Date: Sun, 14 Feb 2016 22:31:17 +0100 Subject: [PATCH 4/5] Fix typo in the constant for the P384 curve. --- acme/crypto.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/acme/crypto.go b/acme/crypto.go index 78a87847..c46310f1 100644 --- a/acme/crypto.go +++ b/acme/crypto.go @@ -29,9 +29,10 @@ import ( type KeyType string type derCertificateBytes []byte +// Constants for all key types we support. const ( EC256 = KeyType("P256") - EC384 = KeyType("P348") + EC384 = KeyType("P384") RSA2048 = KeyType("2048") RSA4096 = KeyType("4096") RSA8192 = KeyType("8192") From c9e1d0a482ee02b18c80843a62bd94f19545c227 Mon Sep 17 00:00:00 2001 From: xenolf Date: Sun, 21 Feb 2016 04:22:03 +0100 Subject: [PATCH 5/5] Remove keyBits from tests, use keyType instead. --- acme/client_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme/client_test.go b/acme/client_test.go index 49824735..e309554f 100644 --- a/acme/client_test.go +++ b/acme/client_test.go @@ -43,7 +43,7 @@ func TestNewClient(t *testing.T) { } if client.keyType != keyType { - t.Errorf("Expected keyBits to be %d but was %d", keyType, client.keyType) + t.Errorf("Expected keyType to be %s but was %s", keyType, client.keyType) } if expected, actual := 2, len(client.solvers); actual != expected {