keypairs/keypairs.go

340 řádky
7.7 KiB
Go
Surový Normální zobrazení Historie

2019-02-07 01:10:30 +00:00
package keypairs
import (
"crypto"
"crypto/dsa"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"math/big"
)
2019-02-07 01:31:48 +00:00
var EInvalidPrivateKey = errors.New("PrivateKey must be of type rsa.PrivateKey or ecdsa.PrivateKey")
var EInvalidPublicKey = errors.New("PublicKey must be of type rsa.PublicKey or ecdsa.PublicKey")
var EParsePrivateKey = errors.New("PrivateKey bytes could not be parsed as PEM or DER (PKCS8, SEC1, or PKCS1) or JWK")
var EParseJWK = errors.New("JWK is missing required base64-encoded JSON fields")
var EInvalidKeyType = errors.New("The JWK's 'kty' must be either 'RSA' or 'EC'")
var EInvalidCurve = errors.New("The JWK's 'crv' must be either of the NIST standards 'P-256' or 'P-384'")
2019-02-07 01:10:30 +00:00
const (
Private KeyPrivacy = 1 << iota
Public
)
const (
EC KeyType = 1 << iota
RSA
)
type KeyType uint
type KeyPrivacy uint
// PrivateKey acts as the missing would-be interface crypto.PrivateKey
type PrivateKey interface {
Public() crypto.PublicKey
}
// JWK is to be used where either a public or private key may exist
type Key interface {
Privacy() KeyPrivacy
Type() KeyType
}
type PublicJWK struct {
// TODO PEM Fingerprint
//BareJWK string `json:"-"`
thumbprint thumbstr `json:"thumbprint"`
jwk jwkstr `json:"jwk"`
2019-02-07 19:30:04 +00:00
x string
y string
2019-02-07 01:10:30 +00:00
}
func (p *PublicJWK) Thumbprint() string {
return string(p.thumbprint)
}
func (p *PublicJWK) JWK() string {
return string(p.jwk)
}
type thumbstr string
type jwkstr string
2019-02-07 01:31:48 +00:00
func PackPublicJWK(key crypto.PublicKey) (pub PublicJWK) {
2019-02-07 01:10:30 +00:00
// thumbprint keys are alphabetically sorted and only include the necessary public parts
switch k := key.(type) {
case *rsa.PublicKey:
2019-02-07 19:30:04 +00:00
pub = marshalRSAPublicKey(k)
2019-02-07 01:10:30 +00:00
case *ecdsa.PublicKey:
2019-02-07 19:30:04 +00:00
pub = MarshalECPublicKey(k)
2019-02-07 01:10:30 +00:00
case *dsa.PublicKey:
panic(EInvalidPublicKey)
default:
// this is unreachable because we know the types that we pass in
panic(EInvalidPublicKey)
}
return
}
2019-02-07 19:30:04 +00:00
func MarshalECPublicKey(k *ecdsa.PublicKey) PublicJWK {
pub := PublicJWK{}
pub.thumbprint = thumbstr(ThumbprintECPublicKey(k))
2019-02-07 01:31:48 +00:00
x := base64.RawURLEncoding.EncodeToString(k.X.Bytes())
y := base64.RawURLEncoding.EncodeToString(k.Y.Bytes())
pub.jwk = jwkstr(fmt.Sprintf(`{"kid":%q,"crv":%q,"kty":"EC","x":%q,"y":%q}`, pub.Thumbprint(), k.Curve, x, y))
2019-02-07 19:30:04 +00:00
return pub
}
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[:])
2019-02-07 01:31:48 +00:00
}
2019-02-07 19:30:04 +00:00
func marshalRSAPublicKey(k *rsa.PublicKey) (pub PublicJWK) {
2019-02-07 01:31:48 +00:00
e := base64.RawURLEncoding.EncodeToString(big.NewInt(int64(k.E)).Bytes())
n := base64.RawURLEncoding.EncodeToString(k.N.Bytes())
thumbprintable := fmt.Sprintf(`{"e":%q,"kty":"RSA","n":%q}`, e, n)
sha := sha256.Sum256([]byte(thumbprintable))
pub.thumbprint = thumbstr(base64.RawURLEncoding.EncodeToString(sha[:]))
pub.jwk = jwkstr(fmt.Sprintf(`{"kid":%q,"e":%q,"kty":"RSA","n":%q}`, pub.Thumbprint(), e, n))
return
}
2019-02-07 01:10:30 +00:00
2019-02-07 19:30:04 +00:00
func ParsePrivateKey(block []byte) (PrivateKey, error) {
2019-02-07 01:10:30 +00:00
var pemblock *pem.Block
2019-02-07 19:30:04 +00:00
var blocks = make([][]byte, 0, 1)
2019-02-07 01:10:30 +00:00
// Parse the PEM, if it's a pem
for {
pemblock, block = pem.Decode(block)
if nil != pemblock {
// got one block, there may be more
blocks = append(blocks, pemblock.Bytes)
} else {
2019-02-07 19:30:04 +00:00
// the last block was not a PEM block
// therefore the next isn't either
2019-02-07 01:10:30 +00:00
if 0 != len(block) {
blocks = append(blocks, block)
}
break
}
}
2019-02-07 19:30:04 +00:00
//fmt.Println("Blocks:")
//fmt.Println(blocks)
2019-02-07 01:10:30 +00:00
// Parse PEM blocks (openssl generates junk metadata blocks for ECs)
// or the original DER, or the JWK
for i, _ := range blocks {
block = blocks[i]
2019-02-07 19:30:04 +00:00
if key, err := parsePrivateKey(block); nil == err {
return key, nil
2019-02-07 01:10:30 +00:00
}
}
// If we didn't parse a key arleady, we failed
2019-02-07 19:30:04 +00:00
return nil, EParsePrivateKey
2019-02-07 01:10:30 +00:00
}
2019-02-07 19:30:04 +00:00
func parsePrivateKey(der []byte) (PrivateKey, error) {
var key PrivateKey
xkey, err := x509.ParsePKCS8PrivateKey(der)
if nil == err {
switch k := xkey.(type) {
case *rsa.PrivateKey:
key = k
case *ecdsa.PrivateKey:
key = k
default:
// ignore nil and unknown key types
}
2019-02-07 01:10:30 +00:00
}
2019-02-07 19:30:04 +00:00
fmt.Println("1. ParsePKCS8PrivateKey")
2019-02-07 01:10:30 +00:00
2019-02-07 19:30:04 +00:00
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")
2019-02-07 01:10:30 +00:00
}
}
}
2019-02-07 19:30:04 +00:00
// 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
2019-02-07 01:10:30 +00:00
}
2019-02-07 19:30:04 +00:00
func ParseJWKPublicKey(b []byte) (crypto.PublicKey, error) {
m := make(map[string]string)
err := json.Unmarshal(b, &m)
2019-02-07 01:31:48 +00:00
if nil != err {
2019-02-07 19:30:04 +00:00
return nil, err
2019-02-07 01:31:48 +00:00
}
switch m["kty"] {
case "RSA":
2019-02-07 19:30:04 +00:00
return parseRSAPublicKey(m)
2019-02-07 01:31:48 +00:00
case "EC":
2019-02-07 19:30:04 +00:00
return parseECPublicKey(m)
2019-02-07 01:31:48 +00:00
default:
err = EInvalidKeyType
}
2019-02-07 19:30:04 +00:00
return nil, err
2019-02-07 01:31:48 +00:00
}
2019-02-07 19:30:04 +00:00
func ParseJWKPrivateKey(b []byte) (PrivateKey, error) {
2019-02-07 01:10:30 +00:00
var m map[string]string
2019-02-07 19:30:04 +00:00
if err := json.Unmarshal(b, &m); nil != err {
return nil, err
2019-02-07 01:10:30 +00:00
}
switch m["kty"] {
case "RSA":
2019-02-07 19:30:04 +00:00
return parseRSAPrivateKey(m)
2019-02-07 01:10:30 +00:00
case "EC":
2019-02-07 19:30:04 +00:00
return parseECPrivateKey(m)
2019-02-07 01:10:30 +00:00
default:
2019-02-07 19:30:04 +00:00
return nil, EInvalidKeyType
2019-02-07 01:10:30 +00:00
}
}
2019-02-07 19:30:04 +00:00
func parseRSAPublicKey(m map[string]string) (pub *rsa.PublicKey, err error) {
2019-02-07 01:10:30 +00:00
n, _ := base64.RawURLEncoding.DecodeString(m["n"])
e, _ := base64.RawURLEncoding.DecodeString(m["e"])
if 0 == len(n) || 0 == len(e) {
2019-02-07 01:31:48 +00:00
err = EParseJWK
return
2019-02-07 01:10:30 +00:00
}
ni := &big.Int{}
ni.SetBytes(n)
ei := &big.Int{}
ei.SetBytes(e)
2019-02-07 01:31:48 +00:00
pub = &rsa.PublicKey{
2019-02-07 01:10:30 +00:00
N: ni,
E: int(ei.Int64()),
}
2019-02-07 01:31:48 +00:00
return
}
2019-02-07 19:30:04 +00:00
func parseRSAPrivateKey(m map[string]string) (key *rsa.PrivateKey, err error) {
2019-02-07 01:31:48 +00:00
var pub *rsa.PublicKey
2019-02-07 19:30:04 +00:00
pub, err = parseRSAPublicKey(m)
2019-02-07 01:31:48 +00:00
if nil != err {
return
}
2019-02-07 01:10:30 +00:00
d, _ := base64.RawURLEncoding.DecodeString(m["d"])
p, _ := base64.RawURLEncoding.DecodeString(m["p"])
q, _ := base64.RawURLEncoding.DecodeString(m["q"])
dp, _ := base64.RawURLEncoding.DecodeString(m["dp"])
dq, _ := base64.RawURLEncoding.DecodeString(m["dq"])
qinv, _ := base64.RawURLEncoding.DecodeString(m["qi"])
if 0 == len(d) || 0 == len(p) || 0 == len(dp) || 0 == len(dq) || 0 == len(qinv) {
return nil, EParseJWK
}
di := &big.Int{}
di.SetBytes(d)
pi := &big.Int{}
pi.SetBytes(p)
qi := &big.Int{}
qi.SetBytes(q)
dpi := &big.Int{}
dpi.SetBytes(dp)
dqi := &big.Int{}
dqi.SetBytes(dq)
qinvi := &big.Int{}
qinvi.SetBytes(qinv)
key = &rsa.PrivateKey{
2019-02-07 01:31:48 +00:00
PublicKey: *pub,
2019-02-07 01:10:30 +00:00
D: di,
Primes: []*big.Int{pi, qi},
Precomputed: rsa.PrecomputedValues{
Dp: dpi,
Dq: dqi,
Qinv: qinvi,
},
}
return
}
2019-02-07 19:30:04 +00:00
func parseECPublicKey(m map[string]string) (pub *ecdsa.PublicKey, err error) {
x, _ := base64.RawURLEncoding.DecodeString(m["x"])
y, _ := base64.RawURLEncoding.DecodeString(m["y"])
2019-02-07 01:10:30 +00:00
if 0 == len(x) || 0 == len(y) || 0 == len(m["crv"]) {
return nil, EParseJWK
}
xi := &big.Int{}
xi.SetBytes(x)
yi := &big.Int{}
yi.SetBytes(y)
var crv elliptic.Curve
switch m["crv"] {
case "P-256":
crv = elliptic.P256()
case "P-384":
crv = elliptic.P384()
case "P-521":
crv = elliptic.P521()
default:
err = EInvalidCurve
return
}
2019-02-07 01:31:48 +00:00
pub = &ecdsa.PublicKey{
2019-02-07 01:10:30 +00:00
Curve: crv,
X: xi,
Y: yi,
}
2019-02-07 01:31:48 +00:00
return
}
2019-02-07 19:30:04 +00:00
func parseECPrivateKey(m map[string]string) (*ecdsa.PrivateKey, error) {
pub, err := parseECPublicKey(m)
2019-02-07 01:31:48 +00:00
if nil != err {
2019-02-07 19:30:04 +00:00
return nil, err
2019-02-07 01:31:48 +00:00
}
2019-02-07 01:10:30 +00:00
d, _ := base64.RawURLEncoding.DecodeString(m["d"])
if 0 == len(d) {
return nil, EParseJWK
}
di := &big.Int{}
di.SetBytes(d)
2019-02-07 19:30:04 +00:00
return &ecdsa.PrivateKey{
2019-02-07 01:31:48 +00:00
PublicKey: *pub,
2019-02-07 01:10:30 +00:00
D: di,
2019-02-07 19:30:04 +00:00
}, nil
2019-02-07 01:10:30 +00:00
}