thinner wrapping, add exp to jwk

This commit is contained in:
AJ ONeal 2019-02-09 00:43:50 +00:00
parent 517865f334
commit 84b07108b6
1 changed files with 25 additions and 12 deletions

View File

@ -19,8 +19,8 @@ import (
"time" "time"
) )
var EInvalidPrivateKey = errors.New("PrivateKey must be of type rsa.PrivateKey or ecdsa.PrivateKey") 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 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 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 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 EInvalidKeyType = errors.New("The JWK's 'kty' must be either 'RSA' or 'EC'")
@ -60,15 +60,22 @@ func (p *ECPublicKey) Thumbprint() string {
func (p *ECPublicKey) Key() crypto.PublicKey { func (p *ECPublicKey) Key() crypto.PublicKey {
return p.PublicKey return p.PublicKey
} }
func (p *ECPublicKey) ExpireAt(t time.Time) {
p.Expiry = t
}
func (p *RSAPublicKey) Thumbprint() string { func (p *RSAPublicKey) Thumbprint() string {
return ThumbprintUntypedPublicKey(p.PublicKey) return ThumbprintUntypedPublicKey(p.PublicKey)
} }
func (p *RSAPublicKey) Key() crypto.PublicKey { func (p *RSAPublicKey) Key() crypto.PublicKey {
return p.PublicKey return p.PublicKey
} }
func (p *RSAPublicKey) ExpireAt(t time.Time) {
p.Expiry = t
}
// TypesafePublicKey wraps a crypto.PublicKey to make it typesafe. // TypesafePublicKey wraps a crypto.PublicKey to make it typesafe.
func NewPublicKey(pub crypto.PublicKey, exp time.Time, kid ...string) PublicKey { func NewPublicKey(pub crypto.PublicKey, kid ...string) PublicKey {
var k PublicKey var k PublicKey
switch p := pub.(type) { switch p := pub.(type) {
case *ecdsa.PublicKey: case *ecdsa.PublicKey:
@ -80,7 +87,6 @@ func NewPublicKey(pub crypto.PublicKey, exp time.Time, kid ...string) PublicKey
} else { } else {
eckey.KID = k.Thumbprint() eckey.KID = k.Thumbprint()
} }
eckey.Expiry = exp
k = eckey k = eckey
case *rsa.PublicKey: case *rsa.PublicKey:
rsakey := &RSAPublicKey{ rsakey := &RSAPublicKey{
@ -91,7 +97,6 @@ func NewPublicKey(pub crypto.PublicKey, exp time.Time, kid ...string) PublicKey
} else { } else {
rsakey.KID = k.Thumbprint() rsakey.KID = k.Thumbprint()
} }
rsakey.Expiry = exp
k = rsakey k = rsakey
case *ecdsa.PrivateKey: case *ecdsa.PrivateKey:
panic(errors.New(EDevSwapPrivatePublic)) panic(errors.New(EDevSwapPrivatePublic))
@ -108,13 +113,13 @@ func NewPublicKey(pub crypto.PublicKey, exp time.Time, kid ...string) PublicKey
return k return k
} }
func MarshalJWKPublicKey(key PublicKey) []byte { func MarshalJWKPublicKey(key PublicKey, exp ...time.Time) []byte {
// 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.Key().(type) { switch k := key.Key().(type) {
case *rsa.PublicKey: case *rsa.PublicKey:
return MarshalRSAPublicKey(k) return MarshalRSAPublicKey(k, exp...)
case *ecdsa.PublicKey: case *ecdsa.PublicKey:
return MarshalECPublicKey(k) return MarshalECPublicKey(k, exp...)
case *dsa.PublicKey: case *dsa.PublicKey:
panic(EInvalidPublicKey) panic(EInvalidPublicKey)
default: default:
@ -139,12 +144,16 @@ func ThumbprintUntypedPublicKey(pub crypto.PublicKey) string {
} }
} }
func MarshalECPublicKey(k *ecdsa.PublicKey) []byte { func MarshalECPublicKey(k *ecdsa.PublicKey, exp ...time.Time) []byte {
thumb := ThumbprintECPublicKey(k) thumb := ThumbprintECPublicKey(k)
crv := k.Curve.Params().Name crv := k.Curve.Params().Name
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())
return []byte(fmt.Sprintf(`{"kid":%q,"crv":%q,"kty":"EC","x":%q,"y":%q}`, thumb, crv, x, y)) expstr := ""
if 0 != len(exp) {
expstr = fmt.Sprintf(`"exp":%q,`, exp[0].Format(time.RFC3339))
}
return []byte(fmt.Sprintf(`{"kid":%q,%s"crv":%q,"kty":"EC","x":%q,"y":%q}`, expstr, thumb, crv, x, y))
} }
func MarshalECPublicKeyWithoutKeyID(k *ecdsa.PublicKey) []byte { func MarshalECPublicKeyWithoutKeyID(k *ecdsa.PublicKey) []byte {
@ -160,11 +169,15 @@ func ThumbprintECPublicKey(k *ecdsa.PublicKey) string {
return base64.RawURLEncoding.EncodeToString(sha[:]) return base64.RawURLEncoding.EncodeToString(sha[:])
} }
func MarshalRSAPublicKey(p *rsa.PublicKey) []byte { func MarshalRSAPublicKey(p *rsa.PublicKey, exp ...time.Time) []byte {
thumb := ThumbprintRSAPublicKey(p) thumb := ThumbprintRSAPublicKey(p)
e := base64.RawURLEncoding.EncodeToString(big.NewInt(int64(p.E)).Bytes()) e := base64.RawURLEncoding.EncodeToString(big.NewInt(int64(p.E)).Bytes())
n := base64.RawURLEncoding.EncodeToString(p.N.Bytes()) n := base64.RawURLEncoding.EncodeToString(p.N.Bytes())
return []byte(fmt.Sprintf(`{"kid":%q,"e":%q,"kty":"RSA","n":%q}`, thumb, e, n)) expstr := ""
if 0 != len(exp) {
expstr = fmt.Sprintf(`"exp":%q,`, exp[0].Format(time.RFC3339))
}
return []byte(fmt.Sprintf(`{"kid":%q,%s"e":%q,"kty":"RSA","n":%q}`, expstr, thumb, e, n))
} }
func MarshalRSAPublicKeyWithoutKeyID(p *rsa.PublicKey) []byte { func MarshalRSAPublicKeyWithoutKeyID(p *rsa.PublicKey) []byte {