friendlier error reporting
This commit is contained in:
parent
fe5cf33bef
commit
5701d77d7a
|
@ -23,7 +23,7 @@ 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,
|
||||
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.
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"kty": "EC",
|
||||
"crv": "P-256",
|
||||
"x": "IT1SWLxsacPiE5Z16jkopAn8_-85rMjgyCokrnjDft4",
|
||||
"y": "mP2JwOAOdMmXuwpxbKng3KZz27mz-nKWIlXJ3rzSGMo"
|
||||
}
|
39
keypairs.go
39
keypairs.go
|
@ -1,6 +1,7 @@
|
|||
package keypairs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
|
@ -16,6 +17,7 @@ import (
|
|||
"io"
|
||||
"log"
|
||||
"math/big"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -26,6 +28,8 @@ var ErrParsePrivateKey = errors.New("PrivateKey bytes could not be parsed as PEM
|
|||
var ErrParseJWK = errors.New("JWK is missing required base64-encoded JSON fields")
|
||||
var ErrInvalidKeyType = errors.New("The JWK's 'kty' must be either 'RSA' or 'EC'")
|
||||
var ErrInvalidCurve = errors.New("The JWK's 'crv' must be either of the NIST standards 'P-256' or 'P-384'")
|
||||
var ErrUnexpectedPublicKey = errors.New("PrivateKey was given where PublicKey was expected")
|
||||
var ErrUnexpectedPrivateKey = errors.New("PublicKey was given where PrivateKey was expected")
|
||||
|
||||
const ErrDevSwapPrivatePublic = "[Developer Error] You passed either crypto.PrivateKey or crypto.PublicKey where the other was expected."
|
||||
|
||||
|
@ -239,6 +243,13 @@ func ParsePrivateKey(block []byte) (PrivateKey, error) {
|
|||
}
|
||||
}
|
||||
|
||||
for i := range blocks {
|
||||
block = blocks[i]
|
||||
if _, err := parsePublicKey(block); nil == err {
|
||||
return nil, ErrUnexpectedPublicKey
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't parse a key arleady, we failed
|
||||
return nil, ErrParsePrivateKey
|
||||
}
|
||||
|
@ -331,6 +342,13 @@ func ParsePublicKey(block []byte) (PublicKey, error) {
|
|||
}
|
||||
}
|
||||
|
||||
for i := range blocks {
|
||||
block = blocks[i]
|
||||
if _, err := parsePrivateKey(block); nil == err {
|
||||
return nil, ErrUnexpectedPrivateKey
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't parse a key arleady, we failed
|
||||
return nil, ErrParsePublicKey
|
||||
}
|
||||
|
@ -399,17 +417,31 @@ func NewJWKPublicKey(m map[string]string) (PublicKey, error) {
|
|||
|
||||
// ParseJWKPublicKey parses a JSON-encoded JWK and returns a PublicKey, or a (hopefully) helpful error message
|
||||
func ParseJWKPublicKey(b []byte) (PublicKey, error) {
|
||||
// RSA and EC have "d" as a private part
|
||||
if bytes.Contains(b, []byte(`"d"`)) {
|
||||
return nil, ErrUnexpectedPrivateKey
|
||||
}
|
||||
return newJWKPublicKey(b)
|
||||
}
|
||||
|
||||
// ParseJWKPublicKeyString calls ParseJWKPublicKey([]byte(key)) for all you lazy folk.
|
||||
func ParseJWKPublicKeyString(s string) (PublicKey, error) {
|
||||
if strings.Contains(s, `"d"`) {
|
||||
return nil, ErrUnexpectedPrivateKey
|
||||
}
|
||||
return newJWKPublicKey(s)
|
||||
}
|
||||
|
||||
// DecodeJWKPublicKey stream-decodes a JSON-encoded JWK and returns a PublicKey, or a (hopefully) helpful error message
|
||||
func DecodeJWKPublicKey(r io.Reader) (PublicKey, error) {
|
||||
return newJWKPublicKey(r)
|
||||
m := make(map[string]string)
|
||||
if err := json.NewDecoder(r).Decode(&m); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
if d := m["d"]; "" != d {
|
||||
return nil, ErrUnexpectedPrivateKey
|
||||
}
|
||||
return newJWKPublicKey(m)
|
||||
}
|
||||
|
||||
// the underpinnings of the parser as used by the typesafe wrappers
|
||||
|
@ -419,11 +451,6 @@ func newJWKPublicKey(data interface{}) (PublicKey, error) {
|
|||
switch d := data.(type) {
|
||||
case map[string]string:
|
||||
m = d
|
||||
case io.Reader:
|
||||
m = make(map[string]string)
|
||||
if err := json.NewDecoder(d).Decode(&m); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
case string:
|
||||
if err := json.Unmarshal([]byte(d), &m); nil != err {
|
||||
return nil, err
|
||||
|
|
|
@ -43,6 +43,53 @@ func TestParsePrivateKeyEC(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestParseUnexpectedPrivateKey(t *testing.T) {
|
||||
keypaths := []string{
|
||||
"fixtures/privkey-ec-p256.jwk.json",
|
||||
"fixtures/privkey-ec-p256.sec1.pem",
|
||||
"fixtures/privkey-ec-p256.pkcs8.pem",
|
||||
"fixtures/privkey-rsa-2048.jwk.json",
|
||||
"fixtures/privkey-rsa-2048.pkcs1.pem",
|
||||
"fixtures/privkey-rsa-2048.pkcs8.pem",
|
||||
}
|
||||
for i := range keypaths {
|
||||
path := keypaths[i]
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if nil != err {
|
||||
t.Fatal(path, err)
|
||||
}
|
||||
|
||||
_, err = ParsePublicKey(b)
|
||||
switch err {
|
||||
case ErrUnexpectedPrivateKey:
|
||||
continue
|
||||
default:
|
||||
t.Fatal(path, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseUnexpectedPublicKey(t *testing.T) {
|
||||
keypaths := []string{
|
||||
"fixtures/pub-ec-p256.jwk.json",
|
||||
}
|
||||
for i := range keypaths {
|
||||
path := keypaths[i]
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if nil != err {
|
||||
t.Fatal(path, err)
|
||||
}
|
||||
|
||||
_, err = ParsePrivateKey(b)
|
||||
switch err {
|
||||
case ErrUnexpectedPublicKey:
|
||||
continue
|
||||
default:
|
||||
t.Fatal(path, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePrivateKeyRSA(t *testing.T) {
|
||||
keypaths := []string{
|
||||
"fixtures/privkey-rsa-2048.jwk.json",
|
||||
|
@ -71,7 +118,7 @@ func TestParsePrivateKeyRSA(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestParseCertificate(t *testing.T) {
|
||||
resp, err := http.Get("http://bigsquid.auth0.com/pem")
|
||||
resp, err := http.Get("https://example.auth0.com/pem")
|
||||
if nil != err {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue