forked from TrueCloudLab/distribution
225 lines
7.7 KiB
Go
225 lines
7.7 KiB
Go
|
/*-
|
||
|
* 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"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
)
|
||
|
|
||
|
// 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
|
||
|
|
||
|
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")
|
||
|
|
||
|
// 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 (
|
||
|
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 (
|
||
|
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)
|
||
|
)
|
||
|
|
||
|
// rawHeader represents the JOSE header for JWE/JWS objects (used for parsing).
|
||
|
type rawHeader struct {
|
||
|
Alg string `json:"alg,omitempty"`
|
||
|
Enc ContentEncryption `json:"enc,omitempty"`
|
||
|
Zip CompressionAlgorithm `json:"zip,omitempty"`
|
||
|
Crit []string `json:"crit,omitempty"`
|
||
|
Apu *byteBuffer `json:"apu,omitempty"`
|
||
|
Apv *byteBuffer `json:"apv,omitempty"`
|
||
|
Epk *JsonWebKey `json:"epk,omitempty"`
|
||
|
Iv *byteBuffer `json:"iv,omitempty"`
|
||
|
Tag *byteBuffer `json:"tag,omitempty"`
|
||
|
Jwk *JsonWebKey `json:"jwk,omitempty"`
|
||
|
Kid string `json:"kid,omitempty"`
|
||
|
Nonce string `json:"nonce,omitempty"`
|
||
|
}
|
||
|
|
||
|
// JoseHeader represents the read-only JOSE header for JWE/JWS objects.
|
||
|
type JoseHeader struct {
|
||
|
KeyID string
|
||
|
JsonWebKey *JsonWebKey
|
||
|
Algorithm string
|
||
|
Nonce string
|
||
|
}
|
||
|
|
||
|
// sanitized produces a cleaned-up header object from the raw JSON.
|
||
|
func (parsed rawHeader) sanitized() JoseHeader {
|
||
|
return JoseHeader{
|
||
|
KeyID: parsed.Kid,
|
||
|
JsonWebKey: parsed.Jwk,
|
||
|
Algorithm: parsed.Alg,
|
||
|
Nonce: parsed.Nonce,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Merge headers from src into dst, giving precedence to headers from l.
|
||
|
func (dst *rawHeader) merge(src *rawHeader) {
|
||
|
if src == nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if dst.Alg == "" {
|
||
|
dst.Alg = src.Alg
|
||
|
}
|
||
|
if dst.Enc == "" {
|
||
|
dst.Enc = src.Enc
|
||
|
}
|
||
|
if dst.Zip == "" {
|
||
|
dst.Zip = src.Zip
|
||
|
}
|
||
|
if dst.Crit == nil {
|
||
|
dst.Crit = src.Crit
|
||
|
}
|
||
|
if dst.Crit == nil {
|
||
|
dst.Crit = src.Crit
|
||
|
}
|
||
|
if dst.Apu == nil {
|
||
|
dst.Apu = src.Apu
|
||
|
}
|
||
|
if dst.Apv == nil {
|
||
|
dst.Apv = src.Apv
|
||
|
}
|
||
|
if dst.Epk == nil {
|
||
|
dst.Epk = src.Epk
|
||
|
}
|
||
|
if dst.Iv == nil {
|
||
|
dst.Iv = src.Iv
|
||
|
}
|
||
|
if dst.Tag == nil {
|
||
|
dst.Tag = src.Tag
|
||
|
}
|
||
|
if dst.Kid == "" {
|
||
|
dst.Kid = src.Kid
|
||
|
}
|
||
|
if dst.Jwk == nil {
|
||
|
dst.Jwk = src.Jwk
|
||
|
}
|
||
|
if dst.Nonce == "" {
|
||
|
dst.Nonce = src.Nonce
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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
|
||
|
}
|