acme: generate correct ES512 signatures

The correct curve name for ES512 signatures is P-521, not P-512.
Author: Matthew Endsley <mendsley@gmail.com>.

Fixes golang/go#18357.

Change-Id: I8d9ba046780921a9e1a5eaa947b9bcbd12e60e34
Reviewed-on: https://go-review.googlesource.com/34555
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/acme/jws.go b/acme/jws.go
index 49ba313..6cbca25 100644
--- a/acme/jws.go
+++ b/acme/jws.go
@@ -134,7 +134,7 @@
 			return "ES256", crypto.SHA256
 		case "P-384":
 			return "ES384", crypto.SHA384
-		case "P-512":
+		case "P-521":
 			return "ES512", crypto.SHA512
 		}
 	}
diff --git a/acme/jws_test.go b/acme/jws_test.go
index 1def873..0ff0fb5 100644
--- a/acme/jws_test.go
+++ b/acme/jws_test.go
@@ -12,11 +12,13 @@
 	"encoding/base64"
 	"encoding/json"
 	"encoding/pem"
+	"fmt"
 	"math/big"
 	"testing"
 )
 
-const testKeyPEM = `
+const (
+	testKeyPEM = `
 -----BEGIN RSA PRIVATE KEY-----
 MIIEowIBAAKCAQEA4xgZ3eRPkwoRvy7qeRUbmMDe0V+xH9eWLdu0iheeLlrmD2mq
 WXfP9IeSKApbn34g8TuAS9g5zhq8ELQ3kmjr+KV86GAMgI6VAcGlq3QrzpTCf/30
@@ -46,10 +48,9 @@
 -----END RSA PRIVATE KEY-----
 `
 
-// This thumbprint is for the testKey defined above.
-const testKeyThumbprint = "6nicxzh6WETQlrvdchkz-U3e3DOQZ4heJKU63rfqMqQ"
+	// This thumbprint is for the testKey defined above.
+	testKeyThumbprint = "6nicxzh6WETQlrvdchkz-U3e3DOQZ4heJKU63rfqMqQ"
 
-const (
 	// openssl ecparam -name secp256k1 -genkey -noout
 	testKeyECPEM = `
 -----BEGIN EC PRIVATE KEY-----
