test ec private keys
This commit is contained in:
parent
5695a0d0e7
commit
b9f5fd197e
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"kty": "EC",
|
||||||
|
"crv": "P-256",
|
||||||
|
"d": "iYydo27aNGO9DBUWeGEPD8oNi1LZDqfxPmQlieLBjVQ",
|
||||||
|
"x": "IT1SWLxsacPiE5Z16jkopAn8_-85rMjgyCokrnjDft4",
|
||||||
|
"y": "mP2JwOAOdMmXuwpxbKng3KZz27mz-nKWIlXJ3rzSGMo"
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgiYydo27aNGO9DBUW
|
||||||
|
eGEPD8oNi1LZDqfxPmQlieLBjVShRANCAAQhPVJYvGxpw+ITlnXqOSikCfz/7zms
|
||||||
|
yODIKiSueMN+3pj9icDgDnTJl7sKcWyp4Nymc9u5s/pyliJVyd680hjK
|
||||||
|
-----END PRIVATE KEY-----
|
|
@ -0,0 +1,8 @@
|
||||||
|
-----BEGIN EC PARAMETERS-----
|
||||||
|
BggqhkjOPQMBBw==
|
||||||
|
-----END EC PARAMETERS-----
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEIImMnaNu2jRjvQwVFnhhDw/KDYtS2Q6n8T5kJYniwY1UoAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAEIT1SWLxsacPiE5Z16jkopAn8/+85rMjgyCokrnjDft6Y/YnA4A50
|
||||||
|
yZe7CnFsqeDcpnPbubP6cpYiVcnevNIYyg==
|
||||||
|
-----END EC PRIVATE KEY-----
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"kty": "EC",
|
||||||
|
"crv": "P-384",
|
||||||
|
"d": "XlyuCEWSTTS8U79O_Mz05z18vh4kb10szvu_7pdXuGWV6lfEyPExyUYWsA6A2kdV",
|
||||||
|
"x": "2zEU0bKCa7ejKLIJ8oPGnLhqhxyiv4_w38K2a0SPC6dsSd9_glNJ8lcqv0sff5Gb",
|
||||||
|
"y": "VD4jnu83S6scn6_TeAj3EZOREGbOs6dzoVpaugn-XQMMyC9O4VLbDDFGBZTJlMsb"
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBeXK4IRZJNNLxTv078
|
||||||
|
zPTnPXy+HiRvXSzO+7/ul1e4ZZXqV8TI8THJRhawDoDaR1WhZANiAATbMRTRsoJr
|
||||||
|
t6Mosgnyg8acuGqHHKK/j/DfwrZrRI8Lp2xJ33+CU0nyVyq/Sx9/kZtUPiOe7zdL
|
||||||
|
qxyfr9N4CPcRk5EQZs6zp3OhWlq6Cf5dAwzIL07hUtsMMUYFlMmUyxs=
|
||||||
|
-----END PRIVATE KEY-----
|
|
@ -0,0 +1,6 @@
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MIGkAgEBBDBeXK4IRZJNNLxTv078zPTnPXy+HiRvXSzO+7/ul1e4ZZXqV8TI8THJ
|
||||||
|
RhawDoDaR1WgBwYFK4EEACKhZANiAATbMRTRsoJrt6Mosgnyg8acuGqHHKK/j/Df
|
||||||
|
wrZrRI8Lp2xJ33+CU0nyVyq/Sx9/kZtUPiOe7zdLqxyfr9N4CPcRk5EQZs6zp3Oh
|
||||||
|
Wlq6Cf5dAwzIL07hUtsMMUYFlMmUyxs=
|
||||||
|
-----END EC PRIVATE KEY-----
|
148
keypairs.go
148
keypairs.go
|
@ -52,6 +52,8 @@ type PublicJWK struct {
|
||||||
//BareJWK string `json:"-"`
|
//BareJWK string `json:"-"`
|
||||||
thumbprint thumbstr `json:"thumbprint"`
|
thumbprint thumbstr `json:"thumbprint"`
|
||||||
jwk jwkstr `json:"jwk"`
|
jwk jwkstr `json:"jwk"`
|
||||||
|
x string
|
||||||
|
y string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PublicJWK) Thumbprint() string {
|
func (p *PublicJWK) Thumbprint() string {
|
||||||
|
@ -68,9 +70,9 @@ func PackPublicJWK(key crypto.PublicKey) (pub PublicJWK) {
|
||||||
// thumbprint keys are alphabetically sorted and only include the necessary public parts
|
// thumbprint keys are alphabetically sorted and only include the necessary public parts
|
||||||
switch k := key.(type) {
|
switch k := key.(type) {
|
||||||
case *rsa.PublicKey:
|
case *rsa.PublicKey:
|
||||||
pub = packPublicRSAJWK(k)
|
pub = marshalRSAPublicKey(k)
|
||||||
case *ecdsa.PublicKey:
|
case *ecdsa.PublicKey:
|
||||||
pub = packPublicECJWK(k)
|
pub = MarshalECPublicKey(k)
|
||||||
case *dsa.PublicKey:
|
case *dsa.PublicKey:
|
||||||
panic(EInvalidPublicKey)
|
panic(EInvalidPublicKey)
|
||||||
default:
|
default:
|
||||||
|
@ -81,17 +83,24 @@ func PackPublicJWK(key crypto.PublicKey) (pub PublicJWK) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func packPublicECJWK(k *ecdsa.PublicKey) (pub PublicJWK) {
|
func MarshalECPublicKey(k *ecdsa.PublicKey) PublicJWK {
|
||||||
|
pub := PublicJWK{}
|
||||||
|
pub.thumbprint = thumbstr(ThumbprintECPublicKey(k))
|
||||||
x := base64.RawURLEncoding.EncodeToString(k.X.Bytes())
|
x := base64.RawURLEncoding.EncodeToString(k.X.Bytes())
|
||||||
y := base64.RawURLEncoding.EncodeToString(k.Y.Bytes())
|
y := base64.RawURLEncoding.EncodeToString(k.Y.Bytes())
|
||||||
thumbprintable := fmt.Sprintf(`{"crv":%q,"kty":"EC","x":%q,"y":%q}`, k.Curve, x, y)
|
|
||||||
sha := sha256.Sum256([]byte(thumbprintable))
|
|
||||||
pub.thumbprint = thumbstr(base64.RawURLEncoding.EncodeToString(sha[:]))
|
|
||||||
pub.jwk = jwkstr(fmt.Sprintf(`{"kid":%q,"crv":%q,"kty":"EC","x":%q,"y":%q}`, pub.Thumbprint(), k.Curve, x, y))
|
pub.jwk = jwkstr(fmt.Sprintf(`{"kid":%q,"crv":%q,"kty":"EC","x":%q,"y":%q}`, pub.Thumbprint(), k.Curve, x, y))
|
||||||
return
|
return pub
|
||||||
}
|
}
|
||||||
|
|
||||||
func packPublicRSAJWK(k *rsa.PublicKey) (pub PublicJWK) {
|
func ThumbprintECPublicKey(k *ecdsa.PublicKey) string {
|
||||||
|
x := base64.RawURLEncoding.EncodeToString(k.X.Bytes())
|
||||||
|
y := base64.RawURLEncoding.EncodeToString(k.Y.Bytes())
|
||||||
|
thumbprintable := []byte(fmt.Sprintf(`{"crv":%q,"kty":"EC","x":%q,"y":%q}`, k.Curve, x, y))
|
||||||
|
sha := sha256.Sum256(thumbprintable)
|
||||||
|
return base64.RawURLEncoding.EncodeToString(sha[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalRSAPublicKey(k *rsa.PublicKey) (pub PublicJWK) {
|
||||||
e := base64.RawURLEncoding.EncodeToString(big.NewInt(int64(k.E)).Bytes())
|
e := base64.RawURLEncoding.EncodeToString(big.NewInt(int64(k.E)).Bytes())
|
||||||
n := base64.RawURLEncoding.EncodeToString(k.N.Bytes())
|
n := base64.RawURLEncoding.EncodeToString(k.N.Bytes())
|
||||||
thumbprintable := fmt.Sprintf(`{"e":%q,"kty":"RSA","n":%q}`, e, n)
|
thumbprintable := fmt.Sprintf(`{"e":%q,"kty":"RSA","n":%q}`, e, n)
|
||||||
|
@ -101,9 +110,9 @@ func packPublicRSAJWK(k *rsa.PublicKey) (pub PublicJWK) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParsePrivateKey(block []byte) (key PrivateKey, err error) {
|
func ParsePrivateKey(block []byte) (PrivateKey, error) {
|
||||||
var pemblock *pem.Block
|
var pemblock *pem.Block
|
||||||
var blocks [][]byte = make([][]byte, 1)
|
var blocks = make([][]byte, 0, 1)
|
||||||
|
|
||||||
// Parse the PEM, if it's a pem
|
// Parse the PEM, if it's a pem
|
||||||
for {
|
for {
|
||||||
|
@ -112,7 +121,8 @@ func ParsePrivateKey(block []byte) (key PrivateKey, err error) {
|
||||||
// got one block, there may be more
|
// got one block, there may be more
|
||||||
blocks = append(blocks, pemblock.Bytes)
|
blocks = append(blocks, pemblock.Bytes)
|
||||||
} else {
|
} else {
|
||||||
// the leftovers are not PEM blocks
|
// the last block was not a PEM block
|
||||||
|
// therefore the next isn't either
|
||||||
if 0 != len(block) {
|
if 0 != len(block) {
|
||||||
blocks = append(blocks, block)
|
blocks = append(blocks, block)
|
||||||
}
|
}
|
||||||
|
@ -120,83 +130,97 @@ func ParsePrivateKey(block []byte) (key PrivateKey, err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//fmt.Println("Blocks:")
|
||||||
|
//fmt.Println(blocks)
|
||||||
|
|
||||||
// Parse PEM blocks (openssl generates junk metadata blocks for ECs)
|
// Parse PEM blocks (openssl generates junk metadata blocks for ECs)
|
||||||
// or the original DER, or the JWK
|
// or the original DER, or the JWK
|
||||||
for i, _ := range blocks {
|
for i, _ := range blocks {
|
||||||
block = blocks[i]
|
block = blocks[i]
|
||||||
if key = parsePrivateKey(block); nil != key {
|
if key, err := parsePrivateKey(block); nil == err {
|
||||||
return
|
return key, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we didn't parse a key arleady, we failed
|
// If we didn't parse a key arleady, we failed
|
||||||
err = EParsePrivateKey
|
return nil, EParsePrivateKey
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parsePrivateKey(der []byte) (key PrivateKey) {
|
func parsePrivateKey(der []byte) (PrivateKey, error) {
|
||||||
xkey, _ := x509.ParsePKCS8PrivateKey(der)
|
var key PrivateKey
|
||||||
switch k := xkey.(type) {
|
|
||||||
case *rsa.PrivateKey:
|
|
||||||
key = k
|
|
||||||
case *ecdsa.PrivateKey:
|
|
||||||
key = k
|
|
||||||
default:
|
|
||||||
// ignore nil and unknown key types
|
|
||||||
}
|
|
||||||
|
|
||||||
key = xkey.(*rsa.PrivateKey)
|
xkey, err := x509.ParsePKCS8PrivateKey(der)
|
||||||
if nil == key {
|
if nil == err {
|
||||||
key, _ = x509.ParseECPrivateKey(der)
|
switch k := xkey.(type) {
|
||||||
if nil == key {
|
case *rsa.PrivateKey:
|
||||||
key, _ = x509.ParsePKCS1PrivateKey(der)
|
key = k
|
||||||
if nil == key {
|
case *ecdsa.PrivateKey:
|
||||||
key, _ = ParseJWKPrivateKey(der)
|
key = k
|
||||||
|
default:
|
||||||
|
// ignore nil and unknown key types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("1. ParsePKCS8PrivateKey")
|
||||||
|
|
||||||
|
if nil != err {
|
||||||
|
key, err = x509.ParseECPrivateKey(der)
|
||||||
|
fmt.Println("2. ParseECPrivateKey")
|
||||||
|
if nil != err {
|
||||||
|
key, err = x509.ParsePKCS1PrivateKey(der)
|
||||||
|
fmt.Println("3. ParsePKCS1PrivateKey")
|
||||||
|
if nil != err {
|
||||||
|
key, err = ParseJWKPrivateKey(der)
|
||||||
|
fmt.Println("4. ParseJWKPrivateKey")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
// But did you know?
|
||||||
|
// You must return nil explicitly for interfaces
|
||||||
|
// https://golang.org/doc/faq#nil_error
|
||||||
|
if nil != err {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseJWKPublicKey(b []byte) (key crypto.PublicKey, err error) {
|
func ParseJWKPublicKey(b []byte) (crypto.PublicKey, error) {
|
||||||
var m map[string]string
|
m := make(map[string]string)
|
||||||
err = json.Unmarshal(b, &m)
|
err := json.Unmarshal(b, &m)
|
||||||
if nil != err {
|
if nil != err {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch m["kty"] {
|
switch m["kty"] {
|
||||||
case "RSA":
|
case "RSA":
|
||||||
key, err = parsePublicRSAJWK(m)
|
return parseRSAPublicKey(m)
|
||||||
case "EC":
|
case "EC":
|
||||||
key, err = parsePublicECJWK(m)
|
return parseECPublicKey(m)
|
||||||
default:
|
default:
|
||||||
err = EInvalidKeyType
|
err = EInvalidKeyType
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseJWKPrivateKey(b []byte) (key PrivateKey, err error) {
|
func ParseJWKPrivateKey(b []byte) (PrivateKey, error) {
|
||||||
var m map[string]string
|
var m map[string]string
|
||||||
err = json.Unmarshal(b, &m)
|
if err := json.Unmarshal(b, &m); nil != err {
|
||||||
if nil != err {
|
return nil, err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch m["kty"] {
|
switch m["kty"] {
|
||||||
case "RSA":
|
case "RSA":
|
||||||
key, err = parsePrivateRSAJWK(m)
|
return parseRSAPrivateKey(m)
|
||||||
case "EC":
|
case "EC":
|
||||||
key, err = parsePrivateECJWK(m)
|
return parseECPrivateKey(m)
|
||||||
default:
|
default:
|
||||||
err = EInvalidKeyType
|
return nil, EInvalidKeyType
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parsePublicRSAJWK(m map[string]string) (pub *rsa.PublicKey, err error) {
|
func parseRSAPublicKey(m map[string]string) (pub *rsa.PublicKey, err error) {
|
||||||
n, _ := base64.RawURLEncoding.DecodeString(m["n"])
|
n, _ := base64.RawURLEncoding.DecodeString(m["n"])
|
||||||
e, _ := base64.RawURLEncoding.DecodeString(m["e"])
|
e, _ := base64.RawURLEncoding.DecodeString(m["e"])
|
||||||
if 0 == len(n) || 0 == len(e) {
|
if 0 == len(n) || 0 == len(e) {
|
||||||
|
@ -215,10 +239,10 @@ func parsePublicRSAJWK(m map[string]string) (pub *rsa.PublicKey, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func parsePrivateRSAJWK(m map[string]string) (key *rsa.PrivateKey, err error) {
|
func parseRSAPrivateKey(m map[string]string) (key *rsa.PrivateKey, err error) {
|
||||||
var pub *rsa.PublicKey
|
var pub *rsa.PublicKey
|
||||||
|
|
||||||
pub, err = parsePublicRSAJWK(m)
|
pub, err = parseRSAPublicKey(m)
|
||||||
if nil != err {
|
if nil != err {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -260,9 +284,9 @@ func parsePrivateRSAJWK(m map[string]string) (key *rsa.PrivateKey, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func parsePublicECJWK(m map[string]string) (pub *ecdsa.PublicKey, err error) {
|
func parseECPublicKey(m map[string]string) (pub *ecdsa.PublicKey, err error) {
|
||||||
x, _ := base64.RawURLEncoding.DecodeString(m["n"])
|
x, _ := base64.RawURLEncoding.DecodeString(m["x"])
|
||||||
y, _ := base64.RawURLEncoding.DecodeString(m["e"])
|
y, _ := base64.RawURLEncoding.DecodeString(m["y"])
|
||||||
if 0 == len(x) || 0 == len(y) || 0 == len(m["crv"]) {
|
if 0 == len(x) || 0 == len(y) || 0 == len(m["crv"]) {
|
||||||
return nil, EParseJWK
|
return nil, EParseJWK
|
||||||
}
|
}
|
||||||
|
@ -295,12 +319,10 @@ func parsePublicECJWK(m map[string]string) (pub *ecdsa.PublicKey, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func parsePrivateECJWK(m map[string]string) (key *ecdsa.PrivateKey, err error) {
|
func parseECPrivateKey(m map[string]string) (*ecdsa.PrivateKey, error) {
|
||||||
var pub *ecdsa.PublicKey
|
pub, err := parseECPublicKey(m)
|
||||||
|
|
||||||
pub, err = parsePublicECJWK(m)
|
|
||||||
if nil != err {
|
if nil != err {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
d, _ := base64.RawURLEncoding.DecodeString(m["d"])
|
d, _ := base64.RawURLEncoding.DecodeString(m["d"])
|
||||||
|
@ -310,10 +332,8 @@ func parsePrivateECJWK(m map[string]string) (key *ecdsa.PrivateKey, err error) {
|
||||||
di := &big.Int{}
|
di := &big.Int{}
|
||||||
di.SetBytes(d)
|
di.SetBytes(d)
|
||||||
|
|
||||||
key = &ecdsa.PrivateKey{
|
return &ecdsa.PrivateKey{
|
||||||
PublicKey: *pub,
|
PublicKey: *pub,
|
||||||
D: di,
|
D: di,
|
||||||
}
|
}, nil
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package keypairs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLoadECJWK(t *testing.T) {
|
||||||
|
// TODO package all fixtures with fileb0x
|
||||||
|
keypaths := []string{
|
||||||
|
"fixtures/privkey-ec-p256.jwk.json",
|
||||||
|
"fixtures/privkey-ec-p256.sec1.pem", // has openssl EC Param block
|
||||||
|
"fixtures/privkey-ec-p256.pkcs8.pem",
|
||||||
|
"fixtures/privkey-ec-p384.jwk.json",
|
||||||
|
"fixtures/privkey-ec-p384.sec1.pem",
|
||||||
|
"fixtures/privkey-ec-p384.pkcs8.pem",
|
||||||
|
}
|
||||||
|
for i := range keypaths {
|
||||||
|
path := keypaths[i]
|
||||||
|
fmt.Println("\n", path)
|
||||||
|
b, err := ioutil.ReadFile(path)
|
||||||
|
if nil != err {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := ParsePrivateKey(b)
|
||||||
|
if nil != err {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
eckey := key.(*ecdsa.PrivateKey)
|
||||||
|
thumb := ThumbprintECPublicKey(eckey.Public().(*ecdsa.PublicKey))
|
||||||
|
fmt.Println(thumb)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue