diff options
Diffstat (limited to 'vendor/gopkg.in/square/go-jose.v2/shared.go')
-rw-r--r-- | vendor/gopkg.in/square/go-jose.v2/shared.go | 499 |
1 files changed, 499 insertions, 0 deletions
diff --git a/vendor/gopkg.in/square/go-jose.v2/shared.go b/vendor/gopkg.in/square/go-jose.v2/shared.go new file mode 100644 index 000000000..b0a6255ec --- /dev/null +++ b/vendor/gopkg.in/square/go-jose.v2/shared.go @@ -0,0 +1,499 @@ +/*- + * Copyright 2014 Square Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package jose + +import ( + "crypto/elliptic" + "crypto/x509" + "encoding/base64" + "errors" + "fmt" + + "gopkg.in/square/go-jose.v2/json" +) + +// KeyAlgorithm represents a key management algorithm. +type KeyAlgorithm string + +// SignatureAlgorithm represents a signature (or MAC) algorithm. +type SignatureAlgorithm string + +// ContentEncryption represents a content encryption algorithm. +type ContentEncryption string + +// CompressionAlgorithm represents an algorithm used for plaintext compression. +type CompressionAlgorithm string + +// ContentType represents type of the contained data. +type ContentType string + +var ( + // ErrCryptoFailure represents an error in cryptographic primitive. This + // occurs when, for example, a message had an invalid authentication tag or + // could not be decrypted. + ErrCryptoFailure = errors.New("square/go-jose: error in cryptographic primitive") + + // ErrUnsupportedAlgorithm indicates that a selected algorithm is not + // supported. This occurs when trying to instantiate an encrypter for an + // algorithm that is not yet implemented. + ErrUnsupportedAlgorithm = errors.New("square/go-jose: unknown/unsupported algorithm") + + // ErrUnsupportedKeyType indicates that the given key type/format is not + // supported. This occurs when trying to instantiate an encrypter and passing + // it a key of an unrecognized type or with unsupported parameters, such as + // an RSA private key with more than two primes. + ErrUnsupportedKeyType = errors.New("square/go-jose: unsupported key type/format") + + // ErrInvalidKeySize indicates that the given key is not the correct size + // for the selected algorithm. This can occur, for example, when trying to + // encrypt with AES-256 but passing only a 128-bit key as input. + ErrInvalidKeySize = errors.New("square/go-jose: invalid key size for algorithm") + + // ErrNotSupported serialization of object is not supported. This occurs when + // trying to compact-serialize an object which can't be represented in + // compact form. + ErrNotSupported = errors.New("square/go-jose: compact serialization not supported for object") + + // ErrUnprotectedNonce indicates that while parsing a JWS or JWE object, a + // nonce header parameter was included in an unprotected header object. + ErrUnprotectedNonce = errors.New("square/go-jose: Nonce parameter included in unprotected header") +) + +// Key management algorithms +const ( + ED25519 = KeyAlgorithm("ED25519") + RSA1_5 = KeyAlgorithm("RSA1_5") // RSA-PKCS1v1.5 + RSA_OAEP = KeyAlgorithm("RSA-OAEP") // RSA-OAEP-SHA1 + RSA_OAEP_256 = KeyAlgorithm("RSA-OAEP-256") // RSA-OAEP-SHA256 + A128KW = KeyAlgorithm("A128KW") // AES key wrap (128) + A192KW = KeyAlgorithm("A192KW") // AES key wrap (192) + A256KW = KeyAlgorithm("A256KW") // AES key wrap (256) + DIRECT = KeyAlgorithm("dir") // Direct encryption + ECDH_ES = KeyAlgorithm("ECDH-ES") // ECDH-ES + ECDH_ES_A128KW = KeyAlgorithm("ECDH-ES+A128KW") // ECDH-ES + AES key wrap (128) + ECDH_ES_A192KW = KeyAlgorithm("ECDH-ES+A192KW") // ECDH-ES + AES key wrap (192) + ECDH_ES_A256KW = KeyAlgorithm("ECDH-ES+A256KW") // ECDH-ES + AES key wrap (256) + A128GCMKW = KeyAlgorithm("A128GCMKW") // AES-GCM key wrap (128) + A192GCMKW = KeyAlgorithm("A192GCMKW") // AES-GCM key wrap (192) + A256GCMKW = KeyAlgorithm("A256GCMKW") // AES-GCM key wrap (256) + PBES2_HS256_A128KW = KeyAlgorithm("PBES2-HS256+A128KW") // PBES2 + HMAC-SHA256 + AES key wrap (128) + PBES2_HS384_A192KW = KeyAlgorithm("PBES2-HS384+A192KW") // PBES2 + HMAC-SHA384 + AES key wrap (192) + PBES2_HS512_A256KW = KeyAlgorithm("PBES2-HS512+A256KW") // PBES2 + HMAC-SHA512 + AES key wrap (256) +) + +// Signature algorithms +const ( + EdDSA = SignatureAlgorithm("EdDSA") + HS256 = SignatureAlgorithm("HS256") // HMAC using SHA-256 + HS384 = SignatureAlgorithm("HS384") // HMAC using SHA-384 + HS512 = SignatureAlgorithm("HS512") // HMAC using SHA-512 + RS256 = SignatureAlgorithm("RS256") // RSASSA-PKCS-v1.5 using SHA-256 + RS384 = SignatureAlgorithm("RS384") // RSASSA-PKCS-v1.5 using SHA-384 + RS512 = SignatureAlgorithm("RS512") // RSASSA-PKCS-v1.5 using SHA-512 + ES256 = SignatureAlgorithm("ES256") // ECDSA using P-256 and SHA-256 + ES384 = SignatureAlgorithm("ES384") // ECDSA using P-384 and SHA-384 + ES512 = SignatureAlgorithm("ES512") // ECDSA using P-521 and SHA-512 + PS256 = SignatureAlgorithm("PS256") // RSASSA-PSS using SHA256 and MGF1-SHA256 + PS384 = SignatureAlgorithm("PS384") // RSASSA-PSS using SHA384 and MGF1-SHA384 + PS512 = SignatureAlgorithm("PS512") // RSASSA-PSS using SHA512 and MGF1-SHA512 +) + +// Content encryption algorithms +const ( + A128CBC_HS256 = ContentEncryption("A128CBC-HS256") // AES-CBC + HMAC-SHA256 (128) + A192CBC_HS384 = ContentEncryption("A192CBC-HS384") // AES-CBC + HMAC-SHA384 (192) + A256CBC_HS512 = ContentEncryption("A256CBC-HS512") // AES-CBC + HMAC-SHA512 (256) + A128GCM = ContentEncryption("A128GCM") // AES-GCM (128) + A192GCM = ContentEncryption("A192GCM") // AES-GCM (192) + A256GCM = ContentEncryption("A256GCM") // AES-GCM (256) +) + +// Compression algorithms +const ( + NONE = CompressionAlgorithm("") // No compression + DEFLATE = CompressionAlgorithm("DEF") // DEFLATE (RFC 1951) +) + +// A key in the protected header of a JWS object. Use of the Header... +// constants is preferred to enhance type safety. +type HeaderKey string + +const ( + HeaderType HeaderKey = "typ" // string + HeaderContentType = "cty" // string + + // These are set by go-jose and shouldn't need to be set by consumers of the + // library. + headerAlgorithm = "alg" // string + headerEncryption = "enc" // ContentEncryption + headerCompression = "zip" // CompressionAlgorithm + headerCritical = "crit" // []string + + headerAPU = "apu" // *byteBuffer + headerAPV = "apv" // *byteBuffer + headerEPK = "epk" // *JSONWebKey + headerIV = "iv" // *byteBuffer + headerTag = "tag" // *byteBuffer + headerX5c = "x5c" // []*x509.Certificate + + headerJWK = "jwk" // *JSONWebKey + headerKeyID = "kid" // string + headerNonce = "nonce" // string + + headerP2C = "p2c" // *byteBuffer (int) + headerP2S = "p2s" // *byteBuffer ([]byte) + +) + +// rawHeader represents the JOSE header for JWE/JWS objects (used for parsing). +// +// The decoding of the constituent items is deferred because we want to marshal +// some members into particular structs rather than generic maps, but at the +// same time we need to receive any extra fields unhandled by this library to +// pass through to consuming code in case it wants to examine them. +type rawHeader map[HeaderKey]*json.RawMessage + +// Header represents the read-only JOSE header for JWE/JWS objects. +type Header struct { + KeyID string + JSONWebKey *JSONWebKey + Algorithm string + Nonce string + + // Unverified certificate chain parsed from x5c header. + certificates []*x509.Certificate + + // Any headers not recognised above get unmarshaled + // from JSON in a generic manner and placed in this map. + ExtraHeaders map[HeaderKey]interface{} +} + +// Certificates verifies & returns the certificate chain present +// in the x5c header field of a message, if one was present. Returns +// an error if there was no x5c header present or the chain could +// not be validated with the given verify options. +func (h Header) Certificates(opts x509.VerifyOptions) ([][]*x509.Certificate, error) { + if len(h.certificates) == 0 { + return nil, errors.New("square/go-jose: no x5c header present in message") + } + + leaf := h.certificates[0] + if opts.Intermediates == nil { + opts.Intermediates = x509.NewCertPool() + for _, intermediate := range h.certificates[1:] { + opts.Intermediates.AddCert(intermediate) + } + } + + return leaf.Verify(opts) +} + +func (parsed rawHeader) set(k HeaderKey, v interface{}) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + parsed[k] = makeRawMessage(b) + return nil +} + +// getString gets a string from the raw JSON, defaulting to "". +func (parsed rawHeader) getString(k HeaderKey) string { + v, ok := parsed[k] + if !ok || v == nil { + return "" + } + var s string + err := json.Unmarshal(*v, &s) + if err != nil { + return "" + } + return s +} + +// getByteBuffer gets a byte buffer from the raw JSON. Returns (nil, nil) if +// not specified. +func (parsed rawHeader) getByteBuffer(k HeaderKey) (*byteBuffer, error) { + v := parsed[k] + if v == nil { + return nil, nil + } + var bb *byteBuffer + err := json.Unmarshal(*v, &bb) + if err != nil { + return nil, err + } + return bb, nil +} + +// getAlgorithm extracts parsed "alg" from the raw JSON as a KeyAlgorithm. +func (parsed rawHeader) getAlgorithm() KeyAlgorithm { + return KeyAlgorithm(parsed.getString(headerAlgorithm)) +} + +// getSignatureAlgorithm extracts parsed "alg" from the raw JSON as a SignatureAlgorithm. +func (parsed rawHeader) getSignatureAlgorithm() SignatureAlgorithm { + return SignatureAlgorithm(parsed.getString(headerAlgorithm)) +} + +// getEncryption extracts parsed "enc" from the raw JSON. +func (parsed rawHeader) getEncryption() ContentEncryption { + return ContentEncryption(parsed.getString(headerEncryption)) +} + +// getCompression extracts parsed "zip" from the raw JSON. +func (parsed rawHeader) getCompression() CompressionAlgorithm { + return CompressionAlgorithm(parsed.getString(headerCompression)) +} + +func (parsed rawHeader) getNonce() string { + return parsed.getString(headerNonce) +} + +// getEPK extracts parsed "epk" from the raw JSON. +func (parsed rawHeader) getEPK() (*JSONWebKey, error) { + v := parsed[headerEPK] + if v == nil { + return nil, nil + } + var epk *JSONWebKey + err := json.Unmarshal(*v, &epk) + if err != nil { + return nil, err + } + return epk, nil +} + +// getAPU extracts parsed "apu" from the raw JSON. +func (parsed rawHeader) getAPU() (*byteBuffer, error) { + return parsed.getByteBuffer(headerAPU) +} + +// getAPV extracts parsed "apv" from the raw JSON. +func (parsed rawHeader) getAPV() (*byteBuffer, error) { + return parsed.getByteBuffer(headerAPV) +} + +// getIV extracts parsed "iv" frpom the raw JSON. +func (parsed rawHeader) getIV() (*byteBuffer, error) { + return parsed.getByteBuffer(headerIV) +} + +// getTag extracts parsed "tag" frpom the raw JSON. +func (parsed rawHeader) getTag() (*byteBuffer, error) { + return parsed.getByteBuffer(headerTag) +} + +// getJWK extracts parsed "jwk" from the raw JSON. +func (parsed rawHeader) getJWK() (*JSONWebKey, error) { + v := parsed[headerJWK] + if v == nil { + return nil, nil + } + var jwk *JSONWebKey + err := json.Unmarshal(*v, &jwk) + if err != nil { + return nil, err + } + return jwk, nil +} + +// getCritical extracts parsed "crit" from the raw JSON. If omitted, it +// returns an empty slice. +func (parsed rawHeader) getCritical() ([]string, error) { + v := parsed[headerCritical] + if v == nil { + return nil, nil + } + + var q []string + err := json.Unmarshal(*v, &q) + if err != nil { + return nil, err + } + return q, nil +} + +// getS2C extracts parsed "p2c" from the raw JSON. +func (parsed rawHeader) getP2C() (int, error) { + v := parsed[headerP2C] + if v == nil { + return 0, nil + } + + var p2c int + err := json.Unmarshal(*v, &p2c) + if err != nil { + return 0, err + } + return p2c, nil +} + +// getS2S extracts parsed "p2s" from the raw JSON. +func (parsed rawHeader) getP2S() (*byteBuffer, error) { + return parsed.getByteBuffer(headerP2S) +} + +// sanitized produces a cleaned-up header object from the raw JSON. +func (parsed rawHeader) sanitized() (h Header, err error) { + for k, v := range parsed { + if v == nil { + continue + } + switch k { + case headerJWK: + var jwk *JSONWebKey + err = json.Unmarshal(*v, &jwk) + if err != nil { + err = fmt.Errorf("failed to unmarshal JWK: %v: %#v", err, string(*v)) + return + } + h.JSONWebKey = jwk + case headerKeyID: + var s string + err = json.Unmarshal(*v, &s) + if err != nil { + err = fmt.Errorf("failed to unmarshal key ID: %v: %#v", err, string(*v)) + return + } + h.KeyID = s + case headerAlgorithm: + var s string + err = json.Unmarshal(*v, &s) + if err != nil { + err = fmt.Errorf("failed to unmarshal algorithm: %v: %#v", err, string(*v)) + return + } + h.Algorithm = s + case headerNonce: + var s string + err = json.Unmarshal(*v, &s) + if err != nil { + err = fmt.Errorf("failed to unmarshal nonce: %v: %#v", err, string(*v)) + return + } + h.Nonce = s + case headerX5c: + c := []string{} + err = json.Unmarshal(*v, &c) + if err != nil { + err = fmt.Errorf("failed to unmarshal x5c header: %v: %#v", err, string(*v)) + return + } + h.certificates, err = parseCertificateChain(c) + if err != nil { + err = fmt.Errorf("failed to unmarshal x5c header: %v: %#v", err, string(*v)) + return + } + default: + if h.ExtraHeaders == nil { + h.ExtraHeaders = map[HeaderKey]interface{}{} + } + var v2 interface{} + err = json.Unmarshal(*v, &v2) + if err != nil { + err = fmt.Errorf("failed to unmarshal value: %v: %#v", err, string(*v)) + return + } + h.ExtraHeaders[k] = v2 + } + } + return +} + +func parseCertificateChain(chain []string) ([]*x509.Certificate, error) { + out := make([]*x509.Certificate, len(chain)) + for i, cert := range chain { + raw, err := base64.StdEncoding.DecodeString(cert) + if err != nil { + return nil, err + } + out[i], err = x509.ParseCertificate(raw) + if err != nil { + return nil, err + } + } + return out, nil +} + +func (dst rawHeader) isSet(k HeaderKey) bool { + dvr := dst[k] + if dvr == nil { + return false + } + + var dv interface{} + err := json.Unmarshal(*dvr, &dv) + if err != nil { + return true + } + + if dvStr, ok := dv.(string); ok { + return dvStr != "" + } + + return true +} + +// Merge headers from src into dst, giving precedence to headers from l. +func (dst rawHeader) merge(src *rawHeader) { + if src == nil { + return + } + + for k, v := range *src { + if dst.isSet(k) { + continue + } + + dst[k] = v + } +} + +// Get JOSE name of curve +func curveName(crv elliptic.Curve) (string, error) { + switch crv { + case elliptic.P256(): + return "P-256", nil + case elliptic.P384(): + return "P-384", nil + case elliptic.P521(): + return "P-521", nil + default: + return "", fmt.Errorf("square/go-jose: unsupported/unknown elliptic curve") + } +} + +// Get size of curve in bytes +func curveSize(crv elliptic.Curve) int { + bits := crv.Params().BitSize + + div := bits / 8 + mod := bits % 8 + + if mod == 0 { + return div + } + + return div + 1 +} + +func makeRawMessage(b []byte) *json.RawMessage { + rm := json.RawMessage(b) + return &rm +} |