@@ -58,39 +59,78 @@
 QAaS/RNouybCiRhRjI3EaxLkQwgrCw0gqQ==
 -----END EC PRIVATE KEY-----
 `
-	// 1. opnessl ec -in key.pem -noout -text
+	// openssl ecparam -name secp384r1 -genkey -noout
+	testKeyEC384PEM = `
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDAQ4lNtXRORWr1bgKR1CGysr9AJ9SyEk4jiVnlUWWUChmSNL+i9SLSD
+Oe/naPqXJ6CgBwYFK4EEACKhZANiAAQzKtj+Ms0vHoTX5dzv3/L5YMXOWuI5UKRj
+JigpahYCqXD2BA1j0E/2xt5vlPf+gm0PL+UHSQsCokGnIGuaHCsJAp3ry0gHQEke
+WYXapUUFdvaK1R2/2hn5O+eiQM8YzCg=
+-----END EC PRIVATE KEY-----
+`
+	// openssl ecparam -name secp521r1 -genkey -noout
+	testKeyEC512PEM = `
+-----BEGIN EC PRIVATE KEY-----
+MIHcAgEBBEIBSNZKFcWzXzB/aJClAb305ibalKgtDA7+70eEkdPt28/3LZMM935Z
+KqYHh/COcxuu3Kt8azRAUz3gyr4zZKhlKUSgBwYFK4EEACOhgYkDgYYABAHUNKbx
+7JwC7H6pa2sV0tERWhHhB3JmW+OP6SUgMWryvIKajlx73eS24dy4QPGrWO9/ABsD
+FqcRSkNVTXnIv6+0mAF25knqIBIg5Q8M9BnOu9GGAchcwt3O7RDHmqewnJJDrbjd
+GGnm6rb+NnWR9DIopM0nKNkToWoF/hzopxu4Ae/GsQ==
+-----END EC PRIVATE KEY-----
+`
+	// 1. openssl ec -in key.pem -noout -text
 	// 2. remove first byte, 04 (the header); the rest is X and Y
-	// 3. covert each with: echo <val> | xxd -r -p | base64 | tr -d '=' | tr '/+' '_-'
-	testKeyECPubX = "5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HQ"
-	testKeyECPubY = "4aiK72sBeUAGkv0TaLsmwokYUYyNxGsS5EMIKwsNIKk"
+	// 3. convert each with: echo <val> | xxd -r -p | base64 -w 100 | tr -d '=' | tr '/+' '_-'
+	testKeyECPubX    = "5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HQ"
+	testKeyECPubY    = "4aiK72sBeUAGkv0TaLsmwokYUYyNxGsS5EMIKwsNIKk"
+	testKeyEC384PubX = "MyrY_jLNLx6E1-Xc79_y-WDFzlriOVCkYyYoKWoWAqlw9gQNY9BP9sbeb5T3_oJt"
+	testKeyEC384PubY = "Dy_lB0kLAqJBpyBrmhwrCQKd68tIB0BJHlmF2qVFBXb2itUdv9oZ-TvnokDPGMwo"
+	testKeyEC512PubX = "AdQ0pvHsnALsfqlraxXS0RFaEeEHcmZb44_pJSAxavK8gpqOXHvd5Lbh3LhA8atY738AGwMWpxFKQ1VNeci_r7SY"
+	testKeyEC512PubY = "AXbmSeogEiDlDwz0Gc670YYByFzC3c7tEMeap7CckkOtuN0Yaebqtv42dZH0MiikzSco2ROhagX-HOinG7gB78ax"
+
 	// echo -n '{"crv":"P-256","kty":"EC","x":"<testKeyECPubX>","y":"<testKeyECPubY>"}' | \
 	// openssl dgst -binary -sha256 | base64 | tr -d '=' | tr '/+' '_-'
 	testKeyECThumbprint = "zedj-Bd1Zshp8KLePv2MB-lJ_Hagp7wAwdkA0NUTniU"
 )
 
 var (
-	testKey   *rsa.PrivateKey
-	testKeyEC *ecdsa.PrivateKey
+	testKey      *rsa.PrivateKey
+	testKeyEC    *ecdsa.PrivateKey
+	testKeyEC384 *ecdsa.PrivateKey
+	testKeyEC512 *ecdsa.PrivateKey
 )
 
 func init() {
-	d, _ := pem.Decode([]byte(testKeyPEM))
-	if d == nil {
-		panic("no block found in testKeyPEM")
-	}
-	var err error
-	testKey, err = x509.ParsePKCS1PrivateKey(d.Bytes)
-	if err != nil {
-		panic(err.Error())
-	}
+	testKey = parseRSA(testKeyPEM, "testKeyPEM")
+	testKeyEC = parseEC(testKeyECPEM, "testKeyECPEM")
+	testKeyEC384 = parseEC(testKeyEC384PEM, "testKeyEC384PEM")
+	testKeyEC512 = parseEC(testKeyEC512PEM, "testKeyEC512PEM")
+}
 
-	if d, _ = pem.Decode([]byte(testKeyECPEM)); d == nil {
-		panic("no block found in testKeyECPEM")
+func decodePEM(s, name string) []byte {
+	d, _ := pem.Decode([]byte(s))
+	if d == nil {
+		panic("no block found in " + name)
 	}
-	testKeyEC, err = x509.ParseECPrivateKey(d.Bytes)
+	return d.Bytes
+}
+
+func parseRSA(s, name string) *rsa.PrivateKey {
+	b := decodePEM(s, name)
+	k, err := x509.ParsePKCS1PrivateKey(b)
 	if err != nil {
-		panic(err.Error())
+		panic(fmt.Sprintf("%s: %v", name, err))
 	}
+	return k
+}
+
+func parseEC(s, name string) *ecdsa.PrivateKey {
+	b := decodePEM(s, name)
+	k, err := x509.ParseECPrivateKey(b)
+	if err != nil {
+		panic(fmt.Sprintf("%s: %v", name, err))
+	}
+	return k
 }
 
 func TestJWSEncodeJSON(t *testing.T) {
@@ -141,50 +181,63 @@
 }
 
 func TestJWSEncodeJSONEC(t *testing.T) {
-	claims := struct{ Msg string }{"Hello JWS"}
+	tt := []struct {
+		key      *ecdsa.PrivateKey
+		x, y     string
+		alg, crv string
+	}{
+		{testKeyEC, testKeyECPubX, testKeyECPubY, "ES256", "P-256"},
+		{testKeyEC384, testKeyEC384PubX, testKeyEC384PubY, "ES384", "P-384"},
+		{testKeyEC512, testKeyEC512PubX, testKeyEC512PubY, "ES512", "P-521"},
+	}
+	for i, test := range tt {
+		claims := struct{ Msg string }{"Hello JWS"}
+		b, err := jwsEncodeJSON(claims, test.key, "nonce")
+		if err != nil {
+			t.Errorf("%d: %v", i, err)
+			continue
+		}
+		var jws struct{ Protected, Payload, Signature string }
+		if err := json.Unmarshal(b, &jws); err != nil {
+			t.Errorf("%d: %v", i, err)
+			continue
+		}
 
-	b, err := jwsEncodeJSON(claims, testKeyEC, "nonce")
-	if err != nil {
-		t.Fatal(err)
-	}
-	var jws struct{ Protected, Payload, Signature string }
-	if err := json.Unmarshal(b, &jws); err != nil {
-		t.Fatal(err)
-	}
-
-	if b, err = base64.RawURLEncoding.DecodeString(jws.Protected); err != nil {
-		t.Fatalf("jws.Protected: %v", err)
-	}
-	var head struct {
-		Alg   string
-		Nonce string
-		JWK   struct {
-			Crv string
-			Kty string
-			X   string
-			Y   string
-		} `json:"jwk"`
-	}
-	if err := json.Unmarshal(b, &head); err != nil {
-		t.Fatalf("jws.Protected: %v", err)
-	}
-	if head.Alg != "ES256" {
-		t.Errorf("head.Alg = %q; want ES256", head.Alg)
-	}
-	if head.Nonce != "nonce" {
-		t.Errorf("head.Nonce = %q; want nonce", head.Nonce)
-	}
-	if head.JWK.Crv != "P-256" {
-		t.Errorf("head.JWK.Crv = %q; want P-256", head.JWK.Crv)
-	}
-	if head.JWK.Kty != "EC" {
-		t.Errorf("head.JWK.Kty = %q; want EC", head.JWK.Kty)
-	}
-	if head.JWK.X != testKeyECPubX {
-		t.Errorf("head.JWK.X = %q; want %q", head.JWK.X, testKeyECPubX)
-	}
-	if head.JWK.Y != testKeyECPubY {
-		t.Errorf("head.JWK.Y = %q; want %q", head.JWK.Y, testKeyECPubY)
+		b, err = base64.RawURLEncoding.DecodeString(jws.Protected)
+		if err != nil {
+			t.Errorf("%d: jws.Protected: %v", i, err)
+		}
+		var head struct {
+			Alg   string
+			Nonce string
+			JWK   struct {
+				Crv string
+				Kty string
+				X   string
+				Y   string
+			} `json:"jwk"`
+		}
+		if err := json.Unmarshal(b, &head); err != nil {
+			t.Errorf("%d: jws.Protected: %v", i, err)
+		}
+		if head.Alg != test.alg {
+			t.Errorf("%d: head.Alg = %q; want %q", i, head.Alg, test.alg)
+		}
+		if head.Nonce != "nonce" {
+			t.Errorf("%d: head.Nonce = %q; want nonce", i, head.Nonce)
+		}
+		if head.JWK.Crv != test.crv {
+			t.Errorf("%d: head.JWK.Crv = %q; want %q", i, head.JWK.Crv, test.crv)
+		}
+		if head.JWK.Kty != "EC" {
+			t.Errorf("%d: head.JWK.Kty = %q; want EC", i, head.JWK.Kty)
+		}
+		if head.JWK.X != test.x {
+			t.Errorf("%d: head.JWK.X = %q; want %q", i, head.JWK.X, test.x)
+		}
+		if head.JWK.Y != test.y {
+			t.Errorf("%d: head.JWK.Y = %q; want %q", i, head.JWK.Y, test.y)
+		}
 	}
 }