go lint and update docs
This commit is contained in:
parent
78847a9cfd
commit
8f66f1d235
58
README.md
58
README.md
|
@ -1,54 +1,53 @@
|
||||||
# go-keypairs
|
# go-keypairs
|
||||||
|
|
||||||
The lightest touch over top of Go's `crypto/ecdsa` and `crypto/rsa` to make them
|
JSON Web Key (JWK) support and type safety lightly placed over top of Go's `crypto/ecdsa` and `crypto/rsa`
|
||||||
*typesafe* and to provide JSON Web Key (JWK) support.
|
|
||||||
|
|
||||||
# Documentation
|
Useful for JWT, JOSE, etc.
|
||||||
|
|
||||||
Use the source, Luke!
|
```go
|
||||||
|
key, err := keypairs.ParsePrivateKey(bytesForJWKOrPEMOrDER)
|
||||||
|
|
||||||
<https://godoc.org/github.com/big-squid/go-keypairs>
|
pub, err := keypairs.ParsePublicKey(bytesForJWKOrPEMOrDER)
|
||||||
|
|
||||||
|
jwk, err := keypairs.MarshalJWKPublicKey(pub, time.Now().Add(2 * time.Day))
|
||||||
|
|
||||||
|
kid, err := keypairs.ThumbprintPublicKey(pub)
|
||||||
|
```
|
||||||
|
|
||||||
|
# API Documentation
|
||||||
|
|
||||||
|
See <https://godoc.org/github.com/big-squid/go-keypairs>
|
||||||
|
|
||||||
# Philosophy
|
# Philosophy
|
||||||
|
|
||||||
Always remember:
|
Go's standard library is great.
|
||||||
|
|
||||||
> Don't roll your own crypto.
|
Go has _excellent_ crytography support and provides wonderful
|
||||||
|
primitives for dealing with them.
|
||||||
|
|
||||||
But also remember:
|
I prefer to stay as close to Go's `crypto` package as possible,
|
||||||
|
just adding a light touch for JWT support and type safety.
|
||||||
> Just because you _don't_ know someone doesn't make them smart.
|
|
||||||
|
|
||||||
Don't get the two mixed up!
|
|
||||||
|
|
||||||
(furthermore, [just because you _do_ know someone doesn't make them _not_ smart](https://www.humancondition.com/asid-prophets-without-honour-in-their-own-home/))
|
|
||||||
|
|
||||||
Although I would **not** want to invent my own cryptographic algorithm,
|
|
||||||
I've read enough source code to know that, for standards I know well,
|
|
||||||
I feel much more confident in the security, extensibility, and documentation
|
|
||||||
of tooling that I've write myself.
|
|
||||||
|
|
||||||
# Type Safety
|
# Type Safety
|
||||||
|
|
||||||
Go has _excellent_ crytography support and provides wonderful
|
`crypto.PublicKey` is a "marker interface", meaning that it is **not typesafe**!
|
||||||
primitives for dealing with them. Its Achilles' heel is they're **not typesafe**!
|
|
||||||
|
|
||||||
As of Go 1.11.5 `crypto.PublicKey` and `crypto.PrivateKey` are "marker interfaces"
|
`go-keypairs` defines `type keypairs.PrivateKey interface { Public() crypto.PublicKey }`,
|
||||||
or, in other words, empty interfaces that only serve to document intent without
|
|
||||||
actually providing a constraint to the type system.
|
|
||||||
|
|
||||||
go-keypairs defines `type keypairs.PrivateKey interface { Public() crypto.PublicKey }`,
|
|
||||||
which is implemented by `crypto/rsa` and `crypto/ecdsa`
|
which is implemented by `crypto/rsa` and `crypto/ecdsa`
|
||||||
(but not `crypto/dsa`, which we really don't care that much about).
|
(but not `crypto/dsa`, which we really don't care that much about).
|
||||||
|
|
||||||
|
Go1.15 will add `[PublicKey.Equal(crypto.PublicKey)](https://github.com/golang/go/issues/21704)`,
|
||||||
|
which will make it possible to remove the additional wrapper over `PublicKey`
|
||||||
|
and use an interface instead.
|
||||||
|
|
||||||
Since there are no common methods between `rsa.PublicKey` and `ecdsa.PublicKey`,
|
Since there are no common methods between `rsa.PublicKey` and `ecdsa.PublicKey`,
|
||||||
go-keypairs lightly wraps each to implement `Thumbprint() string` (part of the JOSE/JWK spec).
|
go-keypairs lightly wraps each to implement `Thumbprint() string` (part of the JOSE/JWK spec).
|
||||||
|
|
||||||
# JSON Web Key "codec"
|
## JSON Web Key (JWK) as a "codec"
|
||||||
|
|
||||||
Although there are many, many ways that JWKs could be interpreted
|
Although there are many, many ways that JWKs could be interpreted
|
||||||
(possibly why they haven't made it into the standard library), go-keypairs
|
(possibly why they haven't made it into the standard library), `go-keypairs`
|
||||||
follows the basic pattern of `encoding/x509` to Parse and Marshal
|
follows the basic pattern of `encoding/x509` to `Parse` and `Marshal`
|
||||||
only the most basic and most meaningful parts of a key.
|
only the most basic and most meaningful parts of a key.
|
||||||
|
|
||||||
I highly recommend that you use `Thumbprint()` for `KeyID` you also
|
I highly recommend that you use `Thumbprint()` for `KeyID` you also
|
||||||
|
@ -57,6 +56,7 @@ between the ASN.1, x509, PEM, and JWK formats.
|
||||||
|
|
||||||
# LICENSE
|
# LICENSE
|
||||||
|
|
||||||
|
Copyright (c) 2020-present AJ ONeal
|
||||||
Copyright (c) 2018-2019 Big Squid, Inc.
|
Copyright (c) 2018-2019 Big Squid, Inc.
|
||||||
|
|
||||||
This work is licensed under the terms of the MIT license.
|
This work is licensed under the terms of the MIT license.
|
||||||
|
|
|
@ -23,11 +23,23 @@ import (
|
||||||
"github.com/big-squid/go-keypairs/keyfetch/uncached"
|
"github.com/big-squid/go-keypairs/keyfetch/uncached"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO should be ErrInvalidJWKURL
|
||||||
|
|
||||||
|
// EInvalidJWKURL means that the url did not provide JWKs
|
||||||
var EInvalidJWKURL = errors.New("url does not lead to valid JWKs")
|
var EInvalidJWKURL = errors.New("url does not lead to valid JWKs")
|
||||||
|
|
||||||
|
// KeyCache is an in-memory key cache
|
||||||
var KeyCache = map[string]CachableKey{}
|
var KeyCache = map[string]CachableKey{}
|
||||||
|
|
||||||
|
// KeyCacheMux is used to guard the in-memory cache
|
||||||
var KeyCacheMux = sync.Mutex{}
|
var KeyCacheMux = sync.Mutex{}
|
||||||
|
|
||||||
|
// ErrInsecureDomain means that plain http was used where https was expected
|
||||||
var ErrInsecureDomain = errors.New("Whitelists should only allow secure URLs (i.e. https://). To allow unsecured private networking (i.e. Docker) pass PrivateWhitelist as a list of private URLs")
|
var ErrInsecureDomain = errors.New("Whitelists should only allow secure URLs (i.e. https://). To allow unsecured private networking (i.e. Docker) pass PrivateWhitelist as a list of private URLs")
|
||||||
|
|
||||||
|
// TODO Cacheable key (shouldn't this be private)?
|
||||||
|
|
||||||
|
// CachableKey represents
|
||||||
type CachableKey struct {
|
type CachableKey struct {
|
||||||
Key keypairs.PublicKey
|
Key keypairs.PublicKey
|
||||||
Expiry time.Time
|
Expiry time.Time
|
||||||
|
@ -55,50 +67,64 @@ type ID interface {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// StaleTime defines when public keys should be renewed (15 minutes by default)
|
||||||
var StaleTime = 15 * time.Minute
|
var StaleTime = 15 * time.Minute
|
||||||
|
|
||||||
|
// DefaultKeyDuration defines how long a key should be considered fresh (48 hours by default)
|
||||||
var DefaultKeyDuration = 48 * time.Hour
|
var DefaultKeyDuration = 48 * time.Hour
|
||||||
|
|
||||||
|
// MinimumKeyDuration defines the minimum time that a key will be cached (1 hour by default)
|
||||||
var MinimumKeyDuration = time.Hour
|
var MinimumKeyDuration = time.Hour
|
||||||
|
|
||||||
|
// MaximumKeyDuration defines the maximum time that a key will be cached (72 hours by default)
|
||||||
var MaximumKeyDuration = 72 * time.Hour
|
var MaximumKeyDuration = 72 * time.Hour
|
||||||
|
|
||||||
type publicKeysMap map[string]keypairs.PublicKey
|
// PublicKeysMap is a newtype for a map of keypairs.PublicKey
|
||||||
|
type PublicKeysMap map[string]keypairs.PublicKey
|
||||||
|
|
||||||
// FetchOIDCPublicKeys fetches baseURL + ".well-known/openid-configuration" and then returns FetchPublicKeys(jwks_uri).
|
// OIDCJWKs fetches baseURL + ".well-known/openid-configuration" and then fetches and returns the Public Keys.
|
||||||
func OIDCJWKs(baseURL string) (publicKeysMap, error) {
|
func OIDCJWKs(baseURL string) (PublicKeysMap, error) {
|
||||||
if maps, keys, err := uncached.OIDCJWKs(baseURL); nil != err {
|
maps, keys, err := uncached.OIDCJWKs(baseURL)
|
||||||
|
|
||||||
|
if nil != err {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
}
|
||||||
cacheKeys(maps, keys, baseURL)
|
cacheKeys(maps, keys, baseURL)
|
||||||
return keys, err
|
return keys, err
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OIDCJWK fetches baseURL + ".well-known/openid-configuration" and then returns the key matching kid (or thumbprint)
|
||||||
func OIDCJWK(kidOrThumb, iss string) (keypairs.PublicKey, error) {
|
func OIDCJWK(kidOrThumb, iss string) (keypairs.PublicKey, error) {
|
||||||
return immediateOneOrFetch(kidOrThumb, iss, uncached.OIDCJWKs)
|
return immediateOneOrFetch(kidOrThumb, iss, uncached.OIDCJWKs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func WellKnownJWKs(kidOrThumb, iss string) (publicKeysMap, error) {
|
// WellKnownJWKs fetches baseURL + ".well-known/jwks.json" and caches and returns the keys
|
||||||
if maps, keys, err := uncached.WellKnownJWKs(iss); nil != err {
|
func WellKnownJWKs(kidOrThumb, iss string) (PublicKeysMap, error) {
|
||||||
|
maps, keys, err := uncached.WellKnownJWKs(iss)
|
||||||
|
|
||||||
|
if nil != err {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
}
|
||||||
cacheKeys(maps, keys, iss)
|
cacheKeys(maps, keys, iss)
|
||||||
return keys, err
|
return keys, err
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WellKnownJWK fetches baseURL + ".well-known/jwks.json" and returns the key matching kid (or thumbprint)
|
||||||
func WellKnownJWK(kidOrThumb, iss string) (keypairs.PublicKey, error) {
|
func WellKnownJWK(kidOrThumb, iss string) (keypairs.PublicKey, error) {
|
||||||
return immediateOneOrFetch(kidOrThumb, iss, uncached.WellKnownJWKs)
|
return immediateOneOrFetch(kidOrThumb, iss, uncached.WellKnownJWKs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// JWKs returns a map of keys identified by their thumbprint
|
// JWKs returns a map of keys identified by their thumbprint
|
||||||
// (since kid may or may not be present)
|
// (since kid may or may not be present)
|
||||||
func JWKs(jwksurl string) (publicKeysMap, error) {
|
func JWKs(jwksurl string) (PublicKeysMap, error) {
|
||||||
if maps, keys, err := uncached.JWKs(jwksurl); nil != err {
|
maps, keys, err := uncached.JWKs(jwksurl)
|
||||||
|
|
||||||
|
if nil != err {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
}
|
||||||
iss := strings.Replace(jwksurl, ".well-known/jwks.json", "", 1)
|
iss := strings.Replace(jwksurl, ".well-known/jwks.json", "", 1)
|
||||||
cacheKeys(maps, keys, iss)
|
cacheKeys(maps, keys, iss)
|
||||||
return keys, err
|
return keys, err
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// JWK tries to return a key from cache, falling back to the /.well-known/jwks.json of the issuer
|
// JWK tries to return a key from cache, falling back to the /.well-known/jwks.json of the issuer
|
||||||
|
@ -379,7 +405,7 @@ func hasImplicitTrust(issURL *url.URL, r *http.Request) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whitelist
|
// Whitelist is a newtype for an array of URLs
|
||||||
type Whitelist []*url.URL
|
type Whitelist []*url.URL
|
||||||
|
|
||||||
// NewWhitelist turns an array of URLs (such as https://example.com/) into
|
// NewWhitelist turns an array of URLs (such as https://example.com/) into
|
||||||
|
|
|
@ -34,7 +34,7 @@ func TestIssuerMatches(t *testing.T) {
|
||||||
|
|
||||||
_, err := NewWhitelist(append(trusted, privates...))
|
_, err := NewWhitelist(append(trusted, privates...))
|
||||||
if nil == err {
|
if nil == err {
|
||||||
t.Fatal(errors.New("An insecure domain got through!"))
|
t.Fatal(errors.New("an insecure domain got through"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty list is allowed... I guess?
|
// Empty list is allowed... I guess?
|
||||||
|
|
|
@ -66,13 +66,14 @@ func JWKs(jwksurl string) (map[string]map[string]string, map[string]keypairs.Pub
|
||||||
k := resp.Keys[i]
|
k := resp.Keys[i]
|
||||||
m := getStringMap(k)
|
m := getStringMap(k)
|
||||||
|
|
||||||
if key, err := keypairs.NewJWKPublicKey(m); nil != err {
|
key, err := keypairs.NewJWKPublicKey(m)
|
||||||
|
|
||||||
|
if nil != err {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
} else {
|
}
|
||||||
keys[key.Thumbprint()] = key
|
keys[key.Thumbprint()] = key
|
||||||
maps[key.Thumbprint()] = m
|
maps[key.Thumbprint()] = m
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return maps, keys, nil
|
return maps, keys, nil
|
||||||
}
|
}
|
||||||
|
|
46
keypairs.go
46
keypairs.go
|
@ -21,18 +21,37 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrInvalidPrivateKey means that the key is not a valid Private Key
|
||||||
var ErrInvalidPrivateKey = errors.New("PrivateKey must be of type *rsa.PrivateKey or *ecdsa.PrivateKey")
|
var ErrInvalidPrivateKey = errors.New("PrivateKey must be of type *rsa.PrivateKey or *ecdsa.PrivateKey")
|
||||||
|
|
||||||
|
// ErrInvalidPublicKey means that the key is not a valid Public Key
|
||||||
var ErrInvalidPublicKey = errors.New("PublicKey must be of type *rsa.PublicKey or *ecdsa.PublicKey")
|
var ErrInvalidPublicKey = errors.New("PublicKey must be of type *rsa.PublicKey or *ecdsa.PublicKey")
|
||||||
|
|
||||||
|
// ErrParsePublicKey means that the bytes cannot be parsed in any known format
|
||||||
var ErrParsePublicKey = errors.New("PublicKey bytes could not be parsed as PEM or DER (PKIX/SPKI, PKCS1, or X509 Certificate) or JWK")
|
var ErrParsePublicKey = errors.New("PublicKey bytes could not be parsed as PEM or DER (PKIX/SPKI, PKCS1, or X509 Certificate) or JWK")
|
||||||
|
|
||||||
|
// ErrParsePrivateKey means that the bytes cannot be parsed in any known format
|
||||||
var ErrParsePrivateKey = errors.New("PrivateKey bytes could not be parsed as PEM or DER (PKCS8, SEC1, or PKCS1) or JWK")
|
var ErrParsePrivateKey = errors.New("PrivateKey bytes could not be parsed as PEM or DER (PKCS8, SEC1, or PKCS1) or JWK")
|
||||||
|
|
||||||
|
// ErrParseJWK means that the JWK is valid JSON but not a valid JWK
|
||||||
var ErrParseJWK = errors.New("JWK is missing required base64-encoded JSON fields")
|
var ErrParseJWK = errors.New("JWK is missing required base64-encoded JSON fields")
|
||||||
|
|
||||||
|
// ErrInvalidKeyType means that the key is not an acceptable type
|
||||||
var ErrInvalidKeyType = errors.New("The JWK's 'kty' must be either 'RSA' or 'EC'")
|
var ErrInvalidKeyType = errors.New("The JWK's 'kty' must be either 'RSA' or 'EC'")
|
||||||
|
|
||||||
|
// ErrInvalidCurve means that a non-standard curve was used
|
||||||
var ErrInvalidCurve = errors.New("The JWK's 'crv' must be either of the NIST standards 'P-256' or 'P-384'")
|
var ErrInvalidCurve = errors.New("The JWK's 'crv' must be either of the NIST standards 'P-256' or 'P-384'")
|
||||||
|
|
||||||
|
// ErrUnexpectedPublicKey means that a Private Key was expected
|
||||||
var ErrUnexpectedPublicKey = errors.New("PrivateKey was given where PublicKey was expected")
|
var ErrUnexpectedPublicKey = errors.New("PrivateKey was given where PublicKey was expected")
|
||||||
|
|
||||||
|
// ErrUnexpectedPrivateKey means that a Public Key was expected
|
||||||
var ErrUnexpectedPrivateKey = errors.New("PublicKey was given where PrivateKey was expected")
|
var ErrUnexpectedPrivateKey = errors.New("PublicKey was given where PrivateKey was expected")
|
||||||
|
|
||||||
|
// ErrDevSwapPrivatePublic means that the developer compiled bad code that swapped public and private keys
|
||||||
const ErrDevSwapPrivatePublic = "[Developer Error] You passed either crypto.PrivateKey or crypto.PublicKey where the other was expected."
|
const ErrDevSwapPrivatePublic = "[Developer Error] You passed either crypto.PrivateKey or crypto.PublicKey where the other was expected."
|
||||||
|
|
||||||
|
// ErrDevBadKeyType means that the developer compiled bad code that passes the wrong type
|
||||||
const ErrDevBadKeyType = "[Developer Error] crypto.PublicKey and crypto.PrivateKey are somewhat deceptive. They're actually empty interfaces that accept any object, even non-crypto objects. You passed an object of type '%T' by mistake."
|
const ErrDevBadKeyType = "[Developer Error] crypto.PublicKey and crypto.PrivateKey are somewhat deceptive. They're actually empty interfaces that accept any object, even non-crypto objects. You passed an object of type '%T' by mistake."
|
||||||
|
|
||||||
// PrivateKey is a zero-cost typesafe substitue for crypto.PrivateKey
|
// PrivateKey is a zero-cost typesafe substitue for crypto.PrivateKey
|
||||||
|
@ -63,34 +82,52 @@ type RSAPublicKey struct {
|
||||||
Expiry time.Time
|
Expiry time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Thumbprint returns a JWK thumbprint. See https://stackoverflow.com/questions/42588786/how-to-fingerprint-a-jwk
|
||||||
func (p *ECPublicKey) Thumbprint() string {
|
func (p *ECPublicKey) Thumbprint() string {
|
||||||
return ThumbprintUntypedPublicKey(p.PublicKey)
|
return ThumbprintUntypedPublicKey(p.PublicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KeyID returns the JWK `kid`, which will be the Thumbprint for keys generated with this library
|
||||||
func (p *ECPublicKey) KeyID() string {
|
func (p *ECPublicKey) KeyID() string {
|
||||||
return p.KID
|
return p.KID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Key returns the PublicKey
|
||||||
func (p *ECPublicKey) Key() crypto.PublicKey {
|
func (p *ECPublicKey) Key() crypto.PublicKey {
|
||||||
return p.PublicKey
|
return p.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExpireAt sets the time at which this Public Key should be considered invalid
|
||||||
func (p *ECPublicKey) ExpireAt(t time.Time) {
|
func (p *ECPublicKey) ExpireAt(t time.Time) {
|
||||||
p.Expiry = t
|
p.Expiry = t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExpiresAt gets the time at which this Public Key should be considered invalid
|
||||||
func (p *ECPublicKey) ExpiresAt() time.Time {
|
func (p *ECPublicKey) ExpiresAt() time.Time {
|
||||||
return p.Expiry
|
return p.Expiry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Thumbprint returns a JWK thumbprint. See https://stackoverflow.com/questions/42588786/how-to-fingerprint-a-jwk
|
||||||
func (p *RSAPublicKey) Thumbprint() string {
|
func (p *RSAPublicKey) Thumbprint() string {
|
||||||
return ThumbprintUntypedPublicKey(p.PublicKey)
|
return ThumbprintUntypedPublicKey(p.PublicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KeyID returns the JWK `kid`, which will be the Thumbprint for keys generated with this library
|
||||||
func (p *RSAPublicKey) KeyID() string {
|
func (p *RSAPublicKey) KeyID() string {
|
||||||
return p.KID
|
return p.KID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Key returns the PublicKey
|
||||||
func (p *RSAPublicKey) Key() crypto.PublicKey {
|
func (p *RSAPublicKey) Key() crypto.PublicKey {
|
||||||
return p.PublicKey
|
return p.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExpireAt sets the time at which this Public Key should be considered invalid
|
||||||
func (p *RSAPublicKey) ExpireAt(t time.Time) {
|
func (p *RSAPublicKey) ExpireAt(t time.Time) {
|
||||||
p.Expiry = t
|
p.Expiry = t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExpiresAt gets the time at which this Public Key should be considered invalid
|
||||||
func (p *RSAPublicKey) ExpiresAt() time.Time {
|
func (p *RSAPublicKey) ExpiresAt() time.Time {
|
||||||
return p.Expiry
|
return p.Expiry
|
||||||
}
|
}
|
||||||
|
@ -126,9 +163,9 @@ func NewPublicKey(pub crypto.PublicKey, kid ...string) PublicKey {
|
||||||
case *dsa.PublicKey:
|
case *dsa.PublicKey:
|
||||||
panic(ErrInvalidPublicKey)
|
panic(ErrInvalidPublicKey)
|
||||||
case *dsa.PrivateKey:
|
case *dsa.PrivateKey:
|
||||||
panic(ErrInvalidPublicKey)
|
panic(ErrInvalidPrivateKey)
|
||||||
default:
|
default:
|
||||||
panic(errors.New(fmt.Sprintf(ErrDevBadKeyType, pub)))
|
panic(fmt.Errorf(ErrDevBadKeyType, pub))
|
||||||
}
|
}
|
||||||
|
|
||||||
return k
|
return k
|
||||||
|
@ -236,7 +273,7 @@ func ParsePrivateKey(block []byte) (PrivateKey, error) {
|
||||||
|
|
||||||
// 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, err := parsePrivateKey(block); nil == err {
|
if key, err := parsePrivateKey(block); nil == err {
|
||||||
return key, nil
|
return key, nil
|
||||||
|
@ -320,9 +357,8 @@ func getPEMBytes(block []byte) ([][]byte, error) {
|
||||||
|
|
||||||
if len(blocks) > 0 {
|
if len(blocks) > 0 {
|
||||||
return blocks, nil
|
return blocks, nil
|
||||||
} else {
|
|
||||||
return nil, errors.New("no PEM blocks found")
|
|
||||||
}
|
}
|
||||||
|
return nil, errors.New("no PEM blocks found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParsePublicKey will try to parse the bytes you give it
|
// ParsePublicKey will try to parse the bytes you give it
|
||||||
|
|
Loading…
Reference in New Issue