This commit is contained in:
AJ ONeal 2019-02-07 21:19:37 +00:00
parent 4afb5dc4cb
commit db7dcc62b4
1 changed files with 24 additions and 60 deletions

View File

@ -23,64 +23,24 @@ 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'")
var EInvalidCurve = errors.New("The JWK's 'crv' must be either of the NIST standards 'P-256' or 'P-384'") var EInvalidCurve = errors.New("The JWK's 'crv' must be either of the NIST standards 'P-256' or 'P-384'")
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 // PrivateKey acts as the missing would-be interface crypto.PrivateKey
type PrivateKey interface { type PrivateKey interface {
Public() crypto.PublicKey Public() crypto.PublicKey
} }
// JWK is to be used where either a public or private key may exist func MarshalPublicJWK(key crypto.PublicKey) []byte {
type Key interface {
Privacy() KeyPrivacy
Type() KeyType
}
type PublicJWK struct {
// TODO PEM Fingerprint
//BareJWK string `json:"-"`
thumbprint thumbstr `json:"thumbprint"`
jwk jwkstr `json:"jwk"`
x string
y string
}
func (p *PublicJWK) Thumbprint() string {
return string(p.thumbprint)
}
func (p *PublicJWK) JWK() string {
return string(p.jwk)
}
type thumbstr string
type jwkstr string
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 = MarshalRSAPublicKey(k) return MarshalRSAPublicKey(k)
case *ecdsa.PublicKey: case *ecdsa.PublicKey:
pub = MarshalECPublicKey(k) return MarshalECPublicKey(k)
case *dsa.PublicKey: case *dsa.PublicKey:
panic(EInvalidPublicKey) panic(EInvalidPublicKey)
default: default:
// this is unreachable because we know the types that we pass in // this is unreachable because we know the types that we pass in
panic(EInvalidPublicKey) panic(EInvalidPublicKey)
} }
return
} }
func ThumbprintPublicKey(pub crypto.PublicKey) string { func ThumbprintPublicKey(pub crypto.PublicKey) string {
@ -94,38 +54,42 @@ func ThumbprintPublicKey(pub crypto.PublicKey) string {
} }
} }
func MarshalECPublicKey(k *ecdsa.PublicKey) PublicJWK { func MarshalECPublicKey(k *ecdsa.PublicKey) []byte {
pub := PublicJWK{} thumb := ThumbprintECPublicKey(k)
pub.thumbprint = thumbstr(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())
pub.jwk = jwkstr(fmt.Sprintf(`{"kid":%q,"crv":%q,"kty":"EC","x":%q,"y":%q}`, pub.Thumbprint(), crv, x, y)) return []byte(fmt.Sprintf(`{"kid":%q,"crv":%q,"kty":"EC","x":%q,"y":%q}`, thumb, crv, x, y))
return pub }
func MarshalECPublicKeyWithoutKeyID(k *ecdsa.PublicKey) []byte {
crv := k.Curve.Params().Name
x := base64.RawURLEncoding.EncodeToString(k.X.Bytes())
y := base64.RawURLEncoding.EncodeToString(k.Y.Bytes())
return []byte(fmt.Sprintf(`{"crv":%q,"kty":"EC","x":%q,"y":%q}`, crv, x, y))
} }
func ThumbprintECPublicKey(k *ecdsa.PublicKey) string { func ThumbprintECPublicKey(k *ecdsa.PublicKey) string {
crv := k.Curve.Params().Name thumbprintable := MarshalECPublicKeyWithoutKeyID(k)
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}`, crv, x, y))
sha := sha256.Sum256(thumbprintable) sha := sha256.Sum256(thumbprintable)
return base64.RawURLEncoding.EncodeToString(sha[:]) return base64.RawURLEncoding.EncodeToString(sha[:])
} }
func MarshalRSAPublicKey(p *rsa.PublicKey) PublicJWK { func MarshalRSAPublicKey(p *rsa.PublicKey) []byte {
pub := PublicJWK{} thumb := ThumbprintRSAPublicKey(p)
pub.thumbprint = thumbstr(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())
pub.jwk = jwkstr(fmt.Sprintf(`{"kid":%q,"e":%q,"kty":"RSA","n":%q}`, pub.Thumbprint(), e, n)) return []byte(fmt.Sprintf(`{"kid":%q,"e":%q,"kty":"RSA","n":%q}`, thumb, e, n))
return pub }
func MarshalRSAPublicKeyWithoutKeyID(p *rsa.PublicKey) []byte {
e := base64.RawURLEncoding.EncodeToString(big.NewInt(int64(p.E)).Bytes())
n := base64.RawURLEncoding.EncodeToString(p.N.Bytes())
return []byte(fmt.Sprintf(`{"e":%q,"kty":"RSA","n":%q}`, e, n))
} }
func ThumbprintRSAPublicKey(p *rsa.PublicKey) string { func ThumbprintRSAPublicKey(p *rsa.PublicKey) string {
e := base64.RawURLEncoding.EncodeToString(big.NewInt(int64(p.E)).Bytes()) thumbprintable := MarshalRSAPublicKeyWithoutKeyID(p)
n := base64.RawURLEncoding.EncodeToString(p.N.Bytes())
thumbprintable := fmt.Sprintf(`{"e":%q,"kty":"RSA","n":%q}`, e, n)
sha := sha256.Sum256([]byte(thumbprintable)) sha := sha256.Sum256([]byte(thumbprintable))
return base64.RawURLEncoding.EncodeToString(sha[:]) return base64.RawURLEncoding.EncodeToString(sha[:])
} }