crypto: change ErrNotRSAPrivateKey to ErrNotRSAPublicKey Fixes: #19
diff --git a/cover.html b/cover.html deleted file mode 100644 index 316b917..0000000 --- a/cover.html +++ /dev/null
@@ -1,268 +0,0 @@ - -<!DOCTYPE html> -<html> - <head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> - <style> - body { - background: black; - color: rgb(80, 80, 80); - } - body, pre, #legend span { - font-family: Menlo, monospace; - font-weight: bold; - } - #topbar { - background: black; - position: fixed; - top: 0; left: 0; right: 0; - height: 42px; - border-bottom: 1px solid rgb(80, 80, 80); - } - #content { - margin-top: 50px; - } - #nav, #legend { - float: left; - margin-left: 10px; - } - #legend { - margin-top: 12px; - } - #nav { - margin-top: 10px; - } - #legend span { - margin: 0 5px; - } - .cov0 { color: rgb(192, 0, 0) } -.cov1 { color: rgb(128, 128, 128) } -.cov2 { color: rgb(116, 140, 131) } -.cov3 { color: rgb(104, 152, 134) } -.cov4 { color: rgb(92, 164, 137) } -.cov5 { color: rgb(80, 176, 140) } -.cov6 { color: rgb(68, 188, 143) } -.cov7 { color: rgb(56, 200, 146) } -.cov8 { color: rgb(44, 212, 149) } -.cov9 { color: rgb(32, 224, 152) } -.cov10 { color: rgb(20, 236, 155) } - - </style> - </head> - <body> - <div id="topbar"> - <div id="nav"> - <select id="files"> - - <option value="file0">github.com/SermoDigital/jose/base64.go (100.0%)</option> - - <option value="file1">github.com/SermoDigital/jose/header.go (58.1%)</option> - - </select> - </div> - <div id="legend"> - <span>not tracked</span> - - <span class="cov0">not covered</span> - <span class="cov8">covered</span> - - </div> - </div> - <div id="content"> - - <pre class="file" id="file0" >package jose - -import "encoding/base64" - -// Encoder is satisfied if the type can marshal itself into a valid -// structure for a JWS. -type Encoder interface { - // Base64 implies T -> JSON -> RawURLEncodingBase64 - Base64() ([]byte, error) -} - -// Base64Decode decodes a base64-encoded byte slice. -func Base64Decode(b []byte) ([]byte, error) <span class="cov8" title="1">{ - buf := make([]byte, base64.RawURLEncoding.DecodedLen(len(b))) - n, err := base64.RawURLEncoding.Decode(buf, b) - return buf[:n], err -}</span> - -// Base64Encode encodes a byte slice. -func Base64Encode(b []byte) []byte <span class="cov8" title="1">{ - buf := make([]byte, base64.RawURLEncoding.EncodedLen(len(b))) - base64.RawURLEncoding.Encode(buf, b) - return buf -}</span> - -// EncodeEscape base64-encodes a byte slice but escapes it for JSON. -// It'll return the format: `"base64"` -func EncodeEscape(b []byte) []byte <span class="cov8" title="1">{ - buf := make([]byte, base64.RawURLEncoding.EncodedLen(len(b))+2) - buf[0] = '"' - base64.RawURLEncoding.Encode(buf[1:], b) - buf[len(buf)-1] = '"' - return buf -}</span> - -// DecodeEscaped decodes a base64-encoded byte slice straight from a JSON -// structure. It assumes it's in the format: `"base64"`, but can handle -// cases where it's not. -func DecodeEscaped(b []byte) ([]byte, error) <span class="cov8" title="1">{ - if len(b) > 1 && b[0] == '"' && b[len(b)-1] == '"' </span><span class="cov8" title="1">{ - b = b[1 : len(b)-1] - }</span> - <span class="cov8" title="1">return Base64Decode(b)</span> -} -</pre> - - <pre class="file" id="file1" style="display: none">package jose - -import "encoding/json" - -// Header implements a JOSE Header with the addition of some helper -// methods, similar to net/url.Values. -type Header map[string]interface{} - -// Get retrieves the value corresponding with key from the Header. -func (h Header) Get(key string) interface{} <span class="cov8" title="1">{ - if h == nil </span><span class="cov8" title="1">{ - return nil - }</span> - <span class="cov8" title="1">return h[key]</span> -} - -// Set sets Claims[key] = val. It'll overwrite without warning. -func (h Header) Set(key string, val interface{}) <span class="cov8" title="1">{ - h[key] = val -}</span> - -// Del removes the value that corresponds with key from the Header. -func (h Header) Del(key string) <span class="cov8" title="1">{ - delete(h, key) -}</span> - -// Has returns true if a value for the given key exists inside the Header. -func (h Header) Has(key string) bool <span class="cov8" title="1">{ - _, ok := h[key] - return ok -}</span> - -// MarshalJSON implements json.Marshaler for Header. -func (h Header) MarshalJSON() ([]byte, error) <span class="cov8" title="1">{ - if h == nil || len(h) == 0 </span><span class="cov0" title="0">{ - return nil, nil - }</span> - <span class="cov8" title="1">b, err := json.Marshal(map[string]interface{}(h)) - if err != nil </span><span class="cov0" title="0">{ - return nil, err - }</span> - <span class="cov8" title="1">return EncodeEscape(b), nil</span> -} - -// Base64 implements the Encoder interface. -func (h Header) Base64() ([]byte, error) <span class="cov0" title="0">{ - return h.MarshalJSON() -}</span> - -// UnmarshalJSON implements json.Unmarshaler for Header. -func (h *Header) UnmarshalJSON(b []byte) error <span class="cov8" title="1">{ - if b == nil </span><span class="cov0" title="0">{ - return nil - }</span> - - <span class="cov8" title="1">b, err := DecodeEscaped(b) - if err != nil </span><span class="cov0" title="0">{ - return err - }</span> - - // Since json.Unmarshal calls UnmarshalJSON, - // calling json.Unmarshal on *p would be infinitely recursive - // A temp variable is needed because &map[string]interface{}(*p) is - // invalid Go. - - <span class="cov8" title="1">tmp := map[string]interface{}(*h) - if err = json.Unmarshal(b, &tmp); err != nil </span><span class="cov0" title="0">{ - return err - }</span> - <span class="cov8" title="1">*h = Header(tmp) - return nil</span> -} - -// Protected Headers are base64-encoded after they're marshaled into -// JSON. -type Protected Header - -// Get retrieves the value corresponding with key from the Protected Header. -func (p Protected) Get(key string) interface{} <span class="cov0" title="0">{ - if p == nil </span><span class="cov0" title="0">{ - return nil - }</span> - <span class="cov0" title="0">return p[key]</span> -} - -// Set sets Protected[key] = val. It'll overwrite without warning. -func (p Protected) Set(key string, val interface{}) <span class="cov0" title="0">{ - p[key] = val -}</span> - -// Del removes the value that corresponds with key from the Protected Header. -func (p Protected) Del(key string) <span class="cov0" title="0">{ - delete(p, key) -}</span> - -// Has returns true if a value for the given key exists inside the Protected -// Header. -func (p Protected) Has(key string) bool <span class="cov0" title="0">{ - _, ok := p[key] - return ok -}</span> - -// MarshalJSON implements json.Marshaler for Protected. -func (p Protected) MarshalJSON() ([]byte, error) <span class="cov8" title="1">{ - b, err := json.Marshal(map[string]interface{}(p)) - if err != nil </span><span class="cov0" title="0">{ - return nil, err - }</span> - <span class="cov8" title="1">return EncodeEscape(b), nil</span> -} - -// Base64 implements the Encoder interface. -func (p Protected) Base64() ([]byte, error) <span class="cov0" title="0">{ - b, err := json.Marshal(map[string]interface{}(p)) - if err != nil </span><span class="cov0" title="0">{ - return nil, err - }</span> - <span class="cov0" title="0">return Base64Encode(b), nil</span> -} - -// UnmarshalJSON implements json.Unmarshaler for Protected. -func (p *Protected) UnmarshalJSON(b []byte) error <span class="cov8" title="1">{ - var h Header - h.UnmarshalJSON(b) - *p = Protected(h) - return nil -}</span> - -var ( - _ json.Marshaler = (Protected)(nil) - _ json.Unmarshaler = (*Protected)(nil) -) -</pre> - - </div> - </body> - <script> - (function() { - var files = document.getElementById('files'); - var visible = document.getElementById('file0'); - files.addEventListener('change', onChange, false); - function onChange() { - visible.style.display = 'none'; - visible = document.getElementById(files.value); - visible.style.display = 'block'; - window.scrollTo(0, 0); - } - })(); - </script> -</html>
diff --git a/crypto/rsa_utils.go b/crypto/rsa_utils.go index 350c394..43aeff3 100644 --- a/crypto/rsa_utils.go +++ b/crypto/rsa_utils.go
@@ -9,8 +9,9 @@ // Errors specific to rsa_utils. var ( - ErrKeyMustBePEMEncoded = errors.New("Invalid Key: Key must be PEM encoded PKCS1 or PKCS8 private key") - ErrNotRSAPrivateKey = errors.New("Key is not a valid RSA private key") + ErrKeyMustBePEMEncoded = errors.New("invalid key: Key must be PEM encoded PKCS1 or PKCS8 private key") + ErrNotRSAPrivateKey = errors.New("key is not a valid RSA private key") + ErrNotRSAPublicKey = errors.New("key is not a valid RSA public key") ) // ParseRSAPrivateKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 private key. @@ -62,7 +63,7 @@ var pkey *rsa.PublicKey var ok bool if pkey, ok = parsedKey.(*rsa.PublicKey); !ok { - return nil, ErrNotRSAPrivateKey + return nil, ErrNotRSAPublicKey } return pkey, nil
diff --git a/jws/jws_validate.go b/jws/jws_validate.go index 1948880..d064113 100644 --- a/jws/jws_validate.go +++ b/jws/jws_validate.go
@@ -27,40 +27,34 @@ return j.VerifyMulti(keys, methods, o) } -// IsMultiError returns true if the given error is type MultiError. +// IsMultiError returns true if the given error is type *MultiError. func IsMultiError(err error) bool { - _, ok := err.(MultiError) + _, ok := err.(*MultiError) return ok } // MultiError is a slice of errors. type MultiError []error -func (m MultiError) sanityCheck() error { - if m == nil { - return nil - } - return m -} - // Errors implements the error interface. -func (m MultiError) Error() string { - s, n := "", 0 - for _, e := range m { - if e != nil { +func (m *MultiError) Error() string { + var s string + var n int + for _, err := range *m { + if err != nil { if n == 0 { - s = e.Error() + s = err.Error() } n++ } } switch n { case 0: - return "(0 errors)" + return "" case 1: return s case 2: - return s + " (and 1 other error)" + return s + " and 1 other error" } return fmt.Sprintf("%s (and %d other errors)", s, n-1) } @@ -101,7 +95,7 @@ var o2 SigningOpts if o == nil { - o = &SigningOpts{} + o = new(SigningOpts) } var m MultiError @@ -112,15 +106,20 @@ } else { o2.Inc() if o.Needs(i) { + o.ptr++ o2.Append(i) } } } - if err := o.Validate(&o2); err != nil { - return err + err := o.Validate(&o2) + if err != nil { + m = append(m, err) } - return m.sanityCheck() + if len(m) == 0 { + return nil + } + return &m } // SigningOpts is a struct which holds options for validating @@ -148,30 +147,24 @@ _ struct{} } -// Append appends x to s's Indices member. +// Append appends x to s' Indices member. func (s *SigningOpts) Append(x int) { s.Indices = append(s.Indices, x) } -// Needs returns true if x resides inside s's Indices member -// for the given index. If true, it increments s's internal -// index. It's used to match two SigningOpts Indices members. +// Needs returns true if x resides inside s' Indices member +// for the given index. It's used to match two SigningOpts Indices members. func (s *SigningOpts) Needs(x int) bool { - if s.ptr < len(s.Indices) && - s.Indices[s.ptr] == x { - s.ptr++ - return true - } - return false + return s.ptr < len(s.Indices) && s.Indices[s.ptr] == x } -// Inc increments s's Number member by one. +// Inc increments s' Number member by one. func (s *SigningOpts) Inc() { s.Number++ } // Validate returns any errors found while validating the -// provided SigningOpts. The receiver validates the parameter `have`. +// provided SigningOpts. The receiver validates |have|. // It'll return an error if the passed SigningOpts' Number member is less -// than s's or if the passed SigningOpts' Indices slice isn't equal to s's. +// than s' or if the passed SigningOpts' Indices slice isn't equal to s'. func (s *SigningOpts) Validate(have *SigningOpts) error { if have.Number < s.Number || (s.Indices != nil && @@ -182,10 +175,7 @@ } func eq(a, b []int) bool { - if a == nil && b == nil { - return true - } - if a == nil || b == nil || len(a) != len(b) { + if len(a) != len(b) { return false } for i := range a {
diff --git a/jws/jwt.go b/jws/jwt.go index f98edf1..29b75b8 100644 --- a/jws/jwt.go +++ b/jws/jwt.go
@@ -10,7 +10,10 @@ // NewJWT creates a new JWT with the given claims. func NewJWT(claims Claims, method crypto.SigningMethod) jwt.JWT { - j := New(claims, method).(*jws) + j, ok := New(claims, method).(*jws) + if !ok { + panic("jws.NewJWT: runtime panic: New(...).(*jws) != true") + } j.sb[0].protected.Set("typ", "JWT") j.isJWT = true return j @@ -98,8 +101,7 @@ } } -// NewValidator returns a pointer to a jwt.Validator structure containing -// the info to be used in the validation of a JWT. +// NewValidator returns a jwt.Validator. func NewValidator(c Claims, exp, nbf time.Duration, fn func(Claims) error) *jwt.Validator { return &jwt.Validator{ Expected: jwt.Claims(c),