Update go dependencies

This commit is contained in:
Manuel de Brito Fontes 2018-05-26 11:27:53 -04:00 committed by Manuel Alejandro de Brito Fontes
parent 15ffb51394
commit bb4d483837
No known key found for this signature in database
GPG key ID: 786136016A8BA02A
1621 changed files with 86368 additions and 284392 deletions

View file

@ -1,504 +0,0 @@
/*-
* 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 (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"errors"
"io"
"math/big"
"testing"
)
func TestVectorsRSA(t *testing.T) {
// Sources:
// http://www.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-rsa-cryptography-standard.htm
// ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15crypt-vectors.txt
priv := &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: fromHexInt(`
a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8
ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0c
bc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bd
bf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93
ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb`),
E: 65537,
},
D: fromHexInt(`
53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf1195
17ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d
4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d6
5a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb
04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1`),
Primes: []*big.Int{
fromHexInt(`
d32737e7267ffe1341b2d5c0d150a81b586fb3132bed2f8d5262
864a9cb9f30af38be448598d413a172efb802c21acf1c11c520c
2f26a471dcad212eac7ca39d`),
fromHexInt(`
cc8853d1d54da630fac004f471f281c7b8982d8224a490edbeb3
3d3e3d5cc93c4765703d1dd791642f1f116a0dd852be2419b2af
72bfe9a030e860b0288b5d77`),
},
}
input := fromHexBytes(
"6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34")
expectedPKCS := fromHexBytes(`
50b4c14136bd198c2f3c3ed243fce036e168d56517984a263cd66492b808
04f169d210f2b9bdfb48b12f9ea05009c77da257cc600ccefe3a6283789d
8ea0e607ac58e2690ec4ebc10146e8cbaa5ed4d5cce6fe7b0ff9efc1eabb
564dbf498285f449ee61dd7b42ee5b5892cb90601f30cda07bf26489310b
cd23b528ceab3c31`)
expectedOAEP := fromHexBytes(`
354fe67b4a126d5d35fe36c777791a3f7ba13def484e2d3908aff722fad4
68fb21696de95d0be911c2d3174f8afcc201035f7b6d8e69402de5451618
c21a535fa9d7bfc5b8dd9fc243f8cf927db31322d6e881eaa91a996170e6
57a05a266426d98c88003f8477c1227094a0d9fa1e8c4024309ce1ecccb5
210035d47ac72e8a`)
// Mock random reader
randReader = bytes.NewReader(fromHexBytes(`
017341ae3875d5f87101f8cc4fa9b9bc156bb04628fccdb2f4f11e905bd3
a155d376f593bd7304210874eba08a5e22bcccb4c9d3882a93a54db022f5
03d16338b6b7ce16dc7f4bbf9a96b59772d6606e9747c7649bf9e083db98
1884a954ab3c6f18b776ea21069d69776a33e96bad48e1dda0a5ef`))
defer resetRandReader()
// RSA-PKCS1v1.5 encrypt
enc := new(rsaEncrypterVerifier)
enc.publicKey = &priv.PublicKey
encryptedPKCS, err := enc.encrypt(input, RSA1_5)
if err != nil {
t.Error("Encryption failed:", err)
return
}
if bytes.Compare(encryptedPKCS, expectedPKCS) != 0 {
t.Error("Output does not match expected value (PKCS1v1.5)")
}
// RSA-OAEP encrypt
encryptedOAEP, err := enc.encrypt(input, RSA_OAEP)
if err != nil {
t.Error("Encryption failed:", err)
return
}
if bytes.Compare(encryptedOAEP, expectedOAEP) != 0 {
t.Error("Output does not match expected value (OAEP)")
}
// Need fake cipher for PKCS1v1.5 decrypt
resetRandReader()
aes := newAESGCM(len(input))
keygen := randomKeyGenerator{
size: aes.keySize(),
}
// RSA-PKCS1v1.5 decrypt
dec := new(rsaDecrypterSigner)
dec.privateKey = priv
decryptedPKCS, err := dec.decrypt(encryptedPKCS, RSA1_5, keygen)
if err != nil {
t.Error("Decryption failed:", err)
return
}
if bytes.Compare(input, decryptedPKCS) != 0 {
t.Error("Output does not match expected value (PKCS1v1.5)")
}
// RSA-OAEP decrypt
decryptedOAEP, err := dec.decrypt(encryptedOAEP, RSA_OAEP, keygen)
if err != nil {
t.Error("decryption failed:", err)
return
}
if bytes.Compare(input, decryptedOAEP) != 0 {
t.Error("output does not match expected value (OAEP)")
}
}
func TestEd25519(t *testing.T) {
_, err := newEd25519Signer("XYZ", nil)
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
enc := new(edEncrypterVerifier)
enc.publicKey = ed25519PublicKey
err = enc.verifyPayload([]byte{}, []byte{}, "XYZ")
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
dec := new(edDecrypterSigner)
dec.privateKey = ed25519PrivateKey
_, err = dec.signPayload([]byte{}, "XYZ")
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
sig, err := dec.signPayload([]byte("This is a test"), "EdDSA")
if err != nil {
t.Error("should not error trying to sign payload")
}
if sig.Signature == nil {
t.Error("Check the signature")
}
err = enc.verifyPayload([]byte("This is a test"), sig.Signature, "EdDSA")
if err != nil {
t.Error("should not error trying to verify payload")
}
err = enc.verifyPayload([]byte("This is test number 2"), sig.Signature, "EdDSA")
if err == nil {
t.Error("should not error trying to verify payload")
}
}
func TestInvalidAlgorithmsRSA(t *testing.T) {
_, err := newRSARecipient("XYZ", nil)
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
_, err = newRSASigner("XYZ", nil)
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
enc := new(rsaEncrypterVerifier)
enc.publicKey = &rsaTestKey.PublicKey
_, err = enc.encryptKey([]byte{}, "XYZ")
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
err = enc.verifyPayload([]byte{}, []byte{}, "XYZ")
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
dec := new(rsaDecrypterSigner)
dec.privateKey = rsaTestKey
_, err = dec.decrypt(make([]byte, 256), "XYZ", randomKeyGenerator{size: 16})
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
_, err = dec.signPayload([]byte{}, "XYZ")
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
}
type failingKeyGenerator struct{}
func (ctx failingKeyGenerator) keySize() int {
return 0
}
func (ctx failingKeyGenerator) genKey() ([]byte, rawHeader, error) {
return nil, rawHeader{}, errors.New("failed to generate key")
}
func TestPKCSKeyGeneratorFailure(t *testing.T) {
dec := new(rsaDecrypterSigner)
dec.privateKey = rsaTestKey
generator := failingKeyGenerator{}
_, err := dec.decrypt(make([]byte, 256), RSA1_5, generator)
if err != ErrCryptoFailure {
t.Error("should return error on invalid algorithm")
}
}
func TestInvalidAlgorithmsEC(t *testing.T) {
_, err := newECDHRecipient("XYZ", nil)
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
_, err = newECDSASigner("XYZ", nil)
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
enc := new(ecEncrypterVerifier)
enc.publicKey = &ecTestKey256.PublicKey
_, err = enc.encryptKey([]byte{}, "XYZ")
if err != ErrUnsupportedAlgorithm {
t.Error("should return error on invalid algorithm")
}
}
func TestInvalidECKeyGen(t *testing.T) {
gen := ecKeyGenerator{
size: 16,
algID: "A128GCM",
publicKey: &ecTestKey256.PublicKey,
}
if gen.keySize() != 16 {
t.Error("ec key generator reported incorrect key size")
}
_, _, err := gen.genKey()
if err != nil {
t.Error("ec key generator failed to generate key", err)
}
}
func TestInvalidECDecrypt(t *testing.T) {
dec := ecDecrypterSigner{
privateKey: ecTestKey256,
}
generator := randomKeyGenerator{size: 16}
// Missing epk header
headers := rawHeader{}
headers.set(headerAlgorithm, ECDH_ES)
_, err := dec.decryptKey(headers, nil, generator)
if err == nil {
t.Error("ec decrypter accepted object with missing epk header")
}
// Invalid epk header
headers.set(headerEPK, &JSONWebKey{})
_, err = dec.decryptKey(headers, nil, generator)
if err == nil {
t.Error("ec decrypter accepted object with invalid epk header")
}
}
func TestDecryptWithIncorrectSize(t *testing.T) {
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
t.Error(err)
return
}
dec := new(rsaDecrypterSigner)
dec.privateKey = priv
aes := newAESGCM(16)
keygen := randomKeyGenerator{
size: aes.keySize(),
}
payload := make([]byte, 254)
_, err = dec.decrypt(payload, RSA1_5, keygen)
if err == nil {
t.Error("Invalid payload size should return error")
}
payload = make([]byte, 257)
_, err = dec.decrypt(payload, RSA1_5, keygen)
if err == nil {
t.Error("Invalid payload size should return error")
}
}
func TestPKCSDecryptNeverFails(t *testing.T) {
// We don't want RSA-PKCS1 v1.5 decryption to ever fail, in order to prevent
// side-channel timing attacks (Bleichenbacher attack in particular).
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
t.Error(err)
return
}
dec := new(rsaDecrypterSigner)
dec.privateKey = priv
aes := newAESGCM(16)
keygen := randomKeyGenerator{
size: aes.keySize(),
}
for i := 1; i < 50; i++ {
payload := make([]byte, 256)
_, err := io.ReadFull(rand.Reader, payload)
if err != nil {
t.Error("Unable to get random data:", err)
return
}
_, err = dec.decrypt(payload, RSA1_5, keygen)
if err != nil {
t.Error("PKCS1v1.5 decrypt should never fail:", err)
return
}
}
}
func BenchmarkPKCSDecryptWithValidPayloads(b *testing.B) {
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
enc := new(rsaEncrypterVerifier)
enc.publicKey = &priv.PublicKey
dec := new(rsaDecrypterSigner)
dec.privateKey = priv
aes := newAESGCM(32)
b.StopTimer()
b.ResetTimer()
for i := 0; i < b.N; i++ {
plaintext := make([]byte, 32)
_, err = io.ReadFull(rand.Reader, plaintext)
if err != nil {
panic(err)
}
ciphertext, err := enc.encrypt(plaintext, RSA1_5)
if err != nil {
panic(err)
}
keygen := randomKeyGenerator{
size: aes.keySize(),
}
b.StartTimer()
_, err = dec.decrypt(ciphertext, RSA1_5, keygen)
b.StopTimer()
if err != nil {
panic(err)
}
}
}
func BenchmarkPKCSDecryptWithInvalidPayloads(b *testing.B) {
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
enc := new(rsaEncrypterVerifier)
enc.publicKey = &priv.PublicKey
dec := new(rsaDecrypterSigner)
dec.privateKey = priv
aes := newAESGCM(16)
keygen := randomKeyGenerator{
size: aes.keySize(),
}
b.StopTimer()
b.ResetTimer()
for i := 0; i < b.N; i++ {
plaintext := make([]byte, 16)
_, err = io.ReadFull(rand.Reader, plaintext)
if err != nil {
panic(err)
}
ciphertext, err := enc.encrypt(plaintext, RSA1_5)
if err != nil {
panic(err)
}
// Do some simple scrambling
ciphertext[128] ^= 0xFF
b.StartTimer()
_, err = dec.decrypt(ciphertext, RSA1_5, keygen)
b.StopTimer()
if err != nil {
panic(err)
}
}
}
func TestInvalidEllipticCurve(t *testing.T) {
signer256 := ecDecrypterSigner{privateKey: ecTestKey256}
signer384 := ecDecrypterSigner{privateKey: ecTestKey384}
signer521 := ecDecrypterSigner{privateKey: ecTestKey521}
_, err := signer256.signPayload([]byte{}, ES384)
if err == nil {
t.Error("should not generate ES384 signature with P-256 key")
}
_, err = signer256.signPayload([]byte{}, ES512)
if err == nil {
t.Error("should not generate ES512 signature with P-256 key")
}
_, err = signer384.signPayload([]byte{}, ES256)
if err == nil {
t.Error("should not generate ES256 signature with P-384 key")
}
_, err = signer384.signPayload([]byte{}, ES512)
if err == nil {
t.Error("should not generate ES512 signature with P-384 key")
}
_, err = signer521.signPayload([]byte{}, ES256)
if err == nil {
t.Error("should not generate ES256 signature with P-521 key")
}
_, err = signer521.signPayload([]byte{}, ES384)
if err == nil {
t.Error("should not generate ES384 signature with P-521 key")
}
}
func estInvalidECPublicKey(t *testing.T) {
// Invalid key
invalid := &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: elliptic.P256(),
X: fromBase64Int("MTEx"),
Y: fromBase64Int("MTEx"),
},
D: fromBase64Int("0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo"),
}
headers := rawHeader{}
headers.set(headerAlgorithm, ECDH_ES)
headers.set(headerEPK, &JSONWebKey{
Key: &invalid.PublicKey,
})
dec := ecDecrypterSigner{
privateKey: ecTestKey256,
}
_, err := dec.decryptKey(headers, nil, randomKeyGenerator{size: 16})
if err == nil {
t.Fatal("decrypter accepted JWS with invalid ECDH public key")
}
}
func TestInvalidAlgorithmEC(t *testing.T) {
err := ecEncrypterVerifier{publicKey: &ecTestKey256.PublicKey}.verifyPayload([]byte{}, []byte{}, "XYZ")
if err != ErrUnsupportedAlgorithm {
t.Fatal("should not accept invalid/unsupported algorithm")
}
}

View file

@ -1,498 +0,0 @@
/*-
* 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 josecipher
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
"strings"
"testing"
)
func TestInvalidInputs(t *testing.T) {
key := []byte{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
}
nonce := []byte{
92, 80, 104, 49, 133, 25, 161, 215, 173, 101, 219, 211, 136, 91, 210, 145}
aead, _ := NewCBCHMAC(key, aes.NewCipher)
ciphertext := aead.Seal(nil, nonce, []byte("plaintext"), []byte("aad"))
// Changed AAD, must fail
_, err := aead.Open(nil, nonce, ciphertext, []byte("INVALID"))
if err == nil {
t.Error("must detect invalid aad")
}
// Empty ciphertext, must fail
_, err = aead.Open(nil, nonce, []byte{}, []byte("aad"))
if err == nil {
t.Error("must detect invalid/empty ciphertext")
}
// Corrupt ciphertext, must fail
corrupt := make([]byte, len(ciphertext))
copy(corrupt, ciphertext)
corrupt[0] ^= 0xFF
_, err = aead.Open(nil, nonce, corrupt, []byte("aad"))
if err == nil {
t.Error("must detect corrupt ciphertext")
}
// Corrupt authtag, must fail
copy(corrupt, ciphertext)
corrupt[len(ciphertext)-1] ^= 0xFF
_, err = aead.Open(nil, nonce, corrupt, []byte("aad"))
if err == nil {
t.Error("must detect corrupt authtag")
}
// Truncated data, must fail
_, err = aead.Open(nil, nonce, ciphertext[:10], []byte("aad"))
if err == nil {
t.Error("must detect corrupt authtag")
}
}
func TestVectorsAESCBC128(t *testing.T) {
// Source: http://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-29#appendix-A.2
plaintext := []byte{
76, 105, 118, 101, 32, 108, 111, 110, 103, 32, 97, 110, 100, 32,
112, 114, 111, 115, 112, 101, 114, 46}
aad := []byte{
101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 83, 85, 48, 69,
120, 88, 122, 85, 105, 76, 67, 74, 108, 98, 109, 77, 105, 79, 105,
74, 66, 77, 84, 73, 52, 81, 48, 74, 68, 76, 85, 104, 84, 77, 106, 85,
50, 73, 110, 48}
expectedCiphertext := []byte{
40, 57, 83, 181, 119, 33, 133, 148, 198, 185, 243, 24, 152, 230, 6,
75, 129, 223, 127, 19, 210, 82, 183, 230, 168, 33, 215, 104, 143,
112, 56, 102}
expectedAuthtag := []byte{
246, 17, 244, 190, 4, 95, 98, 3, 231, 0, 115, 157, 242, 203, 100,
191}
key := []byte{
4, 211, 31, 197, 84, 157, 252, 254, 11, 100, 157, 250, 63, 170, 106, 206,
107, 124, 212, 45, 111, 107, 9, 219, 200, 177, 0, 240, 143, 156, 44, 207}
nonce := []byte{
3, 22, 60, 12, 43, 67, 104, 105, 108, 108, 105, 99, 111, 116, 104, 101}
enc, err := NewCBCHMAC(key, aes.NewCipher)
out := enc.Seal(nil, nonce, plaintext, aad)
if err != nil {
t.Error("Unable to encrypt:", err)
return
}
if bytes.Compare(out[:len(out)-16], expectedCiphertext) != 0 {
t.Error("Ciphertext did not match")
}
if bytes.Compare(out[len(out)-16:], expectedAuthtag) != 0 {
t.Error("Auth tag did not match")
}
}
func TestVectorsAESCBC256(t *testing.T) {
// Source: https://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05#section-5.4
plaintext := []byte{
0x41, 0x20, 0x63, 0x69, 0x70, 0x68, 0x65, 0x72, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20,
0x6d, 0x75, 0x73, 0x74, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75,
0x69, 0x72, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65,
0x74, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, 0x74, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62,
0x65, 0x20, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x61, 0x6c, 0x6c, 0x20, 0x69,
0x6e, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x6f, 0x66,
0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x6e, 0x65, 0x6d, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f,
0x75, 0x74, 0x20, 0x69, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x6e, 0x69, 0x65, 0x6e, 0x63, 0x65}
aad := []byte{
0x54, 0x68, 0x65, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x63,
0x69, 0x70, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x65, 0x20,
0x4b, 0x65, 0x72, 0x63, 0x6b, 0x68, 0x6f, 0x66, 0x66, 0x73}
expectedCiphertext := []byte{
0x4a, 0xff, 0xaa, 0xad, 0xb7, 0x8c, 0x31, 0xc5, 0xda, 0x4b, 0x1b, 0x59, 0x0d, 0x10, 0xff, 0xbd,
0x3d, 0xd8, 0xd5, 0xd3, 0x02, 0x42, 0x35, 0x26, 0x91, 0x2d, 0xa0, 0x37, 0xec, 0xbc, 0xc7, 0xbd,
0x82, 0x2c, 0x30, 0x1d, 0xd6, 0x7c, 0x37, 0x3b, 0xcc, 0xb5, 0x84, 0xad, 0x3e, 0x92, 0x79, 0xc2,
0xe6, 0xd1, 0x2a, 0x13, 0x74, 0xb7, 0x7f, 0x07, 0x75, 0x53, 0xdf, 0x82, 0x94, 0x10, 0x44, 0x6b,
0x36, 0xeb, 0xd9, 0x70, 0x66, 0x29, 0x6a, 0xe6, 0x42, 0x7e, 0xa7, 0x5c, 0x2e, 0x08, 0x46, 0xa1,
0x1a, 0x09, 0xcc, 0xf5, 0x37, 0x0d, 0xc8, 0x0b, 0xfe, 0xcb, 0xad, 0x28, 0xc7, 0x3f, 0x09, 0xb3,
0xa3, 0xb7, 0x5e, 0x66, 0x2a, 0x25, 0x94, 0x41, 0x0a, 0xe4, 0x96, 0xb2, 0xe2, 0xe6, 0x60, 0x9e,
0x31, 0xe6, 0xe0, 0x2c, 0xc8, 0x37, 0xf0, 0x53, 0xd2, 0x1f, 0x37, 0xff, 0x4f, 0x51, 0x95, 0x0b,
0xbe, 0x26, 0x38, 0xd0, 0x9d, 0xd7, 0xa4, 0x93, 0x09, 0x30, 0x80, 0x6d, 0x07, 0x03, 0xb1, 0xf6}
expectedAuthtag := []byte{
0x4d, 0xd3, 0xb4, 0xc0, 0x88, 0xa7, 0xf4, 0x5c, 0x21, 0x68, 0x39, 0x64, 0x5b, 0x20, 0x12, 0xbf,
0x2e, 0x62, 0x69, 0xa8, 0xc5, 0x6a, 0x81, 0x6d, 0xbc, 0x1b, 0x26, 0x77, 0x61, 0x95, 0x5b, 0xc5}
key := []byte{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f}
nonce := []byte{
0x1a, 0xf3, 0x8c, 0x2d, 0xc2, 0xb9, 0x6f, 0xfd, 0xd8, 0x66, 0x94, 0x09, 0x23, 0x41, 0xbc, 0x04}
enc, err := NewCBCHMAC(key, aes.NewCipher)
out := enc.Seal(nil, nonce, plaintext, aad)
if err != nil {
t.Error("Unable to encrypt:", err)
return
}
if bytes.Compare(out[:len(out)-32], expectedCiphertext) != 0 {
t.Error("Ciphertext did not match, got", out[:len(out)-32], "wanted", expectedCiphertext)
}
if bytes.Compare(out[len(out)-32:], expectedAuthtag) != 0 {
t.Error("Auth tag did not match, got", out[len(out)-32:], "wanted", expectedAuthtag)
}
}
func TestAESCBCRoundtrip(t *testing.T) {
key128 := []byte{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
key192 := []byte{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7}
key256 := []byte{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
nonce := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
RunRoundtrip(t, key128, nonce)
RunRoundtrip(t, key192, nonce)
RunRoundtrip(t, key256, nonce)
}
func RunRoundtrip(t *testing.T, key, nonce []byte) {
aead, err := NewCBCHMAC(key, aes.NewCipher)
if err != nil {
panic(err)
}
if aead.NonceSize() != len(nonce) {
panic("invalid nonce")
}
// Test pre-existing data in dst buffer
dst := []byte{15, 15, 15, 15}
plaintext := []byte{0, 0, 0, 0}
aad := []byte{4, 3, 2, 1}
result := aead.Seal(dst, nonce, plaintext, aad)
if bytes.Compare(dst, result[:4]) != 0 {
t.Error("Existing data in dst not preserved")
}
// Test pre-existing (empty) dst buffer with sufficient capacity
dst = make([]byte, 256)[:0]
result, err = aead.Open(dst, nonce, result[4:], aad)
if err != nil {
panic(err)
}
if bytes.Compare(result, plaintext) != 0 {
t.Error("Plaintext does not match output")
}
}
func TestAESCBCOverhead(t *testing.T) {
aead, err := NewCBCHMAC(make([]byte, 32), aes.NewCipher)
if err != nil {
panic(err)
}
if aead.Overhead() != 32 {
t.Error("CBC-HMAC reports incorrect overhead value")
}
}
func TestPadding(t *testing.T) {
for i := 0; i < 256; i++ {
slice := make([]byte, i)
padded := padBuffer(slice, 16)
if len(padded)%16 != 0 {
t.Error("failed to pad slice properly", i)
return
}
unpadded, err := unpadBuffer(padded, 16)
if err != nil || len(unpadded) != i {
t.Error("failed to unpad slice properly", i)
return
}
}
}
func TestInvalidKey(t *testing.T) {
key := make([]byte, 30)
_, err := NewCBCHMAC(key, aes.NewCipher)
if err == nil {
t.Error("should not be able to instantiate CBC-HMAC with invalid key")
}
}
func TestTruncatedCiphertext(t *testing.T) {
key := make([]byte, 32)
nonce := make([]byte, 16)
data := make([]byte, 32)
io.ReadFull(rand.Reader, key)
io.ReadFull(rand.Reader, nonce)
aead, err := NewCBCHMAC(key, aes.NewCipher)
if err != nil {
panic(err)
}
ctx := aead.(*cbcAEAD)
ct := aead.Seal(nil, nonce, data, nil)
// Truncated ciphertext, but with correct auth tag
truncated, tail := resize(ct[:len(ct)-ctx.authtagBytes-2], uint64(len(ct))-2)
copy(tail, ctx.computeAuthTag(nil, nonce, truncated[:len(truncated)-ctx.authtagBytes]))
// Open should fail
_, err = aead.Open(nil, nonce, truncated, nil)
if err == nil {
t.Error("open on truncated ciphertext should fail")
}
}
func TestInvalidPaddingOpen(t *testing.T) {
key := make([]byte, 32)
nonce := make([]byte, 16)
// Plaintext with invalid padding
plaintext := padBuffer(make([]byte, 28), aes.BlockSize)
plaintext[len(plaintext)-1] = 0xFF
io.ReadFull(rand.Reader, key)
io.ReadFull(rand.Reader, nonce)
block, _ := aes.NewCipher(key)
cbc := cipher.NewCBCEncrypter(block, nonce)
buffer := append([]byte{}, plaintext...)
cbc.CryptBlocks(buffer, buffer)
aead, _ := NewCBCHMAC(key, aes.NewCipher)
ctx := aead.(*cbcAEAD)
// Mutated ciphertext, but with correct auth tag
size := uint64(len(buffer))
ciphertext, tail := resize(buffer, size+(uint64(len(key))/2))
copy(tail, ctx.computeAuthTag(nil, nonce, ciphertext[:size]))
// Open should fail (b/c of invalid padding, even though tag matches)
_, err := aead.Open(nil, nonce, ciphertext, nil)
if err == nil || !strings.Contains(err.Error(), "invalid padding") {
t.Error("no or unexpected error on open with invalid padding:", err)
}
}
func TestInvalidPadding(t *testing.T) {
for i := 0; i < 256; i++ {
slice := make([]byte, i)
padded := padBuffer(slice, 16)
if len(padded)%16 != 0 {
t.Error("failed to pad slice properly", i)
return
}
paddingBytes := 16 - (i % 16)
// Mutate padding for testing
for j := 1; j <= paddingBytes; j++ {
mutated := make([]byte, len(padded))
copy(mutated, padded)
mutated[len(mutated)-j] ^= 0xFF
_, err := unpadBuffer(mutated, 16)
if err == nil {
t.Error("unpad on invalid padding should fail", i)
return
}
}
// Test truncated padding
_, err := unpadBuffer(padded[:len(padded)-1], 16)
if err == nil {
t.Error("unpad on truncated padding should fail", i)
return
}
}
}
func TestZeroLengthPadding(t *testing.T) {
data := make([]byte, 16)
data, err := unpadBuffer(data, 16)
if err == nil {
t.Error("padding with 0x00 should never be valid")
}
}
func benchEncryptCBCHMAC(b *testing.B, keySize, chunkSize int) {
key := make([]byte, keySize*2)
nonce := make([]byte, 16)
io.ReadFull(rand.Reader, key)
io.ReadFull(rand.Reader, nonce)
chunk := make([]byte, chunkSize)
aead, err := NewCBCHMAC(key, aes.NewCipher)
if err != nil {
panic(err)
}
b.SetBytes(int64(chunkSize))
b.ResetTimer()
for i := 0; i < b.N; i++ {
aead.Seal(nil, nonce, chunk, nil)
}
}
func benchDecryptCBCHMAC(b *testing.B, keySize, chunkSize int) {
key := make([]byte, keySize*2)
nonce := make([]byte, 16)
io.ReadFull(rand.Reader, key)
io.ReadFull(rand.Reader, nonce)
chunk := make([]byte, chunkSize)
aead, err := NewCBCHMAC(key, aes.NewCipher)
if err != nil {
panic(err)
}
out := aead.Seal(nil, nonce, chunk, nil)
b.SetBytes(int64(chunkSize))
b.ResetTimer()
for i := 0; i < b.N; i++ {
aead.Open(nil, nonce, out, nil)
}
}
func BenchmarkEncryptAES128_CBCHMAC_1k(b *testing.B) {
benchEncryptCBCHMAC(b, 16, 1024)
}
func BenchmarkEncryptAES128_CBCHMAC_64k(b *testing.B) {
benchEncryptCBCHMAC(b, 16, 65536)
}
func BenchmarkEncryptAES128_CBCHMAC_1MB(b *testing.B) {
benchEncryptCBCHMAC(b, 16, 1048576)
}
func BenchmarkEncryptAES128_CBCHMAC_64MB(b *testing.B) {
benchEncryptCBCHMAC(b, 16, 67108864)
}
func BenchmarkDecryptAES128_CBCHMAC_1k(b *testing.B) {
benchDecryptCBCHMAC(b, 16, 1024)
}
func BenchmarkDecryptAES128_CBCHMAC_64k(b *testing.B) {
benchDecryptCBCHMAC(b, 16, 65536)
}
func BenchmarkDecryptAES128_CBCHMAC_1MB(b *testing.B) {
benchDecryptCBCHMAC(b, 16, 1048576)
}
func BenchmarkDecryptAES128_CBCHMAC_64MB(b *testing.B) {
benchDecryptCBCHMAC(b, 16, 67108864)
}
func BenchmarkEncryptAES192_CBCHMAC_64k(b *testing.B) {
benchEncryptCBCHMAC(b, 24, 65536)
}
func BenchmarkEncryptAES192_CBCHMAC_1MB(b *testing.B) {
benchEncryptCBCHMAC(b, 24, 1048576)
}
func BenchmarkEncryptAES192_CBCHMAC_64MB(b *testing.B) {
benchEncryptCBCHMAC(b, 24, 67108864)
}
func BenchmarkDecryptAES192_CBCHMAC_1k(b *testing.B) {
benchDecryptCBCHMAC(b, 24, 1024)
}
func BenchmarkDecryptAES192_CBCHMAC_64k(b *testing.B) {
benchDecryptCBCHMAC(b, 24, 65536)
}
func BenchmarkDecryptAES192_CBCHMAC_1MB(b *testing.B) {
benchDecryptCBCHMAC(b, 24, 1048576)
}
func BenchmarkDecryptAES192_CBCHMAC_64MB(b *testing.B) {
benchDecryptCBCHMAC(b, 24, 67108864)
}
func BenchmarkEncryptAES256_CBCHMAC_64k(b *testing.B) {
benchEncryptCBCHMAC(b, 32, 65536)
}
func BenchmarkEncryptAES256_CBCHMAC_1MB(b *testing.B) {
benchEncryptCBCHMAC(b, 32, 1048576)
}
func BenchmarkEncryptAES256_CBCHMAC_64MB(b *testing.B) {
benchEncryptCBCHMAC(b, 32, 67108864)
}
func BenchmarkDecryptAES256_CBCHMAC_1k(b *testing.B) {
benchDecryptCBCHMAC(b, 32, 1032)
}
func BenchmarkDecryptAES256_CBCHMAC_64k(b *testing.B) {
benchDecryptCBCHMAC(b, 32, 65536)
}
func BenchmarkDecryptAES256_CBCHMAC_1MB(b *testing.B) {
benchDecryptCBCHMAC(b, 32, 1048576)
}
func BenchmarkDecryptAES256_CBCHMAC_64MB(b *testing.B) {
benchDecryptCBCHMAC(b, 32, 67108864)
}

View file

@ -1,150 +0,0 @@
/*-
* 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 josecipher
import (
"bytes"
"crypto"
"testing"
)
// Taken from: https://tools.ietf.org/id/draft-ietf-jose-json-web-algorithms-38.txt
func TestVectorConcatKDF(t *testing.T) {
z := []byte{
158, 86, 217, 29, 129, 113, 53, 211, 114, 131, 66, 131, 191, 132,
38, 156, 251, 49, 110, 163, 218, 128, 106, 72, 246, 218, 167, 121,
140, 254, 144, 196}
algID := []byte{0, 0, 0, 7, 65, 49, 50, 56, 71, 67, 77}
ptyUInfo := []byte{0, 0, 0, 5, 65, 108, 105, 99, 101}
ptyVInfo := []byte{0, 0, 0, 3, 66, 111, 98}
supPubInfo := []byte{0, 0, 0, 128}
supPrivInfo := []byte{}
expected := []byte{
86, 170, 141, 234, 248, 35, 109, 32, 92, 34, 40, 205, 113, 167, 16, 26}
ckdf := NewConcatKDF(crypto.SHA256, z, algID, ptyUInfo, ptyVInfo, supPubInfo, supPrivInfo)
out0 := make([]byte, 9)
out1 := make([]byte, 7)
read0, err := ckdf.Read(out0)
if err != nil {
t.Error("error when reading from concat kdf reader", err)
return
}
read1, err := ckdf.Read(out1)
if err != nil {
t.Error("error when reading from concat kdf reader", err)
return
}
if read0+read1 != len(out0)+len(out1) {
t.Error("did not receive enough bytes from concat kdf reader")
return
}
out := []byte{}
out = append(out, out0...)
out = append(out, out1...)
if bytes.Compare(out, expected) != 0 {
t.Error("did not receive expected output from concat kdf reader")
return
}
}
func TestCache(t *testing.T) {
z := []byte{
158, 86, 217, 29, 129, 113, 53, 211, 114, 131, 66, 131, 191, 132,
38, 156, 251, 49, 110, 163, 218, 128, 106, 72, 246, 218, 167, 121,
140, 254, 144, 196}
algID := []byte{1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4}
ptyUInfo := []byte{1, 2, 3, 4}
ptyVInfo := []byte{4, 3, 2, 1}
supPubInfo := []byte{}
supPrivInfo := []byte{}
outputs := [][]byte{}
// Read the same amount of data in different chunk sizes
chunkSizes := []int{1, 2, 4, 8, 16, 32, 64, 128, 256, 512}
for _, c := range chunkSizes {
out := make([]byte, 1024)
reader := NewConcatKDF(crypto.SHA256, z, algID, ptyUInfo, ptyVInfo, supPubInfo, supPrivInfo)
for i := 0; i < 1024; i += c {
_, _ = reader.Read(out[i : i+c])
}
outputs = append(outputs, out)
}
for i := range outputs {
if bytes.Compare(outputs[i], outputs[(i+1)%len(outputs)]) != 0 {
t.Error("not all outputs from KDF matched")
}
}
}
func benchmarkKDF(b *testing.B, total int) {
z := []byte{
158, 86, 217, 29, 129, 113, 53, 211, 114, 131, 66, 131, 191, 132,
38, 156, 251, 49, 110, 163, 218, 128, 106, 72, 246, 218, 167, 121,
140, 254, 144, 196}
algID := []byte{1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4}
ptyUInfo := []byte{1, 2, 3, 4}
ptyVInfo := []byte{4, 3, 2, 1}
supPubInfo := []byte{}
supPrivInfo := []byte{}
out := make([]byte, total)
reader := NewConcatKDF(crypto.SHA256, z, algID, ptyUInfo, ptyVInfo, supPubInfo, supPrivInfo)
b.ResetTimer()
b.SetBytes(int64(total))
for i := 0; i < b.N; i++ {
_, _ = reader.Read(out)
}
}
func BenchmarkConcatKDF_1k(b *testing.B) {
benchmarkKDF(b, 1024)
}
func BenchmarkConcatKDF_64k(b *testing.B) {
benchmarkKDF(b, 65536)
}
func BenchmarkConcatKDF_1MB(b *testing.B) {
benchmarkKDF(b, 1048576)
}
func BenchmarkConcatKDF_64MB(b *testing.B) {
benchmarkKDF(b, 67108864)
}

View file

@ -1,115 +0,0 @@
/*-
* 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 josecipher
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"encoding/base64"
"math/big"
"testing"
)
// Example keys from JWA, Appendix C
var aliceKey = &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: elliptic.P256(),
X: fromBase64Int("gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0="),
Y: fromBase64Int("SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps="),
},
D: fromBase64Int("0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo="),
}
var bobKey = &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: elliptic.P256(),
X: fromBase64Int("weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ="),
Y: fromBase64Int("e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck="),
},
D: fromBase64Int("VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw="),
}
// Build big int from base64-encoded string. Strips whitespace (for testing).
func fromBase64Int(data string) *big.Int {
val, err := base64.URLEncoding.DecodeString(data)
if err != nil {
panic("Invalid test data: " + err.Error())
}
return new(big.Int).SetBytes(val)
}
func TestVectorECDHES(t *testing.T) {
apuData := []byte("Alice")
apvData := []byte("Bob")
expected := []byte{
86, 170, 141, 234, 248, 35, 109, 32, 92, 34, 40, 205, 113, 167, 16, 26}
output := DeriveECDHES("A128GCM", apuData, apvData, bobKey, &aliceKey.PublicKey, 16)
if bytes.Compare(output, expected) != 0 {
t.Error("output did not match what we expect, got", output, "wanted", expected)
}
}
func TestInvalidECPublicKey(t *testing.T) {
defer func() { recover() }()
// Invalid key
invalid := &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: elliptic.P256(),
X: fromBase64Int("MTEx"),
Y: fromBase64Int("MTEx"),
},
D: fromBase64Int("0_NxaRPUMQoAJt50Gz8YiTr8gRTwyEaCumd-MToTmIo="),
}
DeriveECDHES("A128GCM", []byte{}, []byte{}, bobKey, &invalid.PublicKey, 16)
t.Fatal("should panic if public key was invalid")
}
func BenchmarkECDHES_128(b *testing.B) {
apuData := []byte("APU")
apvData := []byte("APV")
b.ResetTimer()
for i := 0; i < b.N; i++ {
DeriveECDHES("ID", apuData, apvData, bobKey, &aliceKey.PublicKey, 16)
}
}
func BenchmarkECDHES_192(b *testing.B) {
apuData := []byte("APU")
apvData := []byte("APV")
b.ResetTimer()
for i := 0; i < b.N; i++ {
DeriveECDHES("ID", apuData, apvData, bobKey, &aliceKey.PublicKey, 24)
}
}
func BenchmarkECDHES_256(b *testing.B) {
apuData := []byte("APU")
apvData := []byte("APV")
b.ResetTimer()
for i := 0; i < b.N; i++ {
DeriveECDHES("ID", apuData, apvData, bobKey, &aliceKey.PublicKey, 32)
}
}

View file

@ -1,133 +0,0 @@
/*-
* 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 josecipher
import (
"bytes"
"crypto/aes"
"encoding/hex"
"testing"
)
func TestAesKeyWrap(t *testing.T) {
// Test vectors from: http://csrc.nist.gov/groups/ST/toolkit/documents/kms/key-wrap.pdf
kek0, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F")
cek0, _ := hex.DecodeString("00112233445566778899AABBCCDDEEFF")
expected0, _ := hex.DecodeString("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5")
kek1, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F1011121314151617")
cek1, _ := hex.DecodeString("00112233445566778899AABBCCDDEEFF")
expected1, _ := hex.DecodeString("96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D")
kek2, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")
cek2, _ := hex.DecodeString("00112233445566778899AABBCCDDEEFF0001020304050607")
expected2, _ := hex.DecodeString("A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD5D17D6B254DA1")
block0, _ := aes.NewCipher(kek0)
block1, _ := aes.NewCipher(kek1)
block2, _ := aes.NewCipher(kek2)
out0, _ := KeyWrap(block0, cek0)
out1, _ := KeyWrap(block1, cek1)
out2, _ := KeyWrap(block2, cek2)
if bytes.Compare(out0, expected0) != 0 {
t.Error("output 0 not as expected, got", out0, "wanted", expected0)
}
if bytes.Compare(out1, expected1) != 0 {
t.Error("output 1 not as expected, got", out1, "wanted", expected1)
}
if bytes.Compare(out2, expected2) != 0 {
t.Error("output 2 not as expected, got", out2, "wanted", expected2)
}
unwrap0, _ := KeyUnwrap(block0, out0)
unwrap1, _ := KeyUnwrap(block1, out1)
unwrap2, _ := KeyUnwrap(block2, out2)
if bytes.Compare(unwrap0, cek0) != 0 {
t.Error("key unwrap did not return original input, got", unwrap0, "wanted", cek0)
}
if bytes.Compare(unwrap1, cek1) != 0 {
t.Error("key unwrap did not return original input, got", unwrap1, "wanted", cek1)
}
if bytes.Compare(unwrap2, cek2) != 0 {
t.Error("key unwrap did not return original input, got", unwrap2, "wanted", cek2)
}
}
func TestAesKeyWrapInvalid(t *testing.T) {
kek, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F")
// Invalid unwrap input (bit flipped)
input0, _ := hex.DecodeString("1EA68C1A8112B447AEF34BD8FB5A7B828D3E862371D2CFE5")
block, _ := aes.NewCipher(kek)
_, err := KeyUnwrap(block, input0)
if err == nil {
t.Error("key unwrap failed to detect invalid input")
}
// Invalid unwrap input (truncated)
input1, _ := hex.DecodeString("1EA68C1A8112B447AEF34BD8FB5A7B828D3E862371D2CF")
_, err = KeyUnwrap(block, input1)
if err == nil {
t.Error("key unwrap failed to detect truncated input")
}
// Invalid wrap input (not multiple of 8)
input2, _ := hex.DecodeString("0123456789ABCD")
_, err = KeyWrap(block, input2)
if err == nil {
t.Error("key wrap accepted invalid input")
}
}
func BenchmarkAesKeyWrap(b *testing.B) {
kek, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F")
key, _ := hex.DecodeString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
block, _ := aes.NewCipher(kek)
b.ResetTimer()
for i := 0; i < b.N; i++ {
KeyWrap(block, key)
}
}
func BenchmarkAesKeyUnwrap(b *testing.B) {
kek, _ := hex.DecodeString("000102030405060708090A0B0C0D0E0F")
input, _ := hex.DecodeString("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5")
block, _ := aes.NewCipher(kek)
b.ResetTimer()
for i := 0; i < b.N; i++ {
KeyUnwrap(block, input)
}
}

View file

@ -1,838 +0,0 @@
/*-
* 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 (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"fmt"
"io"
"reflect"
"testing"
"golang.org/x/crypto/ed25519"
)
// We generate only a single RSA and EC key for testing, speeds up tests.
var rsaTestKey, _ = rsa.GenerateKey(rand.Reader, 2048)
var ecTestKey256, _ = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
var ecTestKey384, _ = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
var ecTestKey521, _ = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
var ed25519PublicKey, ed25519PrivateKey, _ = ed25519.GenerateKey(rand.Reader)
func RoundtripJWE(keyAlg KeyAlgorithm, encAlg ContentEncryption, compressionAlg CompressionAlgorithm, serializer func(*JSONWebEncryption) (string, error), corrupter func(*JSONWebEncryption) bool, aad []byte, encryptionKey interface{}, decryptionKey interface{}) error {
enc, err := NewEncrypter(encAlg, Recipient{Algorithm: keyAlg, Key: encryptionKey}, &EncrypterOptions{Compression: compressionAlg})
if err != nil {
return fmt.Errorf("error on new encrypter: %s", err)
}
input := []byte("Lorem ipsum dolor sit amet")
obj, err := enc.EncryptWithAuthData(input, aad)
if err != nil {
return fmt.Errorf("error in encrypt: %s", err)
}
msg, err := serializer(obj)
if err != nil {
return fmt.Errorf("error in serializer: %s", err)
}
parsed, err := ParseEncrypted(msg)
if err != nil {
return fmt.Errorf("error in parse: %s, on msg '%s'", err, msg)
}
// (Maybe) mangle object
skip := corrupter(parsed)
if skip {
return fmt.Errorf("corrupter indicated message should be skipped")
}
if bytes.Compare(parsed.GetAuthData(), aad) != 0 {
return fmt.Errorf("auth data in parsed object does not match")
}
output, err := parsed.Decrypt(decryptionKey)
if err != nil {
return fmt.Errorf("error on decrypt: %s", err)
}
if bytes.Compare(input, output) != 0 {
return fmt.Errorf("Decrypted output does not match input, got '%s' but wanted '%s'", output, input)
}
return nil
}
func TestRoundtripsJWE(t *testing.T) {
// Test matrix
keyAlgs := []KeyAlgorithm{
DIRECT, ECDH_ES, ECDH_ES_A128KW, ECDH_ES_A192KW, ECDH_ES_A256KW, A128KW, A192KW, A256KW,
RSA1_5, RSA_OAEP, RSA_OAEP_256, A128GCMKW, A192GCMKW, A256GCMKW}
encAlgs := []ContentEncryption{A128GCM, A192GCM, A256GCM, A128CBC_HS256, A192CBC_HS384, A256CBC_HS512}
zipAlgs := []CompressionAlgorithm{NONE, DEFLATE}
serializers := []func(*JSONWebEncryption) (string, error){
func(obj *JSONWebEncryption) (string, error) { return obj.CompactSerialize() },
func(obj *JSONWebEncryption) (string, error) { return obj.FullSerialize(), nil },
}
corrupter := func(obj *JSONWebEncryption) bool { return false }
// Note: can't use AAD with compact serialization
aads := [][]byte{
nil,
[]byte("Ut enim ad minim veniam"),
}
// Test all different configurations
for _, alg := range keyAlgs {
for _, enc := range encAlgs {
for _, key := range generateTestKeys(alg, enc) {
for _, zip := range zipAlgs {
for i, serializer := range serializers {
err := RoundtripJWE(alg, enc, zip, serializer, corrupter, aads[i], key.enc, key.dec)
if err != nil {
t.Error(err, alg, enc, zip, i)
}
}
}
}
}
}
}
func TestRoundtripsJWECorrupted(t *testing.T) {
// Test matrix
keyAlgs := []KeyAlgorithm{DIRECT, ECDH_ES, ECDH_ES_A128KW, A128KW, RSA1_5, RSA_OAEP, RSA_OAEP_256, A128GCMKW}
encAlgs := []ContentEncryption{A128GCM, A192GCM, A256GCM, A128CBC_HS256, A192CBC_HS384, A256CBC_HS512}
zipAlgs := []CompressionAlgorithm{NONE, DEFLATE}
serializers := []func(*JSONWebEncryption) (string, error){
func(obj *JSONWebEncryption) (string, error) { return obj.CompactSerialize() },
func(obj *JSONWebEncryption) (string, error) { return obj.FullSerialize(), nil },
}
bitflip := func(slice []byte) bool {
if len(slice) > 0 {
slice[0] ^= 0xFF
return false
}
return true
}
corrupters := []func(*JSONWebEncryption) bool{
func(obj *JSONWebEncryption) bool {
// Set invalid ciphertext
return bitflip(obj.ciphertext)
},
func(obj *JSONWebEncryption) bool {
// Set invalid auth tag
return bitflip(obj.tag)
},
func(obj *JSONWebEncryption) bool {
// Set invalid AAD
return bitflip(obj.aad)
},
func(obj *JSONWebEncryption) bool {
// Mess with encrypted key
return bitflip(obj.recipients[0].encryptedKey)
},
func(obj *JSONWebEncryption) bool {
// Mess with GCM-KW auth tag
tag, _ := obj.protected.getTag()
skip := bitflip(tag.bytes())
if skip {
return true
}
obj.protected.set(headerTag, tag)
return false
},
}
// Note: can't use AAD with compact serialization
aads := [][]byte{
nil,
[]byte("Ut enim ad minim veniam"),
}
// Test all different configurations
for _, alg := range keyAlgs {
for _, enc := range encAlgs {
for _, key := range generateTestKeys(alg, enc) {
for _, zip := range zipAlgs {
for i, serializer := range serializers {
for j, corrupter := range corrupters {
err := RoundtripJWE(alg, enc, zip, serializer, corrupter, aads[i], key.enc, key.dec)
if err == nil {
t.Error("failed to detect corrupt data", err, alg, enc, zip, i, j)
}
}
}
}
}
}
}
}
func TestEncrypterWithJWKAndKeyID(t *testing.T) {
enc, err := NewEncrypter(A128GCM, Recipient{Algorithm: A128KW, Key: &JSONWebKey{
KeyID: "test-id",
Key: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
}}, nil)
if err != nil {
t.Error(err)
}
ciphertext, _ := enc.Encrypt([]byte("Lorem ipsum dolor sit amet"))
serialized1, _ := ciphertext.CompactSerialize()
serialized2 := ciphertext.FullSerialize()
parsed1, _ := ParseEncrypted(serialized1)
parsed2, _ := ParseEncrypted(serialized2)
if parsed1.Header.KeyID != "test-id" {
t.Errorf("expected message to have key id from JWK, but found '%s' instead", parsed1.Header.KeyID)
}
if parsed2.Header.KeyID != "test-id" {
t.Errorf("expected message to have key id from JWK, but found '%s' instead", parsed2.Header.KeyID)
}
}
func TestEncrypterWithBrokenRand(t *testing.T) {
keyAlgs := []KeyAlgorithm{ECDH_ES_A128KW, A128KW, RSA1_5, RSA_OAEP, RSA_OAEP_256, A128GCMKW}
encAlgs := []ContentEncryption{A128GCM, A192GCM, A256GCM, A128CBC_HS256, A192CBC_HS384, A256CBC_HS512}
serializer := func(obj *JSONWebEncryption) (string, error) { return obj.CompactSerialize() }
corrupter := func(obj *JSONWebEncryption) bool { return false }
// Break rand reader
readers := []func() io.Reader{
// Totally broken
func() io.Reader { return bytes.NewReader([]byte{}) },
// Not enough bytes
func() io.Reader { return io.LimitReader(rand.Reader, 20) },
}
defer resetRandReader()
for _, alg := range keyAlgs {
for _, enc := range encAlgs {
for _, key := range generateTestKeys(alg, enc) {
for i, getReader := range readers {
randReader = getReader()
err := RoundtripJWE(alg, enc, NONE, serializer, corrupter, nil, key.enc, key.dec)
if err == nil {
t.Error("encrypter should fail if rand is broken", i)
}
}
}
}
}
}
func TestNewEncrypterErrors(t *testing.T) {
_, err := NewEncrypter("XYZ", Recipient{}, nil)
if err == nil {
t.Error("was able to instantiate encrypter with invalid cipher")
}
_, err = NewMultiEncrypter("XYZ", []Recipient{}, nil)
if err == nil {
t.Error("was able to instantiate multi-encrypter with invalid cipher")
}
_, err = NewEncrypter(A128GCM, Recipient{Algorithm: DIRECT, Key: nil}, nil)
if err == nil {
t.Error("was able to instantiate encrypter with invalid direct key")
}
_, err = NewEncrypter(A128GCM, Recipient{Algorithm: ECDH_ES, Key: nil}, nil)
if err == nil {
t.Error("was able to instantiate encrypter with invalid EC key")
}
}
func TestMultiRecipientJWE(t *testing.T) {
sharedKey := []byte{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
}
enc, err := NewMultiEncrypter(A128GCM, []Recipient{
{Algorithm: RSA_OAEP, Key: &rsaTestKey.PublicKey},
{Algorithm: A256GCMKW, Key: sharedKey},
}, nil)
if err != nil {
panic(err)
}
input := []byte("Lorem ipsum dolor sit amet")
obj, err := enc.Encrypt(input)
if err != nil {
t.Fatal("error in encrypt: ", err)
}
msg := obj.FullSerialize()
parsed, err := ParseEncrypted(msg)
if err != nil {
t.Fatal("error in parse: ", err)
}
i, _, output, err := parsed.DecryptMulti(rsaTestKey)
if err != nil {
t.Fatal("error on decrypt with RSA: ", err)
}
if i != 0 {
t.Fatal("recipient index should be 0 for RSA key")
}
if bytes.Compare(input, output) != 0 {
t.Fatal("Decrypted output does not match input: ", output, input)
}
i, _, output, err = parsed.DecryptMulti(sharedKey)
if err != nil {
t.Fatal("error on decrypt with AES: ", err)
}
if i != 1 {
t.Fatal("recipient index should be 1 for shared key")
}
if bytes.Compare(input, output) != 0 {
t.Fatal("Decrypted output does not match input", output, input)
}
}
func TestMultiRecipientErrors(t *testing.T) {
_, err := NewMultiEncrypter(A128GCM, []Recipient{}, nil)
if err == nil {
t.Error("should fail to instantiate with zero recipients")
}
}
func TestEncrypterOptions(t *testing.T) {
sharedKey := []byte{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
}
opts := &EncrypterOptions{
Compression: DEFLATE,
}
opts.WithType("JWT")
opts.WithContentType("JWT")
enc, err := NewEncrypter(A256GCM, Recipient{Algorithm: A256GCMKW, Key: sharedKey}, opts)
if err != nil {
fmt.Println(err)
t.Error("Failed to create encrypter")
}
if !reflect.DeepEqual(*opts, enc.Options()) {
t.Error("Encrypter options do not match")
}
}
// Test that extra headers are generated and parsed in a round trip.
func TestEncrypterExtraHeaderInclusion(t *testing.T) {
sharedKey := []byte{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
}
opts := &EncrypterOptions{
Compression: DEFLATE,
}
opts.WithType("JWT")
opts.WithContentType("JWT")
opts.WithHeader(HeaderKey("myCustomHeader"), "xyz")
enc, err := NewEncrypter(A256GCM, Recipient{Algorithm: A256GCMKW, Key: sharedKey}, opts)
if err != nil {
fmt.Println(err)
t.Error("Failed to create encrypter")
}
if !reflect.DeepEqual(*opts, enc.Options()) {
t.Error("Encrypter options do not match")
}
input := []byte("Lorem ipsum dolor sit amet")
obj, err := enc.Encrypt(input)
if err != nil {
t.Fatal("error in encrypt: ", err)
}
parsed, err := ParseEncrypted(obj.FullSerialize())
if err != nil {
t.Fatal("error in parse: ", err)
}
output, err := parsed.Decrypt(sharedKey)
if err != nil {
t.Fatal("error on decrypt: ", err)
}
if bytes.Compare(input, output) != 0 {
t.Fatal("Decrypted output does not match input: ", output, input)
}
if parsed.Header.ExtraHeaders[HeaderType] != "JWT" ||
parsed.Header.ExtraHeaders[HeaderContentType] != "JWT" ||
parsed.Header.ExtraHeaders[HeaderKey("myCustomHeader")] != "xyz" {
t.Fatalf("Mismatch in extra headers: %#v", parsed.Header.ExtraHeaders)
}
}
type testKey struct {
enc, dec interface{}
}
func symmetricTestKey(size int) []testKey {
key, _, _ := randomKeyGenerator{size: size}.genKey()
return []testKey{
{
enc: key,
dec: key,
},
{
enc: &JSONWebKey{KeyID: "test", Key: key},
dec: &JSONWebKey{KeyID: "test", Key: key},
},
}
}
func generateTestKeys(keyAlg KeyAlgorithm, encAlg ContentEncryption) []testKey {
switch keyAlg {
case DIRECT:
return symmetricTestKey(getContentCipher(encAlg).keySize())
case ECDH_ES, ECDH_ES_A128KW, ECDH_ES_A192KW, ECDH_ES_A256KW:
return []testKey{
{
dec: ecTestKey256,
enc: &ecTestKey256.PublicKey,
},
{
dec: ecTestKey384,
enc: &ecTestKey384.PublicKey,
},
{
dec: ecTestKey521,
enc: &ecTestKey521.PublicKey,
},
{
dec: &JSONWebKey{KeyID: "test", Key: ecTestKey256},
enc: &JSONWebKey{KeyID: "test", Key: &ecTestKey256.PublicKey},
},
}
case A128GCMKW, A128KW:
return symmetricTestKey(16)
case A192GCMKW, A192KW:
return symmetricTestKey(24)
case A256GCMKW, A256KW:
return symmetricTestKey(32)
case RSA1_5, RSA_OAEP, RSA_OAEP_256:
return []testKey{{
dec: rsaTestKey,
enc: &rsaTestKey.PublicKey,
}}
}
panic("Must update test case")
}
func RunRoundtripsJWE(b *testing.B, alg KeyAlgorithm, enc ContentEncryption, zip CompressionAlgorithm, priv, pub interface{}) {
serializer := func(obj *JSONWebEncryption) (string, error) {
return obj.CompactSerialize()
}
corrupter := func(obj *JSONWebEncryption) bool { return false }
b.ResetTimer()
for i := 0; i < b.N; i++ {
err := RoundtripJWE(alg, enc, zip, serializer, corrupter, nil, pub, priv)
if err != nil {
b.Error(err)
}
}
}
var (
chunks = map[string][]byte{
"1B": make([]byte, 1),
"64B": make([]byte, 64),
"1KB": make([]byte, 1024),
"64KB": make([]byte, 65536),
"1MB": make([]byte, 1048576),
"64MB": make([]byte, 67108864),
}
symKey, _, _ = randomKeyGenerator{size: 32}.genKey()
encrypters = map[string]Encrypter{
"OAEPAndGCM": mustEncrypter(RSA_OAEP, A128GCM, &rsaTestKey.PublicKey),
"PKCSAndGCM": mustEncrypter(RSA1_5, A128GCM, &rsaTestKey.PublicKey),
"OAEPAndCBC": mustEncrypter(RSA_OAEP, A128CBC_HS256, &rsaTestKey.PublicKey),
"PKCSAndCBC": mustEncrypter(RSA1_5, A128CBC_HS256, &rsaTestKey.PublicKey),
"DirectGCM128": mustEncrypter(DIRECT, A128GCM, symKey),
"DirectCBC128": mustEncrypter(DIRECT, A128CBC_HS256, symKey),
"DirectGCM256": mustEncrypter(DIRECT, A256GCM, symKey),
"DirectCBC256": mustEncrypter(DIRECT, A256CBC_HS512, symKey),
"AESKWAndGCM128": mustEncrypter(A128KW, A128GCM, symKey),
"AESKWAndCBC256": mustEncrypter(A256KW, A256GCM, symKey),
"ECDHOnP256AndGCM128": mustEncrypter(ECDH_ES, A128GCM, &ecTestKey256.PublicKey),
"ECDHOnP384AndGCM128": mustEncrypter(ECDH_ES, A128GCM, &ecTestKey384.PublicKey),
"ECDHOnP521AndGCM128": mustEncrypter(ECDH_ES, A128GCM, &ecTestKey521.PublicKey),
}
)
func BenchmarkEncrypt1BWithOAEPAndGCM(b *testing.B) { benchEncrypt("1B", "OAEPAndGCM", b) }
func BenchmarkEncrypt64BWithOAEPAndGCM(b *testing.B) { benchEncrypt("64B", "OAEPAndGCM", b) }
func BenchmarkEncrypt1KBWithOAEPAndGCM(b *testing.B) { benchEncrypt("1KB", "OAEPAndGCM", b) }
func BenchmarkEncrypt64KBWithOAEPAndGCM(b *testing.B) { benchEncrypt("64KB", "OAEPAndGCM", b) }
func BenchmarkEncrypt1MBWithOAEPAndGCM(b *testing.B) { benchEncrypt("1MB", "OAEPAndGCM", b) }
func BenchmarkEncrypt64MBWithOAEPAndGCM(b *testing.B) { benchEncrypt("64MB", "OAEPAndGCM", b) }
func BenchmarkEncrypt1BWithPKCSAndGCM(b *testing.B) { benchEncrypt("1B", "PKCSAndGCM", b) }
func BenchmarkEncrypt64BWithPKCSAndGCM(b *testing.B) { benchEncrypt("64B", "PKCSAndGCM", b) }
func BenchmarkEncrypt1KBWithPKCSAndGCM(b *testing.B) { benchEncrypt("1KB", "PKCSAndGCM", b) }
func BenchmarkEncrypt64KBWithPKCSAndGCM(b *testing.B) { benchEncrypt("64KB", "PKCSAndGCM", b) }
func BenchmarkEncrypt1MBWithPKCSAndGCM(b *testing.B) { benchEncrypt("1MB", "PKCSAndGCM", b) }
func BenchmarkEncrypt64MBWithPKCSAndGCM(b *testing.B) { benchEncrypt("64MB", "PKCSAndGCM", b) }
func BenchmarkEncrypt1BWithOAEPAndCBC(b *testing.B) { benchEncrypt("1B", "OAEPAndCBC", b) }
func BenchmarkEncrypt64BWithOAEPAndCBC(b *testing.B) { benchEncrypt("64B", "OAEPAndCBC", b) }
func BenchmarkEncrypt1KBWithOAEPAndCBC(b *testing.B) { benchEncrypt("1KB", "OAEPAndCBC", b) }
func BenchmarkEncrypt64KBWithOAEPAndCBC(b *testing.B) { benchEncrypt("64KB", "OAEPAndCBC", b) }
func BenchmarkEncrypt1MBWithOAEPAndCBC(b *testing.B) { benchEncrypt("1MB", "OAEPAndCBC", b) }
func BenchmarkEncrypt64MBWithOAEPAndCBC(b *testing.B) { benchEncrypt("64MB", "OAEPAndCBC", b) }
func BenchmarkEncrypt1BWithPKCSAndCBC(b *testing.B) { benchEncrypt("1B", "PKCSAndCBC", b) }
func BenchmarkEncrypt64BWithPKCSAndCBC(b *testing.B) { benchEncrypt("64B", "PKCSAndCBC", b) }
func BenchmarkEncrypt1KBWithPKCSAndCBC(b *testing.B) { benchEncrypt("1KB", "PKCSAndCBC", b) }
func BenchmarkEncrypt64KBWithPKCSAndCBC(b *testing.B) { benchEncrypt("64KB", "PKCSAndCBC", b) }
func BenchmarkEncrypt1MBWithPKCSAndCBC(b *testing.B) { benchEncrypt("1MB", "PKCSAndCBC", b) }
func BenchmarkEncrypt64MBWithPKCSAndCBC(b *testing.B) { benchEncrypt("64MB", "PKCSAndCBC", b) }
func BenchmarkEncrypt1BWithDirectGCM128(b *testing.B) { benchEncrypt("1B", "DirectGCM128", b) }
func BenchmarkEncrypt64BWithDirectGCM128(b *testing.B) { benchEncrypt("64B", "DirectGCM128", b) }
func BenchmarkEncrypt1KBWithDirectGCM128(b *testing.B) { benchEncrypt("1KB", "DirectGCM128", b) }
func BenchmarkEncrypt64KBWithDirectGCM128(b *testing.B) { benchEncrypt("64KB", "DirectGCM128", b) }
func BenchmarkEncrypt1MBWithDirectGCM128(b *testing.B) { benchEncrypt("1MB", "DirectGCM128", b) }
func BenchmarkEncrypt64MBWithDirectGCM128(b *testing.B) { benchEncrypt("64MB", "DirectGCM128", b) }
func BenchmarkEncrypt1BWithDirectCBC128(b *testing.B) { benchEncrypt("1B", "DirectCBC128", b) }
func BenchmarkEncrypt64BWithDirectCBC128(b *testing.B) { benchEncrypt("64B", "DirectCBC128", b) }
func BenchmarkEncrypt1KBWithDirectCBC128(b *testing.B) { benchEncrypt("1KB", "DirectCBC128", b) }
func BenchmarkEncrypt64KBWithDirectCBC128(b *testing.B) { benchEncrypt("64KB", "DirectCBC128", b) }
func BenchmarkEncrypt1MBWithDirectCBC128(b *testing.B) { benchEncrypt("1MB", "DirectCBC128", b) }
func BenchmarkEncrypt64MBWithDirectCBC128(b *testing.B) { benchEncrypt("64MB", "DirectCBC128", b) }
func BenchmarkEncrypt1BWithDirectGCM256(b *testing.B) { benchEncrypt("1B", "DirectGCM256", b) }
func BenchmarkEncrypt64BWithDirectGCM256(b *testing.B) { benchEncrypt("64B", "DirectGCM256", b) }
func BenchmarkEncrypt1KBWithDirectGCM256(b *testing.B) { benchEncrypt("1KB", "DirectGCM256", b) }
func BenchmarkEncrypt64KBWithDirectGCM256(b *testing.B) { benchEncrypt("64KB", "DirectGCM256", b) }
func BenchmarkEncrypt1MBWithDirectGCM256(b *testing.B) { benchEncrypt("1MB", "DirectGCM256", b) }
func BenchmarkEncrypt64MBWithDirectGCM256(b *testing.B) { benchEncrypt("64MB", "DirectGCM256", b) }
func BenchmarkEncrypt1BWithDirectCBC256(b *testing.B) { benchEncrypt("1B", "DirectCBC256", b) }
func BenchmarkEncrypt64BWithDirectCBC256(b *testing.B) { benchEncrypt("64B", "DirectCBC256", b) }
func BenchmarkEncrypt1KBWithDirectCBC256(b *testing.B) { benchEncrypt("1KB", "DirectCBC256", b) }
func BenchmarkEncrypt64KBWithDirectCBC256(b *testing.B) { benchEncrypt("64KB", "DirectCBC256", b) }
func BenchmarkEncrypt1MBWithDirectCBC256(b *testing.B) { benchEncrypt("1MB", "DirectCBC256", b) }
func BenchmarkEncrypt64MBWithDirectCBC256(b *testing.B) { benchEncrypt("64MB", "DirectCBC256", b) }
func BenchmarkEncrypt1BWithAESKWAndGCM128(b *testing.B) { benchEncrypt("1B", "AESKWAndGCM128", b) }
func BenchmarkEncrypt64BWithAESKWAndGCM128(b *testing.B) { benchEncrypt("64B", "AESKWAndGCM128", b) }
func BenchmarkEncrypt1KBWithAESKWAndGCM128(b *testing.B) { benchEncrypt("1KB", "AESKWAndGCM128", b) }
func BenchmarkEncrypt64KBWithAESKWAndGCM128(b *testing.B) { benchEncrypt("64KB", "AESKWAndGCM128", b) }
func BenchmarkEncrypt1MBWithAESKWAndGCM128(b *testing.B) { benchEncrypt("1MB", "AESKWAndGCM128", b) }
func BenchmarkEncrypt64MBWithAESKWAndGCM128(b *testing.B) { benchEncrypt("64MB", "AESKWAndGCM128", b) }
func BenchmarkEncrypt1BWithAESKWAndCBC256(b *testing.B) { benchEncrypt("1B", "AESKWAndCBC256", b) }
func BenchmarkEncrypt64BWithAESKWAndCBC256(b *testing.B) { benchEncrypt("64B", "AESKWAndCBC256", b) }
func BenchmarkEncrypt1KBWithAESKWAndCBC256(b *testing.B) { benchEncrypt("1KB", "AESKWAndCBC256", b) }
func BenchmarkEncrypt64KBWithAESKWAndCBC256(b *testing.B) { benchEncrypt("64KB", "AESKWAndCBC256", b) }
func BenchmarkEncrypt1MBWithAESKWAndCBC256(b *testing.B) { benchEncrypt("1MB", "AESKWAndCBC256", b) }
func BenchmarkEncrypt64MBWithAESKWAndCBC256(b *testing.B) { benchEncrypt("64MB", "AESKWAndCBC256", b) }
func BenchmarkEncrypt1BWithECDHOnP256AndGCM128(b *testing.B) {
benchEncrypt("1B", "ECDHOnP256AndGCM128", b)
}
func BenchmarkEncrypt64BWithECDHOnP256AndGCM128(b *testing.B) {
benchEncrypt("64B", "ECDHOnP256AndGCM128", b)
}
func BenchmarkEncrypt1KBWithECDHOnP256AndGCM128(b *testing.B) {
benchEncrypt("1KB", "ECDHOnP256AndGCM128", b)
}
func BenchmarkEncrypt64KBWithECDHOnP256AndGCM128(b *testing.B) {
benchEncrypt("64KB", "ECDHOnP256AndGCM128", b)
}
func BenchmarkEncrypt1MBWithECDHOnP256AndGCM128(b *testing.B) {
benchEncrypt("1MB", "ECDHOnP256AndGCM128", b)
}
func BenchmarkEncrypt64MBWithECDHOnP256AndGCM128(b *testing.B) {
benchEncrypt("64MB", "ECDHOnP256AndGCM128", b)
}
func BenchmarkEncrypt1BWithECDHOnP384AndGCM128(b *testing.B) {
benchEncrypt("1B", "ECDHOnP384AndGCM128", b)
}
func BenchmarkEncrypt64BWithECDHOnP384AndGCM128(b *testing.B) {
benchEncrypt("64B", "ECDHOnP384AndGCM128", b)
}
func BenchmarkEncrypt1KBWithECDHOnP384AndGCM128(b *testing.B) {
benchEncrypt("1KB", "ECDHOnP384AndGCM128", b)
}
func BenchmarkEncrypt64KBWithECDHOnP384AndGCM128(b *testing.B) {
benchEncrypt("64KB", "ECDHOnP384AndGCM128", b)
}
func BenchmarkEncrypt1MBWithECDHOnP384AndGCM128(b *testing.B) {
benchEncrypt("1MB", "ECDHOnP384AndGCM128", b)
}
func BenchmarkEncrypt64MBWithECDHOnP384AndGCM128(b *testing.B) {
benchEncrypt("64MB", "ECDHOnP384AndGCM128", b)
}
func BenchmarkEncrypt1BWithECDHOnP521AndGCM128(b *testing.B) {
benchEncrypt("1B", "ECDHOnP521AndGCM128", b)
}
func BenchmarkEncrypt64BWithECDHOnP521AndGCM128(b *testing.B) {
benchEncrypt("64B", "ECDHOnP521AndGCM128", b)
}
func BenchmarkEncrypt1KBWithECDHOnP521AndGCM128(b *testing.B) {
benchEncrypt("1KB", "ECDHOnP521AndGCM128", b)
}
func BenchmarkEncrypt64KBWithECDHOnP521AndGCM128(b *testing.B) {
benchEncrypt("64KB", "ECDHOnP521AndGCM128", b)
}
func BenchmarkEncrypt1MBWithECDHOnP521AndGCM128(b *testing.B) {
benchEncrypt("1MB", "ECDHOnP521AndGCM128", b)
}
func BenchmarkEncrypt64MBWithECDHOnP521AndGCM128(b *testing.B) {
benchEncrypt("64MB", "ECDHOnP521AndGCM128", b)
}
func benchEncrypt(chunkKey, primKey string, b *testing.B) {
data, ok := chunks[chunkKey]
if !ok {
b.Fatalf("unknown chunk size %s", chunkKey)
}
enc, ok := encrypters[primKey]
if !ok {
b.Fatalf("unknown encrypter %s", primKey)
}
b.SetBytes(int64(len(data)))
for i := 0; i < b.N; i++ {
enc.Encrypt(data)
}
}
var (
decryptionKeys = map[string]interface{}{
"OAEPAndGCM": rsaTestKey,
"PKCSAndGCM": rsaTestKey,
"OAEPAndCBC": rsaTestKey,
"PKCSAndCBC": rsaTestKey,
"DirectGCM128": symKey,
"DirectCBC128": symKey,
"DirectGCM256": symKey,
"DirectCBC256": symKey,
"AESKWAndGCM128": symKey,
"AESKWAndCBC256": symKey,
"ECDHOnP256AndGCM128": ecTestKey256,
"ECDHOnP384AndGCM128": ecTestKey384,
"ECDHOnP521AndGCM128": ecTestKey521,
}
)
func BenchmarkDecrypt1BWithOAEPAndGCM(b *testing.B) { benchDecrypt("1B", "OAEPAndGCM", b) }
func BenchmarkDecrypt64BWithOAEPAndGCM(b *testing.B) { benchDecrypt("64B", "OAEPAndGCM", b) }
func BenchmarkDecrypt1KBWithOAEPAndGCM(b *testing.B) { benchDecrypt("1KB", "OAEPAndGCM", b) }
func BenchmarkDecrypt64KBWithOAEPAndGCM(b *testing.B) { benchDecrypt("64KB", "OAEPAndGCM", b) }
func BenchmarkDecrypt1MBWithOAEPAndGCM(b *testing.B) { benchDecrypt("1MB", "OAEPAndGCM", b) }
func BenchmarkDecrypt64MBWithOAEPAndGCM(b *testing.B) { benchDecrypt("64MB", "OAEPAndGCM", b) }
func BenchmarkDecrypt1BWithPKCSAndGCM(b *testing.B) { benchDecrypt("1B", "PKCSAndGCM", b) }
func BenchmarkDecrypt64BWithPKCSAndGCM(b *testing.B) { benchDecrypt("64B", "PKCSAndGCM", b) }
func BenchmarkDecrypt1KBWithPKCSAndGCM(b *testing.B) { benchDecrypt("1KB", "PKCSAndGCM", b) }
func BenchmarkDecrypt64KBWithPKCSAndGCM(b *testing.B) { benchDecrypt("64KB", "PKCSAndGCM", b) }
func BenchmarkDecrypt1MBWithPKCSAndGCM(b *testing.B) { benchDecrypt("1MB", "PKCSAndGCM", b) }
func BenchmarkDecrypt64MBWithPKCSAndGCM(b *testing.B) { benchDecrypt("64MB", "PKCSAndGCM", b) }
func BenchmarkDecrypt1BWithOAEPAndCBC(b *testing.B) { benchDecrypt("1B", "OAEPAndCBC", b) }
func BenchmarkDecrypt64BWithOAEPAndCBC(b *testing.B) { benchDecrypt("64B", "OAEPAndCBC", b) }
func BenchmarkDecrypt1KBWithOAEPAndCBC(b *testing.B) { benchDecrypt("1KB", "OAEPAndCBC", b) }
func BenchmarkDecrypt64KBWithOAEPAndCBC(b *testing.B) { benchDecrypt("64KB", "OAEPAndCBC", b) }
func BenchmarkDecrypt1MBWithOAEPAndCBC(b *testing.B) { benchDecrypt("1MB", "OAEPAndCBC", b) }
func BenchmarkDecrypt64MBWithOAEPAndCBC(b *testing.B) { benchDecrypt("64MB", "OAEPAndCBC", b) }
func BenchmarkDecrypt1BWithPKCSAndCBC(b *testing.B) { benchDecrypt("1B", "PKCSAndCBC", b) }
func BenchmarkDecrypt64BWithPKCSAndCBC(b *testing.B) { benchDecrypt("64B", "PKCSAndCBC", b) }
func BenchmarkDecrypt1KBWithPKCSAndCBC(b *testing.B) { benchDecrypt("1KB", "PKCSAndCBC", b) }
func BenchmarkDecrypt64KBWithPKCSAndCBC(b *testing.B) { benchDecrypt("64KB", "PKCSAndCBC", b) }
func BenchmarkDecrypt1MBWithPKCSAndCBC(b *testing.B) { benchDecrypt("1MB", "PKCSAndCBC", b) }
func BenchmarkDecrypt64MBWithPKCSAndCBC(b *testing.B) { benchDecrypt("64MB", "PKCSAndCBC", b) }
func BenchmarkDecrypt1BWithDirectGCM128(b *testing.B) { benchDecrypt("1B", "DirectGCM128", b) }
func BenchmarkDecrypt64BWithDirectGCM128(b *testing.B) { benchDecrypt("64B", "DirectGCM128", b) }
func BenchmarkDecrypt1KBWithDirectGCM128(b *testing.B) { benchDecrypt("1KB", "DirectGCM128", b) }
func BenchmarkDecrypt64KBWithDirectGCM128(b *testing.B) { benchDecrypt("64KB", "DirectGCM128", b) }
func BenchmarkDecrypt1MBWithDirectGCM128(b *testing.B) { benchDecrypt("1MB", "DirectGCM128", b) }
func BenchmarkDecrypt64MBWithDirectGCM128(b *testing.B) { benchDecrypt("64MB", "DirectGCM128", b) }
func BenchmarkDecrypt1BWithDirectCBC128(b *testing.B) { benchDecrypt("1B", "DirectCBC128", b) }
func BenchmarkDecrypt64BWithDirectCBC128(b *testing.B) { benchDecrypt("64B", "DirectCBC128", b) }
func BenchmarkDecrypt1KBWithDirectCBC128(b *testing.B) { benchDecrypt("1KB", "DirectCBC128", b) }
func BenchmarkDecrypt64KBWithDirectCBC128(b *testing.B) { benchDecrypt("64KB", "DirectCBC128", b) }
func BenchmarkDecrypt1MBWithDirectCBC128(b *testing.B) { benchDecrypt("1MB", "DirectCBC128", b) }
func BenchmarkDecrypt64MBWithDirectCBC128(b *testing.B) { benchDecrypt("64MB", "DirectCBC128", b) }
func BenchmarkDecrypt1BWithDirectGCM256(b *testing.B) { benchDecrypt("1B", "DirectGCM256", b) }
func BenchmarkDecrypt64BWithDirectGCM256(b *testing.B) { benchDecrypt("64B", "DirectGCM256", b) }
func BenchmarkDecrypt1KBWithDirectGCM256(b *testing.B) { benchDecrypt("1KB", "DirectGCM256", b) }
func BenchmarkDecrypt64KBWithDirectGCM256(b *testing.B) { benchDecrypt("64KB", "DirectGCM256", b) }
func BenchmarkDecrypt1MBWithDirectGCM256(b *testing.B) { benchDecrypt("1MB", "DirectGCM256", b) }
func BenchmarkDecrypt64MBWithDirectGCM256(b *testing.B) { benchDecrypt("64MB", "DirectGCM256", b) }
func BenchmarkDecrypt1BWithDirectCBC256(b *testing.B) { benchDecrypt("1B", "DirectCBC256", b) }
func BenchmarkDecrypt64BWithDirectCBC256(b *testing.B) { benchDecrypt("64B", "DirectCBC256", b) }
func BenchmarkDecrypt1KBWithDirectCBC256(b *testing.B) { benchDecrypt("1KB", "DirectCBC256", b) }
func BenchmarkDecrypt64KBWithDirectCBC256(b *testing.B) { benchDecrypt("64KB", "DirectCBC256", b) }
func BenchmarkDecrypt1MBWithDirectCBC256(b *testing.B) { benchDecrypt("1MB", "DirectCBC256", b) }
func BenchmarkDecrypt64MBWithDirectCBC256(b *testing.B) { benchDecrypt("64MB", "DirectCBC256", b) }
func BenchmarkDecrypt1BWithAESKWAndGCM128(b *testing.B) { benchDecrypt("1B", "AESKWAndGCM128", b) }
func BenchmarkDecrypt64BWithAESKWAndGCM128(b *testing.B) { benchDecrypt("64B", "AESKWAndGCM128", b) }
func BenchmarkDecrypt1KBWithAESKWAndGCM128(b *testing.B) { benchDecrypt("1KB", "AESKWAndGCM128", b) }
func BenchmarkDecrypt64KBWithAESKWAndGCM128(b *testing.B) { benchDecrypt("64KB", "AESKWAndGCM128", b) }
func BenchmarkDecrypt1MBWithAESKWAndGCM128(b *testing.B) { benchDecrypt("1MB", "AESKWAndGCM128", b) }
func BenchmarkDecrypt64MBWithAESKWAndGCM128(b *testing.B) { benchDecrypt("64MB", "AESKWAndGCM128", b) }
func BenchmarkDecrypt1BWithAESKWAndCBC256(b *testing.B) { benchDecrypt("1B", "AESKWAndCBC256", b) }
func BenchmarkDecrypt64BWithAESKWAndCBC256(b *testing.B) { benchDecrypt("64B", "AESKWAndCBC256", b) }
func BenchmarkDecrypt1KBWithAESKWAndCBC256(b *testing.B) { benchDecrypt("1KB", "AESKWAndCBC256", b) }
func BenchmarkDecrypt64KBWithAESKWAndCBC256(b *testing.B) { benchDecrypt("64KB", "AESKWAndCBC256", b) }
func BenchmarkDecrypt1MBWithAESKWAndCBC256(b *testing.B) { benchDecrypt("1MB", "AESKWAndCBC256", b) }
func BenchmarkDecrypt64MBWithAESKWAndCBC256(b *testing.B) { benchDecrypt("64MB", "AESKWAndCBC256", b) }
func BenchmarkDecrypt1BWithECDHOnP256AndGCM128(b *testing.B) {
benchDecrypt("1B", "ECDHOnP256AndGCM128", b)
}
func BenchmarkDecrypt64BWithECDHOnP256AndGCM128(b *testing.B) {
benchDecrypt("64B", "ECDHOnP256AndGCM128", b)
}
func BenchmarkDecrypt1KBWithECDHOnP256AndGCM128(b *testing.B) {
benchDecrypt("1KB", "ECDHOnP256AndGCM128", b)
}
func BenchmarkDecrypt64KBWithECDHOnP256AndGCM128(b *testing.B) {
benchDecrypt("64KB", "ECDHOnP256AndGCM128", b)
}
func BenchmarkDecrypt1MBWithECDHOnP256AndGCM128(b *testing.B) {
benchDecrypt("1MB", "ECDHOnP256AndGCM128", b)
}
func BenchmarkDecrypt64MBWithECDHOnP256AndGCM128(b *testing.B) {
benchDecrypt("64MB", "ECDHOnP256AndGCM128", b)
}
func BenchmarkDecrypt1BWithECDHOnP384AndGCM128(b *testing.B) {
benchDecrypt("1B", "ECDHOnP384AndGCM128", b)
}
func BenchmarkDecrypt64BWithECDHOnP384AndGCM128(b *testing.B) {
benchDecrypt("64B", "ECDHOnP384AndGCM128", b)
}
func BenchmarkDecrypt1KBWithECDHOnP384AndGCM128(b *testing.B) {
benchDecrypt("1KB", "ECDHOnP384AndGCM128", b)
}
func BenchmarkDecrypt64KBWithECDHOnP384AndGCM128(b *testing.B) {
benchDecrypt("64KB", "ECDHOnP384AndGCM128", b)
}
func BenchmarkDecrypt1MBWithECDHOnP384AndGCM128(b *testing.B) {
benchDecrypt("1MB", "ECDHOnP384AndGCM128", b)
}
func BenchmarkDecrypt64MBWithECDHOnP384AndGCM128(b *testing.B) {
benchDecrypt("64MB", "ECDHOnP384AndGCM128", b)
}
func BenchmarkDecrypt1BWithECDHOnP521AndGCM128(b *testing.B) {
benchDecrypt("1B", "ECDHOnP521AndGCM128", b)
}
func BenchmarkDecrypt64BWithECDHOnP521AndGCM128(b *testing.B) {
benchDecrypt("64B", "ECDHOnP521AndGCM128", b)
}
func BenchmarkDecrypt1KBWithECDHOnP521AndGCM128(b *testing.B) {
benchDecrypt("1KB", "ECDHOnP521AndGCM128", b)
}
func BenchmarkDecrypt64KBWithECDHOnP521AndGCM128(b *testing.B) {
benchDecrypt("64KB", "ECDHOnP521AndGCM128", b)
}
func BenchmarkDecrypt1MBWithECDHOnP521AndGCM128(b *testing.B) {
benchDecrypt("1MB", "ECDHOnP521AndGCM128", b)
}
func BenchmarkDecrypt64MBWithECDHOnP521AndGCM128(b *testing.B) {
benchDecrypt("64MB", "ECDHOnP521AndGCM128", b)
}
func benchDecrypt(chunkKey, primKey string, b *testing.B) {
chunk, ok := chunks[chunkKey]
if !ok {
b.Fatalf("unknown chunk size %s", chunkKey)
}
enc, ok := encrypters[primKey]
if !ok {
b.Fatalf("unknown encrypter %s", primKey)
}
dec, ok := decryptionKeys[primKey]
if !ok {
b.Fatalf("unknown decryption key %s", primKey)
}
data, err := enc.Encrypt(chunk)
if err != nil {
b.Fatal(err)
}
b.SetBytes(int64(len(chunk)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
data.Decrypt(dec)
}
}
func mustEncrypter(keyAlg KeyAlgorithm, encAlg ContentEncryption, encryptionKey interface{}) Encrypter {
enc, err := NewEncrypter(encAlg, Recipient{Algorithm: keyAlg, Key: encryptionKey}, nil)
if err != nil {
panic(err)
}
return enc
}

View file

@ -1,201 +0,0 @@
/*-
* 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/ecdsa"
"crypto/rand"
"crypto/rsa"
"fmt"
)
// Dummy encrypter for use in examples
var encrypter Encrypter
func Example_jWE() {
// Generate a public/private key pair to use for this example.
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
// Instantiate an encrypter using RSA-OAEP with AES128-GCM. An error would
// indicate that the selected algorithm(s) are not currently supported.
publicKey := &privateKey.PublicKey
encrypter, err := NewEncrypter(A128GCM, Recipient{Algorithm: RSA_OAEP, Key: publicKey}, nil)
if err != nil {
panic(err)
}
// Encrypt a sample plaintext. Calling the encrypter returns an encrypted
// JWE object, which can then be serialized for output afterwards. An error
// would indicate a problem in an underlying cryptographic primitive.
var plaintext = []byte("Lorem ipsum dolor sit amet")
object, err := encrypter.Encrypt(plaintext)
if err != nil {
panic(err)
}
// Serialize the encrypted object using the full serialization format.
// Alternatively you can also use the compact format here by calling
// object.CompactSerialize() instead.
serialized := object.FullSerialize()
// Parse the serialized, encrypted JWE object. An error would indicate that
// the given input did not represent a valid message.
object, err = ParseEncrypted(serialized)
if err != nil {
panic(err)
}
// Now we can decrypt and get back our original plaintext. An error here
// would indicate the the message failed to decrypt, e.g. because the auth
// tag was broken or the message was tampered with.
decrypted, err := object.Decrypt(privateKey)
if err != nil {
panic(err)
}
fmt.Printf(string(decrypted))
// output: Lorem ipsum dolor sit amet
}
func Example_jWS() {
// Generate a public/private key pair to use for this example.
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
// Instantiate a signer using RSASSA-PSS (SHA512) with the given private key.
signer, err := NewSigner(SigningKey{Algorithm: PS512, Key: privateKey}, nil)
if err != nil {
panic(err)
}
// Sign a sample payload. Calling the signer returns a protected JWS object,
// which can then be serialized for output afterwards. An error would
// indicate a problem in an underlying cryptographic primitive.
var payload = []byte("Lorem ipsum dolor sit amet")
object, err := signer.Sign(payload)
if err != nil {
panic(err)
}
// Serialize the encrypted object using the full serialization format.
// Alternatively you can also use the compact format here by calling
// object.CompactSerialize() instead.
serialized := object.FullSerialize()
// Parse the serialized, protected JWS object. An error would indicate that
// the given input did not represent a valid message.
object, err = ParseSigned(serialized)
if err != nil {
panic(err)
}
// Now we can verify the signature on the payload. An error here would
// indicate the the message failed to verify, e.g. because the signature was
// broken or the message was tampered with.
output, err := object.Verify(&privateKey.PublicKey)
if err != nil {
panic(err)
}
fmt.Printf(string(output))
// output: Lorem ipsum dolor sit amet
}
func ExampleNewEncrypter_publicKey() {
var publicKey *rsa.PublicKey
// Instantiate an encrypter using RSA-OAEP with AES128-GCM.
NewEncrypter(A128GCM, Recipient{Algorithm: RSA_OAEP, Key: publicKey}, nil)
// Instantiate an encrypter using RSA-PKCS1v1.5 with AES128-CBC+HMAC.
NewEncrypter(A128CBC_HS256, Recipient{Algorithm: RSA1_5, Key: publicKey}, nil)
}
func ExampleNewEncrypter_symmetric() {
var sharedKey []byte
// Instantiate an encrypter using AES128-GCM with AES-GCM key wrap.
NewEncrypter(A128GCM, Recipient{Algorithm: A128GCMKW, Key: sharedKey}, nil)
// Instantiate an encrypter using AES128-GCM directly, w/o key wrapping.
NewEncrypter(A128GCM, Recipient{Algorithm: DIRECT, Key: sharedKey}, nil)
}
func ExampleNewSigner_publicKey() {
var rsaPrivateKey *rsa.PrivateKey
var ecdsaPrivateKey *ecdsa.PrivateKey
// Instantiate a signer using RSA-PKCS#1v1.5 with SHA-256.
NewSigner(SigningKey{Algorithm: RS256, Key: rsaPrivateKey}, nil)
// Instantiate a signer using ECDSA with SHA-384.
NewSigner(SigningKey{Algorithm: ES384, Key: ecdsaPrivateKey}, nil)
}
func ExampleNewSigner_symmetric() {
var sharedKey []byte
// Instantiate an signer using HMAC-SHA256.
NewSigner(SigningKey{Algorithm: HS256, Key: sharedKey}, nil)
// Instantiate an signer using HMAC-SHA512.
NewSigner(SigningKey{Algorithm: HS512, Key: sharedKey}, nil)
}
func ExampleNewMultiEncrypter() {
var publicKey *rsa.PublicKey
var sharedKey []byte
// Instantiate an encrypter using AES-GCM.
NewMultiEncrypter(A128GCM, []Recipient{
{Algorithm: A128GCMKW, Key: sharedKey},
{Algorithm: RSA_OAEP, Key: publicKey},
}, nil)
}
func ExampleNewMultiSigner() {
var privateKey *rsa.PrivateKey
var sharedKey []byte
// Instantiate a signer for multiple recipients.
NewMultiSigner([]SigningKey{
{Algorithm: HS256, Key: sharedKey},
{Algorithm: PS384, Key: privateKey},
}, nil)
}
func ExampleEncrypter_encrypt() {
// Encrypt a plaintext in order to get an encrypted JWE object.
var plaintext = []byte("This is a secret message")
encrypter.Encrypt(plaintext)
}
func ExampleEncrypter_encryptWithAuthData() {
// Encrypt a plaintext in order to get an encrypted JWE object. Also attach
// some additional authenticated data (AAD) to the object. Note that objects
// with attached AAD can only be represented using full serialization.
var plaintext = []byte("This is a secret message")
var aad = []byte("This is authenticated, but public data")
encrypter.EncryptWithAuthData(plaintext, aad)
}

View file

@ -1,122 +0,0 @@
/*-
* 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 (
"bytes"
"strings"
"testing"
)
func TestDeflateRoundtrip(t *testing.T) {
original := []byte("Lorem ipsum dolor sit amet")
compressed, err := deflate(original)
if err != nil {
panic(err)
}
output, err := inflate(compressed)
if err != nil {
panic(err)
}
if bytes.Compare(output, original) != 0 {
t.Error("Input and output do not match")
}
}
func TestInvalidCompression(t *testing.T) {
_, err := compress("XYZ", []byte{})
if err == nil {
t.Error("should not accept invalid algorithm")
}
_, err = decompress("XYZ", []byte{})
if err == nil {
t.Error("should not accept invalid algorithm")
}
_, err = decompress(DEFLATE, []byte{1, 2, 3, 4})
if err == nil {
t.Error("should not accept invalid data")
}
}
func TestByteBufferTrim(t *testing.T) {
buf := newBufferFromInt(1)
if !bytes.Equal(buf.data, []byte{1}) {
t.Error("Byte buffer for integer '1' should contain [0x01]")
}
buf = newBufferFromInt(65537)
if !bytes.Equal(buf.data, []byte{1, 0, 1}) {
t.Error("Byte buffer for integer '65537' should contain [0x01, 0x00, 0x01]")
}
}
func TestFixedSizeBuffer(t *testing.T) {
data0 := []byte{}
data1 := []byte{1}
data2 := []byte{1, 2}
data3 := []byte{1, 2, 3}
data4 := []byte{1, 2, 3, 4}
buf0 := newFixedSizeBuffer(data0, 4)
buf1 := newFixedSizeBuffer(data1, 4)
buf2 := newFixedSizeBuffer(data2, 4)
buf3 := newFixedSizeBuffer(data3, 4)
buf4 := newFixedSizeBuffer(data4, 4)
if !bytes.Equal(buf0.data, []byte{0, 0, 0, 0}) {
t.Error("Invalid padded buffer for buf0")
}
if !bytes.Equal(buf1.data, []byte{0, 0, 0, 1}) {
t.Error("Invalid padded buffer for buf1")
}
if !bytes.Equal(buf2.data, []byte{0, 0, 1, 2}) {
t.Error("Invalid padded buffer for buf2")
}
if !bytes.Equal(buf3.data, []byte{0, 1, 2, 3}) {
t.Error("Invalid padded buffer for buf3")
}
if !bytes.Equal(buf4.data, []byte{1, 2, 3, 4}) {
t.Error("Invalid padded buffer for buf4")
}
}
func TestSerializeJSONRejectsNil(t *testing.T) {
defer func() {
r := recover()
if r == nil || !strings.Contains(r.(string), "nil pointer") {
t.Error("serialize function should not accept nil pointer")
}
}()
mustSerializeJSON(nil)
}
func TestFixedSizeBufferTooLarge(t *testing.T) {
defer func() {
r := recover()
if r == nil {
t.Error("should not be able to create fixed size buffer with oversized data")
}
}()
newFixedSizeBuffer(make([]byte, 2), 1)
}

View file

@ -1,223 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Large data benchmark.
// The JSON data is a summary of agl's changes in the
// go, webkit, and chromium open source projects.
// We benchmark converting between the JSON form
// and in-memory data structures.
package json
import (
"bytes"
"compress/gzip"
"io/ioutil"
"os"
"strings"
"testing"
)
type codeResponse struct {
Tree *codeNode `json:"tree"`
Username string `json:"username"`
}
type codeNode struct {
Name string `json:"name"`
Kids []*codeNode `json:"kids"`
CLWeight float64 `json:"cl_weight"`
Touches int `json:"touches"`
MinT int64 `json:"min_t"`
MaxT int64 `json:"max_t"`
MeanT int64 `json:"mean_t"`
}
var codeJSON []byte
var codeStruct codeResponse
func codeInit() {
f, err := os.Open("testdata/code.json.gz")
if err != nil {
panic(err)
}
defer f.Close()
gz, err := gzip.NewReader(f)
if err != nil {
panic(err)
}
data, err := ioutil.ReadAll(gz)
if err != nil {
panic(err)
}
codeJSON = data
if err := Unmarshal(codeJSON, &codeStruct); err != nil {
panic("unmarshal code.json: " + err.Error())
}
if data, err = Marshal(&codeStruct); err != nil {
panic("marshal code.json: " + err.Error())
}
if !bytes.Equal(data, codeJSON) {
println("different lengths", len(data), len(codeJSON))
for i := 0; i < len(data) && i < len(codeJSON); i++ {
if data[i] != codeJSON[i] {
println("re-marshal: changed at byte", i)
println("orig: ", string(codeJSON[i-10:i+10]))
println("new: ", string(data[i-10:i+10]))
break
}
}
panic("re-marshal code.json: different result")
}
}
func BenchmarkCodeEncoder(b *testing.B) {
if codeJSON == nil {
b.StopTimer()
codeInit()
b.StartTimer()
}
enc := NewEncoder(ioutil.Discard)
for i := 0; i < b.N; i++ {
if err := enc.Encode(&codeStruct); err != nil {
b.Fatal("Encode:", err)
}
}
b.SetBytes(int64(len(codeJSON)))
}
func BenchmarkCodeMarshal(b *testing.B) {
if codeJSON == nil {
b.StopTimer()
codeInit()
b.StartTimer()
}
for i := 0; i < b.N; i++ {
if _, err := Marshal(&codeStruct); err != nil {
b.Fatal("Marshal:", err)
}
}
b.SetBytes(int64(len(codeJSON)))
}
func BenchmarkCodeDecoder(b *testing.B) {
if codeJSON == nil {
b.StopTimer()
codeInit()
b.StartTimer()
}
var buf bytes.Buffer
dec := NewDecoder(&buf)
var r codeResponse
for i := 0; i < b.N; i++ {
buf.Write(codeJSON)
// hide EOF
buf.WriteByte('\n')
buf.WriteByte('\n')
buf.WriteByte('\n')
if err := dec.Decode(&r); err != nil {
b.Fatal("Decode:", err)
}
}
b.SetBytes(int64(len(codeJSON)))
}
func BenchmarkDecoderStream(b *testing.B) {
b.StopTimer()
var buf bytes.Buffer
dec := NewDecoder(&buf)
buf.WriteString(`"` + strings.Repeat("x", 1000000) + `"` + "\n\n\n")
var x interface{}
if err := dec.Decode(&x); err != nil {
b.Fatal("Decode:", err)
}
ones := strings.Repeat(" 1\n", 300000) + "\n\n\n"
b.StartTimer()
for i := 0; i < b.N; i++ {
if i%300000 == 0 {
buf.WriteString(ones)
}
x = nil
if err := dec.Decode(&x); err != nil || x != 1.0 {
b.Fatalf("Decode: %v after %d", err, i)
}
}
}
func BenchmarkCodeUnmarshal(b *testing.B) {
if codeJSON == nil {
b.StopTimer()
codeInit()
b.StartTimer()
}
for i := 0; i < b.N; i++ {
var r codeResponse
if err := Unmarshal(codeJSON, &r); err != nil {
b.Fatal("Unmmarshal:", err)
}
}
b.SetBytes(int64(len(codeJSON)))
}
func BenchmarkCodeUnmarshalReuse(b *testing.B) {
if codeJSON == nil {
b.StopTimer()
codeInit()
b.StartTimer()
}
var r codeResponse
for i := 0; i < b.N; i++ {
if err := Unmarshal(codeJSON, &r); err != nil {
b.Fatal("Unmmarshal:", err)
}
}
}
func BenchmarkUnmarshalString(b *testing.B) {
data := []byte(`"hello, world"`)
var s string
for i := 0; i < b.N; i++ {
if err := Unmarshal(data, &s); err != nil {
b.Fatal("Unmarshal:", err)
}
}
}
func BenchmarkUnmarshalFloat64(b *testing.B) {
var f float64
data := []byte(`3.14`)
for i := 0; i < b.N; i++ {
if err := Unmarshal(data, &f); err != nil {
b.Fatal("Unmarshal:", err)
}
}
}
func BenchmarkUnmarshalInt64(b *testing.B) {
var x int64
data := []byte(`3`)
for i := 0; i < b.N; i++ {
if err := Unmarshal(data, &x); err != nil {
b.Fatal("Unmarshal:", err)
}
}
}
func BenchmarkIssue10335(b *testing.B) {
b.ReportAllocs()
var s struct{}
j := []byte(`{"a":{ }}`)
for n := 0; n < b.N; n++ {
if err := Unmarshal(j, &s); err != nil {
b.Fatal(err)
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,538 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package json
import (
"bytes"
"math"
"reflect"
"testing"
"unicode"
)
type Optionals struct {
Sr string `json:"sr"`
So string `json:"so,omitempty"`
Sw string `json:"-"`
Ir int `json:"omitempty"` // actually named omitempty, not an option
Io int `json:"io,omitempty"`
Slr []string `json:"slr,random"`
Slo []string `json:"slo,omitempty"`
Mr map[string]interface{} `json:"mr"`
Mo map[string]interface{} `json:",omitempty"`
Fr float64 `json:"fr"`
Fo float64 `json:"fo,omitempty"`
Br bool `json:"br"`
Bo bool `json:"bo,omitempty"`
Ur uint `json:"ur"`
Uo uint `json:"uo,omitempty"`
Str struct{} `json:"str"`
Sto struct{} `json:"sto,omitempty"`
}
var optionalsExpected = `{
"sr": "",
"omitempty": 0,
"slr": null,
"mr": {},
"fr": 0,
"br": false,
"ur": 0,
"str": {},
"sto": {}
}`
func TestOmitEmpty(t *testing.T) {
var o Optionals
o.Sw = "something"
o.Mr = map[string]interface{}{}
o.Mo = map[string]interface{}{}
got, err := MarshalIndent(&o, "", " ")
if err != nil {
t.Fatal(err)
}
if got := string(got); got != optionalsExpected {
t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected)
}
}
type StringTag struct {
BoolStr bool `json:",string"`
IntStr int64 `json:",string"`
StrStr string `json:",string"`
}
var stringTagExpected = `{
"BoolStr": "true",
"IntStr": "42",
"StrStr": "\"xzbit\""
}`
func TestStringTag(t *testing.T) {
var s StringTag
s.BoolStr = true
s.IntStr = 42
s.StrStr = "xzbit"
got, err := MarshalIndent(&s, "", " ")
if err != nil {
t.Fatal(err)
}
if got := string(got); got != stringTagExpected {
t.Fatalf(" got: %s\nwant: %s\n", got, stringTagExpected)
}
// Verify that it round-trips.
var s2 StringTag
err = NewDecoder(bytes.NewReader(got)).Decode(&s2)
if err != nil {
t.Fatalf("Decode: %v", err)
}
if !reflect.DeepEqual(s, s2) {
t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", s, string(got), s2)
}
}
// byte slices are special even if they're renamed types.
type renamedByte byte
type renamedByteSlice []byte
type renamedRenamedByteSlice []renamedByte
func TestEncodeRenamedByteSlice(t *testing.T) {
s := renamedByteSlice("abc")
result, err := Marshal(s)
if err != nil {
t.Fatal(err)
}
expect := `"YWJj"`
if string(result) != expect {
t.Errorf(" got %s want %s", result, expect)
}
r := renamedRenamedByteSlice("abc")
result, err = Marshal(r)
if err != nil {
t.Fatal(err)
}
if string(result) != expect {
t.Errorf(" got %s want %s", result, expect)
}
}
var unsupportedValues = []interface{}{
math.NaN(),
math.Inf(-1),
math.Inf(1),
}
func TestUnsupportedValues(t *testing.T) {
for _, v := range unsupportedValues {
if _, err := Marshal(v); err != nil {
if _, ok := err.(*UnsupportedValueError); !ok {
t.Errorf("for %v, got %T want UnsupportedValueError", v, err)
}
} else {
t.Errorf("for %v, expected error", v)
}
}
}
// Ref has Marshaler and Unmarshaler methods with pointer receiver.
type Ref int
func (*Ref) MarshalJSON() ([]byte, error) {
return []byte(`"ref"`), nil
}
func (r *Ref) UnmarshalJSON([]byte) error {
*r = 12
return nil
}
// Val has Marshaler methods with value receiver.
type Val int
func (Val) MarshalJSON() ([]byte, error) {
return []byte(`"val"`), nil
}
// RefText has Marshaler and Unmarshaler methods with pointer receiver.
type RefText int
func (*RefText) MarshalText() ([]byte, error) {
return []byte(`"ref"`), nil
}
func (r *RefText) UnmarshalText([]byte) error {
*r = 13
return nil
}
// ValText has Marshaler methods with value receiver.
type ValText int
func (ValText) MarshalText() ([]byte, error) {
return []byte(`"val"`), nil
}
func TestRefValMarshal(t *testing.T) {
var s = struct {
R0 Ref
R1 *Ref
R2 RefText
R3 *RefText
V0 Val
V1 *Val
V2 ValText
V3 *ValText
}{
R0: 12,
R1: new(Ref),
R2: 14,
R3: new(RefText),
V0: 13,
V1: new(Val),
V2: 15,
V3: new(ValText),
}
const want = `{"R0":"ref","R1":"ref","R2":"\"ref\"","R3":"\"ref\"","V0":"val","V1":"val","V2":"\"val\"","V3":"\"val\""}`
b, err := Marshal(&s)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
if got := string(b); got != want {
t.Errorf("got %q, want %q", got, want)
}
}
// C implements Marshaler and returns unescaped JSON.
type C int
func (C) MarshalJSON() ([]byte, error) {
return []byte(`"<&>"`), nil
}
// CText implements Marshaler and returns unescaped text.
type CText int
func (CText) MarshalText() ([]byte, error) {
return []byte(`"<&>"`), nil
}
func TestMarshalerEscaping(t *testing.T) {
var c C
want := `"\u003c\u0026\u003e"`
b, err := Marshal(c)
if err != nil {
t.Fatalf("Marshal(c): %v", err)
}
if got := string(b); got != want {
t.Errorf("Marshal(c) = %#q, want %#q", got, want)
}
var ct CText
want = `"\"\u003c\u0026\u003e\""`
b, err = Marshal(ct)
if err != nil {
t.Fatalf("Marshal(ct): %v", err)
}
if got := string(b); got != want {
t.Errorf("Marshal(ct) = %#q, want %#q", got, want)
}
}
type IntType int
type MyStruct struct {
IntType
}
func TestAnonymousNonstruct(t *testing.T) {
var i IntType = 11
a := MyStruct{i}
const want = `{"IntType":11}`
b, err := Marshal(a)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
if got := string(b); got != want {
t.Errorf("got %q, want %q", got, want)
}
}
type BugA struct {
S string
}
type BugB struct {
BugA
S string
}
type BugC struct {
S string
}
// Legal Go: We never use the repeated embedded field (S).
type BugX struct {
A int
BugA
BugB
}
// Issue 5245.
func TestEmbeddedBug(t *testing.T) {
v := BugB{
BugA{"A"},
"B",
}
b, err := Marshal(v)
if err != nil {
t.Fatal("Marshal:", err)
}
want := `{"S":"B"}`
got := string(b)
if got != want {
t.Fatalf("Marshal: got %s want %s", got, want)
}
// Now check that the duplicate field, S, does not appear.
x := BugX{
A: 23,
}
b, err = Marshal(x)
if err != nil {
t.Fatal("Marshal:", err)
}
want = `{"A":23}`
got = string(b)
if got != want {
t.Fatalf("Marshal: got %s want %s", got, want)
}
}
type BugD struct { // Same as BugA after tagging.
XXX string `json:"S"`
}
// BugD's tagged S field should dominate BugA's.
type BugY struct {
BugA
BugD
}
// Test that a field with a tag dominates untagged fields.
func TestTaggedFieldDominates(t *testing.T) {
v := BugY{
BugA{"BugA"},
BugD{"BugD"},
}
b, err := Marshal(v)
if err != nil {
t.Fatal("Marshal:", err)
}
want := `{"S":"BugD"}`
got := string(b)
if got != want {
t.Fatalf("Marshal: got %s want %s", got, want)
}
}
// There are no tags here, so S should not appear.
type BugZ struct {
BugA
BugC
BugY // Contains a tagged S field through BugD; should not dominate.
}
func TestDuplicatedFieldDisappears(t *testing.T) {
v := BugZ{
BugA{"BugA"},
BugC{"BugC"},
BugY{
BugA{"nested BugA"},
BugD{"nested BugD"},
},
}
b, err := Marshal(v)
if err != nil {
t.Fatal("Marshal:", err)
}
want := `{}`
got := string(b)
if got != want {
t.Fatalf("Marshal: got %s want %s", got, want)
}
}
func TestStringBytes(t *testing.T) {
// Test that encodeState.stringBytes and encodeState.string use the same encoding.
es := &encodeState{}
var r []rune
for i := '\u0000'; i <= unicode.MaxRune; i++ {
r = append(r, i)
}
s := string(r) + "\xff\xff\xffhello" // some invalid UTF-8 too
es.string(s)
esBytes := &encodeState{}
esBytes.stringBytes([]byte(s))
enc := es.Buffer.String()
encBytes := esBytes.Buffer.String()
if enc != encBytes {
i := 0
for i < len(enc) && i < len(encBytes) && enc[i] == encBytes[i] {
i++
}
enc = enc[i:]
encBytes = encBytes[i:]
i = 0
for i < len(enc) && i < len(encBytes) && enc[len(enc)-i-1] == encBytes[len(encBytes)-i-1] {
i++
}
enc = enc[:len(enc)-i]
encBytes = encBytes[:len(encBytes)-i]
if len(enc) > 20 {
enc = enc[:20] + "..."
}
if len(encBytes) > 20 {
encBytes = encBytes[:20] + "..."
}
t.Errorf("encodings differ at %#q vs %#q", enc, encBytes)
}
}
func TestIssue6458(t *testing.T) {
type Foo struct {
M RawMessage
}
x := Foo{RawMessage(`"foo"`)}
b, err := Marshal(&x)
if err != nil {
t.Fatal(err)
}
if want := `{"M":"foo"}`; string(b) != want {
t.Errorf("Marshal(&x) = %#q; want %#q", b, want)
}
b, err = Marshal(x)
if err != nil {
t.Fatal(err)
}
if want := `{"M":"ImZvbyI="}`; string(b) != want {
t.Errorf("Marshal(x) = %#q; want %#q", b, want)
}
}
func TestIssue10281(t *testing.T) {
type Foo struct {
N Number
}
x := Foo{Number(`invalid`)}
b, err := Marshal(&x)
if err == nil {
t.Errorf("Marshal(&x) = %#q; want error", b)
}
}
func TestHTMLEscape(t *testing.T) {
var b, want bytes.Buffer
m := `{"M":"<html>foo &` + "\xe2\x80\xa8 \xe2\x80\xa9" + `</html>"}`
want.Write([]byte(`{"M":"\u003chtml\u003efoo \u0026\u2028 \u2029\u003c/html\u003e"}`))
HTMLEscape(&b, []byte(m))
if !bytes.Equal(b.Bytes(), want.Bytes()) {
t.Errorf("HTMLEscape(&b, []byte(m)) = %s; want %s", b.Bytes(), want.Bytes())
}
}
// golang.org/issue/8582
func TestEncodePointerString(t *testing.T) {
type stringPointer struct {
N *int64 `json:"n,string"`
}
var n int64 = 42
b, err := Marshal(stringPointer{N: &n})
if err != nil {
t.Fatalf("Marshal: %v", err)
}
if got, want := string(b), `{"n":"42"}`; got != want {
t.Errorf("Marshal = %s, want %s", got, want)
}
var back stringPointer
err = Unmarshal(b, &back)
if err != nil {
t.Fatalf("Unmarshal: %v", err)
}
if back.N == nil {
t.Fatalf("Unmarshalled nil N field")
}
if *back.N != 42 {
t.Fatalf("*N = %d; want 42", *back.N)
}
}
var encodeStringTests = []struct {
in string
out string
}{
{"\x00", `"\u0000"`},
{"\x01", `"\u0001"`},
{"\x02", `"\u0002"`},
{"\x03", `"\u0003"`},
{"\x04", `"\u0004"`},
{"\x05", `"\u0005"`},
{"\x06", `"\u0006"`},
{"\x07", `"\u0007"`},
{"\x08", `"\u0008"`},
{"\x09", `"\t"`},
{"\x0a", `"\n"`},
{"\x0b", `"\u000b"`},
{"\x0c", `"\u000c"`},
{"\x0d", `"\r"`},
{"\x0e", `"\u000e"`},
{"\x0f", `"\u000f"`},
{"\x10", `"\u0010"`},
{"\x11", `"\u0011"`},
{"\x12", `"\u0012"`},
{"\x13", `"\u0013"`},
{"\x14", `"\u0014"`},
{"\x15", `"\u0015"`},
{"\x16", `"\u0016"`},
{"\x17", `"\u0017"`},
{"\x18", `"\u0018"`},
{"\x19", `"\u0019"`},
{"\x1a", `"\u001a"`},
{"\x1b", `"\u001b"`},
{"\x1c", `"\u001c"`},
{"\x1d", `"\u001d"`},
{"\x1e", `"\u001e"`},
{"\x1f", `"\u001f"`},
}
func TestEncodeString(t *testing.T) {
for _, tt := range encodeStringTests {
b, err := Marshal(tt.in)
if err != nil {
t.Errorf("Marshal(%q): %v", tt.in, err)
continue
}
out := string(b)
if out != tt.out {
t.Errorf("Marshal(%q) = %#q, want %#q", tt.in, out, tt.out)
}
}
}

View file

@ -1,133 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package json
import (
"regexp"
"testing"
)
func TestNumberIsValid(t *testing.T) {
// From: http://stackoverflow.com/a/13340826
var jsonNumberRegexp = regexp.MustCompile(`^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$`)
validTests := []string{
"0",
"-0",
"1",
"-1",
"0.1",
"-0.1",
"1234",
"-1234",
"12.34",
"-12.34",
"12E0",
"12E1",
"12e34",
"12E-0",
"12e+1",
"12e-34",
"-12E0",
"-12E1",
"-12e34",
"-12E-0",
"-12e+1",
"-12e-34",
"1.2E0",
"1.2E1",
"1.2e34",
"1.2E-0",
"1.2e+1",
"1.2e-34",
"-1.2E0",
"-1.2E1",
"-1.2e34",
"-1.2E-0",
"-1.2e+1",
"-1.2e-34",
"0E0",
"0E1",
"0e34",
"0E-0",
"0e+1",
"0e-34",
"-0E0",
"-0E1",
"-0e34",
"-0E-0",
"-0e+1",
"-0e-34",
}
for _, test := range validTests {
if !isValidNumber(test) {
t.Errorf("%s should be valid", test)
}
var f float64
if err := Unmarshal([]byte(test), &f); err != nil {
t.Errorf("%s should be valid but Unmarshal failed: %v", test, err)
}
if !jsonNumberRegexp.MatchString(test) {
t.Errorf("%s should be valid but regexp does not match", test)
}
}
invalidTests := []string{
"",
"invalid",
"1.0.1",
"1..1",
"-1-2",
"012a42",
"01.2",
"012",
"12E12.12",
"1e2e3",
"1e+-2",
"1e--23",
"1e",
"e1",
"1e+",
"1ea",
"1a",
"1.a",
"1.",
"01",
"1.e1",
}
for _, test := range invalidTests {
if isValidNumber(test) {
t.Errorf("%s should be invalid", test)
}
var f float64
if err := Unmarshal([]byte(test), &f); err == nil {
t.Errorf("%s should be invalid but unmarshal wrote %v", test, f)
}
if jsonNumberRegexp.MatchString(test) {
t.Errorf("%s should be invalid but matches regexp", test)
}
}
}
func BenchmarkNumberIsValid(b *testing.B) {
s := "-61657.61667E+61673"
for i := 0; i < b.N; i++ {
isValidNumber(s)
}
}
func BenchmarkNumberIsValidRegexp(b *testing.B) {
var jsonNumberRegexp = regexp.MustCompile(`^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$`)
s := "-61657.61667E+61673"
for i := 0; i < b.N; i++ {
jsonNumberRegexp.MatchString(s)
}
}

View file

@ -1,316 +0,0 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package json
import (
"bytes"
"math"
"math/rand"
"reflect"
"testing"
)
// Tests of simple examples.
type example struct {
compact string
indent string
}
var examples = []example{
{`1`, `1`},
{`{}`, `{}`},
{`[]`, `[]`},
{`{"":2}`, "{\n\t\"\": 2\n}"},
{`[3]`, "[\n\t3\n]"},
{`[1,2,3]`, "[\n\t1,\n\t2,\n\t3\n]"},
{`{"x":1}`, "{\n\t\"x\": 1\n}"},
{ex1, ex1i},
}
var ex1 = `[true,false,null,"x",1,1.5,0,-5e+2]`
var ex1i = `[
true,
false,
null,
"x",
1,
1.5,
0,
-5e+2
]`
func TestCompact(t *testing.T) {
var buf bytes.Buffer
for _, tt := range examples {
buf.Reset()
if err := Compact(&buf, []byte(tt.compact)); err != nil {
t.Errorf("Compact(%#q): %v", tt.compact, err)
} else if s := buf.String(); s != tt.compact {
t.Errorf("Compact(%#q) = %#q, want original", tt.compact, s)
}
buf.Reset()
if err := Compact(&buf, []byte(tt.indent)); err != nil {
t.Errorf("Compact(%#q): %v", tt.indent, err)
continue
} else if s := buf.String(); s != tt.compact {
t.Errorf("Compact(%#q) = %#q, want %#q", tt.indent, s, tt.compact)
}
}
}
func TestCompactSeparators(t *testing.T) {
// U+2028 and U+2029 should be escaped inside strings.
// They should not appear outside strings.
tests := []struct {
in, compact string
}{
{"{\"\u2028\": 1}", `{"\u2028":1}`},
{"{\"\u2029\" :2}", `{"\u2029":2}`},
}
for _, tt := range tests {
var buf bytes.Buffer
if err := Compact(&buf, []byte(tt.in)); err != nil {
t.Errorf("Compact(%q): %v", tt.in, err)
} else if s := buf.String(); s != tt.compact {
t.Errorf("Compact(%q) = %q, want %q", tt.in, s, tt.compact)
}
}
}
func TestIndent(t *testing.T) {
var buf bytes.Buffer
for _, tt := range examples {
buf.Reset()
if err := Indent(&buf, []byte(tt.indent), "", "\t"); err != nil {
t.Errorf("Indent(%#q): %v", tt.indent, err)
} else if s := buf.String(); s != tt.indent {
t.Errorf("Indent(%#q) = %#q, want original", tt.indent, s)
}
buf.Reset()
if err := Indent(&buf, []byte(tt.compact), "", "\t"); err != nil {
t.Errorf("Indent(%#q): %v", tt.compact, err)
continue
} else if s := buf.String(); s != tt.indent {
t.Errorf("Indent(%#q) = %#q, want %#q", tt.compact, s, tt.indent)
}
}
}
// Tests of a large random structure.
func TestCompactBig(t *testing.T) {
initBig()
var buf bytes.Buffer
if err := Compact(&buf, jsonBig); err != nil {
t.Fatalf("Compact: %v", err)
}
b := buf.Bytes()
if !bytes.Equal(b, jsonBig) {
t.Error("Compact(jsonBig) != jsonBig")
diff(t, b, jsonBig)
return
}
}
func TestIndentBig(t *testing.T) {
initBig()
var buf bytes.Buffer
if err := Indent(&buf, jsonBig, "", "\t"); err != nil {
t.Fatalf("Indent1: %v", err)
}
b := buf.Bytes()
if len(b) == len(jsonBig) {
// jsonBig is compact (no unnecessary spaces);
// indenting should make it bigger
t.Fatalf("Indent(jsonBig) did not get bigger")
}
// should be idempotent
var buf1 bytes.Buffer
if err := Indent(&buf1, b, "", "\t"); err != nil {
t.Fatalf("Indent2: %v", err)
}
b1 := buf1.Bytes()
if !bytes.Equal(b1, b) {
t.Error("Indent(Indent(jsonBig)) != Indent(jsonBig)")
diff(t, b1, b)
return
}
// should get back to original
buf1.Reset()
if err := Compact(&buf1, b); err != nil {
t.Fatalf("Compact: %v", err)
}
b1 = buf1.Bytes()
if !bytes.Equal(b1, jsonBig) {
t.Error("Compact(Indent(jsonBig)) != jsonBig")
diff(t, b1, jsonBig)
return
}
}
type indentErrorTest struct {
in string
err error
}
var indentErrorTests = []indentErrorTest{
{`{"X": "foo", "Y"}`, &SyntaxError{"invalid character '}' after object key", 17}},
{`{"X": "foo" "Y": "bar"}`, &SyntaxError{"invalid character '\"' after object key:value pair", 13}},
}
func TestIndentErrors(t *testing.T) {
for i, tt := range indentErrorTests {
slice := make([]uint8, 0)
buf := bytes.NewBuffer(slice)
if err := Indent(buf, []uint8(tt.in), "", ""); err != nil {
if !reflect.DeepEqual(err, tt.err) {
t.Errorf("#%d: Indent: %#v", i, err)
continue
}
}
}
}
func TestNextValueBig(t *testing.T) {
initBig()
var scan scanner
item, rest, err := nextValue(jsonBig, &scan)
if err != nil {
t.Fatalf("nextValue: %s", err)
}
if len(item) != len(jsonBig) || &item[0] != &jsonBig[0] {
t.Errorf("invalid item: %d %d", len(item), len(jsonBig))
}
if len(rest) != 0 {
t.Errorf("invalid rest: %d", len(rest))
}
item, rest, err = nextValue(append(jsonBig, "HELLO WORLD"...), &scan)
if err != nil {
t.Fatalf("nextValue extra: %s", err)
}
if len(item) != len(jsonBig) {
t.Errorf("invalid item: %d %d", len(item), len(jsonBig))
}
if string(rest) != "HELLO WORLD" {
t.Errorf("invalid rest: %d", len(rest))
}
}
var benchScan scanner
func BenchmarkSkipValue(b *testing.B) {
initBig()
b.ResetTimer()
for i := 0; i < b.N; i++ {
nextValue(jsonBig, &benchScan)
}
b.SetBytes(int64(len(jsonBig)))
}
func diff(t *testing.T, a, b []byte) {
for i := 0; ; i++ {
if i >= len(a) || i >= len(b) || a[i] != b[i] {
j := i - 10
if j < 0 {
j = 0
}
t.Errorf("diverge at %d: «%s» vs «%s»", i, trim(a[j:]), trim(b[j:]))
return
}
}
}
func trim(b []byte) []byte {
if len(b) > 20 {
return b[0:20]
}
return b
}
// Generate a random JSON object.
var jsonBig []byte
func initBig() {
n := 10000
if testing.Short() {
n = 100
}
b, err := Marshal(genValue(n))
if err != nil {
panic(err)
}
jsonBig = b
}
func genValue(n int) interface{} {
if n > 1 {
switch rand.Intn(2) {
case 0:
return genArray(n)
case 1:
return genMap(n)
}
}
switch rand.Intn(3) {
case 0:
return rand.Intn(2) == 0
case 1:
return rand.NormFloat64()
case 2:
return genString(30)
}
panic("unreachable")
}
func genString(stddev float64) string {
n := int(math.Abs(rand.NormFloat64()*stddev + stddev/2))
c := make([]rune, n)
for i := range c {
f := math.Abs(rand.NormFloat64()*64 + 32)
if f > 0x10ffff {
f = 0x10ffff
}
c[i] = rune(f)
}
return string(c)
}
func genArray(n int) []interface{} {
f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2)))
if f > n {
f = n
}
if f < 1 {
f = 1
}
x := make([]interface{}, f)
for i := range x {
x[i] = genValue(((i+1)*n)/f - (i*n)/f)
}
return x
}
func genMap(n int) map[string]interface{} {
f := int(math.Abs(rand.NormFloat64()) * math.Min(10, float64(n/2)))
if f > n {
f = n
}
if n > 0 && f == 0 {
f = 1
}
x := make(map[string]interface{})
for i := 0; i < f; i++ {
x[genString(10)] = genValue(((i+1)*n)/f - (i*n)/f)
}
return x
}

View file

@ -1,354 +0,0 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package json
import (
"bytes"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"net/http/httptest"
"reflect"
"strings"
"testing"
)
// Test values for the stream test.
// One of each JSON kind.
var streamTest = []interface{}{
0.1,
"hello",
nil,
true,
false,
[]interface{}{"a", "b", "c"},
map[string]interface{}{"": "Kelvin", "ß": "long s"},
3.14, // another value to make sure something can follow map
}
var streamEncoded = `0.1
"hello"
null
true
false
["a","b","c"]
{"ß":"long s","":"Kelvin"}
3.14
`
func TestEncoder(t *testing.T) {
for i := 0; i <= len(streamTest); i++ {
var buf bytes.Buffer
enc := NewEncoder(&buf)
for j, v := range streamTest[0:i] {
if err := enc.Encode(v); err != nil {
t.Fatalf("encode #%d: %v", j, err)
}
}
if have, want := buf.String(), nlines(streamEncoded, i); have != want {
t.Errorf("encoding %d items: mismatch", i)
diff(t, []byte(have), []byte(want))
break
}
}
}
func TestDecoder(t *testing.T) {
for i := 0; i <= len(streamTest); i++ {
// Use stream without newlines as input,
// just to stress the decoder even more.
// Our test input does not include back-to-back numbers.
// Otherwise stripping the newlines would
// merge two adjacent JSON values.
var buf bytes.Buffer
for _, c := range nlines(streamEncoded, i) {
if c != '\n' {
buf.WriteRune(c)
}
}
out := make([]interface{}, i)
dec := NewDecoder(&buf)
for j := range out {
if err := dec.Decode(&out[j]); err != nil {
t.Fatalf("decode #%d/%d: %v", j, i, err)
}
}
if !reflect.DeepEqual(out, streamTest[0:i]) {
t.Errorf("decoding %d items: mismatch", i)
for j := range out {
if !reflect.DeepEqual(out[j], streamTest[j]) {
t.Errorf("#%d: have %v want %v", j, out[j], streamTest[j])
}
}
break
}
}
}
func TestDecoderBuffered(t *testing.T) {
r := strings.NewReader(`{"Name": "Gopher"} extra `)
var m struct {
Name string
}
d := NewDecoder(r)
err := d.Decode(&m)
if err != nil {
t.Fatal(err)
}
if m.Name != "Gopher" {
t.Errorf("Name = %q; want Gopher", m.Name)
}
rest, err := ioutil.ReadAll(d.Buffered())
if err != nil {
t.Fatal(err)
}
if g, w := string(rest), " extra "; g != w {
t.Errorf("Remaining = %q; want %q", g, w)
}
}
func nlines(s string, n int) string {
if n <= 0 {
return ""
}
for i, c := range s {
if c == '\n' {
if n--; n == 0 {
return s[0 : i+1]
}
}
}
return s
}
func TestRawMessage(t *testing.T) {
// TODO(rsc): Should not need the * in *RawMessage
var data struct {
X float64
Id *RawMessage
Y float32
}
const raw = `["\u0056",null]`
const msg = `{"X":0.1,"Id":["\u0056",null],"Y":0.2}`
err := Unmarshal([]byte(msg), &data)
if err != nil {
t.Fatalf("Unmarshal: %v", err)
}
if string([]byte(*data.Id)) != raw {
t.Fatalf("Raw mismatch: have %#q want %#q", []byte(*data.Id), raw)
}
b, err := Marshal(&data)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
if string(b) != msg {
t.Fatalf("Marshal: have %#q want %#q", b, msg)
}
}
func TestNullRawMessage(t *testing.T) {
// TODO(rsc): Should not need the * in *RawMessage
var data struct {
X float64
Id *RawMessage
Y float32
}
data.Id = new(RawMessage)
const msg = `{"X":0.1,"Id":null,"Y":0.2}`
err := Unmarshal([]byte(msg), &data)
if err != nil {
t.Fatalf("Unmarshal: %v", err)
}
if data.Id != nil {
t.Fatalf("Raw mismatch: have non-nil, want nil")
}
b, err := Marshal(&data)
if err != nil {
t.Fatalf("Marshal: %v", err)
}
if string(b) != msg {
t.Fatalf("Marshal: have %#q want %#q", b, msg)
}
}
var blockingTests = []string{
`{"x": 1}`,
`[1, 2, 3]`,
}
func TestBlocking(t *testing.T) {
for _, enc := range blockingTests {
r, w := net.Pipe()
go w.Write([]byte(enc))
var val interface{}
// If Decode reads beyond what w.Write writes above,
// it will block, and the test will deadlock.
if err := NewDecoder(r).Decode(&val); err != nil {
t.Errorf("decoding %s: %v", enc, err)
}
r.Close()
w.Close()
}
}
func BenchmarkEncoderEncode(b *testing.B) {
b.ReportAllocs()
type T struct {
X, Y string
}
v := &T{"foo", "bar"}
for i := 0; i < b.N; i++ {
if err := NewEncoder(ioutil.Discard).Encode(v); err != nil {
b.Fatal(err)
}
}
}
type tokenStreamCase struct {
json string
expTokens []interface{}
}
type decodeThis struct {
v interface{}
}
var tokenStreamCases []tokenStreamCase = []tokenStreamCase{
// streaming token cases
{json: `10`, expTokens: []interface{}{float64(10)}},
{json: ` [10] `, expTokens: []interface{}{
Delim('['), float64(10), Delim(']')}},
{json: ` [false,10,"b"] `, expTokens: []interface{}{
Delim('['), false, float64(10), "b", Delim(']')}},
{json: `{ "a": 1 }`, expTokens: []interface{}{
Delim('{'), "a", float64(1), Delim('}')}},
{json: `{"a": 1, "b":"3"}`, expTokens: []interface{}{
Delim('{'), "a", float64(1), "b", "3", Delim('}')}},
{json: ` [{"a": 1},{"a": 2}] `, expTokens: []interface{}{
Delim('['),
Delim('{'), "a", float64(1), Delim('}'),
Delim('{'), "a", float64(2), Delim('}'),
Delim(']')}},
{json: `{"obj": {"a": 1}}`, expTokens: []interface{}{
Delim('{'), "obj", Delim('{'), "a", float64(1), Delim('}'),
Delim('}')}},
{json: `{"obj": [{"a": 1}]}`, expTokens: []interface{}{
Delim('{'), "obj", Delim('['),
Delim('{'), "a", float64(1), Delim('}'),
Delim(']'), Delim('}')}},
// streaming tokens with intermittent Decode()
{json: `{ "a": 1 }`, expTokens: []interface{}{
Delim('{'), "a",
decodeThis{float64(1)},
Delim('}')}},
{json: ` [ { "a" : 1 } ] `, expTokens: []interface{}{
Delim('['),
decodeThis{map[string]interface{}{"a": float64(1)}},
Delim(']')}},
{json: ` [{"a": 1},{"a": 2}] `, expTokens: []interface{}{
Delim('['),
decodeThis{map[string]interface{}{"a": float64(1)}},
decodeThis{map[string]interface{}{"a": float64(2)}},
Delim(']')}},
{json: `{ "obj" : [ { "a" : 1 } ] }`, expTokens: []interface{}{
Delim('{'), "obj", Delim('['),
decodeThis{map[string]interface{}{"a": float64(1)}},
Delim(']'), Delim('}')}},
{json: `{"obj": {"a": 1}}`, expTokens: []interface{}{
Delim('{'), "obj",
decodeThis{map[string]interface{}{"a": float64(1)}},
Delim('}')}},
{json: `{"obj": [{"a": 1}]}`, expTokens: []interface{}{
Delim('{'), "obj",
decodeThis{[]interface{}{
map[string]interface{}{"a": float64(1)},
}},
Delim('}')}},
{json: ` [{"a": 1} {"a": 2}] `, expTokens: []interface{}{
Delim('['),
decodeThis{map[string]interface{}{"a": float64(1)}},
decodeThis{&SyntaxError{"expected comma after array element", 0}},
}},
{json: `{ "a" 1 }`, expTokens: []interface{}{
Delim('{'), "a",
decodeThis{&SyntaxError{"expected colon after object key", 0}},
}},
}
func TestDecodeInStream(t *testing.T) {
for ci, tcase := range tokenStreamCases {
dec := NewDecoder(strings.NewReader(tcase.json))
for i, etk := range tcase.expTokens {
var tk interface{}
var err error
if dt, ok := etk.(decodeThis); ok {
etk = dt.v
err = dec.Decode(&tk)
} else {
tk, err = dec.Token()
}
if experr, ok := etk.(error); ok {
if err == nil || err.Error() != experr.Error() {
t.Errorf("case %v: Expected error %v in %q, but was %v", ci, experr, tcase.json, err)
}
break
} else if err == io.EOF {
t.Errorf("case %v: Unexpected EOF in %q", ci, tcase.json)
break
} else if err != nil {
t.Errorf("case %v: Unexpected error '%v' in %q", ci, err, tcase.json)
break
}
if !reflect.DeepEqual(tk, etk) {
t.Errorf(`case %v: %q @ %v expected %T(%v) was %T(%v)`, ci, tcase.json, i, etk, etk, tk, tk)
break
}
}
}
}
// Test from golang.org/issue/11893
func TestHTTPDecoding(t *testing.T) {
const raw = `{ "foo": "bar" }`
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(raw))
}))
defer ts.Close()
res, err := http.Get(ts.URL)
if err != nil {
log.Fatalf("GET failed: %v", err)
}
defer res.Body.Close()
foo := struct {
Foo string `json:"foo"`
}{}
d := NewDecoder(res.Body)
err = d.Decode(&foo)
if err != nil {
t.Fatalf("Decode: %v", err)
}
if foo.Foo != "bar" {
t.Errorf("decoded %q; want \"bar\"", foo.Foo)
}
// make sure we get the EOF the second time
err = d.Decode(&foo)
if err != io.EOF {
t.Errorf("err = %v; want io.EOF", err)
}
}

View file

@ -1,115 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package json
import (
"testing"
)
type basicLatin2xTag struct {
V string `json:"$%-/"`
}
type basicLatin3xTag struct {
V string `json:"0123456789"`
}
type basicLatin4xTag struct {
V string `json:"ABCDEFGHIJKLMO"`
}
type basicLatin5xTag struct {
V string `json:"PQRSTUVWXYZ_"`
}
type basicLatin6xTag struct {
V string `json:"abcdefghijklmno"`
}
type basicLatin7xTag struct {
V string `json:"pqrstuvwxyz"`
}
type miscPlaneTag struct {
V string `json:"色は匂へど"`
}
type percentSlashTag struct {
V string `json:"text/html%"` // https://golang.org/issue/2718
}
type punctuationTag struct {
V string `json:"!#$%&()*+-./:<=>?@[]^_{|}~"` // https://golang.org/issue/3546
}
type emptyTag struct {
W string
}
type misnamedTag struct {
X string `jsom:"Misnamed"`
}
type badFormatTag struct {
Y string `:"BadFormat"`
}
type badCodeTag struct {
Z string `json:" !\"#&'()*+,."`
}
type spaceTag struct {
Q string `json:"With space"`
}
type unicodeTag struct {
W string `json:"Ελλάδα"`
}
var structTagObjectKeyTests = []struct {
raw interface{}
value string
key string
}{
{basicLatin2xTag{"2x"}, "2x", "$%-/"},
{basicLatin3xTag{"3x"}, "3x", "0123456789"},
{basicLatin4xTag{"4x"}, "4x", "ABCDEFGHIJKLMO"},
{basicLatin5xTag{"5x"}, "5x", "PQRSTUVWXYZ_"},
{basicLatin6xTag{"6x"}, "6x", "abcdefghijklmno"},
{basicLatin7xTag{"7x"}, "7x", "pqrstuvwxyz"},
{miscPlaneTag{"いろはにほへと"}, "いろはにほへと", "色は匂へど"},
{emptyTag{"Pour Moi"}, "Pour Moi", "W"},
{misnamedTag{"Animal Kingdom"}, "Animal Kingdom", "X"},
{badFormatTag{"Orfevre"}, "Orfevre", "Y"},
{badCodeTag{"Reliable Man"}, "Reliable Man", "Z"},
{percentSlashTag{"brut"}, "brut", "text/html%"},
{punctuationTag{"Union Rags"}, "Union Rags", "!#$%&()*+-./:<=>?@[]^_{|}~"},
{spaceTag{"Perreddu"}, "Perreddu", "With space"},
{unicodeTag{"Loukanikos"}, "Loukanikos", "Ελλάδα"},
}
func TestStructTagObjectKey(t *testing.T) {
for _, tt := range structTagObjectKeyTests {
b, err := Marshal(tt.raw)
if err != nil {
t.Fatalf("Marshal(%#q) failed: %v", tt.raw, err)
}
var f interface{}
err = Unmarshal(b, &f)
if err != nil {
t.Fatalf("Unmarshal(%#q) failed: %v", b, err)
}
for i, v := range f.(map[string]interface{}) {
switch i {
case tt.key:
if s, ok := v.(string); !ok || s != tt.value {
t.Fatalf("Unexpected value: %#q, want %v", s, tt.value)
}
default:
t.Fatalf("Unexpected key: %#q, from %#q", i, b)
}
}
}
}

View file

@ -1,28 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package json
import (
"testing"
)
func TestTagParsing(t *testing.T) {
name, opts := parseTag("field,foobar,foo")
if name != "field" {
t.Fatalf("name = %q, want field", name)
}
for _, tt := range []struct {
opt string
want bool
}{
{"foobar", true},
{"foo", true},
{"bar", false},
} {
if opts.Contains(tt.opt) != tt.want {
t.Errorf("Contains(%q) = %v", tt.opt, !tt.want)
}
}
}

View file

@ -1,543 +0,0 @@
/*-
* 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 (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/x509"
"math/big"
"testing"
)
func TestCompactParseJWE(t *testing.T) {
// Should parse
msg := "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA.dGVzdA"
_, err := ParseEncrypted(msg)
if err != nil {
t.Error("Unable to parse valid message:", err)
}
// Messages that should fail to parse
failures := []string{
// Too many parts
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
// Not enough parts
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA",
// Invalid encrypted key
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.//////.dGVzdA.dGVzdA.dGVzdA",
// Invalid IV
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.//////.dGVzdA.dGVzdA",
// Invalid ciphertext
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.//////.dGVzdA",
// Invalid tag
"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.dGVzdA.dGVzdA.dGVzdA.//////",
// Invalid header
"W10.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
// Invalid header
"######.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
// Missing alc/enc params
"e30.dGVzdA.dGVzdA.dGVzdA.dGVzdA",
}
for _, msg := range failures {
_, err = ParseEncrypted(msg)
if err == nil {
t.Error("Able to parse invalid message", msg)
}
}
}
func TestFullParseJWE(t *testing.T) {
// Messages that should succeed to parse
successes := []string{
// Flattened serialization, single recipient
"{\"protected\":\"eyJhbGciOiJYWVoiLCJlbmMiOiJYWVoifQo\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
// Unflattened serialization, single recipient
"{\"protected\":\"\",\"unprotected\":{\"enc\":\"XYZ\"},\"recipients\":[{\"header\":{\"alg\":\"XYZ\"},\"encrypted_key\":\"QUJD\"}],\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
}
for i := range successes {
_, err := ParseEncrypted(successes[i])
if err != nil {
t.Error("Unble to parse valid message", err, successes[i])
}
}
// Messages that should fail to parse
failures := []string{
// Empty
"{}",
// Invalid JSON
"{XX",
// Invalid protected header
"{\"protected\":\"###\"}",
// Invalid protected header
"{\"protected\":\"e1gK\"}",
// Invalid encrypted key
"{\"protected\":\"e30\",\"encrypted_key\":\"###\"}",
// Invalid IV
"{\"protected\":\"e30\",\"encrypted_key\":\"QUJD\",\"iv\":\"###\"}",
// Invalid ciphertext
"{\"protected\":\"e30\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"###\"}",
// Invalid tag
"{\"protected\":\"e30\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"###\"}",
// Invalid AAD
"{\"protected\":\"e30\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\",\"aad\":\"###\"}",
// Missing alg/enc headers
"{\"protected\":\"e30\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
// Missing enc header
"{\"protected\":\"eyJhbGciOiJYWVoifQ\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
// Missing alg header
"{\"protected\":\"eyJlbmMiOiJYWVoifQ\",\"encrypted_key\":\"QUJD\",\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
// Unflattened serialization, single recipient, invalid encrypted_key
"{\"protected\":\"\",\"recipients\":[{\"header\":{\"alg\":\"XYZ\", \"enc\":\"XYZ\"},\"encrypted_key\":\"###\"}],\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
// Unflattened serialization, single recipient, missing alg
"{\"protected\":\"eyJhbGciOiJYWVoifQ\",\"recipients\":[{\"encrypted_key\":\"QUJD\"}],\"iv\":\"QUJD\",\"ciphertext\":\"QUJD\",\"tag\":\"QUJD\"}",
}
for i := range failures {
_, err := ParseEncrypted(failures[i])
if err == nil {
t.Error("Able to parse invalid message", err, failures[i])
}
}
}
func TestMissingInvalidHeaders(t *testing.T) {
protected := &rawHeader{}
protected.set(headerEncryption, A128GCM)
obj := &JSONWebEncryption{
protected: protected,
unprotected: &rawHeader{},
recipients: []recipientInfo{
{},
},
}
_, err := obj.Decrypt(nil)
if err != ErrUnsupportedKeyType {
t.Error("should detect invalid key")
}
obj.unprotected.set(headerCritical, []string{"1", "2"})
_, err = obj.Decrypt(nil)
if err == nil {
t.Error("should reject message with crit header")
}
obj.unprotected.set(headerCritical, nil)
obj.protected = &rawHeader{}
obj.protected.set(headerAlgorithm, RSA1_5)
_, err = obj.Decrypt(rsaTestKey)
if err == nil || err == ErrCryptoFailure {
t.Error("should detect missing enc header")
}
}
func TestRejectUnprotectedJWENonce(t *testing.T) {
// No need to test compact, since that's always protected
// Flattened JSON
input := `{
"header": {
"alg": "XYZ", "enc": "XYZ",
"nonce": "should-cause-an-error"
},
"encrypted_key": "does-not-matter",
"aad": "does-not-matter",
"iv": "does-not-matter",
"ciphertext": "does-not-matter",
"tag": "does-not-matter"
}`
_, err := ParseEncrypted(input)
if err == nil {
t.Error("JWE with an unprotected nonce parsed as valid.")
} else if err.Error() != "square/go-jose: Nonce parameter included in unprotected header" {
t.Errorf("Improper error for unprotected nonce: %v", err)
}
input = `{
"unprotected": {
"alg": "XYZ", "enc": "XYZ",
"nonce": "should-cause-an-error"
},
"encrypted_key": "does-not-matter",
"aad": "does-not-matter",
"iv": "does-not-matter",
"ciphertext": "does-not-matter",
"tag": "does-not-matter"
}`
_, err = ParseEncrypted(input)
if err == nil {
t.Error("JWE with an unprotected nonce parsed as valid.")
} else if err.Error() != "square/go-jose: Nonce parameter included in unprotected header" {
t.Errorf("Improper error for unprotected nonce: %v", err)
}
// Full JSON
input = `{
"header": { "alg": "XYZ", "enc": "XYZ" },
"aad": "does-not-matter",
"iv": "does-not-matter",
"ciphertext": "does-not-matter",
"tag": "does-not-matter",
"recipients": [{
"header": { "nonce": "should-cause-an-error" },
"encrypted_key": "does-not-matter"
}]
}`
_, err = ParseEncrypted(input)
if err == nil {
t.Error("JWS with an unprotected nonce parsed as valid.")
} else if err.Error() != "square/go-jose: Nonce parameter included in unprotected header" {
t.Errorf("Improper error for unprotected nonce: %v", err)
}
}
func TestCompactSerialize(t *testing.T) {
// Compact serialization must fail if we have unprotected headers
obj := &JSONWebEncryption{
unprotected: &rawHeader{},
}
obj.unprotected.set(headerAlgorithm, "XYZ")
_, err := obj.CompactSerialize()
if err == nil {
t.Error("Object with unprotected headers can't be compact serialized")
}
}
func TestVectorsJWE(t *testing.T) {
plaintext := []byte("The true sign of intelligence is not knowledge but imagination.")
publicKey := &rsa.PublicKey{
N: fromBase64Int(`
oahUIoWw0K0usKNuOR6H4wkf4oBUXHTxRvgb48E-BVvxkeDNjbC4he8rUW
cJoZmds2h7M70imEVhRU5djINXtqllXI4DFqcI1DgjT9LewND8MW2Krf3S
psk_ZkoFnilakGygTwpZ3uesH-PFABNIUYpOiN15dsQRkgr0vEhxN92i2a
sbOenSZeyaxziK72UwxrrKoExv6kc5twXTq4h-QChLOln0_mtUZwfsRaMS
tPs6mS6XrgxnxbWhojf663tuEQueGC-FCMfra36C9knDFGzKsNa7LZK2dj
YgyD3JR_MB_4NUJW_TqOQtwHYbxevoJArm-L5StowjzGy-_bq6Gw`),
E: 65537,
}
expectedCompact := stripWhitespace(`
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.ROQCfge4JPm_
yACxv1C1NSXmwNbL6kvmCuyxBRGpW57DvlwByjyjsb6g8m7wtLMqKEyhFCn
tV7sjippEePIlKln6BvVnz5ZLXHNYQgmubuNq8MC0KTwcaGJ_C0z_T8j4PZ
a1nfpbhSe-ePYaALrf_nIsSRKu7cWsrwOSlaRPecRnYeDd_ytAxEQWYEKFi
Pszc70fP9geZOB_09y9jq0vaOF0jGmpIAmgk71lCcUpSdrhNokTKo5y8MH8
3NcbIvmuZ51cjXQj1f0_AwM9RW3oCh2Hu0z0C5l4BujZVsDuGgMsGZsjUhS
RZsAQSXHCAmlJ2NlnN60U7y4SPJhKv5tKYw.48V1_ALb6US04U3b.5eym8T
W_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiS
diwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ`)
expectedFull := stripWhitespace(`
{ "protected":"eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ",
"encrypted_key":
"ROQCfge4JPm_yACxv1C1NSXmwNbL6kvmCuyxBRGpW57DvlwByjyjsb
6g8m7wtLMqKEyhFCntV7sjippEePIlKln6BvVnz5ZLXHNYQgmubuNq
8MC0KTwcaGJ_C0z_T8j4PZa1nfpbhSe-ePYaALrf_nIsSRKu7cWsrw
OSlaRPecRnYeDd_ytAxEQWYEKFiPszc70fP9geZOB_09y9jq0vaOF0
jGmpIAmgk71lCcUpSdrhNokTKo5y8MH83NcbIvmuZ51cjXQj1f0_Aw
M9RW3oCh2Hu0z0C5l4BujZVsDuGgMsGZsjUhSRZsAQSXHCAmlJ2Nln
N60U7y4SPJhKv5tKYw",
"iv": "48V1_ALb6US04U3b",
"ciphertext":
"5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFS
hS8iB7j6jiSdiwkIr3ajwQzaBtQD_A",
"tag":"XFBoMYUZodetZdvTiFvSkQ" }`)
// Mock random reader
randReader = bytes.NewReader([]byte{
// Encryption key
177, 161, 244, 128, 84, 143, 225, 115, 63, 180, 3, 255, 107, 154,
212, 246, 138, 7, 110, 91, 112, 46, 34, 105, 47, 130, 203, 46, 122,
234, 64, 252,
// Randomness for RSA-OAEP
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Initialization vector
227, 197, 117, 252, 2, 219, 233, 68, 180, 225, 77, 219})
defer resetRandReader()
// Encrypt with a dummy key
encrypter, err := NewEncrypter(A256GCM, Recipient{Algorithm: RSA_OAEP, Key: publicKey}, nil)
if err != nil {
panic(err)
}
object, err := encrypter.Encrypt(plaintext)
if err != nil {
panic(err)
}
serialized, err := object.CompactSerialize()
if serialized != expectedCompact {
t.Error("Compact serialization is not what we expected", serialized, expectedCompact)
}
serialized = object.FullSerialize()
if serialized != expectedFull {
t.Error("Full serialization is not what we expected")
}
}
func TestVectorsJWECorrupt(t *testing.T) {
priv := &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: fromHexInt(`
a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8
ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0c
bc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bd
bf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93
ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb`),
E: 65537,
},
D: fromHexInt(`
53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf1195
17ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d
4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d6
5a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb
04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1`),
Primes: []*big.Int{
fromHexInt(`
d32737e7267ffe1341b2d5c0d150a81b586fb3132bed2f8d5262
864a9cb9f30af38be448598d413a172efb802c21acf1c11c520c
2f26a471dcad212eac7ca39d`),
fromHexInt(`
cc8853d1d54da630fac004f471f281c7b8982d8224a490edbeb3
3d3e3d5cc93c4765703d1dd791642f1f116a0dd852be2419b2af
72bfe9a030e860b0288b5d77`),
},
}
corruptCiphertext := stripWhitespace(`
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.NFl09dehy
IR2Oh5iSsvEa82Ps7DLjRHeo0RnuTuSR45OsaIP6U8yu7vLlWaZKSZMy
B2qRBSujf-5XIRoNhtyIyjk81eJRXGa_Bxaor1XBCMyyhGchW2H2P71f
PhDO6ufSC7kV4bNqgHR-4ziS7KXwzN83_5kogXqxUpymUoJDNc.tk-GT
W_VVhiTIKFF.D_BE6ImZUl9F.52a-zFnRb3YQwIC7UrhVyQ`)
corruptAuthtag := stripWhitespace(`
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.NFl09dehy
IR2Oh5iSsvEa82Ps7DLjRHeo0RnuTuSR45OsaIP6U8yu7vLlWaZKSZMy
B2qRBSujf-5XIRoNhtyIyjk81eJRXGa_Bxaor1XBCMyyhGchW2H2P71f
PhDO6ufSC7kV4bNqgHR-4ziS7KNwzN83_5kogXqxUpymUoJDNc.tk-GT
W_VVhiTIKFF.D_BE6ImZUl9F.52a-zFnRb3YQwiC7UrhVyQ`)
msg, _ := ParseEncrypted(corruptCiphertext)
_, err := msg.Decrypt(priv)
if err != ErrCryptoFailure {
t.Error("should detect corrupt ciphertext")
}
msg, _ = ParseEncrypted(corruptAuthtag)
_, err = msg.Decrypt(priv)
if err != ErrCryptoFailure {
t.Error("should detect corrupt auth tag")
}
}
// Test vectors generated with nimbus-jose-jwt
func TestSampleNimbusJWEMessagesRSA(t *testing.T) {
rsaPrivateKey, err := x509.ParsePKCS8PrivateKey(fromBase64Bytes(`
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCNRCEmf5PlbXKuT4uwnb
wGKvFrtpi+bDYxOZxxqxdVkZM/bYATAnD1fg9pNvLMKeF+MWJ9kPIMmDgOh9RdnRdLvQGb
BzhLmxwhhcua2QYiHEZizXmiaXvNP12bzEBhebdX7ObW8izMVW0p0lqHPNzkK3K75B0Sxo
FMVKkZ7KtBHgepBT5yPhPPcNe5lXQeTne5bo3I60DRcN9jTBgMJOXdq0I9o4y6ZmoXdNTm
0EyLzn9/EYiHqBxtKFh791EHR7wYgyi/t+nOKr4sO74NbEByP0mHDil+mPvZSzFW4l7fPx
OclRZvpRIKIub2TroZA9s2WsshGf79eqqXYbBB9NNRAgMBAAECggEAIExbZ/nzTplfhwsY
3SCzRJW87OuqsJ79JPQPGM4NX7sQ94eJqM7+FKLl0yCFErjgnYGdCyiArvB+oJPdsimgke
h83X0hGeg03lVA3/6OsG3WifCAxulnLN44AM8KST8S9D9t5+cm5vEBLHazzAfWWTS13s+g
9hH8rf8NSqgZ36EutjKlvLdHx1mWcKX7SREFVHT8FWPAbdhTLEHUjoWHrfSektnczaSHnt
q8fFJy6Ld13QkF1ZJRUhtA24XrD+qLTc+M36IuedjeZaLHFB+KyhYR3YvXEtrbCug7dCRd
uG6uTlDCSaSy7xHeTPolWtWo9F202jal54otxiAJFGUHgQKBgQDRAT0s6YQZUfwE0wluXV
k0JdhDdCo8sC1aMmKlRKWUkBAqrDl7BI3MF56VOr4ybr90buuscshFf9TtrtBOjHSGcfDI
tSKfhhkW5ewQKB0YqyHzoD6UKT0/XAshFY3esc3uCxuJ/6vOiXV0og9o7eFvr51O0TfDFh
mcTvW4wirKlQKBgQCtB7UAu8I9Nn8czkd6oXLDRyTWYviuiqFmxR+PM9klgZtsumkeSxO1
lkfFoj9+G8nFaqYEBA9sPeNtJVTSROCvj/iQtoqpV2NiI/wWeVszpBwsswx2mlks4LJa8a
Yz9xrsfNoroKYVppefc/MCoSx4M+99RSm3FSpLGZQHAUGyzQKBgQDMQmq4JuuMF1y2lk0E
SESyuz21BqV0tDVOjilsHT+5hmXWXoS6nkO6L2czrrpM7YE82F6JJZBmo7zEIXHBInGLJ3
XLoYLZ5qNEhqYDUEDHaBCBWZ1vDTKnZlwWFEuXVavNNZvPbUhKTHq25t8qjDki/r09Vykp
BsM2yNBKpbBOVQKBgCJyUVd3CaFUExQyAMrqD0XPCQdhJq7gzGcAQVsp8EXmOoH3zmuIeM
ECzQEMXuWFNLMHm0tbX5Kl83vMHcnKioyI9ewhWxOBYTitf0ceG8j5F97SOl32NmCXzwoJ
55Oa0xJXfLuIvOe8hZzp4WwZmBfKBxiCR166aPQQgIawelrVAoGAEJsHomfCI4epxH4oMw
qYJMCGy95zloB+2+c86BZCOJAGwnfzbtc2eutWZw61/9sSO8sQCfzA8oX+5HwAgnFVzwW4
lNMZohppYcpwN9EyjkPaCXuALC7p5rF2o63wY7JLvnjS2aYZliknh2yW6X6fSB0PK0Cpvd
lAIyRw6Kud0zI=`))
if err != nil {
panic(err)
}
rsaSampleMessages := []string{
"eyJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiUlNBMV81In0.EW0KOhHeoAxTBnLjYhh2T6HjwI-srNs6RpcSdZvE-GJ5iww3EYWBCmeGGj1UVz6OcBfwW3wllZ6GPOHU-hxVQH5KYpVOjkmrFIYU6-8BHhxBP_PjSJEBCZzjOgsCm9Th4-zmlO7UWTdK_UtwE7nk4X-kkmEy-aZBCShA8nFe2MVvqD5F7nvEWNFBOHh8ae_juo-kvycoIzvxLV9g1B0Zn8K9FAlu8YF1KiL5NFekn76f3jvAwlExuRbFPUx4gJN6CeBDK_D57ABsY2aBVDSiQceuYZxvCIAajqSS6dMT382FNJzAiQhToOpo_1w5FnnBjzJLLEKDk_I-Eo2YCWxxsQ.5mCMuxJqLRuPXGAr.Ghe4INeBhP3MDWGvyNko7qanKdZIzKjfeiU.ja3UlVWJXKNFJ-rZsJWycw",
"eyJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiUlNBMV81In0.JsJeYoP0St1bRYNUaAmA34DAA27usE7RNuC2grGikBRmh1xrwUOpnEIXXpwr7fjVmNi52zzWkNHC8JkkRTrLcCh2VXvnOnarpH8DCr9qM6440bSrahzbxIvDds8z8q0wT1W4kjVnq1mGwGxg8RQNBWTV6Sp2FLQkZyjzt_aXsgYzr3zEmLZxB-d41lBS81Mguk_hdFJIg_WO4ao54lozvxkCn_uMiIZ8eLb8qHy0h-N21tiHGCaiC2vV8KXomwoqbJ0SXrEH4r9_R2J844H80TBZdbvNBd8whvoQNHvOX659LNs9EQ9xxvHU2kqGZekXBu7sDXXTjctMkMITobGSzw.1v5govaDvanP3LGp.llwYNBDrD7MwVLaFHesljlratfmndWs4XPQ.ZGT1zk9_yIKi2GzW6CuAyA",
"eyJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBMV81In0.fBv3fA3TMS3ML8vlsCuvwdsKvB0ym8R30jJrlOiqkWKk7WVUkjDInFzr1zw3Owla6c5BqOJNoACXt4IWbkLbkoWV3tweXlWwpafuaWPkjLOUH_K31rS2fCX5x-MTj8_hScquVQXpbz3vk2EfulRmGXZc_8JU2NqQCAsYy3a28houqP3rDe5jEAvZS2SOFvJkKW--f5S-z39t1D7fNz1N8Btd9SmXWQzjbul5YNxI9ctqxhJpkKYpxOLlvrzdA6YdJjOlDx3n6S-HnSZGM6kQd_xKtAf8l1EGwhQmhbXhMhjVxMvGwE5BX7PAb8Ccde5bzOCJx-PVbVetuLb169ZYqQ._jiZbOPRR82FEWMZ.88j68LI-K2KT6FMBEdlz6amG5nvaJU8a-90.EnEbUTJsWNqJYKzfO0x4Yw",
"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiUlNBMV81In0.bN6FN0qmGxhkESiVukrCaDVG3woL0xE-0bHN_Mu0WZXTQWbzzT-7jOvaN1xhGK8nzi8qpCSRgE5onONNB9i8OnJm3MMIxF7bUUEAXO9SUAFn2v--wNc4drPc5OjIu0RiJrDVDkkGjNrBDIuBaEQcke7A0v91PH58dXE7o4TLPzC8UJmRtXWhUSwjXVF3-UmYRMht2rjHJlvRbtm6Tu2LMBIopRL0zj6tlPP4Dm7I7sz9OEB3VahYAhpXnFR7D_f8RjLSXQmBvB1FiI5l_vMz2NFt2hYUmQF3EJMLIEdHvvPp3iHDGiXC1obJrDID_CCf3qs9UY7DMYL622KLvP2NIg.qb72oxECzxd_aNuHVR0aNg.Gwet9Ms8hB8rKEb0h4RGdFNRq97Qs2LQaJM0HWrCqoI.03ljVThOFvgXzMmQJ79VjQ",
"eyJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiUlNBMV81In0.ZbEOP6rqdiIP4g7Nl1PL5gwhgDwv9RinyiUQxZXPOmD7kwEZrZ093dJnhqI9kEd3QGFlHDpB7HgNz53d27z2zmEj1-27v6miizq6tH4sN2MoeZLwSyk16O1_n3bVdDmROawsTYYFJfHsuLwyVJxPd37duIYnbUCFO9J8lLIv-2VI50KJ1t47YfE4P-Wt9jVzxP2CVUQaJwTlcwfiDLJTagYmfyrDjf525WlQFlgfJGqsJKp8BX9gmKvAo-1iCBAM8VpEjS0u0_hW9VSye36yh8BthVV-VJkhJ-0tMpto3bbBmj7M25Xf4gbTrrVU7Nz6wb18YZuhHZWmj2Y2nHV6Jg.AjnS44blTrIIfFlqVw0_Mg.muCRgaEXNKKpW8rMfW7jf7Zpn3VwSYDz-JTRg16jZxY.qjc9OGlMaaWKDWQSIwVpR4K556Pp6SF9",
"eyJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiUlNBMV81In0.c7_F1lMlRHQQE3WbKmtHBYTosdZrG9hPfs-F9gNQYet61zKG8NXVkSy0Zf2UFHt0vhcO8hP2qrqOFsy7vmRj20xnGHQ2EE29HH6hwX5bx1Jj3uE5WT9Gvh0OewpvF9VubbwWTIObBpdEG7XdJsMAQlIxtXUmQYAtLTWcy2ZJipyJtVlWQLaPuE8BKfZH-XAsp2CpQNiRPI8Ftza3EAspiyRfVQbjKt7nF8nuZ2sESjt7Y50q4CSiiCuGT28T3diMN0_rWrH-I-xx7OQvJlrQaNGglGtu3jKUcrJDcvxW2e1OxriaTeuQ848ayuRvGUNeSv6WoVYmkiK1x_gNwUAAbw.7XtSqHJA7kjt6JrfxJMwiA.Yvi4qukAbdT-k-Fd2s4G8xzL4VFxaFC0ZIzgFDAI6n0.JSWPJ-HjOE3SK9Lm0yHclmjS7Z1ahtQga9FHGCWVRcc",
"eyJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.SYVxJbCnJ_tcR13LJpaqHQj-nGNkMxre4A1FmnUdxnvzeJwuvyrLiUdRsZR1IkP4fqLtDON2mumx39QeJQf0WIObPBYlIxycRLkwxDHRVlyTmPvdZHAxN26jPrk09wa5SgK1UF1W1VSQIPm-Tek8jNAmarF1Yxzxl-t54wZFlQiHP4TuaczugO5f-J4nlWenfla2mU1snDgdUMlEZGOAQ_gTEtwSgd1MqXmK_7LZBkoDqqoCujMZhziafJPXPDaUUqBLW3hHkkDA7GpVec3XcTtNUWQJqOpMyQhqo1KQMc8jg3fuirILp-hjvvNVtBnCRBvbrKUCPzu2_yH3HM_agA.2VsdijtonAxShNIW.QzzB3P9CxYP3foNKN0Ma1Z9tMwijAlkWo08.ZdQkIPDY_M-hxqi5fD4NGw",
"eyJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.Z2oTJXXib1u-S38Vn3DRKE3JnhnwgUa92UhsefzY2Wpdn0dmxMfYt9iRoJGFfSAcA97MOfjyvXVRCKWXGrG5AZCMAXEqU8SNQwKPRjlcqojcVzQyMucXI0ikLC4mUgeRlfKTwsBicq6JZZylzRoLGGSNJQbni3_BLsf7H3Qor0BYg0FPCLG9Z2OVvrFzvjTLmZtV6gFlVrMHBxJub_aUet9gAkxiu1Wx_Kx46TlLX2tkumXIpTGlzX6pef6jLeZ5EIg_K-Uz4tkWgWQIEkLD7qmTyk5pAGmzukHa_08jIh5-U-Sd8XGZdx4J1pVPJ5CPg0qDJGZ_cfgkgpWbP_wB6A.4qgKfokK1EwYxz20._Md82bv_KH2Vru0Ue2Eb6oAqHP2xBBP5jF8.WFRojvQpD5VmZlOr_dN0rQ",
"eyJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.JzCUgJcBJmBgByp4PBAABUfhezPvndxBIVzaoZ96DAS0HPni0OjMbsOGsz6JwNsiTr1gSn_S6R1WpZM8GJc9R2z0EKKVP67TR62ZSG0MEWyLpHmG_4ug0fAp1HWWMa9bT4ApSaOLgwlpVAb_-BPZZgIu6c8cREuMon6UBHDqW1euTBbzk8zix3-FTZ6p5b_3soDL1wXfRiRBEsxxUGMnpryx1OFb8Od0JdyGF0GgfLt6OoaujDJpo-XtLRawu1Xlg6GqRs0NQwSHZ5jXgQ6-zgCufXonAmYTiIyBXY2no9XmECTexjwrS_05nA7H-UyIZEBOCp3Yhz2zxrt5j_0pvQ.SJR-ghhaUKP4zXtZ.muiuzLfZA0y0BDNsroGTw2r2-l73SLf9lK8.XFMH1oHr1G6ByP3dWSUUPA",
"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiUlNBLU9BRVAifQ.U946MVfIm4Dpk_86HrnIA-QXyiUu0LZ67PL93CMLmEtJemMNDqmRd9fXyenCIhAC7jPIV1aaqW7gS194xyrrnUpBoJBdbegiPqOfquy493Iq_GQ8OXnFxFibPNQ6rU0l8BwIfh28ei_VIF2jqN6bhxFURCVW7fG6n6zkCCuEyc7IcxWafSHjH2FNttREuVj-jS-4LYDZsFzSKbpqoYF6mHt8H3btNEZDTSmy_6v0fV1foNtUKNfWopCp-iE4hNh4EzJfDuU8eXLhDb03aoOockrUiUCh-E0tQx9su4rOv-mDEOHHAQK7swm5etxoa7__9PC3Hg97_p4GM9gC9ykNgw.pnXwvoSPi0kMQP54of-HGg.RPJt1CMWs1nyotx1fOIfZ8760mYQ69HlyDp3XmdVsZ8.Yxw2iPVWaBROFE_FGbvodA",
"eyJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiUlNBLU9BRVAifQ.eKEOIJUJpXmO_ghH_nGCJmoEspqKyiy3D5l0P8lKutlo8AuYHPQlgOsaFYnDkypyUVWd9zi-JaQuCeo7dzoBiS1L71nAZo-SUoN0anQBkVuyuRjr-deJMhPPfq1H86tTk-4rKzPr1Ivd2RGXMtWsrUpNGk81r1v8DdMntLE7UxZQqT34ONuZg1IXnD_U6di7k07unI29zuU1ySeUr6w1YPw5aUDErMlpZcEJWrgOEYWaS2nuC8sWGlPGYEjqkACMFGn-y40UoS_JatNZO6gHK3SKZnXD7vN5NAaMo_mFNbh50e1t_zO8DaUdLtXPOBLcx_ULoteNd9H8HyDGWqwAPw.0xmtzJfeVMoIT1Cp68QrXA.841l1aA4c3uvSYfw6l180gn5JZQjL53WQ5fr8ejtvoI.lojzeWql_3gDq-AoaIbl_aGQRH_54w_f",
"eyJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiUlNBLU9BRVAifQ.D0QkvIXR1TL7dIHWuPNMybmmD8UPyQd1bRKjRDNbA2HmKGpamCtcJmpNB_EetNFe-LDmhe44BYI_XN2wIBbYURKgDK_WG9BH0LQw_nCVqQ-sKqjtj3yQeytXhLHYTDmiF0TO-uW-RFR7GbPAdARBfuf4zj82r_wDD9sD5WSCGx89iPfozDOYQ_OLwdL2WD99VvDyfwS3ZhxA-9IMSYv5pwqPkxj4C0JdjCqrN0YNrZn_1ORgjtsVmcWXsmusObTozUGA7n5GeVepfZdU1vrMulAwdRYqOYtlqKaOpFowe9xFN3ncBG7wb4f9pmzbS_Dgt-1_Ii_4SEB9GQ4NiuBZ0w.N4AZeCxMGUv52A0UVJsaZw.5eHOGbZdtahnp3l_PDY-YojYib4ft4SRmdsQ2kggrTs.WsmGH8ZDv4ctBFs7qsQvw2obe4dVToRcAQaZ3PYL34E",
"eyJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.fDTxO_ZzZ3Jdrdw-bxvg7u-xWB2q1tp3kI5zH6JfhLUm4h6rt9qDA_wZlRym8-GzEtkUjkTtQGs6HgQx_qlyy8ylCakY5GHsNhCG4m0UNhRiNfcasAs03JSXfON9-tfTJimWD9n4k5OHHhvcrsCW1G3jYeLsK9WHCGRIhNz5ULbo8HBrCTbmZ6bOEQ9mqhdssLpdV24HDpebotf3bgPJqoaTfWU6Uy7tLmPiNuuNRLQ-iTpLyNMTVvGqqZhpcV3lAEN5l77QabI5xLJYucvYjrXQhAEZ7YXO8oRYhGkdG2XXIRcwr87rBeRH-47HAyhZgF_PBPBhhrJNS9UNMqdfBw.FvU4_s7Md6vxnXWd.fw29Q4_gHt4f026DPPV-CNebQ8plJ6IVLX8._apBZrw7WsT8HOmxgCrTwA",
"eyJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.bYuorK-rHMbO4c2CRWtvyOEaM1EN-o-wLRZ0wFWRX9mCXQ-iTNarZn7ksYM1XnGmZ4u3CSowX1Hpca9Rg72_VJCmKapqCT7r3YfasN4_oeLwuSKI_gT-uVOznod97tn3Gf_EDv0y1V4H0k9BEIFGbajAcG1znTD_ODY3j2KZJxisfrsBoslc6N-HI0kKZMC2hSGuHOcOf8HN1sTE-BLqZCtoj-zxQECJK8Wh14Ih4jzzdmmiu_qmSR780K6su-4PRt3j8uY7oCiLBfwpCsCmhJgp8rKd91zoedZmamfvX38mJIfE52j4fG6HmIYw9Ov814fk9OffV6tzixjcg54Q2g.yeVJz4aSh2s-GUr9.TBzzWP5llEiDdugpP2SmPf2U4MEGG9EoPWk.g25UoWpsBaOd45J__FX7mA",
"eyJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.h9tFtmh762JuffBxlSQbJujCyI4Zs9yc3IOb1yR8g65W4ZHosIvzVGHWbShj4EY9MNrz-RbKtHfqQGGzDeo3Xb4-HcQ2ZDHyWoUg7VfA8JafJ5zIKL1npz8eUExOVMLsAaRfHg8qNfczodg3egoSmX5Q-nrx4DeidDSXYZaZjV0C72stLTPcuQ7XPV7z1tvERAkqpvcsRmJn_PiRNxIbAgoyHMJ4Gijuzt1bWZwezlxYmw0TEuwCTVC2fl9NJTZyxOntS1Lcm-WQGlPkVYeVgYTOQXLlp7tF9t-aAvYpth2oWGT6Y-hbPrjx_19WaKD0XyWCR46V32DlXEVDP3Xl2A.NUgfnzQyEaJjzt9r.k2To43B2YVWMeR-w3n4Pr2b5wYq2o87giHk.X8_QYCg0IGnn1pJqe8p_KA",
"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.EDq6cNP6Yp1sds5HZ4CkXYp7bs9plIYVZScKvuyxUy0H1VyBC_YWg0HvndPNb-vwh1LA6KMxRazlOwJ9iPR9YzHnYmGgPM3Je_ZzBfiPlRfq6hQBpGnNaypBI1XZ2tyFBhulsVLqyJe2SmM2Ud00kasOdMYgcN8FNFzq7IOE7E0FUQkIwLdUL1nrzepiYDp-5bGkxWRcL02cYfdqdm00G4m0GkUxAmdxa3oPNxZlt2NeBI_UVWQSgJE-DJVJQkDcyA0id27TV2RCDnmujYauNT_wYlyb0bFDx3pYzzNXfAXd4wHZxt75QaLZ5APJ0EVfiXJ0qki6kT-GRVmOimUbQA.vTULZL7LvS0WD8kR8ZUtLg.mb2f0StEmmkuuvsyz8UplMvF58FtZzlu8eEwzvPUvN0.hbhveEN40V-pgG2hSVgyKg",
"eyJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.DuYk92p7u-YIN-JKn-XThmlVcnhU9x5TieQ2uhsLQVNlo0iWC9JJPP6bT6aI6u_1BIS3yE8_tSGGL7eM-zyEk6LuTqSWFRaZcZC06d0MnS9eYZcw1T2D17fL-ki-NtCaTahJD7jE2s0HevRVW49YtL-_V8whnO_EyVjvXIAQlPYqhH_o-0Nzcpng9ggdAnuF2rY1_6iRPYFJ3BLQvG1oWhyJ9s6SBttlOa0i6mmFCVLHx6sRpdGAB3lbCL3wfmHq4tpIv77gfoYUNP0SNff-zNmBXF_wp3dCntLZFTjbfMpGyHlruF_uoaLqwdjYpUGNUFVUoeSiMnSbMKm9NxiDgQ.6Mdgcqz7bMU1UeoAwFC8pg.W36QWOlBaJezakUX5FMZzbAgeAu_R14AYKZCQmuhguw.5OeyIJ03olxmJft8uBmjuOFQPWNZMYLI",
"eyJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.ECulJArWFsPL2FlpCN0W8E7IseSjJg1cZqE3wz5jk9gvwgNForAUEv5KYZqhNI-p5IxkGV0f8K6Y2X8pWzbLwiPIjZe8_dVqHYJoINxqCSgWLBhz0V36qL9Nc_xARTBk4-ZteIu75NoXVeos9gNvFnkOCj4tm-jGo8z8EFO9XfODgjhiR4xv8VqUtvrkjo9GQConaga5zpV-J4JQlXbdqbDjnuwacnJAxYpFyuemqcgqsl6BnFX3tovGkmSUPqcvF1A6tiHqr-TEmcgVqo5C3xswknRBKTQRM00iAmJ92WlVdkoOCx6E6O7cVHFawZ14BLzWzm66Crb4tv0ucYvk_Q.mxolwUaoj5S5kHCfph0w8g.nFpgYdnYg3blHCCEi2XXQGkkKQBXs2OkZaH11m3PRvk.k8BAVT4EcyrUFVIKr-KOSPbF89xyL0Vri2rFTu2iIWM",
}
for _, msg := range rsaSampleMessages {
obj, err := ParseEncrypted(msg)
if err != nil {
t.Error("unable to parse message", msg, err)
continue
}
plaintext, err := obj.Decrypt(rsaPrivateKey)
if err != nil {
t.Error("unable to decrypt message", msg, err)
continue
}
if string(plaintext) != "Lorem ipsum dolor sit amet" {
t.Error("plaintext is not what we expected for msg", msg)
}
}
}
// Test vectors generated with nimbus-jose-jwt
func TestSampleNimbusJWEMessagesAESKW(t *testing.T) {
aesTestKeys := [][]byte{
fromHexBytes("DF1FA4F36FFA7FC42C81D4B3C033928D"),
fromHexBytes("DF1FA4F36FFA7FC42C81D4B3C033928D95EC9CDC2D82233C"),
fromHexBytes("DF1FA4F36FFA7FC42C81D4B3C033928D95EC9CDC2D82233C333C35BA29044E90"),
}
aesSampleMessages := [][]string{
{
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwidGFnIjoib2ZMd2Q5NGloVWFRckJ0T1pQUDdjUSIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoiV2Z3TnN5cjEwWUFjY2p2diJ9.9x3RxdqIS6P9xjh93Eu1bQ.6fs3_fSGt2jull_5.YDlzr6sWACkFg_GU5MEc-ZEWxNLwI_JMKe_jFA.f-pq-V7rlSSg_q2e1gDygw",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwidGFnIjoic2RneXB1ckFjTEFzTmZJU0lkZUNpUSIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoieVFMR0dCdDJFZ0c1THdyViJ9.arslKo4aKlh6f4s0z1_-U-8JbmhAoZHN.Xw2Q-GX98YXwuc4i.halTEWMWAYZbv-qOD52G6bte4x6sxlh1_VpGEA.Z1spn016v58cW6Q2o0Qxag",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwidGFnIjoicTNzejF5VUlhbVBDYXJfZ05kSVJqQSIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoiM0ZRM0FsLWJWdWhmcEIyQyJ9.dhVipWbzIdsINttuZM4hnjpHvwEHf0VsVrOp4GAg01g.dk7dUyt1Qj13Pipw.5Tt70ONATF0BZAS8dBkYmCV7AQUrfb8qmKNLmw.A6ton9MQjZg0b3C0QcW-hg",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwidGFnIjoiUHNpTGphZnJZNE16UlRmNlBPLTZfdyIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoiSUFPbnd2ODR5YXFEaUxtbSJ9.swf92_LyCvjsvkynHTuMNXRl_MX2keU-fMDWIMezHG4.LOp9SVIXzs4yTnOtMyXZYQ.HUlXrzqJ1qXYl3vUA-ydezCg77WvJNtKdmZ3FPABoZw.8UYl1LOofQLAxHHvWqoTbg",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwidGFnIjoiWGRndHQ5dUVEMVlVeU1rVHl6M3lqZyIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoiWF90V2RhSmh6X3J1SHJvQSJ9.JQ3dS1JSgzIFi5M9ig63FoFU1nHBTmPwXY_ovNE2m1JOSUvHtalmihIuraPDloCf.e920JVryUIWt7zJJQM-www.8DUrl4LmsxIEhRr9RLTHG9tBTOcwXqEbQHAJd_qMHzE.wHinoqGUhL4O7lx125kponpwNtlp8VGJ",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwidGFnIjoicGgyaTdoY0FWNlh3ZkQta1RHYlVXdyIsImFsZyI6IkExMjhHQ01LVyIsIml2IjoiaG41Smk4Wm1rUmRrSUxWVSJ9._bQlJXl22dhsBgYPhkxUyinBNi871teGWbviOueWj2PqG9OPxIc9SDS8a27YLSVDMircd5Q1Df28--vcXIABQA.DssmhrAg6w_f2VDaPpxTbQ.OGclEmqrxwvZqAfn7EgXlIfXgr0wiGvEbZz3zADnqJs.YZeP0uKVEiDl8VyC-s20YN-RbdyGNsbdtoGDP3eMof8",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiQTEyOEtXIn0.TEMcXEoY8WyqGjYs5GZgS-M_Niwu6wDY.i-26KtTt51Td6Iwd.wvhkagvPsLj3QxhPBbfH_th8OqxisUtme2UadQ.vlfvBPv3bw2Zk2H60JVNLQ",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiQTEyOEtXIn0.gPaR6mgQ9TUx05V6DRfgTQeZxl0ZSzBa5uQd-qw6yLs.MojplOD77FkMooS-.2yuD7dKR_C3sFbhgwiBccKKOF8DrSvNiwX7wPQ.qDKUbSvMnJv0qifjpWC14g",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiQTEyOEtXIn0.Fg-dgSkUW1KEaL5YDPoWHNL8fpX1WxWVLA9OOWsjIFhQVDKyUZI7BQ.mjRBpyJTZf7H-quf.YlNHezMadtaSKp23G-ozmYhHOeHwuJnvWGTtGg.YagnR7awBItUlMDo4uklvg",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiQTEyOEtXIn0.x1vYzUE-E2XBWva9OPuwtqfQaf9rlJCIBAyAe6N2q2kWfJrkxGxFsQ.gAwe78dyODFaoP2IOityAA.Yh5YfovkWxGBNAs1sVhvXow_2izHHsBiYEc9JYD6kVg.mio1p3ncp2wLEaEaRa7P0w",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiQTEyOEtXIn0.szGrdnmF7D5put2aRBvSSFfp0vRgkRGYaafijJIqAF6PWd1IxsysZRV8aQkQOW1cB6d0fXsTfYM.Ru25LVOOk4xhaK-cIZ0ThA.pF9Ok5zot7elVqXFW5YYHV8MuF9gVGzpQnG1XDs_g_w.-7la0uwcNPpteev185pMHZjbVDXlrec8",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiQTEyOEtXIn0.cz-hRv0xR5CnOcnoRWNK8Q9poyVYzRCVTjfmEXQN6xPOZUkJ3zKNqb8Pir_FS0o2TVvxmIbuxeISeATTR2Ttx_YGCNgMkc93.SF5rEQT94lZR-UORcMKqGw.xphygoU7zE0ZggOczXCi_ytt-Evln8CL-7WLDlWcUHg.5h99r8xCCwP2PgDbZqzCJ13oFfB2vZWetD5qZjmmVho",
},
{
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwidGFnIjoiVWR5WUVKdEJ5ZTA5dzdjclY0cXI1QSIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoiZlBBV0QwUmdSbHlFdktQcCJ9.P1uTfTuH-imL-NJJMpuTRA.22yqZ1NIfx3KNPgc.hORWZaTSgni1FS-JT90vJly-cU37qTn-tWSqTg.gMN0ufXF92rSXupTtBNkhA",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwidGFnIjoiOU9qX3B2LTJSNW5lZl9YbWVkUWltUSIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoiY3BybGEwYUYzREVQNmFJTSJ9.6NVpAm_APiC7km2v-oNR8g23K9U_kf1-.jIg-p8tNwSvwxch0.1i-GPaxS4qR6Gy4tzeVtSdRFRSKQSMpmn-VhzA.qhFWPqtA6vVPl7OM3DThsA",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwidGFnIjoiOVc3THg3MVhGQVJCb3NaLVZ5dXc4ZyIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoiZ1N4ZE5heFdBSVBRR0tHYiJ9.3YjPz6dVQwAtCekvtXiHZrooOUlmCsMSvyfwmGwdrOA.hA_C0IDJmGaRzsB0.W4l7OPqpFxiVOZTGfAlRktquyRTo4cEOk9KurQ.l4bGxOkO_ql_jlPo3Oz3TQ",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwidGFnIjoiOHJYbWl2WXFWZjNfbHhhd2NUbHJoUSIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoiVXBWeXprVTNKcjEwYXRqYyJ9.8qft-Q_xqUbo5j_aVrVNHchooeLttR4Kb6j01O8k98M.hXO-5IKBYCL9UdwBFVm0tg.EBM4lCZX_K6tfqYmfoDxVPHcf6cT--AegXTTjfSqsIw.Of8xUvEQSh3xgFT3uENnAg",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwidGFnIjoiVnItSnVaX0tqV2hSWWMzdzFwZ3cwdyIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoiRGg2R3dISVBVS3ljZGNZeCJ9.YSEDjCnGWr_n9H94AvLoRnwm6bdU9w6-Q67k-QQRVcKRd6673pgH9zEF9A9Dt6o1.gcmVN4kxqBuMq6c7GrK3UQ.vWzJb0He6OY1lhYYjYS7CLh55REAAq1O7yNN-ND4R5Q.OD0B6nwyFaDr_92ysDOtlVnJaeoIqhGw",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwidGFnIjoieEtad1BGYURpQ3NqUnBqZUprZHhmZyIsImFsZyI6IkExOTJHQ01LVyIsIml2IjoieTVHRFdteXdkb2R1SDJlYyJ9.AW0gbhWqlptOQ1y9aoNVwrTIIkBfrp33C2OWJsbrDRk6lhxg_IgFhMDTE37moReySGUtttC4CXQD_7etHmd3Hw.OvKXK-aRKlXHOpJQ9ZY_YQ.Ngv7WarDDvR2uBj_DavPAR3DYuIaygvSSdcHrc8-ZqM.MJ6ElitzFCKf_0h5fIJw8uOLC6ps7dKZPozF8juQmUY",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiQTE5MktXIn0.8qu63pppcSvp1vv37WrZ44qcCTg7dQMA.cDp-f8dJTrDEpZW4.H6OBJYs4UvFR_IZHLYQZxB6u9a0wOdAif2LNfQ.1dB-id0UIwRSlmwHx5BJCg",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiQTE5MktXIn0._FdoKQvC8qUs7K0upriEihUwztK8gOwonXpOxdIwrfs.UO38ok8gDdpLVa1T.x1GvHdVCy4fxoQRg-OQK4Ez3jDOvu9gllLPeEA.3dLeZGIprh_nHizOTVi1xw",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiQTE5MktXIn0.uzCJskgSIK6VkjJIu-dQi18biqaY0INc_A1Ehx0oESafgtR99_n4IA.W2eKK8Y14WwTowI_.J2cJC7R6Bz6maR0s1UBMPyRi5BebNUAmof4pvw.-7w6htAlc4iUsOJ6I04rFg",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiQTE5MktXIn0.gImQeQETp_6dfJypFDPLlv7c5pCzuq86U16gzrLiCXth6X9XfxJpvQ.YlC4MxjtLWrsyEvlFhvsqw.Vlpvmg9F3gkz4e1xG01Yl2RXx-jG99rF5UvCxOBXSLc.RZUrU_FoR5bG3M-j3GY0Dw",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiQTE5MktXIn0.T2EfQ6Tu2wJyRMgZzfvBYmQNCCfdMudMrg86ibEMVAOUKJPtR3WMPEb_Syy9p2VjrLKRlv7nebo.GPc8VbarPPRtzIRATB8NsA.ugPCqLvVLwh55bWlwjsFkmWzJ31z5z-wuih2oJqmG_U.m7FY3EjvV6mKosEYJ5cY7ezFoVQoJS8X",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiQTE5MktXIn0.OgLMhZ-2ZhslQyHfzOfyC-qmT6bNg9AdpP59B4jtyxWkQu3eW475WCdiAjojjeyBtVRGQ5vOomwaOIFejY_IekzH6I_taii3.U9x44MF6Wyz5TIwIzwhoxQ.vK7yvSF2beKdNxNY_7n4XdF7JluCGZoxdFJyTJVkSmI.bXRlI8KL-g7gpprQxGmXjVYjYghhWJq7mlCfWI8q2uA",
},
{
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwidGFnIjoiR3BjX3pfbjduZjJVZlEtWGdsaTBaQSIsImFsZyI6IkEyNTZHQ01LVyIsIml2IjoiUk40eUdhOVlvYlFhUmZ1TCJ9.Q4ukD6_hZpmASAVcqWJ9Wg.Zfhny_1WNdlp4fH-.3sekDCjkExQCcv28ZW4yrcFnz0vma3vgoenSXA.g8_Ird2Y0itTCDP61du-Yg",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwidGFnIjoiWC05UkNVWVh4U3NRelcwelVJS01VUSIsImFsZyI6IkEyNTZHQ01LVyIsIml2IjoiY3JNMnJfa3RrdWpyQ1h5OSJ9.c0q2jCxxV4y1h9u_Xvn7FqUDnbkmNEG4.S_noOTZKuUo9z1l6.ez0RdA25vXMUGH96iXmj3DEVox0J7TasJMnzgg.RbuSPTte_NzTtEEokbc5Ig",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwidGFnIjoiWmwyaDFpUW11QWZWd2lJeVp5RHloZyIsImFsZyI6IkEyNTZHQ01LVyIsIml2Ijoib19xZmljb0N0NzNzRWo1QyJ9.NpJxRJ0aqcpekD6HU2u9e6_pL_11JXjWvjfeQnAKkZU.4c5qBcBBrMWi27Lf.NKwNIb4b6cRDJ1TwMKsPrjs7ADn6aNoBdQClVw.yNWmSSRBqQfIQObzj8zDqw",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwidGFnIjoiMXdwVEI3LWhjdzZUVXhCbVh2UzdhUSIsImFsZyI6IkEyNTZHQ01LVyIsIml2IjoiOUdIVnZJaDZ0a09vX2pHUSJ9.MFgIhp9mzlq9hoPqqKVKHJ3HL79EBYtV4iNhD63yqiU.UzW5iq8ou21VpZYJgKEN8A.1gOEzA4uAPvHP76GMfs9uLloAV10mKaxiZVAeL7iQA0.i1X_2i0bCAz-soXF9bI_zw",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwidGFnIjoiNThocUtsSk15Y1BFUEFRUlNfSzlNUSIsImFsZyI6IkEyNTZHQ01LVyIsIml2IjoiUDh3aTBWMTluVnZqNXpkOSJ9.FXidOWHNFJODO74Thq3J2cC-Z2B8UZkn7SikeosU0bUK6Jx_lzzmUZ-Lafadpdpj.iLfcDbpuBKFiSfiBzUQc7Q.VZK-aD7BFspqfvbwa0wE2wwWxdomzk2IKMetFe8bI44.7wC6rJRGa4x48xbYMd6NH9VzK8uNn4Cb",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwidGFnIjoicGcwOEpUcXdzMXdEaXBaRUlpVExoQSIsImFsZyI6IkEyNTZHQ01LVyIsIml2IjoiSlpodk9CdU1RUDFFZTZTNSJ9.wqVgTPm6TcYCTkpbwmn9sW4mgJROH2A3dIdSXo5oKIQUIVbQsmy7KXH8UYO2RS9slMGtb869C8o0My67GKg9dQ.ogrRiLlqjB1S5j-7a05OwA.2Y_LyqhU4S_RXMsB74bxcBacd23J2Sp5Lblw-sOkaUY.XGMiYoU-f3GaEzSvG41vpJP2DMGbeDFoWmkUGLUjc4M",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4R0NNIiwiYWxnIjoiQTI1NktXIn0.QiIZm9NYfahqYFIbiaoUhCCHjotHMkup.EsU0XLn4FjzzCILn.WuCoQkm9vzo95E7hxBtfYpt-Mooc_vmSTyzj6Q.NbeeYVy6gQPlmhoWDrZwaQ",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyR0NNIiwiYWxnIjoiQTI1NktXIn0.1ol3j_Lt0Os3UMe2Gypj0o8b77k0FSmqD7kNRNoMa9U.vZ2HMTgN2dgUd42h.JvNcy8-c8sYzOC089VtFSg2BOQx3YF8CqSTuJw.t03LRioWWKN3d7SjinU6SQ",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiQTI1NktXIn0.gbkk03l1gyrE9qGEMVtORiyyUqKsgzbqjLd8lw0RQ07WWn--TV4BgA.J8ThH4ac2UhSsMIP.g-W1piEGrdi3tNwQDJXpYm3fQjTf82mtVCrCOg.-vY05P4kiB9FgF2vwrSeXQ",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiQTI1NktXIn0.k86pQs7gmQIzuIWRFwesF32XY2xi1WbYxi7XUf_CYlOlehwGCTINHg.3NcC9VzfQgsECISKf4xy-g.v2amdo-rgeGsg-II_tvPukX9D-KAP27xxf2uQJ277Ws.E4LIE3fte3glAnPpnd8D9Q",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMTkyQ0JDLUhTMzg0IiwiYWxnIjoiQTI1NktXIn0.b8iN0Am3fCUvj7sBd7Z0lpfzBjh1MOgojV7J5rDfrcTU3b35RGYgEV1RdcrtUTBgUwITDjmU7jM.wsSDBFghDga_ERv36I2AOg.6uJsucCb2YReFOJGBdo4zidTIKLUmZBIXfm_M0AJpKk.YwdAfXI3HHcw2wLSnfCRtw4huZQtSKhz",
"eyJ6aXAiOiJERUYiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwiYWxnIjoiQTI1NktXIn0.akY9pHCbkHPh5VpXIrX0At41XnJIKBR9iMMkf301vKeJNAZYJTxWzeJhFd-DhQ47tMctc3YYkwZkQ5I_9fGYb_f0oBcw4esh.JNwuuHud78h6S99NO1oBQQ.0RwckPYATBgvw67upkAQ1AezETHc-gh3rryz19i5ryc.3XClRTScgzfMgLCHxHHoRF8mm9VVGXv_Ahtx65PskKQ",
},
}
for i, msgs := range aesSampleMessages {
for _, msg := range msgs {
obj, err := ParseEncrypted(msg)
if err != nil {
t.Error("unable to parse message", msg, err)
continue
}
plaintext, err := obj.Decrypt(aesTestKeys[i])
if err != nil {
t.Error("unable to decrypt message", msg, err)
continue
}
if string(plaintext) != "Lorem ipsum dolor sit amet" {
t.Error("plaintext is not what we expected for msg", msg)
}
}
}
}
// Test vectors generated with jose4j
func TestSampleJose4jJWEMessagesECDH(t *testing.T) {
ecTestKey := &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: elliptic.P256(),
X: fromBase64Int("weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ"),
Y: fromBase64Int("e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck"),
},
D: fromBase64Int("VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw"),
}
ecSampleMessages := []string{
"eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTEyOENCQy1IUzI1NiIsImVwayI6eyJrdHkiOiJFQyIsIngiOiJTQzAtRnJHUkVvVkpKSmg1TGhORmZqZnFXMC1XSUFyd3RZMzJzQmFQVVh3IiwieSI6ImFQMWlPRENveU9laTVyS1l2VENMNlRMZFN5UEdUN0djMnFsRnBwNXdiWFEiLCJjcnYiOiJQLTI1NiJ9fQ..3mifklTnTTGuA_etSUBBCw.dj8KFM8OlrQ3rT35nHcHZ7A5p84VB2OZb054ghSjS-M.KOIgnJjz87LGqMtikXGxXw",
"eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTE5MkNCQy1IUzM4NCIsImVwayI6eyJrdHkiOiJFQyIsIngiOiJUaHRGc0lRZ1E5MkZOYWFMbUFDQURLbE93dmNGVlRORHc4ampfWlJidUxjIiwieSI6IjJmRDZ3UXc3YmpYTm1nVThXMGpFbnl5ZUZkX3Y4ZmpDa3l1R29vTFhGM0EiLCJjcnYiOiJQLTI1NiJ9fQ..90zFayMkKc-fQC_19f6P3A.P1Y_7lMnfkUQOXW_en31lKZ3zAn1nEYn6fXLjmyVPrQ.hrgwy1cePVfhMWT0h-crKTXldglHZ-4g",
"eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTI1NkNCQy1IUzUxMiIsImVwayI6eyJrdHkiOiJFQyIsIngiOiI5R1Z6c3VKNWgySl96UURVUFR3WU5zUkFzVzZfY2RzN0pELVQ2RDREQ1ZVIiwieSI6InFZVGl1dVU4aTB1WFpoaS14VGlRNlZJQm5vanFoWENPVnpmWm1pR2lRTEUiLCJjcnYiOiJQLTI1NiJ9fQ..v2reRlDkIsw3eWEsTCc1NA.0qakrFdbhtBCTSl7EREf9sxgHBP9I-Xw29OTJYnrqP8.54ozViEBYYmRkcKp7d2Ztt4hzjQ9Vb5zCeijN_RQrcI",
"eyJhbGciOiJFQ0RILUVTK0EyNTZLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiOElUemg3VVFaaUthTWtfME9qX1hFaHZENXpUWjE2Ti13WVdjeTJYUC1tdyIsInkiOiJPNUJiVEk0bUFpU005ZmpCejBRU3pXaU5vbnl3cWlQLUN0RGgwdnNGYXNRIiwiY3J2IjoiUC0yNTYifX0.D3DP3wqPvJv4TYYfhnfrOG6nsM-MMH_CqGfnOGjgdXHNF7xRwEJBOA.WL9Kz3gNYA7S5Rs5mKcXmA.EmQkXhO_nFqAwxJWaM0DH4s3pmCscZovB8YWJ3Ru4N8.Bf88uzwfxiyTjpejU5B0Ng",
"eyJhbGciOiJFQ0RILUVTK0EyNTZLVyIsImVuYyI6IkExOTJDQkMtSFMzODQiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiMjlJMk4zRkF0UlBlNGhzYjRLWlhTbmVyV0wyTVhtSUN1LXJJaXhNSHpJQSIsInkiOiJvMjY1bzFReEdmbDhzMHQ0U1JROS00RGNpc3otbXh4NlJ6WVF4SktyeWpJIiwiY3J2IjoiUC0yNTYifX0.DRmsmXz6fCnLc_njDIKdpM7Oc4jTqd_yd9J94TOUksAstEUkAl9Ie3Wg-Ji_LzbdX2xRLXIimcw.FwJOHPQhnqKJCfxt1_qRnQ.ssx3q1ZYILsMTln5q-K8HVn93BVPI5ViusstKMxZzRs.zzcfzWNYSdNDdQ4CiHfymj0bePaAbVaT",
"eyJhbGciOiJFQ0RILUVTK0EyNTZLVyIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiRUp6bTViQnRzVXJNYTl2Y1Q2d1hZRXI3ZjNMcjB0N1V4SDZuZzdGcFF0VSIsInkiOiJRYTNDSDllVTFXYjItdFdVSDN3Sk9fTDVMZXRsRUlMQWNkNE9XR2tFd0hZIiwiY3J2IjoiUC0yNTYifX0.5WxwluZpVWAOJdVrsnDIlEc4_wfRE1gXOaQyx_rKkElNz157Ykf-JsAD7aEvXfx--NKF4js5zYyjeCtxWBhRWPOoNNZJlqV_.Iuo82-qsP2S1SgQQklAnrw.H4wB6XoLKOKWCu6Y3LPAEuHkvyvr-xAh4IBm53uRF8g._fOLKq0bqDZ8KNjni_MJ4olHNaYz376dV9eNmp9O9PU",
"eyJhbGciOiJFQ0RILUVTK0ExOTJLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiZktNSG5sRkoxajBTSnJ3WGtVWlpaX3BtWHdUQlJtcHhlaTkxdUpaczUycyIsInkiOiJLRkxKaXhEUTJQcjEybWp1aFdYb3pna2U1V3lhWnhmTWlxZkJ0OEJpbkRvIiwiY3J2IjoiUC0yNTYifX0.2LSD2Mw4tyYJyfsmpVmzBtJRd12jMEYGdlhFbaXIbKi5A33CGNQ1tg.s40aAjmZOvK8Us86FCBdHg.jpYSMAKp___oMCoWM495mTfbi_YC80ObeoCmGE3H_gs.A6V-jJJRY1yz24CaXGUbzg",
"eyJhbGciOiJFQ0RILUVTK0ExOTJLVyIsImVuYyI6IkExOTJDQkMtSFMzODQiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiSDRxcFUzeWtuRktWRnV4SmxLa3NZSE5ieHF3aXM0WWtCVVFHVE1Td05JQSIsInkiOiJHb0lpRUZaUGRRSHJCbVR4ZTA3akJoZmxrdWNqUjVoX1QwNWVXc3Zib0prIiwiY3J2IjoiUC0yNTYifX0.KTrwwV2uzD--gf3PGG-kjEAGgi7u0eMqZPZfa4kpyFGm3x8t2m1NHdz3t9rfiqjuaqsxPKhF4gs.cu16fEOzYaSxhHu_Ht9w4g.BRJdxVBI9spVtY5KQ6gTR4CNcKvmLUMKZap0AO-RF2I.DZyUaa2p6YCIaYtjWOjC9GN_VIYgySlZ",
"eyJhbGciOiJFQ0RILUVTK0ExOTJLVyIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoieDBYSGRkSGM2Q0ktSnlfbUVMOEZZRExhWnV0UkVFczR4c3BMQmcwZk1jbyIsInkiOiJEa0xzOUJGTlBkTTVTNkpLYVJ3cnV1TWMwcUFzWW9yNW9fZWp6NXBNVXFrIiwiY3J2IjoiUC0yNTYifX0.mfCxJ7JYIqTMqcAh5Vp2USF0eF7OhOeluqda7YagOUJNwxA9wC9o23DSoLUylfrZUfanZrJJJcG69awlv-LY7anOLHlp3Ht5.ec48A_JWb4qa_PVHWZaTfQ.kDAjIDb3LzJpfxNh-DiAmAuaKMYaOGSTb0rkiJLuVeY.oxGCpPlii4pr89XMk4b9s084LucTqPGU6TLbOW2MZoc",
"eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiQXB5TnlqU2d0bmRUcFg0eENYenNDRnZva1l3X18weXg2dGRUYzdPUUhIMCIsInkiOiJYUHdHMDVDaW1vOGlhWmxZbDNsMEp3ZllhY1FZWHFuM2RRZEJUWFpldDZBIiwiY3J2IjoiUC0yNTYifX0.yTA2PwK9IPqkaGPenZ9R-gOn9m9rvcSEfuX_Nm8AkuwHIYLzzYeAEA.ZW1F1iyHYKfo-YoanNaIVg.PouKQD94DlPA5lbpfGJXY-EJhidC7l4vSayVN2vVzvA.MexquqtGaXKUvX7WBmD4bA",
"eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExOTJDQkMtSFMzODQiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiaDRWeGNzNVUzWk1fTlp4WmJxQ3hMTVB5UmEtR2ktSVNZa0xDTzE1RHJkZyIsInkiOiJFeVotS3dWNVE5OXlnWk5zU0lpSldpR3hqbXNLUk1WVE5sTTNSd1VYTFRvIiwiY3J2IjoiUC0yNTYifX0.wo56VISyL1QAbi2HLuVut5NGF2FvxKt7B8zHzJ3FpmavPozfbVZV08-GSYQ6jLQWJ4xsO80I4Kg.3_9Bo5ozvD96WHGhqp_tfQ.48UkJ6jk6WK70QItb2QZr0edKH7O-aMuVahTEeqyfW4.ulMlY2tbC341ct20YSmNdtc84FRz1I4g",
"eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkEyNTZDQkMtSFM1MTIiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiN0xZRzZZWTJkel9ZaGNvNnRCcG1IX0tPREQ2X2hwX05tajdEc1c2RXgxcyIsInkiOiI5Y2lPeDcwUkdGT0tpVnBRX0NHQXB5NVlyeThDazBmUkpwNHVrQ2tjNmQ0IiwiY3J2IjoiUC0yNTYifX0.bWwW3J80k46HG1fQAZxUroko2OO8OKkeRavr_o3AnhJDMvp78OR229x-fZUaBm4uWv27_Yjm0X9T2H2lhlIli2Rl9v1PNC77.1NmsJBDGI1fDjRzyc4mtyA.9KfCFynQj7LmJq08qxAG4c-6ZPz1Lh3h3nUbgVwB0TI.cqech0d8XHzWfkWqgKZq1SlAfmO0PUwOsNVkuByVGWk",
}
for _, msg := range ecSampleMessages {
obj, err := ParseEncrypted(msg)
if err != nil {
t.Error("unable to parse message", msg, err)
continue
}
plaintext, err := obj.Decrypt(ecTestKey)
if err != nil {
t.Error("unable to decrypt message", msg, err)
continue
}
if string(plaintext) != "Lorem ipsum dolor sit amet." {
t.Error("plaintext is not what we expected for msg", msg)
}
}
}

View file

@ -1,715 +0,0 @@
/*-
* 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 (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/x509"
"encoding/hex"
"math/big"
"reflect"
"testing"
"golang.org/x/crypto/ed25519"
"gopkg.in/square/go-jose.v2/json"
)
// Test chain of two X.509 certificates
var testCertificates, _ = x509.ParseCertificates(fromBase64Bytes(`
MIIDfDCCAmSgAwIBAgIJANWAkzF7PA8/MA0GCSqGSIb3DQEBCwUAMFUxCzAJ
BgNVBAYTAlVTMQswCQYDVQQIEwJDQTEQMA4GA1UEChMHY2VydGlnbzEQMA4G
A1UECxMHZXhhbXBsZTEVMBMGA1UEAxMMZXhhbXBsZS1sZWFmMB4XDTE2MDYx
MDIyMTQxMVoXDTIzMDQxNTIyMTQxMVowVTELMAkGA1UEBhMCVVMxCzAJBgNV
BAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQLEwdleGFtcGxlMRUw
EwYDVQQDEwxleGFtcGxlLWxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQC7stSvfQyGuHw3v34fisqIdDXberrFoFk9ht/WdXgYzX2uLNKd
sR/J5sbWSl8K/5djpzj31eIzqU69w8v7SChM5x9bouDsABHz3kZucx5cSafE
gJojysBkcrq3VY+aJanzbL+qErYX+lhRpPcZK6JMWIwar8Y3B2la4yWwieec
w2/WfEVvG0M/DOYKnR8QHFsfl3US1dnBM84czKPyt9r40gDk2XiH/lGts5a9
4rAGvbr8IMCtq0mA5aH3Fx3mDSi3+4MZwygCAHrF5O5iSV9rEI+m2+7j2S+j
HDUnvV+nqcpb9m6ENECnYX8FD2KcqlOjTmw8smDy09N2Np6i464lAgMBAAGj
TzBNMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAsBgNVHREEJTAj
hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABgglsb2NhbGhvc3QwDQYJKoZIhvcN
AQELBQADggEBAGM4aa/qrURUweZBIwZYv8O9b2+r4l0HjGAh982/B9sMlM05
kojyDCUGvj86z18Lm8mKr4/y+i0nJ+vDIksEvfDuzw5ALAXGcBzPJKtICUf7
LstA/n9NNpshWz0kld9ylnB5mbUzSFDncVyeXkEf5sGQXdIIZT9ChRBoiloS
aa7dvBVCcsX1LGP2LWqKtD+7nUnw5qCwtyAVT8pthEUxFTpywoiJS5ZdzeEx
8MNGvUeLFj2kleqPF78EioEQlSOxViCuctEtnQuPcDLHNFr10byTZY9roObi
qdsJLMVvb2XliJjAqaPa9AkYwGE6xHw2ispwg64Rse0+AtKups19WIUwggNT
MIICO6ADAgECAgkAqD4tCWKt9/AwDQYJKoZIhvcNAQELBQAwVTELMAkGA1UE
BhMCVVMxCzAJBgNVBAgTAkNBMRAwDgYDVQQKEwdjZXJ0aWdvMRAwDgYDVQQL
EwdleGFtcGxlMRUwEwYDVQQDEwxleGFtcGxlLXJvb3QwHhcNMTYwNjEwMjIx
NDExWhcNMjMwNDE1MjIxNDExWjBVMQswCQYDVQQGEwJVUzELMAkGA1UECBMC
Q0ExEDAOBgNVBAoTB2NlcnRpZ28xEDAOBgNVBAsTB2V4YW1wbGUxFTATBgNV
BAMTDGV4YW1wbGUtcm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAMo4ShKI2MxDz/NQVxBbz0tbD5R5NcobA0NKkaPKLyMEpnWVY9ucyauM
joNn1F568cfOoF0pm3700U8UTPt2MMxEHIi4mFG/OF8UF+Voh1J42Tb42lRo
W5RRR3ogh4+7QB1G94nxkYddHAJ4QMhUJlLigFg8c6Ff/MxYODy9I7ilLFOM
Zzsjx8fFpRKRXNQFt471P/V4WTSba7GzdTOJRyTZf/xipF36n8RoEQPvyde8
pEAsCC4oDOrEiCTdxw8rRJVAU0Wr55XX+qjxyi55C6oykIC/BWR+lUqGd7IL
Y2Uyt/OVxllt8b+KuVKNCfn4TFlfgizLWkJRs6JV9KuwJ20CAwEAAaMmMCQw
DgYDVR0PAQH/BAQDAgIEMBIGA1UdEwEB/wQIMAYBAf8CAQAwDQYJKoZIhvcN
AQELBQADggEBAIsQlTrm9NT6gts0cs4JHp8AutuMrvGyLpIUOlJcEybvgxaz
LebIMGZek5w3yEJiCyCK9RdNDP3Kdc/+nM6PhvzfPOVo58+0tMCYyEpZVXhD
zmasNDP4fMbiUpczvx5OwPw/KuhwD+1ITuZUQnQlqXgTYoj9n39+qlgUsHos
WXHmfzd6Fcz96ADSXg54IL2cEoJ41Q3ewhA7zmWWPLMAl21aex2haiAmzqqN
xXyfZTnGNnE3lkV1yVguOrqDZyMRdcxDFvxvtmEeMtYV2Mc/zlS9ccrcOkrc
mZSDxthLu3UMl98NA2NrCGWwzJwpk36vQ0PRSbibsCMarFspP8zbIoU=`))
func TestCurveSize(t *testing.T) {
size256 := curveSize(elliptic.P256())
size384 := curveSize(elliptic.P384())
size521 := curveSize(elliptic.P521())
if size256 != 32 {
t.Error("P-256 have 32 bytes")
}
if size384 != 48 {
t.Error("P-384 have 48 bytes")
}
if size521 != 66 {
t.Error("P-521 have 66 bytes")
}
}
func TestRoundtripRsaPrivate(t *testing.T) {
jwk, err := fromRsaPrivateKey(rsaTestKey)
if err != nil {
t.Error("problem constructing JWK from rsa key", err)
}
rsa2, err := jwk.rsaPrivateKey()
if err != nil {
t.Error("problem converting RSA private -> JWK", err)
}
if rsa2.N.Cmp(rsaTestKey.N) != 0 {
t.Error("RSA private N mismatch")
}
if rsa2.E != rsaTestKey.E {
t.Error("RSA private E mismatch")
}
if rsa2.D.Cmp(rsaTestKey.D) != 0 {
t.Error("RSA private D mismatch")
}
if len(rsa2.Primes) != 2 {
t.Error("RSA private roundtrip expected two primes")
}
if rsa2.Primes[0].Cmp(rsaTestKey.Primes[0]) != 0 {
t.Error("RSA private P mismatch")
}
if rsa2.Primes[1].Cmp(rsaTestKey.Primes[1]) != 0 {
t.Error("RSA private Q mismatch")
}
}
func TestRsaPrivateInsufficientPrimes(t *testing.T) {
brokenRsaPrivateKey := rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: rsaTestKey.N,
E: rsaTestKey.E,
},
D: rsaTestKey.D,
Primes: []*big.Int{rsaTestKey.Primes[0]},
}
_, err := fromRsaPrivateKey(&brokenRsaPrivateKey)
if err != ErrUnsupportedKeyType {
t.Error("expected unsupported key type error, got", err)
}
}
func TestRsaPrivateExcessPrimes(t *testing.T) {
brokenRsaPrivateKey := rsa.PrivateKey{
PublicKey: rsa.PublicKey{
N: rsaTestKey.N,
E: rsaTestKey.E,
},
D: rsaTestKey.D,
Primes: []*big.Int{
rsaTestKey.Primes[0],
rsaTestKey.Primes[1],
big.NewInt(3),
},
}
_, err := fromRsaPrivateKey(&brokenRsaPrivateKey)
if err != ErrUnsupportedKeyType {
t.Error("expected unsupported key type error, got", err)
}
}
func TestRoundtripEcPublic(t *testing.T) {
for i, ecTestKey := range []*ecdsa.PrivateKey{ecTestKey256, ecTestKey384, ecTestKey521} {
jwk, err := fromEcPublicKey(&ecTestKey.PublicKey)
ec2, err := jwk.ecPublicKey()
if err != nil {
t.Error("problem converting ECDSA private -> JWK", i, err)
}
if !reflect.DeepEqual(ec2.Curve, ecTestKey.Curve) {
t.Error("ECDSA private curve mismatch", i)
}
if ec2.X.Cmp(ecTestKey.X) != 0 {
t.Error("ECDSA X mismatch", i)
}
if ec2.Y.Cmp(ecTestKey.Y) != 0 {
t.Error("ECDSA Y mismatch", i)
}
}
}
func TestRoundtripEcPrivate(t *testing.T) {
for i, ecTestKey := range []*ecdsa.PrivateKey{ecTestKey256, ecTestKey384, ecTestKey521} {
jwk, err := fromEcPrivateKey(ecTestKey)
ec2, err := jwk.ecPrivateKey()
if err != nil {
t.Error("problem converting ECDSA private -> JWK", i, err)
}
if !reflect.DeepEqual(ec2.Curve, ecTestKey.Curve) {
t.Error("ECDSA private curve mismatch", i)
}
if ec2.X.Cmp(ecTestKey.X) != 0 {
t.Error("ECDSA X mismatch", i)
}
if ec2.Y.Cmp(ecTestKey.Y) != 0 {
t.Error("ECDSA Y mismatch", i)
}
if ec2.D.Cmp(ecTestKey.D) != 0 {
t.Error("ECDSA D mismatch", i)
}
}
}
func TestRoundtripX5C(t *testing.T) {
jwk := JSONWebKey{
Key: rsaTestKey,
KeyID: "bar",
Algorithm: "foo",
Certificates: testCertificates,
}
jsonbar, err := jwk.MarshalJSON()
if err != nil {
t.Error("problem marshaling", err)
}
var jwk2 JSONWebKey
err = jwk2.UnmarshalJSON(jsonbar)
if err != nil {
t.Error("problem unmarshalling", err)
}
if !reflect.DeepEqual(testCertificates, jwk2.Certificates) {
t.Error("Certificates not equal", jwk.Certificates, jwk2.Certificates)
}
jsonbar2, err := jwk2.MarshalJSON()
if err != nil {
t.Error("problem marshaling", err)
}
if !bytes.Equal(jsonbar, jsonbar2) {
t.Error("roundtrip should not lose information")
}
}
func TestMarshalUnmarshal(t *testing.T) {
kid := "DEADBEEF"
for i, key := range []interface{}{ecTestKey256, ecTestKey384, ecTestKey521, rsaTestKey, ed25519PrivateKey} {
for _, use := range []string{"", "sig", "enc"} {
jwk := JSONWebKey{Key: key, KeyID: kid, Algorithm: "foo"}
if use != "" {
jwk.Use = use
}
jsonbar, err := jwk.MarshalJSON()
if err != nil {
t.Error("problem marshaling", i, err)
}
var jwk2 JSONWebKey
err = jwk2.UnmarshalJSON(jsonbar)
if err != nil {
t.Error("problem unmarshalling", i, err)
}
jsonbar2, err := jwk2.MarshalJSON()
if err != nil {
t.Error("problem marshaling", i, err)
}
if !bytes.Equal(jsonbar, jsonbar2) {
t.Error("roundtrip should not lose information", i)
}
if jwk2.KeyID != kid {
t.Error("kid did not roundtrip JSON marshalling", i)
}
if jwk2.Algorithm != "foo" {
t.Error("alg did not roundtrip JSON marshalling", i)
}
if jwk2.Use != use {
t.Error("use did not roundtrip JSON marshalling", i)
}
}
}
}
func TestMarshalNonPointer(t *testing.T) {
type EmbedsKey struct {
Key JSONWebKey
}
keyJSON := []byte(`{
"e": "AQAB",
"kty": "RSA",
"n": "vd7rZIoTLEe-z1_8G1FcXSw9CQFEJgV4g9V277sER7yx5Qjz_Pkf2YVth6wwwFJEmzc0hoKY-MMYFNwBE4hQHw"
}`)
var parsedKey JSONWebKey
err := json.Unmarshal(keyJSON, &parsedKey)
if err != nil {
t.Errorf("Error unmarshalling key: %v", err)
return
}
ek := EmbedsKey{
Key: parsedKey,
}
out, err := json.Marshal(ek)
if err != nil {
t.Errorf("Error marshalling JSON: %v", err)
return
}
expected := "{\"Key\":{\"kty\":\"RSA\",\"n\":\"vd7rZIoTLEe-z1_8G1FcXSw9CQFEJgV4g9V277sER7yx5Qjz_Pkf2YVth6wwwFJEmzc0hoKY-MMYFNwBE4hQHw\",\"e\":\"AQAB\"}}"
if string(out) != expected {
t.Error("Failed to marshal embedded non-pointer JWK properly:", string(out))
}
}
func TestMarshalUnmarshalInvalid(t *testing.T) {
// Make an invalid curve coordinate by creating a byte array that is one
// byte too large, and setting the first byte to 1 (otherwise it's just zero).
invalidCoord := make([]byte, curveSize(ecTestKey256.Curve)+1)
invalidCoord[0] = 1
keys := []interface{}{
// Empty keys
&rsa.PrivateKey{},
&ecdsa.PrivateKey{},
// Invalid keys
&ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
// Missing values in pub key
Curve: elliptic.P256(),
},
},
&ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
// Invalid curve
Curve: nil,
X: ecTestKey256.X,
Y: ecTestKey256.Y,
},
},
&ecdsa.PrivateKey{
// Valid pub key, but missing priv key values
PublicKey: ecTestKey256.PublicKey,
},
&ecdsa.PrivateKey{
// Invalid pub key, values too large
PublicKey: ecdsa.PublicKey{
Curve: ecTestKey256.Curve,
X: big.NewInt(0).SetBytes(invalidCoord),
Y: big.NewInt(0).SetBytes(invalidCoord),
},
D: ecTestKey256.D,
},
nil,
}
for i, key := range keys {
jwk := JSONWebKey{Key: key}
_, err := jwk.MarshalJSON()
if err == nil {
t.Error("managed to serialize invalid key", i)
}
}
}
func TestWebKeyVectorsInvalid(t *testing.T) {
keys := []string{
// Invalid JSON
"{X",
// Empty key
"{}",
// Invalid RSA keys
`{"kty":"RSA"}`,
`{"kty":"RSA","e":""}`,
`{"kty":"RSA","e":"XXXX"}`,
`{"kty":"RSA","d":"XXXX"}`,
// Invalid EC keys
`{"kty":"EC","crv":"ABC"}`,
`{"kty":"EC","crv":"P-256"}`,
`{"kty":"EC","crv":"P-256","d":"XXX"}`,
`{"kty":"EC","crv":"ABC","d":"dGVzdA","x":"dGVzdA"}`,
`{"kty":"EC","crv":"P-256","d":"dGVzdA","x":"dGVzdA"}`,
}
for _, key := range keys {
var jwk2 JSONWebKey
err := jwk2.UnmarshalJSON([]byte(key))
if err == nil {
t.Error("managed to parse invalid key:", key)
}
}
}
// Test vectors from RFC 7520
var cookbookJWKs = []string{
// EC Public
stripWhitespace(`{
"kty": "EC",
"kid": "bilbo.baggins@hobbiton.example",
"use": "sig",
"crv": "P-521",
"x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9
A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt",
"y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVy
SsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1"
}`),
//ED Private
stripWhitespace(`{
"kty": "OKP",
"crv": "Ed25519",
"d": "nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A",
"x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"
}`),
// EC Private
stripWhitespace(`{
"kty": "EC",
"kid": "bilbo.baggins@hobbiton.example",
"use": "sig",
"crv": "P-521",
"x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9
A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt",
"y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVy
SsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1",
"d": "AAhRON2r9cqXX1hg-RoI6R1tX5p2rUAYdmpHZoC1XNM56KtscrX6zb
KipQrCW9CGZH3T4ubpnoTKLDYJ_fF3_rJt"
}`),
// RSA Public
stripWhitespace(`{
"kty": "RSA",
"kid": "bilbo.baggins@hobbiton.example",
"use": "sig",
"n": "n4EPtAOCc9AlkeQHPzHStgAbgs7bTZLwUBZdR8_KuKPEHLd4rHVTeT
-O-XV2jRojdNhxJWTDvNd7nqQ0VEiZQHz_AJmSCpMaJMRBSFKrKb2wqV
wGU_NsYOYL-QtiWN2lbzcEe6XC0dApr5ydQLrHqkHHig3RBordaZ6Aj-
oBHqFEHYpPe7Tpe-OfVfHd1E6cS6M1FZcD1NNLYD5lFHpPI9bTwJlsde
3uhGqC0ZCuEHg8lhzwOHrtIQbS0FVbb9k3-tVTU4fg_3L_vniUFAKwuC
LqKnS2BYwdq_mzSnbLY7h_qixoR7jig3__kRhuaxwUkRz5iaiQkqgc5g
HdrNP5zw",
"e": "AQAB"
}`),
// RSA Private
stripWhitespace(`{"kty":"RSA",
"kid":"juliet@capulet.lit",
"use":"enc",
"n":"t6Q8PWSi1dkJj9hTP8hNYFlvadM7DflW9mWepOJhJ66w7nyoK1gPNqFMSQRy
O125Gp-TEkodhWr0iujjHVx7BcV0llS4w5ACGgPrcAd6ZcSR0-Iqom-QFcNP
8Sjg086MwoqQU_LYywlAGZ21WSdS_PERyGFiNnj3QQlO8Yns5jCtLCRwLHL0
Pb1fEv45AuRIuUfVcPySBWYnDyGxvjYGDSM-AqWS9zIQ2ZilgT-GqUmipg0X
OC0Cc20rgLe2ymLHjpHciCKVAbY5-L32-lSeZO-Os6U15_aXrk9Gw8cPUaX1
_I8sLGuSiVdt3C_Fn2PZ3Z8i744FPFGGcG1qs2Wz-Q",
"e":"AQAB",
"d":"GRtbIQmhOZtyszfgKdg4u_N-R_mZGU_9k7JQ_jn1DnfTuMdSNprTeaSTyWfS
NkuaAwnOEbIQVy1IQbWVV25NY3ybc_IhUJtfri7bAXYEReWaCl3hdlPKXy9U
vqPYGR0kIXTQRqns-dVJ7jahlI7LyckrpTmrM8dWBo4_PMaenNnPiQgO0xnu
ToxutRZJfJvG4Ox4ka3GORQd9CsCZ2vsUDmsXOfUENOyMqADC6p1M3h33tsu
rY15k9qMSpG9OX_IJAXmxzAh_tWiZOwk2K4yxH9tS3Lq1yX8C1EWmeRDkK2a
hecG85-oLKQt5VEpWHKmjOi_gJSdSgqcN96X52esAQ",
"p":"2rnSOV4hKSN8sS4CgcQHFbs08XboFDqKum3sc4h3GRxrTmQdl1ZK9uw-PIHf
QP0FkxXVrx-WE-ZEbrqivH_2iCLUS7wAl6XvARt1KkIaUxPPSYB9yk31s0Q8
UK96E3_OrADAYtAJs-M3JxCLfNgqh56HDnETTQhH3rCT5T3yJws",
"q":"1u_RiFDP7LBYh3N4GXLT9OpSKYP0uQZyiaZwBtOCBNJgQxaj10RWjsZu0c6I
edis4S7B_coSKB0Kj9PaPaBzg-IySRvvcQuPamQu66riMhjVtG6TlV8CLCYK
rYl52ziqK0E_ym2QnkwsUX7eYTB7LbAHRK9GqocDE5B0f808I4s",
"dp":"KkMTWqBUefVwZ2_Dbj1pPQqyHSHjj90L5x_MOzqYAJMcLMZtbUtwKqvVDq3
tbEo3ZIcohbDtt6SbfmWzggabpQxNxuBpoOOf_a_HgMXK_lhqigI4y_kqS1w
Y52IwjUn5rgRrJ-yYo1h41KR-vz2pYhEAeYrhttWtxVqLCRViD6c",
"dq":"AvfS0-gRxvn0bwJoMSnFxYcK1WnuEjQFluMGfwGitQBWtfZ1Er7t1xDkbN9
GQTB9yqpDoYaN06H7CFtrkxhJIBQaj6nkF5KKS3TQtQ5qCzkOkmxIe3KRbBy
mXxkb5qwUpX5ELD5xFc6FeiafWYY63TmmEAu_lRFCOJ3xDea-ots",
"qi":"lSQi-w9CpyUReMErP1RsBLk7wNtOvs5EQpPqmuMvqW57NBUczScEoPwmUqq
abu9V0-Py4dQ57_bapoKRu1R90bvuFnU63SHWEFglZQvJDMeAvmj4sm-Fp0o
Yu_neotgQ0hzbI5gry7ajdYy9-2lNx_76aBZoOUu9HCJ-UsfSOI8"}`),
// X.509 Certificate Chain
stripWhitespace(`{"kty":"RSA",
"use":"sig",
"kid":"1b94c",
"n":"vrjOfz9Ccdgx5nQudyhdoR17V-IubWMeOZCwX_jj0hgAsz2J_pqYW08
PLbK_PdiVGKPrqzmDIsLI7sA25VEnHU1uCLNwBuUiCO11_-7dYbsr4iJmG0Q
u2j8DsVyT1azpJC_NG84Ty5KKthuCaPod7iI7w0LK9orSMhBEwwZDCxTWq4a
YWAchc8t-emd9qOvWtVMDC2BXksRngh6X5bUYLy6AyHKvj-nUy1wgzjYQDwH
MTplCoLtU-o-8SNnZ1tmRoGE9uJkBLdh5gFENabWnU5m1ZqZPdwS-qo-meMv
VfJb6jJVWRpl2SUtCnYG2C32qvbWbjZ_jBPD5eunqsIo1vQ",
"e":"AQAB",
"x5c":
["MIIDQjCCAiqgAwIBAgIGATz/FuLiMA0GCSqGSIb3DQEBBQUAMGIxCzAJB
gNVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYD
VQQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1
wYmVsbDAeFw0xMzAyMjEyMzI5MTVaFw0xODA4MTQyMjI5MTVaMGIxCzAJBg
NVBAYTAlVTMQswCQYDVQQIEwJDTzEPMA0GA1UEBxMGRGVudmVyMRwwGgYDV
QQKExNQaW5nIElkZW50aXR5IENvcnAuMRcwFQYDVQQDEw5CcmlhbiBDYW1w
YmVsbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64zn8/QnH
YMeZ0LncoXaEde1fiLm1jHjmQsF/449IYALM9if6amFtPDy2yvz3YlRij66
s5gyLCyO7ANuVRJx1NbgizcAblIgjtdf/u3WG7K+IiZhtELto/A7Fck9Ws6
SQvzRvOE8uSirYbgmj6He4iO8NCyvaK0jIQRMMGQwsU1quGmFgHIXPLfnpn
fajr1rVTAwtgV5LEZ4Iel+W1GC8ugMhyr4/p1MtcIM42EA8BzE6ZQqC7VPq
PvEjZ2dbZkaBhPbiZAS3YeYBRDWm1p1OZtWamT3cEvqqPpnjL1XyW+oyVVk
aZdklLQp2Btgt9qr21m42f4wTw+Xrp6rCKNb0CAwEAATANBgkqhkiG9w0BA
QUFAAOCAQEAh8zGlfSlcI0o3rYDPBB07aXNswb4ECNIKG0CETTUxmXl9KUL
+9gGlqCz5iWLOgWsnrcKcY0vXPG9J1r9AqBNTqNgHq2G03X09266X5CpOe1
zFo+Owb1zxtp3PehFdfQJ610CDLEaS9V9Rqp17hCyybEpOGVwe8fnk+fbEL
2Bo3UPGrpsHzUoaGpDftmWssZkhpBJKVMJyf/RuP2SmmaIzmnw9JiSlYhzo
4tpzd5rFXhjRbg4zW9C+2qok+2+qDM1iJ684gPHMIY8aLWrdgQTxkumGmTq
gawR+N5MDtdPTEQ0XfIBc2cJEUyMTY5MPvACWpkA6SdS4xSvdXK3IVfOWA=="]}`),
}
// SHA-256 thumbprints of the above keys, hex-encoded
var cookbookJWKThumbprints = []string{
"747ae2dd2003664aeeb21e4753fe7402846170a16bc8df8f23a8cf06d3cbe793",
"f6934029a341ddf81dceb753e91d17efe16664f40d9f4ed84bc5ea87e111f29d",
"747ae2dd2003664aeeb21e4753fe7402846170a16bc8df8f23a8cf06d3cbe793",
"f63838e96077ad1fc01c3f8405774dedc0641f558ebb4b40dccf5f9b6d66a932",
"0fc478f8579325fcee0d4cbc6d9d1ce21730a6e97e435d6008fb379b0ebe47d4",
"0ddb05bfedbec2070fa037324ba397396561d3425d6d69245570c261dc49dee3",
}
func TestWebKeyVectorsValid(t *testing.T) {
for _, key := range cookbookJWKs {
var jwk2 JSONWebKey
err := jwk2.UnmarshalJSON([]byte(key))
if err != nil {
t.Error("unable to parse valid key:", key, err)
}
}
}
func TestThumbprint(t *testing.T) {
for i, key := range cookbookJWKs {
var jwk2 JSONWebKey
err := jwk2.UnmarshalJSON([]byte(key))
if err != nil {
t.Error("unable to parse valid key:", key, err)
}
tp, err := jwk2.Thumbprint(crypto.SHA256)
if err != nil {
t.Error("unable to compute thumbprint:", key, err)
}
tpHex := hex.EncodeToString(tp)
if cookbookJWKThumbprints[i] != tpHex {
t.Error("incorrect thumbprint:", i, cookbookJWKThumbprints[i], tpHex)
}
}
}
func TestMarshalUnmarshalJWKSet(t *testing.T) {
jwk1 := JSONWebKey{Key: rsaTestKey, KeyID: "ABCDEFG", Algorithm: "foo"}
jwk2 := JSONWebKey{Key: rsaTestKey, KeyID: "GFEDCBA", Algorithm: "foo"}
var set JSONWebKeySet
set.Keys = append(set.Keys, jwk1)
set.Keys = append(set.Keys, jwk2)
jsonbar, err := json.Marshal(&set)
if err != nil {
t.Error("problem marshalling set", err)
}
var set2 JSONWebKeySet
err = json.Unmarshal(jsonbar, &set2)
if err != nil {
t.Error("problem unmarshalling set", err)
}
jsonbar2, err := json.Marshal(&set2)
if err != nil {
t.Error("problem marshalling set", err)
}
if !bytes.Equal(jsonbar, jsonbar2) {
t.Error("roundtrip should not lose information")
}
}
func TestJWKSetKey(t *testing.T) {
jwk1 := JSONWebKey{Key: rsaTestKey, KeyID: "ABCDEFG", Algorithm: "foo"}
jwk2 := JSONWebKey{Key: rsaTestKey, KeyID: "GFEDCBA", Algorithm: "foo"}
var set JSONWebKeySet
set.Keys = append(set.Keys, jwk1)
set.Keys = append(set.Keys, jwk2)
k := set.Key("ABCDEFG")
if len(k) != 1 {
t.Errorf("method should return slice with one key not %d", len(k))
}
if k[0].KeyID != "ABCDEFG" {
t.Error("method should return key with ID ABCDEFG")
}
}
func TestJWKSymmetricKey(t *testing.T) {
sample1 := `{"kty":"oct","alg":"A128KW","k":"GawgguFyGrWKav7AX4VKUg"}`
sample2 := `{"kty":"oct","k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow","kid":"HMAC key used in JWS spec Appendix A.1 example"}`
var jwk1 JSONWebKey
json.Unmarshal([]byte(sample1), &jwk1)
if jwk1.Algorithm != "A128KW" {
t.Errorf("expected Algorithm to be A128KW, but was '%s'", jwk1.Algorithm)
}
expected1 := fromHexBytes("19ac2082e1721ab58a6afec05f854a52")
if !bytes.Equal(jwk1.Key.([]byte), expected1) {
t.Errorf("expected Key to be '%s', but was '%s'", hex.EncodeToString(expected1), hex.EncodeToString(jwk1.Key.([]byte)))
}
var jwk2 JSONWebKey
json.Unmarshal([]byte(sample2), &jwk2)
if jwk2.KeyID != "HMAC key used in JWS spec Appendix A.1 example" {
t.Errorf("expected KeyID to be 'HMAC key used in JWS spec Appendix A.1 example', but was '%s'", jwk2.KeyID)
}
expected2 := fromHexBytes(`
0323354b2b0fa5bc837e0665777ba68f5ab328e6f054c928a90f84b2d2502ebf
d3fb5a92d20647ef968ab4c377623d223d2e2172052e4f08c0cd9af567d080a3`)
if !bytes.Equal(jwk2.Key.([]byte), expected2) {
t.Errorf("expected Key to be '%s', but was '%s'", hex.EncodeToString(expected2), hex.EncodeToString(jwk2.Key.([]byte)))
}
}
func TestJWKSymmetricRoundtrip(t *testing.T) {
jwk1 := JSONWebKey{Key: []byte{1, 2, 3, 4}}
marshaled, err := jwk1.MarshalJSON()
if err != nil {
t.Error("failed to marshal valid JWK object", err)
}
var jwk2 JSONWebKey
err = jwk2.UnmarshalJSON(marshaled)
if err != nil {
t.Error("failed to unmarshal valid JWK object", err)
}
if !bytes.Equal(jwk1.Key.([]byte), jwk2.Key.([]byte)) {
t.Error("round-trip of symmetric JWK gave different raw keys")
}
}
func TestJWKSymmetricInvalid(t *testing.T) {
invalid := JSONWebKey{}
_, err := invalid.MarshalJSON()
if err == nil {
t.Error("excepted error on marshaling invalid symmetric JWK object")
}
var jwk JSONWebKey
err = jwk.UnmarshalJSON([]byte(`{"kty":"oct"}`))
if err == nil {
t.Error("excepted error on unmarshaling invalid symmetric JWK object")
}
}
func TestJWKIsPublic(t *testing.T) {
bigInt := big.NewInt(0)
eccPub := ecdsa.PublicKey{elliptic.P256(), bigInt, bigInt}
rsaPub := rsa.PublicKey{bigInt, 1}
cases := []struct {
key interface{}
expectedIsPublic bool
}{
{&eccPub, true},
{&ecdsa.PrivateKey{eccPub, bigInt}, false},
{&rsaPub, true},
{&rsa.PrivateKey{rsaPub, bigInt, []*big.Int{bigInt, bigInt}, rsa.PrecomputedValues{}}, false},
{ed25519PublicKey, true},
{ed25519PrivateKey, false},
}
for _, tc := range cases {
k := &JSONWebKey{Key: tc.key}
if public := k.IsPublic(); public != tc.expectedIsPublic {
t.Errorf("expected IsPublic to return %t, got %t", tc.expectedIsPublic, public)
}
}
}
func TestJWKValid(t *testing.T) {
bigInt := big.NewInt(0)
eccPub := ecdsa.PublicKey{elliptic.P256(), bigInt, bigInt}
rsaPub := rsa.PublicKey{bigInt, 1}
edPubEmpty := ed25519.PublicKey([]byte{})
edPrivEmpty := ed25519.PublicKey([]byte{})
cases := []struct {
key interface{}
expectedValidity bool
}{
{nil, false},
{&ecdsa.PublicKey{}, false},
{&eccPub, true},
{&ecdsa.PrivateKey{}, false},
{&ecdsa.PrivateKey{eccPub, bigInt}, true},
{&rsa.PublicKey{}, false},
{&rsaPub, true},
{&rsa.PrivateKey{}, false},
{&rsa.PrivateKey{rsaPub, bigInt, []*big.Int{bigInt, bigInt}, rsa.PrecomputedValues{}}, true},
{ed25519PublicKey, true},
{ed25519PrivateKey, true},
{edPubEmpty, false},
{edPrivEmpty, false},
}
for _, tc := range cases {
k := &JSONWebKey{Key: tc.key}
valid := k.Valid()
if valid != tc.expectedValidity {
t.Errorf("expected Valid to return %t, got %t", tc.expectedValidity, valid)
}
if valid {
wasPublic := k.IsPublic()
p := k.Public() // all aforemention keys are asymmetric
if !p.Valid() {
t.Errorf("unable to derive public key from valid asymmetric key")
}
if wasPublic != k.IsPublic() {
t.Errorf("original key was touched during public key derivation")
}
}
}
}

View file

@ -1,616 +0,0 @@
/*-
* 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/x509"
"strings"
"testing"
)
const trustedCA = `
-----BEGIN CERTIFICATE-----
MIIE6DCCAtCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwlUcnVz
dGVkQ0EwHhcNMTgwMzI4MTg0MzA0WhcNMzgwMzI4MTg0MzA0WjAUMRIwEAYDVQQD
EwlUcnVzdGVkQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsHcd3
uaKBilWQUe2epNf86xvq2HZV+JDULjJlKfUQAkpG+huHDEMiPEFPSlQK17bFj7gc
qOx/INeeCU2nBVtZDtlm3U0jfQWO2F2kZgH1JWnEArrAWWy3BP/NYv7apBLcl7nD
hkL4USVUnXF8mtuegiSMI2YT7TVchGzYMjrj/j+oRuDm1GF1OxoIMeUuVmqyJ6jK
Kxv9YVmCB+e/QaUltkPGwxl2dKWdBwECXDgSr7hcZhT8ANmgFR1dJjLCy0Us12yw
5eKUANDlfNP+z9urykoAwHXpBlmga1ze45aL+p+7K+8sl/PgMqKO7VdT5GBsOCzf
xaBDG5Qy92Di34Sc27ZZz0mfaIy5kySnceBclMyWb8vdhEGkyHVsGpWc63JBmtg+
bKeh876m7KVLfiykfpMqHUhq/ImQwiQTwX2RonFK5gP+XU0I9V+4rE0iqucbcvCS
HuHzhf6B+TybhalRsvOZ6GB/SokF5YCmf8ylAq4be/HSxnJQcBhpSSQp0zz4ZKOD
ikXuwf29yhWZ0lgIyaZpT9H4QecWNcyx4UcqO3wQAGjxadTG3gzjLu/OJwPkw+bK
RvXWSBZjlQ9+JPmrHH+oKMgHshR4TQmtmXqXLaarrAe+HXCZEiBKFOqPgeo2RMxr
LAO+MYIsVtEz39gISRhEvqcAls01sV1l7oGicQIDAQABo0UwQzAOBgNVHQ8BAf8E
BAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUy9Nqk0mDRwC5tcmN
xQ1YWO5MAhgwDQYJKoZIhvcNAQELBQADggIBAHbpsqY+tPSj8BSky+acZoZjF7fZ
Ae3MKVogwm5tecmwTKf5xDj9J99ZpGvcWCKtoxxWw0LZ+JI/aeqANSRDXZIelcIw
yZefw06z/coQJwAIy1RSoKJPV72mkG0Es9w2HxSEoLaZ9tql0TyV8D/QseUM8Yt/
nNtShRoj6iMnZjhmut5pLfrLWHwQkt4fguBpL7rtydS/wAsOmnJ7lmOrU6zrBJzD
vEER3AJtgdIt4GvKf4MupKLgKvYDB4sUQVmMyAS78B9+WZDDRTClsx+/Oc1ggkWz
8X7EmIw+3U9V2hd67qZ81EwcSB8ixV06E7ZcbhnJs7ds7swqUjwMArFWuzqO4cjW
2BnyVzCO9pymFLI7qol32xCEgaQlOVS/kFHP3meygfeaeYe902sJw6NevOA4e0AO
AKR8FDfGRXJ9cOmYzeHeWKex8yt1Ul6+N8SXzjOhf39JM0QqTfHN7pPfFthTAFOs
9rI/buJteJqR1WxgVk/jY4wLGEOcEyO6Y/Uj5iWWTvm5G/C1yZfSg+NvWoytxZ7P
3S0qtEfmT4UwuHBsd5ZfEZoxb+GbqL/nhrKz/0B9LyKS0SJP9+mz7nSORz7t35Uc
BhiG6T9W7P/NRW4Tqb2tEN1VwU6eP5SEf7c7C1VVaepk0fvc1p5dl67IERqPucPD
dT2rDsCMBV7SXMUM
-----END CERTIFICATE-----`
const intermediateCA = `
-----BEGIN CERTIFICATE-----
MIIEHTCCAgWgAwIBAgIQXzZsEQv0cvSRLJAkS9FmWTANBgkqhkiG9w0BAQsFADAU
MRIwEAYDVQQDEwlUcnVzdGVkQ0EwHhcNMTgwMzI4MTg0MzMzWhcNMzgwMzI4MTg0
MzAzWjAZMRcwFQYDVQQDEw5JbnRlcm1lZGlhdGVDQTCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAN3aYpH/1yEYf/kHuHWyO3AO4tgwlYYLhCDT2GvaPdaE
cqhe/VuYiqx3xY7IRDqsW2rau/OXgW6KzLHdRZHogK07hUj1Lfr7X+Oqbp22IV4y
dyiL7jwK9AtVXvDuuv5ET+oRfV82j0uhyk0ueGD9r6C/h+6NTzHBD+3xo6Yuc0Vk
BfY5zIyhaFqlm1aRYvupDRjC/63uBgAlrGxy2LyiTMVnYMuxoJM5ahDepz3sqjuN
WVyPhfGwIezjXuXRdEvlmWX05XLnsTdP4zu4fHq9Z7c3TKWWONM3z64ECAZmGQVf
MAcEDX7qP0gZX5PCT+0WcvTgTWE4Q+WIh5AmYyxQ04cCAwEAAaNmMGQwDgYDVR0P
AQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFMAYlq86RZzT
WxLpYE7KTTM7DHOuMB8GA1UdIwQYMBaAFMvTapNJg0cAubXJjcUNWFjuTAIYMA0G
CSqGSIb3DQEBCwUAA4ICAQBmYRpQoWEm5g16kwUrpwWrH7OIqqMtUhM1dcskECfk
i3/hcsV+MQRkGHLIItucYIWqs7oOQIglsyGcohAbnvE1PVtKKojUHC0lfbjgIenD
Pbvz15QB6A3KLDR82QbQGeGniACy924p66zlfPwHJbkMo5ZaqtNqI//EIa2YCpyy
okhFXaSFmPWXXrTOCsEEsFJKsoSCH1KUpTcwACGkkilNseg1edZB6/lBDwybxVuY
+dbUlHip3r5tFcP66Co3tKAaEcVY0AsZ/8GKwH+IM2AR6q7jdn9Gp2OX4E1ul9Wy
+hW5GHMmfixkgTVwRowuKgkCPEKV2/Xy3k9rlSpnKr2NpYYq0mu6An9HYt8THQ+e
wGZHwWufuDFDWuzlu7CxFOjpXLKv8qqVnwSFC91S3HsPAzPKLC9ZMEC+iQs2Vkes
Os0nFLZeMaMGAO5W6xiyQ5p94oo0bqa1XbmSV1bNp1HWuNEGIiZKrEUDxfYuDc6f
C6hJZKsjJkMkBeadlQAlLcjIx1rDV171CKLLTxy/dT5kv4p9UrJlnleyMVG6S/3d
6nX/WLSgZIMYbOwiZVVPlSrobuG38ULJMCSuxndxD0l+HahJaH8vYXuR67A0XT+b
TEe305AI6A/9MEaRrActBnq6/OviQgBsKAvtTv1FmDbnpZsKeoFuwc3OPdTveQdC
RA==
-----END CERTIFICATE-----`
func TestEmbeddedHMAC(t *testing.T) {
// protected: {"alg":"HS256", "jwk":{"kty":"oct", "k":"MTEx"}}, aka HMAC key.
msg := `{"payload":"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ","protected":"eyJhbGciOiJIUzI1NiIsICJqd2siOnsia3R5Ijoib2N0IiwgImsiOiJNVEV4In19","signature":"lvo41ZZsuHwQvSh0uJtEXRR3vmuBJ7in6qMoD7p9jyo"}`
_, err := ParseSigned(msg)
if err == nil {
t.Error("should not allow parsing JWS with embedded JWK with HMAC key")
}
}
func TestCompactParseJWS(t *testing.T) {
// Should parse
msg := "eyJhbGciOiJYWVoifQ.cGF5bG9hZA.c2lnbmF0dXJl"
_, err := ParseSigned(msg)
if err != nil {
t.Error("Unable to parse valid message:", err)
}
// Should parse (detached signature missing payload)
msg = "eyJhbGciOiJYWVoifQ..c2lnbmF0dXJl"
_, err = ParseSigned(msg)
if err != nil {
t.Error("Unable to parse valid message:", err)
}
// Messages that should fail to parse
failures := []string{
// Not enough parts
"eyJhbGciOiJYWVoifQ.cGF5bG9hZA",
// Invalid signature
"eyJhbGciOiJYWVoifQ.cGF5bG9hZA.////",
// Invalid payload
"eyJhbGciOiJYWVoifQ.////.c2lnbmF0dXJl",
// Invalid header
"////.eyJhbGciOiJYWVoifQ.c2lnbmF0dXJl",
// Invalid header
"cGF5bG9hZA.cGF5bG9hZA.c2lnbmF0dXJl",
}
for i := range failures {
_, err = ParseSigned(failures[i])
if err == nil {
t.Error("Able to parse invalid message")
}
}
}
func TestFullParseJWS(t *testing.T) {
// Messages that should succeed to parse
successes := []string{
"{\"payload\":\"CUJD\",\"signatures\":[{\"protected\":\"e30\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"},{\"protected\":\"e30\",\"signature\":\"CUJD\"}]}",
}
for i := range successes {
_, err := ParseSigned(successes[i])
if err != nil {
t.Error("Unble to parse valid message", err, successes[i])
}
}
// Messages that should fail to parse
failures := []string{
// Empty
"{}",
// Invalid JSON
"{XX",
// Invalid protected header
"{\"payload\":\"CUJD\",\"signatures\":[{\"protected\":\"CUJD\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"}]}",
// Invalid protected header
"{\"payload\":\"CUJD\",\"protected\":\"CUJD\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"}",
// Invalid protected header
"{\"payload\":\"CUJD\",\"signatures\":[{\"protected\":\"###\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"}]}",
// Invalid payload
"{\"payload\":\"###\",\"signatures\":[{\"protected\":\"CUJD\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"CUJD\"}]}",
// Invalid payload
"{\"payload\":\"CUJD\",\"signatures\":[{\"protected\":\"e30\",\"header\":{\"kid\":\"XYZ\"},\"signature\":\"###\"}]}",
}
for i := range failures {
_, err := ParseSigned(failures[i])
if err == nil {
t.Error("Able to parse invalid message", err, failures[i])
}
}
}
func TestRejectUnprotectedJWSNonce(t *testing.T) {
// No need to test compact, since that's always protected
// Flattened JSON
input := `{
"header": { "nonce": "should-cause-an-error" },
"payload": "does-not-matter",
"signature": "does-not-matter"
}`
_, err := ParseSigned(input)
if err == nil {
t.Error("JWS with an unprotected nonce parsed as valid.")
} else if err != ErrUnprotectedNonce {
t.Errorf("Improper error for unprotected nonce: %v", err)
}
// Full JSON
input = `{
"payload": "does-not-matter",
"signatures": [{
"header": { "nonce": "should-cause-an-error" },
"signature": "does-not-matter"
}]
}`
_, err = ParseSigned(input)
if err == nil {
t.Error("JWS with an unprotected nonce parsed as valid.")
} else if err != ErrUnprotectedNonce {
t.Errorf("Improper error for unprotected nonce: %v", err)
}
}
func TestVerifyFlattenedWithIncludedUnprotectedKey(t *testing.T) {
input := `{
"header": {
"alg": "RS256",
"jwk": {
"e": "AQAB",
"kty": "RSA",
"n": "tSwgy3ORGvc7YJI9B2qqkelZRUC6F1S5NwXFvM4w5-M0TsxbFsH5UH6adigV0jzsDJ5imAechcSoOhAh9POceCbPN1sTNwLpNbOLiQQ7RD5mY_pSUHWXNmS9R4NZ3t2fQAzPeW7jOfF0LKuJRGkekx6tXP1uSnNibgpJULNc4208dgBaCHo3mvaE2HV2GmVl1yxwWX5QZZkGQGjNDZYnjFfa2DKVvFs0QbAk21ROm594kAxlRlMMrvqlf24Eq4ERO0ptzpZgm_3j_e4hGRD39gJS7kAzK-j2cacFQ5Qi2Y6wZI2p-FCq_wiYsfEAIkATPBiLKl_6d_Jfcvs_impcXQ"
}
},
"payload": "Zm9vCg",
"signature": "hRt2eYqBd_MyMRNIh8PEIACoFtmBi7BHTLBaAhpSU6zyDAFdEBaX7us4VB9Vo1afOL03Q8iuoRA0AT4akdV_mQTAQ_jhTcVOAeXPr0tB8b8Q11UPQ0tXJYmU4spAW2SapJIvO50ntUaqU05kZd0qw8-noH1Lja-aNnU-tQII4iYVvlTiRJ5g8_CADsvJqOk6FcHuo2mG643TRnhkAxUtazvHyIHeXMxydMMSrpwUwzMtln4ZJYBNx4QGEq6OhpAD_VSp-w8Lq5HOwGQoNs0bPxH1SGrArt67LFQBfjlVr94E1sn26p4vigXm83nJdNhWAMHHE9iV67xN-r29LT-FjA"
}`
jws, err := ParseSigned(input)
if err != nil {
t.Error("Unable to parse valid message.")
}
if len(jws.Signatures) != 1 {
t.Error("Too many or too few signatures.")
}
sig := jws.Signatures[0]
if sig.Header.JSONWebKey == nil {
t.Error("No JWK in signature header.")
}
payload, err := jws.Verify(sig.Header.JSONWebKey)
if err != nil {
t.Errorf("Signature did not validate: %v", err)
}
if string(payload) != "foo\n" {
t.Errorf("Payload was incorrect: '%s' should have been 'foo\\n'", string(payload))
}
}
// Test verification of a detached signature
func TestDetachedVerifyJWS(t *testing.T) {
rsaPublicKey, err := x509.ParsePKIXPublicKey(fromBase64Bytes(`
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3aLSGwbeX0ZA2Ha+EvELaIFGzO
91+Q15JQc/tdGdCgGW3XAbrh7ZUhDh1XKzbs+UOQxqn3Eq4YOx18IG0WsJSuCaHQIxnDlZ
t/GP8WLwjMC0izlJLm2SyfM/EEoNpmTC3w6MQ2dHK7SZ9Zoq+sKijQd+V7CYdr8zHMpDrd
NKoEcR0HjmvzzdMoUChhkGH5TaNbZyollULTggepaYUKS8QphqdSDMWiSetKG+g6V87lv6
CVYyK1FF6g7Esp5OOj5pNn3/bmF+7V+b7TvK91NCIlURCjE9toRgNoIP4TDnWRn/vvfZ3G
zNrtWmlizqz3r5KdvIs71ahWgMUSD4wfazrwIDAQAB`))
if err != nil {
t.Fatal(err)
}
sampleMessages := []string{
"eyJhbGciOiJSUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.YHX849fvekz6wJGeyqnQhFqyHFcUXNJKj3o2w3ddR46YLlsCopUJrlifRU_ZuTWzpYxt5oC--T2eoqMhlCvltSWrE5_1_EumqiMfAYsZULx9E6Jns7q3w7mttonYFSIh7aR3-yg2HMMfTCgoAY1y_AZ4VjXwHDcZ5gu1oZDYgvZF4uXtCmwT6e5YtR1m8abiWPF8BgoTG_BD3KV6ClLj_QQiNFdfdxAMDw7vKVOKG1T7BFtz6cDs2Q3ILS4To5E2IjcVSSYS8mi77EitCrWmrqbK_G3WCdKeUFGnMnyuKXaCDy_7FLpAZ6Z5RomRr5iskXeJZdZqIKcJV8zl4fpsPA",
"eyJhbGciOiJSUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.meyfoOTjAAjXHFYiNlU7EEnsYtbeUYeEglK6BL_cxISEr2YAGLr1Gwnn2HnucTnH6YilyRio7ZC1ohy_ZojzmaljPHqpr8kn1iqNFu9nFE2M16ZPgJi38-PGzppcDNliyzOQO-c7L-eA-v8Gfww5uyRaOJdiWg-hUJmeGBIngPIeLtSVmhJtz8oTeqeNdUOqQv7f7VRCuvagLhW1PcEM91VUS-gS0WEUXoXWZ2lp91No0v1O24izgX3__FKiX_16XhrOfAgJ82F61vjbTIQYwhexHPZyYTlXYt_scNRzFGhSKeGFin4zVdFLOXWJqKWdUd5IrDP5Nya3FSoWbWDXAg",
}
for _, msg := range sampleMessages {
obj, err := ParseSigned(msg)
if err != nil {
t.Error("unable to parse message", msg, err)
continue
}
payload := obj.payload
obj.payload = nil
err = obj.DetachedVerify(payload, rsaPublicKey)
if err != nil {
t.Error("unable to verify message", msg, err)
continue
}
idx, _, err := obj.DetachedVerifyMulti(payload, rsaPublicKey)
if idx != 0 || err != nil {
t.Error("unable to verify message", msg, err)
continue
}
}
}
func TestVerifyFlattenedWithPrivateProtected(t *testing.T) {
// The protected field contains a Private Header Parameter name, per
// https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-4
// Base64-decoded, it's '{"nonce":"8HIepUNFZUa-exKTrXVf4g"}'
input := `{"header":{"alg":"RS256","jwk":{"kty":"RSA","n":"7ixeydcbxxppzxrBphrW1atUiEZqTpiHDpI-79olav5XxAgWolHmVsJyxzoZXRxmtED8PF9-EICZWBGdSAL9ZTD0hLUCIsPcpdgT_LqNW3Sh2b2caPL2hbMF7vsXvnCGg9varpnHWuYTyRrCLUF9vM7ES-V3VCYTa7LcCSRm56Gg9r19qar43Z9kIKBBxpgt723v2cC4bmLmoAX2s217ou3uCpCXGLOeV_BesG4--Nl3pso1VhCfO85wEWjmW6lbv7Kg4d7Jdkv5DjDZfJ086fkEAYZVYGRpIgAvJBH3d3yKDCrSByUEud1bWuFjQBmMaeYOrVDXO_mbYg5PwUDMhw","e":"AQAB"}},"protected":"eyJub25jZSI6IjhISWVwVU5GWlVhLWV4S1RyWFZmNGcifQ","payload":"eyJjb250YWN0IjpbIm1haWx0bzpmb29AYmFyLmNvbSJdfQ","signature":"AyvVGMgXsQ1zTdXrZxE_gyO63pQgotL1KbI7gv6Wi8I7NRy0iAOkDAkWcTQT9pcCYApJ04lXfEDZfP5i0XgcFUm_6spxi5mFBZU-NemKcvK9dUiAbXvb4hB3GnaZtZiuVnMQUb_ku4DOaFFKbteA6gOYCnED_x7v0kAPHIYrQnvIa-KZ6pTajbV9348zgh9TL7NgGIIsTcMHd-Jatr4z1LQ0ubGa8tS300hoDhVzfoDQaEetYjCo1drR1RmdEN1SIzXdHOHfubjA3ZZRbrF_AJnNKpRRoIwzu1VayOhRmdy1qVSQZq_tENF4VrQFycEL7DhG7JLoXC4T2p1urwMlsw"}`
jws, err := ParseSigned(input)
if err != nil {
t.Error("Unable to parse valid message.")
}
if len(jws.Signatures) != 1 {
t.Error("Too many or too few signatures.")
}
sig := jws.Signatures[0]
if sig.Header.JSONWebKey == nil {
t.Error("No JWK in signature header.")
}
payload, err := jws.Verify(sig.Header.JSONWebKey)
if err != nil {
t.Errorf("Signature did not validate: %v", err)
}
expected := "{\"contact\":[\"mailto:foo@bar.com\"]}"
if string(payload) != expected {
t.Errorf("Payload was incorrect: '%s' should have been '%s'", string(payload), expected)
}
}
// Test vectors generated with nimbus-jose-jwt
func TestSampleNimbusJWSMessagesRSA(t *testing.T) {
rsaPublicKey, err := x509.ParsePKIXPublicKey(fromBase64Bytes(`
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3aLSGwbeX0ZA2Ha+EvELaIFGzO
91+Q15JQc/tdGdCgGW3XAbrh7ZUhDh1XKzbs+UOQxqn3Eq4YOx18IG0WsJSuCaHQIxnDlZ
t/GP8WLwjMC0izlJLm2SyfM/EEoNpmTC3w6MQ2dHK7SZ9Zoq+sKijQd+V7CYdr8zHMpDrd
NKoEcR0HjmvzzdMoUChhkGH5TaNbZyollULTggepaYUKS8QphqdSDMWiSetKG+g6V87lv6
CVYyK1FF6g7Esp5OOj5pNn3/bmF+7V+b7TvK91NCIlURCjE9toRgNoIP4TDnWRn/vvfZ3G
zNrtWmlizqz3r5KdvIs71ahWgMUSD4wfazrwIDAQAB`))
if err != nil {
panic(err)
}
rsaSampleMessages := []string{
"eyJhbGciOiJSUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.YHX849fvekz6wJGeyqnQhFqyHFcUXNJKj3o2w3ddR46YLlsCopUJrlifRU_ZuTWzpYxt5oC--T2eoqMhlCvltSWrE5_1_EumqiMfAYsZULx9E6Jns7q3w7mttonYFSIh7aR3-yg2HMMfTCgoAY1y_AZ4VjXwHDcZ5gu1oZDYgvZF4uXtCmwT6e5YtR1m8abiWPF8BgoTG_BD3KV6ClLj_QQiNFdfdxAMDw7vKVOKG1T7BFtz6cDs2Q3ILS4To5E2IjcVSSYS8mi77EitCrWmrqbK_G3WCdKeUFGnMnyuKXaCDy_7FLpAZ6Z5RomRr5iskXeJZdZqIKcJV8zl4fpsPA",
"eyJhbGciOiJSUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.meyfoOTjAAjXHFYiNlU7EEnsYtbeUYeEglK6BL_cxISEr2YAGLr1Gwnn2HnucTnH6YilyRio7ZC1ohy_ZojzmaljPHqpr8kn1iqNFu9nFE2M16ZPgJi38-PGzppcDNliyzOQO-c7L-eA-v8Gfww5uyRaOJdiWg-hUJmeGBIngPIeLtSVmhJtz8oTeqeNdUOqQv7f7VRCuvagLhW1PcEM91VUS-gS0WEUXoXWZ2lp91No0v1O24izgX3__FKiX_16XhrOfAgJ82F61vjbTIQYwhexHPZyYTlXYt_scNRzFGhSKeGFin4zVdFLOXWJqKWdUd5IrDP5Nya3FSoWbWDXAg",
"eyJhbGciOiJSUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.rQPz0PDh8KyE2AX6JorgI0MLwv-qi1tcWlz6tuZuWQG1hdrlzq5tR1tQg1evYNc_SDDX87DWTSKXT7JEqhKoFixLfZa13IJrOc7FB8r5ZLx7OwOBC4F--OWrvxMA9Y3MTJjPN3FemQePUo-na2vNUZv-YgkcbuOgbO3hTxwQ7j1JGuqy-YutXOFnccdXvntp3t8zYZ4Mg1It_IyL9pzgGqHIEmMV1pCFGHsDa-wStB4ffmdhrADdYZc0q_SvxUdobyC_XzZCz9ENzGIhgwYxyyrqg7kjqUGoKmCLmoSlUFW7goTk9IC5SXdUyLPuESxOWNfHoRClGav230GYjPFQFA",
"eyJhbGciOiJQUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.UTtxjsv_6x4CdlAmZfAW6Lun3byMjJbcwRp_OlPH2W4MZaZar7aql052mIB_ddK45O9VUz2aphYVRvKPZY8WHmvlTUU30bk0z_cDJRYB9eIJVMOiRCYj0oNkz1iEZqsP0YgngxwuUDv4Q4A6aJ0Bo5E_rZo3AnrVHMHUjPp_ZRRSBFs30tQma1qQ0ApK4Gxk0XYCYAcxIv99e78vldVRaGzjEZmQeAVZx4tGcqZP20vG1L84nlhSGnOuZ0FhR8UjRFLXuob6M7EqtMRoqPgRYw47EI3fYBdeSivAg98E5S8R7R1NJc7ef-l03RvfUSY0S3_zBq_4PlHK6A-2kHb__w",
"eyJhbGciOiJSUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.meyfoOTjAAjXHFYiNlU7EEnsYtbeUYeEglK6BL_cxISEr2YAGLr1Gwnn2HnucTnH6YilyRio7ZC1ohy_ZojzmaljPHqpr8kn1iqNFu9nFE2M16ZPgJi38-PGzppcDNliyzOQO-c7L-eA-v8Gfww5uyRaOJdiWg-hUJmeGBIngPIeLtSVmhJtz8oTeqeNdUOqQv7f7VRCuvagLhW1PcEM91VUS-gS0WEUXoXWZ2lp91No0v1O24izgX3__FKiX_16XhrOfAgJ82F61vjbTIQYwhexHPZyYTlXYt_scNRzFGhSKeGFin4zVdFLOXWJqKWdUd5IrDP5Nya3FSoWbWDXAg",
"eyJhbGciOiJSUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.rQPz0PDh8KyE2AX6JorgI0MLwv-qi1tcWlz6tuZuWQG1hdrlzq5tR1tQg1evYNc_SDDX87DWTSKXT7JEqhKoFixLfZa13IJrOc7FB8r5ZLx7OwOBC4F--OWrvxMA9Y3MTJjPN3FemQePUo-na2vNUZv-YgkcbuOgbO3hTxwQ7j1JGuqy-YutXOFnccdXvntp3t8zYZ4Mg1It_IyL9pzgGqHIEmMV1pCFGHsDa-wStB4ffmdhrADdYZc0q_SvxUdobyC_XzZCz9ENzGIhgwYxyyrqg7kjqUGoKmCLmoSlUFW7goTk9IC5SXdUyLPuESxOWNfHoRClGav230GYjPFQFA",
}
for _, msg := range rsaSampleMessages {
obj, err := ParseSigned(msg)
if err != nil {
t.Error("unable to parse message", msg, err)
continue
}
payload, err := obj.Verify(rsaPublicKey)
if err != nil {
t.Error("unable to verify message", msg, err)
continue
}
if string(payload) != "Lorem ipsum dolor sit amet" {
t.Error("payload is not what we expected for msg", msg)
}
}
}
// Test vectors generated with nimbus-jose-jwt
func TestSampleNimbusJWSMessagesEC(t *testing.T) {
ecPublicKeyP256, err := x509.ParsePKIXPublicKey(fromBase64Bytes("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIg62jq6FyL1otEj9Up7S35BUrwGF9TVrAzrrY1rHUKZqYIGEg67u/imjgadVcr7y9Q32I0gB8W8FHqbqt696rA=="))
if err != nil {
panic(err)
}
ecPublicKeyP384, err := x509.ParsePKIXPublicKey(fromBase64Bytes("MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEPXsVlqCtN2oTY+F+hFZm3M0ldYpb7IeeJM5wYmT0k1RaqzBFDhDMNnYK5Q5x+OyssZrAtHgYDFw02AVJhhng/eHRp7mqmL/vI3wbxJtrLKYldIbBA+9fYBQcKeibjlu5"))
if err != nil {
panic(err)
}
ecPublicKeyP521, err := x509.ParsePKIXPublicKey(fromBase64Bytes("MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAa2w3MMJ5FWD6tSf68G+Wy5jIhWXOD3IA7pE5IC/myQzo1lWcD8KS57SM6nm4POtPcxyLmDhL7FLuh8DKoIZyvtAAdK8+tOQP7XXRlT2bkvzIuazp05It3TAPu00YzTIpKfDlc19Y1lvf7etrbFqhShD92B+hHmhT4ddrdbPCBDW8hvU="))
if err != nil {
panic(err)
}
ecPublicKeys := []interface{}{ecPublicKeyP256, ecPublicKeyP384, ecPublicKeyP521}
ecSampleMessages := []string{
"eyJhbGciOiJFUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.MEWJVlvGRQyzMEGOYm4rwuiwxrX-6LjnlbaRDAuhwmnBm2Gtn7pRpGXRTMFZUXsSGDz2L1p-Hz1qn8j9bFIBtQ",
"eyJhbGciOiJFUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.nbdjPnJPYQtVNNdBIx8-KbFKplTxrz-hnW5UNhYUY7SBkwHK4NZnqc2Lv4DXoA0aWHq9eiypgOh1kmyPWGEmqKAHUx0xdIEkBoHk3ZsbmhOQuq2jL_wcMUG6nTWNhLrB",
"eyJhbGciOiJFUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.AeYNFC1rwIgQv-5fwd8iRyYzvTaSCYTEICepgu9gRId-IW99kbSVY7yH0MvrQnqI-a0L8zwKWDR35fW5dukPAYRkADp3Y1lzqdShFcEFziUVGo46vqbiSajmKFrjBktJcCsfjKSaLHwxErF-T10YYPCQFHWb2nXJOOI3CZfACYqgO84g",
}
for i, msg := range ecSampleMessages {
obj, err := ParseSigned(msg)
if err != nil {
t.Error("unable to parse message", msg, err)
continue
}
payload, err := obj.Verify(ecPublicKeys[i])
if err != nil {
t.Error("unable to verify message", msg, err)
continue
}
if string(payload) != "Lorem ipsum dolor sit amet" {
t.Error("payload is not what we expected for msg", msg)
}
}
}
// Test vectors generated with nimbus-jose-jwt
func TestSampleNimbusJWSMessagesHMAC(t *testing.T) {
hmacTestKey := fromHexBytes("DF1FA4F36FFA7FC42C81D4B3C033928D")
hmacSampleMessages := []string{
"eyJhbGciOiJIUzI1NiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.W5tc_EUhxexcvLYEEOckyyvdb__M5DQIVpg6Nmk1XGM",
"eyJhbGciOiJIUzM4NCJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.sBu44lXOJa4Nd10oqOdYH2uz3lxlZ6o32QSGHaoGdPtYTDG5zvSja6N48CXKqdAh",
"eyJhbGciOiJIUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.M0yR4tmipsORIix-BitIbxEPGaxPchDfj8UNOpKuhDEfnb7URjGvCKn4nOlyQ1z9mG1FKbwnqR1hOVAWSzAU_w",
}
for _, msg := range hmacSampleMessages {
obj, err := ParseSigned(msg)
if err != nil {
t.Error("unable to parse message", msg, err)
continue
}
payload, err := obj.Verify(hmacTestKey)
if err != nil {
t.Error("unable to verify message", msg, err)
continue
}
if string(payload) != "Lorem ipsum dolor sit amet" {
t.Error("payload is not what we expected for msg", msg)
}
}
}
func TestHeaderFieldsCompact(t *testing.T) {
msg := "eyJhbGciOiJFUzUxMiJ9.TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ.AeYNFC1rwIgQv-5fwd8iRyYzvTaSCYTEICepgu9gRId-IW99kbSVY7yH0MvrQnqI-a0L8zwKWDR35fW5dukPAYRkADp3Y1lzqdShFcEFziUVGo46vqbiSajmKFrjBktJcCsfjKSaLHwxErF-T10YYPCQFHWb2nXJOOI3CZfACYqgO84g"
obj, err := ParseSigned(msg)
if err != nil {
t.Fatal("unable to parse message", msg, err)
}
if obj.Signatures[0].Header.Algorithm != "ES512" {
t.Error("merged header did not contain expected alg value")
}
if obj.Signatures[0].Protected.Algorithm != "ES512" {
t.Error("protected header did not contain expected alg value")
}
if obj.Signatures[0].Unprotected.Algorithm != "" {
t.Error("unprotected header contained an alg value")
}
}
func TestHeaderFieldsFull(t *testing.T) {
msg := `{"payload":"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQ","protected":"eyJhbGciOiJFUzUxMiJ9","header":{"custom":"test"},"signature":"AeYNFC1rwIgQv-5fwd8iRyYzvTaSCYTEICepgu9gRId-IW99kbSVY7yH0MvrQnqI-a0L8zwKWDR35fW5dukPAYRkADp3Y1lzqdShFcEFziUVGo46vqbiSajmKFrjBktJcCsfjKSaLHwxErF-T10YYPCQFHWb2nXJOOI3CZfACYqgO84g"}`
obj, err := ParseSigned(msg)
if err != nil {
t.Fatal("unable to parse message", msg, err)
}
if obj.Signatures[0].Header.Algorithm != "ES512" {
t.Error("merged header did not contain expected alg value")
}
if obj.Signatures[0].Protected.Algorithm != "ES512" {
t.Error("protected header did not contain expected alg value")
}
if obj.Signatures[0].Unprotected.Algorithm != "" {
t.Error("unprotected header contained an alg value")
}
if obj.Signatures[0].Unprotected.ExtraHeaders["custom"] != "test" {
t.Error("unprotected header did not contain custom header value")
}
}
// Test vectors generated with nimbus-jose-jwt
func TestErrorMissingPayloadJWS(t *testing.T) {
_, err := (&rawJSONWebSignature{}).sanitized()
if err == nil {
t.Error("was able to parse message with missing payload")
}
if !strings.Contains(err.Error(), "missing payload") {
t.Errorf("unexpected error message, should contain 'missing payload': %s", err)
}
}
// Test that a null value in the header doesn't panic
func TestNullHeaderValue(t *testing.T) {
msg := `{
"payload":
"eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGF
tcGxlLmNvbS9pc19yb290Ijp0cnVlfQ",
"protected":"eyJhbGciOiJFUzI1NiIsIm5vbmNlIjpudWxsfQ",
"header":
{"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"},
"signature":
"DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8IS
lSApmWQxfKTUJqPP3-Kg6NU1Q"
}`
defer func() {
if r := recover(); r != nil {
t.Errorf("ParseSigned panic'd when parsing a message with a null protected header value")
}
}()
ParseSigned(msg)
}
// Test for bug:
// https://github.com/square/go-jose/issues/157
func TestEmbedJWKBug(t *testing.T) {
signerKey := SigningKey{
Key: &JSONWebKey{
Key: rsaTestKey,
KeyID: "rsa-test-key",
},
Algorithm: RS256,
}
signer, err := NewSigner(signerKey, &SignerOptions{EmbedJWK: true})
if err != nil {
t.Fatal(err)
}
signerNoEmbed, err := NewSigner(signerKey, &SignerOptions{EmbedJWK: false})
if err != nil {
t.Fatal(err)
}
jws, err := signer.Sign([]byte("Lorem ipsum dolor sit amet"))
if err != nil {
t.Fatal(err)
}
jwsNoEmbed, err := signerNoEmbed.Sign([]byte("Lorem ipsum dolor sit amet"))
if err != nil {
t.Fatal(err)
}
// This used to panic with:
// json: error calling MarshalJSON for type *jose.JSONWebKey: square/go-jose: unknown key type '%!s(<nil>)'
output := jws.FullSerialize()
outputNoEmbed := jwsNoEmbed.FullSerialize()
// Expected output with embed set to true is a JWS with the public JWK embedded, with kid header empty.
// Expected output with embed set to false is that we set the kid header for key identification instead.
parsed, err := ParseSigned(output)
if err != nil {
t.Fatal(err)
}
parsedNoEmbed, err := ParseSigned(outputNoEmbed)
if err != nil {
t.Fatal(err)
}
if parsed.Signatures[0].Header.KeyID != "" {
t.Error("expected kid field in protected header to be empty")
}
if parsed.Signatures[0].Header.JSONWebKey.KeyID != "rsa-test-key" {
t.Error("expected rsa-test-key to be kid in embedded JWK in protected header")
}
if parsedNoEmbed.Signatures[0].Header.KeyID != "rsa-test-key" {
t.Error("expected kid field in protected header to be rsa-test-key")
}
if parsedNoEmbed.Signatures[0].Header.JSONWebKey != nil {
t.Error("expected no embedded JWK to be present")
}
}
func TestJWSWithCertificateChain(t *testing.T) {
signerKey := SigningKey{
Key: rsaTestKey,
Algorithm: RS256,
}
certs := []string{
// CN=TrustedSigner, signed by IntermediateCA
"MIIDLDCCAhSgAwIBAgIQNsV1i7m3kXGugqOQuuC7FzANBgkqhkiG9w0BAQsFADAZMRcwFQYDVQQDEw5JbnRlcm1lZGlhdGVDQTAeFw0xODAzMjgxODQzNDlaFw0zODAzMjgxODQzMDJaMBgxFjAUBgNVBAMTDVRydXN0ZWRTaWduZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLpvmOEDRxzQJUKHLkLQSsFDo9eGnolSERa6fz1E1F4wmk6nieHqssPd28C6Vb1sHJFne/j93DXNrx7W9Gy9fQvWa+VNHfGuYAodaS2pyV4VUPWMXI2a+qjxW85orq34XtcHzU+qm+ekR5W06ypW+xewbXJW//P9ulrsv3bDoDFaiggHY/u3p5CRSB9mg+Pbpf6E/k/N85sFJUsRE9hzgwg27Kqhh6p3hP3QnA+0WZRcWhwG0gykoD6layRLCPVcxlTSUdpyStDiK8w2whLJQfixCBGLS3/tB/GKb726bxTQK72OLzIMtOo4ZMtTva7bcA2PRgwfRz7bJg4DXz7oHTAgMBAAGjcTBvMA4GA1UdDwEB/wQEAwIDuDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFCpZEyJGAyK//NsYSSC4xkOqNnh3MB8GA1UdIwQYMBaAFMAYlq86RZzTWxLpYE7KTTM7DHOuMA0GCSqGSIb3DQEBCwUAA4IBAQBSIln6jPFkctPC17le0O+wkCStFOuqUM9cjwPuj4xBQ47RxmC0Pjv52N3TuVH7slmMykITQO/vVqQZguf+N5u4BCh223qWiu1muYBTfBPXCPgJjJ79bUL/dy9QEocOfPiIqTFC6xHKeSUCu6qi5jCPFynOaoVvlNPZEb2MR+QrkKVzg09aDEfk6J+wE6eH9+kNOtwvd/z2a2t2hterURtJEnYt7AQGviEpUf1gbHxCE9f3FW5iJGdgcshrk5ZwUfxvND2x4qFq2fYQRxNBnkO+TSYzwYoAItcGAUvlZFH+rdsq3N+UpRptXRkj5iMq59VlcXFOT675EkkNREgromWn",
// CN=IntermediateCA, signed by TrustedCA
"MIIEHTCCAgWgAwIBAgIQXzZsEQv0cvSRLJAkS9FmWTANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwlUcnVzdGVkQ0EwHhcNMTgwMzI4MTg0MzMzWhcNMzgwMzI4MTg0MzAzWjAZMRcwFQYDVQQDEw5JbnRlcm1lZGlhdGVDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN3aYpH/1yEYf/kHuHWyO3AO4tgwlYYLhCDT2GvaPdaEcqhe/VuYiqx3xY7IRDqsW2rau/OXgW6KzLHdRZHogK07hUj1Lfr7X+Oqbp22IV4ydyiL7jwK9AtVXvDuuv5ET+oRfV82j0uhyk0ueGD9r6C/h+6NTzHBD+3xo6Yuc0VkBfY5zIyhaFqlm1aRYvupDRjC/63uBgAlrGxy2LyiTMVnYMuxoJM5ahDepz3sqjuNWVyPhfGwIezjXuXRdEvlmWX05XLnsTdP4zu4fHq9Z7c3TKWWONM3z64ECAZmGQVfMAcEDX7qP0gZX5PCT+0WcvTgTWE4Q+WIh5AmYyxQ04cCAwEAAaNmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFMAYlq86RZzTWxLpYE7KTTM7DHOuMB8GA1UdIwQYMBaAFMvTapNJg0cAubXJjcUNWFjuTAIYMA0GCSqGSIb3DQEBCwUAA4ICAQBmYRpQoWEm5g16kwUrpwWrH7OIqqMtUhM1dcskECfki3/hcsV+MQRkGHLIItucYIWqs7oOQIglsyGcohAbnvE1PVtKKojUHC0lfbjgIenDPbvz15QB6A3KLDR82QbQGeGniACy924p66zlfPwHJbkMo5ZaqtNqI//EIa2YCpyyokhFXaSFmPWXXrTOCsEEsFJKsoSCH1KUpTcwACGkkilNseg1edZB6/lBDwybxVuY+dbUlHip3r5tFcP66Co3tKAaEcVY0AsZ/8GKwH+IM2AR6q7jdn9Gp2OX4E1ul9Wy+hW5GHMmfixkgTVwRowuKgkCPEKV2/Xy3k9rlSpnKr2NpYYq0mu6An9HYt8THQ+ewGZHwWufuDFDWuzlu7CxFOjpXLKv8qqVnwSFC91S3HsPAzPKLC9ZMEC+iQs2VkesOs0nFLZeMaMGAO5W6xiyQ5p94oo0bqa1XbmSV1bNp1HWuNEGIiZKrEUDxfYuDc6fC6hJZKsjJkMkBeadlQAlLcjIx1rDV171CKLLTxy/dT5kv4p9UrJlnleyMVG6S/3d6nX/WLSgZIMYbOwiZVVPlSrobuG38ULJMCSuxndxD0l+HahJaH8vYXuR67A0XT+bTEe305AI6A/9MEaRrActBnq6/OviQgBsKAvtTv1FmDbnpZsKeoFuwc3OPdTveQdCRA==",
}
testCases := []struct {
// Cert chain to embed in message
chain []string
// Intermediates & root certificate to verify against
intermediates []string
root string
// Should this test case verify?
success bool
}{
{certs, nil, trustedCA, true},
{certs, []string{intermediateCA}, trustedCA, true},
{certs[0:1], nil, intermediateCA, true},
{certs[0:1], nil, trustedCA, false},
{[]string{}, nil, trustedCA, false},
}
for i, testCase := range testCases {
signer, err := NewSigner(signerKey, &SignerOptions{
ExtraHeaders: map[HeaderKey]interface{}{HeaderKey("x5c"): testCase.chain},
})
if err != nil {
t.Fatal(err)
}
signed, err := signer.Sign([]byte("Lorem ipsum dolor sit amet"))
if err != nil {
t.Fatal(err)
}
parsed, err := ParseSigned(signed.FullSerialize())
if err != nil {
t.Fatal(err)
}
opts := x509.VerifyOptions{
DNSName: "TrustedSigner",
Roots: x509.NewCertPool(),
}
ok := opts.Roots.AppendCertsFromPEM([]byte(testCase.root))
if !ok {
t.Fatal("failed to parse trusted root certificate")
}
if len(testCase.intermediates) > 0 {
opts.Intermediates = x509.NewCertPool()
for _, intermediate := range testCase.intermediates {
ok := opts.Intermediates.AppendCertsFromPEM([]byte(intermediate))
if !ok {
t.Fatal("failed to parse trusted root certificate")
}
}
}
chains, err := parsed.Signatures[0].Protected.Certificates(opts)
if testCase.success && (len(chains) == 0 || err != nil) {
t.Fatalf("failed to verify certificate chain for test case %d: %s", i, err)
}
if !testCase.success && (len(chains) != 0 && err == nil) {
t.Fatalf("incorrectly verified certificate chain for test case %d (should fail)", i)
}
}
}

View file

@ -1,507 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 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 jwt
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/hex"
"encoding/pem"
"errors"
"fmt"
"io"
"reflect"
"sort"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/json"
)
type testClaims struct {
Subject string `json:"sub"`
}
type invalidMarshalClaims struct {
}
var errInvalidMarshalClaims = errors.New("Failed marshaling invalid claims.")
func (c invalidMarshalClaims) MarshalJSON() ([]byte, error) {
return nil, errInvalidMarshalClaims
}
var sampleClaims = Claims{
Subject: "42",
IssuedAt: NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
Issuer: "issuer",
Audience: Audience{"a1", "a2"},
}
type numberClaims struct {
Int int64 `json:"int"`
Float float64 `json:"float"`
}
func TestIntegerAndFloatsNormalize(t *testing.T) {
c := numberClaims{1 << 60, 12345.6789}
normalized, err := normalize(c)
if err != nil {
t.Fatal(err)
}
ni, err := (normalized["int"].(json.Number)).Int64()
nf, err := (normalized["float"].(json.Number)).Float64()
if ni != c.Int {
t.Error(fmt.Sprintf("normalize failed to preserve int64 (got %v, wanted %v, type %s)", normalized["int"], c.Int, reflect.TypeOf(normalized["int"])))
}
if nf != c.Float {
t.Error(fmt.Sprintf("normalize failed to preserve float64 (got %v, wanted %v, type %s)", normalized["float"], c.Float, reflect.TypeOf(normalized["float"])))
}
}
func TestBuilderCustomClaimsNonPointer(t *testing.T) {
jwt, err := Signed(rsaSigner).Claims(testClaims{"foo"}).CompactSerialize()
require.NoError(t, err, "Error creating JWT.")
parsed, err := ParseSigned(jwt)
require.NoError(t, err, "Error parsing JWT.")
out := &testClaims{}
if assert.NoError(t, parsed.Claims(&testPrivRSAKey1.PublicKey, out), "Error unmarshaling claims.") {
assert.Equal(t, "foo", out.Subject)
}
}
func TestBuilderCustomClaimsPointer(t *testing.T) {
jwt, err := Signed(rsaSigner).Claims(&testClaims{"foo"}).CompactSerialize()
require.NoError(t, err, "Error creating JWT.")
parsed, err := ParseSigned(jwt)
require.NoError(t, err, "Error parsing JWT.")
out := &testClaims{}
if assert.NoError(t, parsed.Claims(&testPrivRSAKey1.PublicKey, out), "Error unmarshaling claims.") {
assert.Equal(t, "foo", out.Subject)
}
}
func TestBuilderMergeClaims(t *testing.T) {
jwt, err := Signed(rsaSigner).
Claims(&Claims{
Subject: "42",
}).
Claims(map[string]interface{}{
"Scopes": []string{"read:users"},
}).
CompactSerialize()
require.NoError(t, err, "Error creating JWT.")
parsed, err := ParseSigned(jwt)
require.NoError(t, err, "Error parsing JWT.")
out := make(map[string]interface{})
if assert.NoError(t, parsed.Claims(&testPrivRSAKey1.PublicKey, &out), "Error unmarshaling claims.") {
assert.Equal(t, map[string]interface{}{
"sub": "42",
"Scopes": []interface{}{"read:users"},
}, out)
}
_, err = Signed(rsaSigner).Claims("invalid-claims").Claims(&testClaims{"foo"}).CompactSerialize()
assert.Equal(t, err, ErrInvalidClaims)
_, err = Signed(rsaSigner).Claims(&invalidMarshalClaims{}).CompactSerialize()
assert.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
}
func TestSignedFullSerializeAndToken(t *testing.T) {
b := Signed(rsaSigner).Claims(&testClaims{"foo"})
jwt, err := b.FullSerialize()
require.NoError(t, err, "Error creating JWT.")
parsed, err := ParseSigned(jwt)
require.NoError(t, err, "Error parsing JWT.")
out := &testClaims{}
if assert.NoError(t, parsed.Claims(&testPrivRSAKey1.PublicKey, &out), "Error unmarshaling claims.") {
assert.Equal(t, &testClaims{
Subject: "foo",
}, out)
}
jwt2, err := b.Token()
require.NoError(t, err, "Error creating JWT.")
out2 := &testClaims{}
if assert.NoError(t, jwt2.Claims(&testPrivRSAKey1.PublicKey, &out2), "Error unmarshaling claims.") {
assert.Equal(t, &testClaims{
Subject: "foo",
}, out2)
}
b2 := Signed(rsaSigner).Claims(&invalidMarshalClaims{})
_, err = b2.FullSerialize()
require.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
_, err = b2.Token()
require.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
}
func TestEncryptedFullSerializeAndToken(t *testing.T) {
recipient := jose.Recipient{
Algorithm: jose.RSA1_5,
Key: testPrivRSAKey1.Public(),
}
encrypter, err := jose.NewEncrypter(jose.A128CBC_HS256, recipient, nil)
require.NoError(t, err, "Error creating encrypter.")
b := Encrypted(encrypter).Claims(&testClaims{"foo"})
jwt, err := b.FullSerialize()
require.NoError(t, err, "Error creating JWT.")
parsed, err := ParseEncrypted(jwt)
require.NoError(t, err, "Error parsing JWT.")
out := &testClaims{}
if assert.NoError(t, parsed.Claims(testPrivRSAKey1, &out)) {
assert.Equal(t, &testClaims{
Subject: "foo",
}, out)
}
jwt2, err := b.Token()
require.NoError(t, err, "Error creating JWT.")
out2 := &testClaims{}
if assert.NoError(t, jwt2.Claims(testPrivRSAKey1, &out2)) {
assert.Equal(t, &testClaims{
Subject: "foo",
}, out2)
}
b2 := Encrypted(encrypter).Claims(&invalidMarshalClaims{})
_, err = b2.FullSerialize()
require.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
_, err = b2.Token()
require.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
}
func TestBuilderSignedAndEncrypted(t *testing.T) {
recipient := jose.Recipient{
Algorithm: jose.RSA1_5,
Key: testPrivRSAKey1.Public(),
}
encrypter, err := jose.NewEncrypter(jose.A128CBC_HS256, recipient, (&jose.EncrypterOptions{}).WithContentType("JWT").WithType("JWT"))
require.NoError(t, err, "Error creating encrypter.")
jwt1, err := SignedAndEncrypted(rsaSigner, encrypter).Claims(&testClaims{"foo"}).Token()
require.NoError(t, err, "Error marshaling signed-then-encrypted token.")
if nested, err := jwt1.Decrypt(testPrivRSAKey1); assert.NoError(t, err, "Error decrypting signed-then-encrypted token.") {
out := &testClaims{}
assert.NoError(t, nested.Claims(&testPrivRSAKey1.PublicKey, out))
assert.Equal(t, &testClaims{"foo"}, out)
}
b := SignedAndEncrypted(rsaSigner, encrypter).Claims(&testClaims{"foo"})
tok1, err := b.CompactSerialize()
if assert.NoError(t, err) {
jwt, err := ParseSignedAndEncrypted(tok1)
if assert.NoError(t, err, "Error parsing signed-then-encrypted compact token.") {
if nested, err := jwt.Decrypt(testPrivRSAKey1); assert.NoError(t, err) {
out := &testClaims{}
assert.NoError(t, nested.Claims(&testPrivRSAKey1.PublicKey, out))
assert.Equal(t, &testClaims{"foo"}, out)
}
}
}
tok2, err := b.FullSerialize()
if assert.NoError(t, err) {
jwe, err := ParseSignedAndEncrypted(tok2)
if assert.NoError(t, err, "Error parsing signed-then-encrypted full token.") {
assert.Equal(t, []jose.Header{{
Algorithm: string(jose.RSA1_5),
ExtraHeaders: map[jose.HeaderKey]interface{}{
jose.HeaderType: "JWT",
jose.HeaderContentType: "JWT",
"enc": "A128CBC-HS256",
},
}}, jwe.Headers)
if jws, err := jwe.Decrypt(testPrivRSAKey1); assert.NoError(t, err) {
assert.Equal(t, []jose.Header{{
Algorithm: string(jose.RS256),
ExtraHeaders: map[jose.HeaderKey]interface{}{
jose.HeaderType: "JWT",
},
}}, jws.Headers)
out := &testClaims{}
assert.NoError(t, jws.Claims(&testPrivRSAKey1.PublicKey, out))
assert.Equal(t, &testClaims{"foo"}, out)
}
}
}
b2 := SignedAndEncrypted(rsaSigner, encrypter).Claims(&invalidMarshalClaims{})
_, err = b2.CompactSerialize()
assert.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
_, err = b2.FullSerialize()
assert.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
encrypter2, err := jose.NewEncrypter(jose.A128CBC_HS256, recipient, nil)
require.NoError(t, err, "Error creating encrypter.")
_, err = SignedAndEncrypted(rsaSigner, encrypter2).CompactSerialize()
assert.EqualError(t, err, "square/go-jose/jwt: expected content type to be JWT (cty header)")
}
func TestBuilderHeadersSigner(t *testing.T) {
tests := []struct {
Keys []*rsa.PrivateKey
Claims interface{}
}{
{
Keys: []*rsa.PrivateKey{testPrivRSAKey1},
Claims: &Claims{Issuer: "foo"},
},
{
Keys: []*rsa.PrivateKey{testPrivRSAKey1, testPrivRSAKey2},
Claims: &Claims{Issuer: "foo"},
},
}
for i, tc := range tests {
wantKeyIDs := make([]string, len(tc.Keys))
signingKeys := make([]jose.SigningKey, len(tc.Keys))
for j, key := range tc.Keys {
keyIDBytes := make([]byte, 20)
if _, err := io.ReadFull(rand.Reader, keyIDBytes); err != nil {
t.Fatalf("failed to read random bytes: %v", err)
}
keyID := hex.EncodeToString(keyIDBytes)
wantKeyIDs[j] = keyID
signingKeys[j] = jose.SigningKey{
Algorithm: jose.RS256,
Key: &jose.JSONWebKey{
KeyID: keyID,
Algorithm: "RSA",
Key: key,
},
}
}
signer, err := jose.NewMultiSigner(signingKeys, nil)
if err != nil {
t.Errorf("case %d: NewMultiSigner(): %v", i, err)
continue
}
var token string
if len(tc.Keys) == 1 {
token, err = Signed(signer).Claims(tc.Claims).CompactSerialize()
} else {
token, err = Signed(signer).Claims(tc.Claims).FullSerialize()
}
if err != nil {
t.Errorf("case %d: failed to create token: %v", i, err)
continue
}
jws, err := jose.ParseSigned(token)
if err != nil {
t.Errorf("case %d: parse signed: %v", i, err)
continue
}
gotKeyIDs := make([]string, len(jws.Signatures))
for i, sig := range jws.Signatures {
gotKeyIDs[i] = sig.Header.KeyID
}
sort.Strings(wantKeyIDs)
sort.Strings(gotKeyIDs)
if !reflect.DeepEqual(wantKeyIDs, gotKeyIDs) {
t.Errorf("case %d: wanted=%q got=%q", i, wantKeyIDs, gotKeyIDs)
}
}
}
func TestBuilderHeadersEncrypter(t *testing.T) {
key := testPrivRSAKey1
claims := &Claims{Issuer: "foo"}
keyIDBytes := make([]byte, 20)
if _, err := io.ReadFull(rand.Reader, keyIDBytes); err != nil {
t.Fatalf("failed to read random bytes: %v", err)
}
keyID := hex.EncodeToString(keyIDBytes)
wantKeyID := keyID
recipient := jose.Recipient{
Algorithm: jose.RSA1_5,
Key: key.Public(),
KeyID: keyID,
}
wantType := jose.ContentType("JWT")
encrypter, err := jose.NewEncrypter(jose.A128CBC_HS256, recipient, (&jose.EncrypterOptions{}).WithType(wantType))
require.NoError(t, err, "failed to create encrypter")
token, err := Encrypted(encrypter).Claims(claims).CompactSerialize()
require.NoError(t, err, "failed to create token")
jwe, err := jose.ParseEncrypted(token)
if assert.NoError(t, err, "error parsing encrypted token") {
assert.Equal(t, jose.Header{
ExtraHeaders: map[jose.HeaderKey]interface{}{
jose.HeaderType: string(wantType),
"enc": "A128CBC-HS256",
},
Algorithm: string(jose.RSA1_5),
KeyID: wantKeyID,
}, jwe.Header)
}
}
func BenchmarkMapClaims(b *testing.B) {
m := map[string]interface{}{
"sub": "42",
"iat": 1451606400,
"iss": "issuer",
"aud": []string{"a1", "a2"},
}
for i := 0; i < b.N; i++ {
Signed(rsaSigner).Claims(m)
}
}
func BenchmarkStructClaims(b *testing.B) {
for i := 0; i < b.N; i++ {
Signed(rsaSigner).Claims(sampleClaims)
}
}
func BenchmarkSignedCompactSerializeRSA(b *testing.B) {
tb := Signed(rsaSigner).Claims(sampleClaims)
b.ResetTimer()
for i := 0; i < b.N; i++ {
tb.CompactSerialize()
}
}
func BenchmarkSignedCompactSerializeSHA(b *testing.B) {
tb := Signed(hmacSigner).Claims(sampleClaims)
b.ResetTimer()
for i := 0; i < b.N; i++ {
tb.CompactSerialize()
}
}
func mustUnmarshalRSA(data string) *rsa.PrivateKey {
block, _ := pem.Decode([]byte(data))
if block == nil {
panic("failed to decode PEM data")
}
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
panic("failed to parse RSA key: " + err.Error())
}
if key, ok := key.(*rsa.PrivateKey); ok {
return key
}
panic("key is not of type *rsa.PrivateKey")
}
func mustMakeSigner(alg jose.SignatureAlgorithm, k interface{}) jose.Signer {
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: alg, Key: k}, (&jose.SignerOptions{}).WithType("JWT"))
if err != nil {
panic("failed to create signer:" + err.Error())
}
return sig
}
var (
sharedKey = []byte("secret")
sharedEncryptionKey = []byte("itsa16bytesecret")
testPrivRSAKey1 = mustUnmarshalRSA(`-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDIHBvDHAr7jh8h
xaqBCl11fjI9YZtdC5b3HtXTXZW3c2dIOImNUjffT8POP6p5OpzivmC1om7iOyuZ
3nJjC9LT3zqqs3f2i5d4mImxEuqG6uWdryFfkp0uIv5VkjVO+iQWd6pDAPGP7r1Z
foXCleyCtmyNH4JSkJneNPOk/4BxO8vcvRnCMT/Gv81IT6H+OQ6OovWOuJr8RX9t
1wuCjC9ezZxeI9ONffhiO5FMrVh5H9LJTl3dPOVa4aEcOvgd45hBmvxAyXqf8daE
6Kl2O7vQ4uwgnSTVXYIIjCjbepuersApIMGx/XPSgiU1K3Xtah/TBvep+S3VlwPc
q/QH25S9AgMBAAECggEAe+y8XKYfPw4SxY1uPB+5JSwT3ON3nbWxtjSIYy9Pqp5z
Vcx9kuFZ7JevQSk4X38m7VzM8282kC/ono+d8yy9Uayq3k/qeOqV0X9Vti1qxEbw
ECkG1/MqGApfy4qSLOjINInDDV+mOWa2KJgsKgdCwuhKbVMYGB2ozG2qfYIlfvlY
vLcBEpGWmswJHNmkcjTtGFIyJgPbsI6ndkkOeQbqQKAaadXtG1xUzH+vIvqaUl/l
AkNf+p4qhPkHsoAWXf1qu9cYa2T8T+mEo79AwlgVC6awXQWNRTiyClDJC7cu6NBy
ZHXCLFMbalzWF9qeI2OPaFX2x3IBWrbyDxcJ4TSdQQKBgQD/Fp/uQonMBh1h4Vi4
HlxZdqSOArTitXValdLFGVJ23MngTGV/St4WH6eRp4ICfPyldsfcv6MZpNwNm1Rn
lB5Gtpqpby1dsrOSfvVbY7U3vpLnd8+hJ/lT5zCYt5Eor46N6iWRkYWzNe4PixiF
z1puGUvFCbZdeeACVrPLmW3JKQKBgQDI0y9WTf8ezKPbtap4UEE6yBf49ftohVGz
p4iD6Ng1uqePwKahwoVXKOc179CjGGtW/UUBORAoKRmxdHajHq6LJgsBxpaARz21
COPy99BUyp9ER5P8vYn63lC7Cpd/K7uyMjaz1DAzYBZIeVZHIw8O9wuGNJKjRFy9
SZyD3V0ddQKBgFMdohrWH2QVEfnUnT3Q1rJn0BJdm2bLTWOosbZ7G72TD0xAWEnz
sQ1wXv88n0YER6X6YADziEdQykq8s/HT91F/KkHO8e83zP8M0xFmGaQCOoelKEgQ
aFMIX3NDTM7+9OoUwwz9Z50PE3SJFAJ1n7eEEoYvNfabQXxBl+/dHEKRAoGAPEvU
EaiXacrtg8EWrssB2sFLGU/ZrTciIbuybFCT4gXp22pvXXAHEvVP/kzDqsRhLhwb
BNP6OuSkNziNikpjA5pngZ/7fgZly54gusmW/m5bxWdsUl0iOXVYbeAvPlqGH2me
LP4Pfs1hw17S/cbT9Z1NE31jbavP4HFikeD73SUCgYEArQfuudml6ei7XZ1Emjq8
jZiD+fX6e6BD/ISatVnuyZmGj9wPFsEhY2BpLiAMQHMDIvH9nlKzsFvjkTPB86qG
jCh3D67Os8eSBk5uRC6iW3Fc4DXvB5EFS0W9/15Sl+V5vXAcrNMpYS82OTSMG2Gt
b9Ym/nxaqyTu0PxajXkKm5Q=
-----END PRIVATE KEY-----`)
testPrivRSAKey2 = mustUnmarshalRSA(`-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxJ09jkXZ5Okyq
FrEKrs+GTzZRvoLziyzDTIZLJC6BVryau4gaFjuBG+pnm4z53oDP0XVnjFsx1mBw
R6RHeXlXbxLXsMfJpMzU9I2SRen9DokpD187CAnjLOoN9QRl1h8CA+sqR5Jw9mdl
mdaBKC99M9QYAPK3vGNfPC4soo8LDSBiemmt5raL4WSfoYh/6qg5rHUTymY28uxV
ew3I9Yp+3ltIw+WlRDtW5l+MM5CSUofjj2zcgcG3LEuPtvyZ+CSObxxcZZugm9zc
JdiazNyUxtX8yAj3Xg8Hde0jt0QDXv7A+U0KMVi9lX6PJEaNj4tOhOmQhJVMzAyr
1W/bifZVAgMBAAECggEAduKnn21GMZLTUi4KP94SvNK55F/Sp7hVoPbhBNpSL1BT
IBAMBV24LyvZwhAcqq8MiOrLPGNv6+EvNQqPD7xQl0GeRouHeCYVpDA+NdSfc8jm
eVysjwQVBpTkudsdSW5JvuN8VRJVD2P8/a0gy+p4/C/k/Prd6DoQAiBz6FZrYoEd
iYgIegHOMXWd4vzO3ENOWSIUI6ci7Aro+Y0Z75kfiVokAGhUcFgrZ58E82fBYh8I
cxO20oMnucGrLicQzj536jx4wX3Cdd4jr9UVEJ9ZII1ldlp03nZlFLXqJH1547Aq
ZM+3vVcBGoJ8T9ZQ4VDAL++0K2DLC9JkTARAYCEi/QKBgQDebIc1+2zblhQtVQ/e
IbEErZcB7v+TkUoRoBfR0lj7bKBFJgRe37fgu1xf95/s63okdnOw/OuQqtGmgx/J
TL3yULBdNcwTCRm41t+cqoGymjK0VRbqk6CWBId0E3r5TaCVWedk2JI2XwTvIJ1A
eDiqfJeDHUD44yaonwbysj9ZDwKBgQDL5VQfTppVaJk2PXNwhAkRQklZ8RFmt/7p
yA3dddQNdwMk4Fl8F7QuO1gBxDiHdnwIrlEOz6fTsM3LwIS+Q12P1vYFIhpo7HDB
wvjfMwCPxBIS4jI28RgcAf0VbZ/+CHAm6bb9iDwsjXhh1J5oOm5VKnju6/rPH/QY
+md40pnSWwKBgBnKPbdNquafNUG4XjmkcHEZa6wGuU20CAGZLYnfuP+WLdM2wET7
7cc6ElDyVnHTL/twXKPF/85rcBm9lH7zzgZ9wqVcKoh+gqQDDjSNNLKv3Hc6cojK
i1E5vzb/Vz/290q5/PGdhv6U7+6GOpWSGwfxoGPMjY8OT5o3rkeP0XaTAoGBALLR
GQmr4eZtqZDMK+XNpjYgsDvVE7HGRCW7cY17vNFiQruglloiX778BJ7n+7uxye3D
EwuuSj15ncLHwKMsaW2w1GqEEi1azzjfSWxWSnPLPR6aifdtUfueMtsMHXio5dL6
vaV0SXG5UI5b7eDy/bhrW0wOYRQtreIKGZz49jZpAoGBAIvxYngkLwmq6g6MmnAc
YK4oT6YAm2wfSy2mzpEQP5r1igp1rN7T46o7FMUPDLS9wK3ESAaIYe01qT6Yftcc
5qF+yiOGDTr9XQiHwe4BcyrNEMfUjDhDU5ao2gH8+t1VGr1KspLsUNbedrJwZsY4
UCZVKEEDHzKfLO/iBgKjJQF7
-----END PRIVATE KEY-----`)
rsaSigner = mustMakeSigner(jose.RS256, testPrivRSAKey1)
hmacSigner = mustMakeSigner(jose.HS256, sharedKey)
)

View file

@ -1,80 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 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 jwt
import (
"testing"
"time"
"gopkg.in/square/go-jose.v2/json"
"github.com/stretchr/testify/assert"
)
func TestEncodeClaims(t *testing.T) {
now := time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)
c := Claims{
Issuer: "issuer",
Subject: "subject",
Audience: Audience{"a1", "a2"},
NotBefore: NewNumericDate(time.Time{}),
IssuedAt: NewNumericDate(now),
Expiry: NewNumericDate(now.Add(1 * time.Hour)),
}
b, err := json.Marshal(c)
assert.NoError(t, err)
expected := `{"iss":"issuer","sub":"subject","aud":["a1","a2"],"exp":1451610000,"iat":1451606400}`
assert.Equal(t, expected, string(b))
}
func TestDecodeClaims(t *testing.T) {
s := []byte(`{"iss":"issuer","sub":"subject","aud":["a1","a2"],"exp":1451610000,"iat":1451606400}`)
now := time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)
c := Claims{}
if err := json.Unmarshal(s, &c); assert.NoError(t, err) {
assert.Equal(t, "issuer", c.Issuer)
assert.Equal(t, "subject", c.Subject)
assert.Equal(t, Audience{"a1", "a2"}, c.Audience)
assert.True(t, now.Equal(c.IssuedAt.Time()))
assert.True(t, now.Add(1*time.Hour).Equal(c.Expiry.Time()))
}
s2 := []byte(`{"aud": "a1"}`)
c2 := Claims{}
if err := json.Unmarshal(s2, &c2); assert.NoError(t, err) {
assert.Equal(t, Audience{"a1"}, c2.Audience)
}
invalid := []struct {
Raw string
Err error
}{
{`{"aud": 5}`, ErrUnmarshalAudience},
{`{"aud": ["foo", 5, "bar"]}`, ErrUnmarshalAudience},
{`{"exp": "invalid"}`, ErrUnmarshalNumericDate},
}
for _, v := range invalid {
c := Claims{}
assert.Equal(t, v.Err, json.Unmarshal([]byte(v.Raw), &c))
}
}

View file

@ -1,340 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 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 jwt_test
import (
"fmt"
"strings"
"time"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
)
var sharedKey = []byte("secret")
var sharedEncryptionKey = []byte("itsa16bytesecret")
var signer, _ = jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: sharedKey}, &jose.SignerOptions{})
func ExampleParseSigned() {
raw := `eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzdWIiOiJzdWJqZWN0In0.gpHyA1B1H6X4a4Edm9wo7D3X2v3aLSDBDG2_5BzXYe0`
tok, err := jwt.ParseSigned(raw)
if err != nil {
panic(err)
}
out := jwt.Claims{}
if err := tok.Claims(sharedKey, &out); err != nil {
panic(err)
}
fmt.Printf("iss: %s, sub: %s\n", out.Issuer, out.Subject)
// Output: iss: issuer, sub: subject
}
func ExampleParseEncrypted() {
key := []byte("itsa16bytesecret")
raw := `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..jg45D9nmr6-8awml.z-zglLlEw9MVkYHi-Znd9bSwc-oRGbqKzf9WjXqZxno.kqji2DiZHZmh-1bLF6ARPw`
tok, err := jwt.ParseEncrypted(raw)
if err != nil {
panic(err)
}
out := jwt.Claims{}
if err := tok.Claims(key, &out); err != nil {
panic(err)
}
fmt.Printf("iss: %s, sub: %s\n", out.Issuer, out.Subject)
// Output: iss: issuer, sub: subject
}
func ExampleParseSignedAndEncrypted() {
raw := `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIiwiY3R5IjoiSldUIn0..-keV-9YpsxotBEHw.yC9SHWgnkjykgJqXZGlzYC5Wg_EdWKO5TgfqeqsWWJYw7fX9zXQE3NtXmA3nAiUrYOr3H2s0AgTeAhTNbELLEHQu0blfRaPa_uKOAgFgmhJwbGe2iFLn9J0U72wk56318nI-pTLCV8FijoGpXvAxQlaKrPLKkl9yDQimPhb7UiDwLWYkJeoayciAXhR5f40E8ORGjCz8oawXRvjDaSjgRElUwy4kMGzvJy_difemEh4lfMSIwUNVEqJkEYaalRttSymMYuV6NvBVU0N0Jb6omdM4tW961OySB4KPWCWH9UJUX0XSEcqbW9WLxpg3ftx5R7xNiCnaVaCx_gJZfXJ9yFLqztIrKh2N05zHM0tddSOwCOnq7_1rJtaVz0nTXjSjf1RrVaxJya59p3K-e41QutiGFiJGzXG-L2OyLETIaVSU3ptvaCz4IxCF3GzeCvOgaICvXkpBY1-bv-fk1ilyjmcTDnLp2KivWIxcnoQmpN9xj06ZjagdG09AHUhS5WixADAg8mIdGcanNblALecnCWG-otjM9Kw.RZoaHtSgnzOin2od3D9tnA`
tok, err := jwt.ParseSignedAndEncrypted(raw)
if err != nil {
panic(err)
}
nested, err := tok.Decrypt(sharedEncryptionKey)
if err != nil {
panic(err)
}
out := jwt.Claims{}
if err := nested.Claims(&rsaPrivKey.PublicKey, &out); err != nil {
panic(err)
}
fmt.Printf("iss: %s, sub: %s\n", out.Issuer, out.Subject)
// Output: iss: issuer, sub: subject
}
func ExampleClaims_Validate() {
cl := jwt.Claims{
Subject: "subject",
Issuer: "issuer",
NotBefore: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
Expiry: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 15, 0, 0, time.UTC)),
Audience: jwt.Audience{"leela", "fry"},
}
err := cl.Validate(jwt.Expected{
Issuer: "issuer",
Time: time.Date(2016, 1, 1, 0, 10, 0, 0, time.UTC),
})
if err != nil {
panic(err)
}
fmt.Printf("valid!")
// Output: valid!
}
func ExampleClaims_Validate_withParse() {
raw := `eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzdWIiOiJzdWJqZWN0In0.gpHyA1B1H6X4a4Edm9wo7D3X2v3aLSDBDG2_5BzXYe0`
tok, err := jwt.ParseSigned(raw)
if err != nil {
panic(err)
}
cl := jwt.Claims{}
if err := tok.Claims(sharedKey, &cl); err != nil {
panic(err)
}
err = cl.Validate(jwt.Expected{
Issuer: "issuer",
Subject: "subject",
})
if err != nil {
panic(err)
}
fmt.Printf("valid!")
// Output: valid!
}
func ExampleSigned() {
key := []byte("secret")
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: key}, (&jose.SignerOptions{}).WithType("JWT"))
if err != nil {
panic(err)
}
cl := jwt.Claims{
Subject: "subject",
Issuer: "issuer",
NotBefore: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
Audience: jwt.Audience{"leela", "fry"},
}
raw, err := jwt.Signed(sig).Claims(cl).CompactSerialize()
if err != nil {
panic(err)
}
fmt.Println(raw)
// Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsibGVlbGEiLCJmcnkiXSwiaXNzIjoiaXNzdWVyIiwibmJmIjoxNDUxNjA2NDAwLCJzdWIiOiJzdWJqZWN0In0.4PgCj0VO-uG_cb1mNA38NjJyp0N-NdGIDLoYelEkciw
}
func ExampleSigned_privateClaims() {
key := []byte("secret")
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: key}, (&jose.SignerOptions{}).WithType("JWT"))
if err != nil {
panic(err)
}
cl := jwt.Claims{
Subject: "subject",
Issuer: "issuer",
NotBefore: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
Audience: jwt.Audience{"leela", "fry"},
}
// When setting private claims, make sure to add struct tags
// to specify how to serialize the field. The naming behavior
// should match the encoding/json package otherwise.
privateCl := struct {
CustomClaim string `json:"custom"`
}{
"custom claim value",
}
raw, err := jwt.Signed(sig).Claims(cl).Claims(privateCl).CompactSerialize()
if err != nil {
panic(err)
}
fmt.Println(raw)
// Ouput: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsibGVlbGEiLCJmcnkiXSwiY3VzdG9tIjoiY3VzdG9tIGNsYWltIHZhbHVlIiwiaXNzIjoiaXNzdWVyIiwibmJmIjoxNDUxNjA2NDAwLCJzdWIiOiJzdWJqZWN0In0.knXH3ReNJToS5XI7BMCkk80ugpCup3tOy53xq-ga47o
}
func ExampleEncrypted() {
enc, err := jose.NewEncrypter(
jose.A128GCM,
jose.Recipient{Algorithm: jose.DIRECT, Key: sharedEncryptionKey},
(&jose.EncrypterOptions{}).WithType("JWT"),
)
if err != nil {
panic(err)
}
cl := jwt.Claims{
Subject: "subject",
Issuer: "issuer",
}
raw, err := jwt.Encrypted(enc).Claims(cl).CompactSerialize()
if err != nil {
panic(err)
}
fmt.Println(raw)
}
func ExampleSignedAndEncrypted() {
enc, err := jose.NewEncrypter(
jose.A128GCM,
jose.Recipient{
Algorithm: jose.DIRECT,
Key: sharedEncryptionKey,
},
(&jose.EncrypterOptions{}).WithType("JWT").WithContentType("JWT"))
if err != nil {
panic(err)
}
cl := jwt.Claims{
Subject: "subject",
Issuer: "issuer",
}
raw, err := jwt.SignedAndEncrypted(rsaSigner, enc).Claims(cl).CompactSerialize()
if err != nil {
panic(err)
}
fmt.Println(raw)
}
func ExampleSigned_multipleClaims() {
c := &jwt.Claims{
Subject: "subject",
Issuer: "issuer",
}
c2 := struct {
Scopes []string
}{
[]string{"foo", "bar"},
}
raw, err := jwt.Signed(signer).Claims(c).Claims(c2).CompactSerialize()
if err != nil {
panic(err)
}
fmt.Println(raw)
// Output: eyJhbGciOiJIUzI1NiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sImlzcyI6Imlzc3VlciIsInN1YiI6InN1YmplY3QifQ.esKOIsmwkudr_gnfnB4SngxIr-7pspd5XzG3PImfQ6Y
}
func ExampleJSONWebToken_Claims_map() {
raw := `eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzdWIiOiJzdWJqZWN0In0.gpHyA1B1H6X4a4Edm9wo7D3X2v3aLSDBDG2_5BzXYe0`
tok, err := jwt.ParseSigned(raw)
if err != nil {
panic(err)
}
out := make(map[string]interface{})
if err := tok.Claims(sharedKey, &out); err != nil {
panic(err)
}
fmt.Printf("iss: %s, sub: %s\n", out["iss"], out["sub"])
// Output: iss: issuer, sub: subject
}
func ExampleJSONWebToken_Claims_multiple() {
raw := `eyJhbGciOiJIUzI1NiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sImlzcyI6Imlzc3VlciIsInN1YiI6InN1YmplY3QifQ.esKOIsmwkudr_gnfnB4SngxIr-7pspd5XzG3PImfQ6Y`
tok, err := jwt.ParseSigned(raw)
if err != nil {
panic(err)
}
out := jwt.Claims{}
out2 := struct {
Scopes []string
}{}
if err := tok.Claims(sharedKey, &out, &out2); err != nil {
panic(err)
}
fmt.Printf("iss: %s, sub: %s, scopes: %s\n", out.Issuer, out.Subject, strings.Join(out2.Scopes, ","))
// Output: iss: issuer, sub: subject, scopes: foo,bar
}
func mustUnmarshalRSA(data string) *rsa.PrivateKey {
block, _ := pem.Decode([]byte(data))
if block == nil {
panic("failed to decode PEM data")
}
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
panic("failed to parse RSA key: " + err.Error())
}
if key, ok := key.(*rsa.PrivateKey); ok {
return key
}
panic("key is not of type *rsa.PrivateKey")
}
func mustMakeSigner(alg jose.SignatureAlgorithm, k interface{}) jose.Signer {
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: alg, Key: k}, nil)
if err != nil {
panic("failed to create signer:" + err.Error())
}
return sig
}
var rsaPrivKey = mustUnmarshalRSA(`-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDIHBvDHAr7jh8h
xaqBCl11fjI9YZtdC5b3HtXTXZW3c2dIOImNUjffT8POP6p5OpzivmC1om7iOyuZ
3nJjC9LT3zqqs3f2i5d4mImxEuqG6uWdryFfkp0uIv5VkjVO+iQWd6pDAPGP7r1Z
foXCleyCtmyNH4JSkJneNPOk/4BxO8vcvRnCMT/Gv81IT6H+OQ6OovWOuJr8RX9t
1wuCjC9ezZxeI9ONffhiO5FMrVh5H9LJTl3dPOVa4aEcOvgd45hBmvxAyXqf8daE
6Kl2O7vQ4uwgnSTVXYIIjCjbepuersApIMGx/XPSgiU1K3Xtah/TBvep+S3VlwPc
q/QH25S9AgMBAAECggEAe+y8XKYfPw4SxY1uPB+5JSwT3ON3nbWxtjSIYy9Pqp5z
Vcx9kuFZ7JevQSk4X38m7VzM8282kC/ono+d8yy9Uayq3k/qeOqV0X9Vti1qxEbw
ECkG1/MqGApfy4qSLOjINInDDV+mOWa2KJgsKgdCwuhKbVMYGB2ozG2qfYIlfvlY
vLcBEpGWmswJHNmkcjTtGFIyJgPbsI6ndkkOeQbqQKAaadXtG1xUzH+vIvqaUl/l
AkNf+p4qhPkHsoAWXf1qu9cYa2T8T+mEo79AwlgVC6awXQWNRTiyClDJC7cu6NBy
ZHXCLFMbalzWF9qeI2OPaFX2x3IBWrbyDxcJ4TSdQQKBgQD/Fp/uQonMBh1h4Vi4
HlxZdqSOArTitXValdLFGVJ23MngTGV/St4WH6eRp4ICfPyldsfcv6MZpNwNm1Rn
lB5Gtpqpby1dsrOSfvVbY7U3vpLnd8+hJ/lT5zCYt5Eor46N6iWRkYWzNe4PixiF
z1puGUvFCbZdeeACVrPLmW3JKQKBgQDI0y9WTf8ezKPbtap4UEE6yBf49ftohVGz
p4iD6Ng1uqePwKahwoVXKOc179CjGGtW/UUBORAoKRmxdHajHq6LJgsBxpaARz21
COPy99BUyp9ER5P8vYn63lC7Cpd/K7uyMjaz1DAzYBZIeVZHIw8O9wuGNJKjRFy9
SZyD3V0ddQKBgFMdohrWH2QVEfnUnT3Q1rJn0BJdm2bLTWOosbZ7G72TD0xAWEnz
sQ1wXv88n0YER6X6YADziEdQykq8s/HT91F/KkHO8e83zP8M0xFmGaQCOoelKEgQ
aFMIX3NDTM7+9OoUwwz9Z50PE3SJFAJ1n7eEEoYvNfabQXxBl+/dHEKRAoGAPEvU
EaiXacrtg8EWrssB2sFLGU/ZrTciIbuybFCT4gXp22pvXXAHEvVP/kzDqsRhLhwb
BNP6OuSkNziNikpjA5pngZ/7fgZly54gusmW/m5bxWdsUl0iOXVYbeAvPlqGH2me
LP4Pfs1hw17S/cbT9Z1NE31jbavP4HFikeD73SUCgYEArQfuudml6ei7XZ1Emjq8
jZiD+fX6e6BD/ISatVnuyZmGj9wPFsEhY2BpLiAMQHMDIvH9nlKzsFvjkTPB86qG
jCh3D67Os8eSBk5uRC6iW3Fc4DXvB5EFS0W9/15Sl+V5vXAcrNMpYS82OTSMG2Gt
b9Ym/nxaqyTu0PxajXkKm5Q=
-----END PRIVATE KEY-----`)
var rsaSigner = mustMakeSigner(jose.RS256, rsaPrivKey)

View file

@ -1,137 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 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 jwt
import (
"testing"
"github.com/stretchr/testify/assert"
)
var (
hmacSignedToken = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwic2NvcGVzIjpbInMxIiwiczIiXX0.Y6_PfQHrzRJ_Vlxij5VI07-pgDIuJNN3Z_g5sSaGQ0c`
rsaSignedToken = `eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzY29wZXMiOlsiczEiLCJzMiJdLCJzdWIiOiJzdWJqZWN0In0.UDDtyK9gC9kyHltcP7E_XODsnqcJWZIiXeGmSAH7SE9YKy3N0KSfFIN85dCNjTfs6zvy4rkrCHzLB7uKAtzMearh3q7jL4nxbhUMhlUcs_9QDVoN4q_j58XmRqBqRnBk-RmDu9TgcV8RbErP4awpIhwWb5UU-hR__4_iNbHdKqwSUPDKYGlf5eicuiYrPxH8mxivk4LRD-vyRdBZZKBt0XIDnEU4TdcNCzAXojkftqcFWYsczwS8R4JHd1qYsMyiaWl4trdHZkO4QkeLe34z4ZAaPMt3wE-gcU-VoqYTGxz-K3Le2VaZ0r3j_z6bOInsv0yngC_cD1dCXMyQJWnWjQ`
invalidPayloadSignedToken = `eyJhbGciOiJIUzI1NiJ9.aW52YWxpZC1wYXlsb2Fk.ScBKKm18jcaMLGYDNRUqB5gVMRZl4DM6dh3ShcxeNgY`
invalidPartsSignedToken = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwic2NvcGVzIjpbInMxIiwiczIiXX0`
hmacEncryptedToken = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..NZrU98U4QNO0y-u6.HSq5CvlmkUT1BPqLGZ4.1-zuiZ4RbHrTTUoA8Dvfhg`
rsaEncryptedToken = `eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.IvkVHHiI8JwwavvTR80xGjYvkzubMrZ-TDDx8k8SNJMEylfFfNUc7F2rC3WAABF_xmJ3SW2A6on-S6EAG97k0RsjqHHNqZuaFpDvjeuLqZFfYKzI45aCtkGG4C2ij2GbeySqJ784CcvFJPUWJ-6VPN2Ho2nhefUSqig0jE2IvOKy1ywTj_VBVBxF_dyXFnXwxPKGUQr3apxrWeRJfDh2Cf8YPBlLiRznjfBfwgePB1jP7WCZNwItj10L7hsT_YWEx01XJcbxHaXFLwKyVzwWaDhreFyaWMRbGqEfqVuOT34zfmhLDhQlgLLwkXrvYqX90NsQ9Ftg0LLIfRMbsfdgug.BFy2Tj1RZN8yq2Lk-kMiZQ.9Z0eOyPiv5cEzmXh64RlAQ36Uvz0WpZgqRcc2_69zHTmUOv0Vnl1I6ks8sTraUEvukAilolNBjBj47s0b4b-Og.VM8-eJg5ZsqnTqs0LtGX_Q`
invalidPayloadEncryptedToken = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..T4jCS4Yyw1GCH0aW.y4gFaMITdBs_QZM8RKrL.6MPyk1cMVaOJFoNGlEuaRQ`
invalidPartsEncryptedToken = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..NZrU98U4QNO0y-u6.HSq5CvlmkUT1BPqLGZ4`
signedAndEncryptedToken = `eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiY3R5IjoiSldUIn0.icnR7M1HSgMDaUnJhfzT5nLmT0eRPeNsKPkioNcyq9TZsm-LgbE7wZkNFGfQqYwvbmrZ3UpOhNkrq4n2KN3N1dtjH9TVxzfMxz2OMh0dRWUNMi58EMadhmIpH3PLyyaeDyd0dyHpOIRPFTAoOdn2GoO_flV5CvPMhgdVKYB3h3vQW-ZZDu4cOZwXAjTuThdoUZCNWFhJhXyj-PrKLyVpX6rE1o4X05IS8008SLZyx-PZlsUPyLs6CJi7Z4PzZRzOJTV00a-7UOi-fBKBZV5V8eRpWuzJ673pMALlRCBzrRin-JeEA_QnAejtMAHG7RSGP60easQN4I-0jLTQNNNynw.oFrO-5ZgRrnWmbkPsbyMiQ.BVaWUzlrdfhe0otPJpb3DGoDCT6-BOmN_Pgq5NOqVFYIAwG5pM4pf7TaiPUJeQLf0phbLgpT4RfJ20Zhwfc2MH5unCqc8TZEP2dOrYRhb8o-X57x6IQppIDbjK2i_CAWf3yF5JUB7qRqOizpKZTh3HFTVEglY3WF8tAJ8KpnatTUmwcnqlyjdBFvYu4usiyvc_u9wNbXx5-lFt0slQYleHQMUirBprKyswIBjMoFJEe7kDvU_MCKI4NI9_fSfWJpaUdNxQEvRYR1PV4ZQdwBY0X9u2n2QH5iVQMrmgmQ5hPbWxwRv1-7jXBMPBpGeFQZHeEtSwif1_Umwyt8cDyRChb3OM7XQ3eY0UJRrbmvhcLWIcMp8FpblDaBinbjD6qIVXZVmaAdIbi2a_HblfoeL3-UABb82AAxOqQcAFjDEDTR2TFalDXSwgPZrAaQ_Mql3eFe9r2y0UVkgG7XYF4ik8sSK48CkZPUvkZFr-K9QMq-RZLzT3Zw0edxNaKgje27S26H9qClh6CCr9nk38AZZ76_Xz7f-Fil5xI0Dq95UzvwW__U3JJWE6OVUVx_RVJgdOJn8_B7hluckwBLUblscA.83pPXNnH0sKgHvFboiJVDA`
invalidSignedAndEncryptedToken = `eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.QKYu3DkFEXBUa2U0Sgtm-e44BMuaFVbMu2T-GB3qEGONrmOuaB5BtNCvBUnuj6HR0v6u-tvawToRSzExQQLFTvPcLiQR8iclWirqAFUqLrg8kRU3qIRLkmErYeGIfCML1jq9ofKg0DI5-YrU5RSyUg9cwfXKEx8KNwFcjeVeDZwWEACdU8xBnQp57rNfr0Tj-dPnGKID7LU5ZV0vhK90FpEG7UqOeSHFmvONQyz6Ca-ZkE8X2swqGad-q5xl8f9pApdFqHzADox5OlgtxPkr-Khkm6WGfvf1K_e-iW5LYtvWIAjNByft2TexsNcYpdAO2oNAgh2nkhoohl-zCWU-og.UAU65JWKqvHZ_Z0V-xLyjQ.M6sQ4lAzKFelSmL6C6uoK00rB8IFCAK-eJ0iByGhtg8eYtmSBFsP_oUySfKPtxcPRkQ7YxnEX5D-DOo20wCV7il2Be9No__0R6_5heISOMXcKmKP3D6pFusaPisNGOgLw8SKXBuVpe20PvOJ9RgOXRKucSR2UMINXtqIn9RdxbKOlBBmMJhnX4TeQ00fRILng2sMbUHsWExSthQODHGx6VcwLFp-Aqmsnv2q2KkLpA8sEm48AHHFQXSGtlVGVgWKi3dOQYUnDJW4P64Xxr1Uq3yT7w_dRwK4BA7l3Biecj5dwkKrFMJ_RaCt-ED_R15zpxg6PmnXeeJnif58Fai40ZWOsGvLZNYwL1jbi-TrsargpdUQedfzuTk8Na2NkCzFNg2BYXVDHJ_WAX1daVyhvunaURwAlBatAcmnOGxWebwV1xQoQ7iHg6ZGohCannn_pqGwJlMHMgnCcnCIhwfj9uL9Ejz_TVceZNMlT1KvLRafVfxGhkp48bdnd8OcXmjT9pQzZUB3OqrstWKhbItZ1xMpy6dZ54ldWvtTTyQ4tQJaVWgXERUM1erDT6Ypyl15-fumOB9MRcgMG3NDblKowA.P9WTBITvVUgrLjX6bS0opQ`
)
type customClaims struct {
Scopes []string `json:"scopes,omitempty"`
}
func TestDecodeToken(t *testing.T) {
tok, err := ParseSigned(hmacSignedToken)
if assert.NoError(t, err, "Error parsing signed token.") {
c := &Claims{}
c2 := &customClaims{}
if assert.NoError(t, tok.Claims(sharedKey, c, c2)) {
assert.Equal(t, "subject", c.Subject)
assert.Equal(t, "issuer", c.Issuer)
assert.Equal(t, []string{"s1", "s2"}, c2.Scopes)
}
}
assert.EqualError(t, tok.Claims([]byte("invalid-secret")), "square/go-jose: error in cryptographic primitive")
tok2, err := ParseSigned(rsaSignedToken)
if assert.NoError(t, err, "Error parsing encrypted token.") {
c := make(map[string]interface{})
if assert.NoError(t, tok2.Claims(&testPrivRSAKey1.PublicKey, &c)) {
assert.Equal(t, map[string]interface{}{
"sub": "subject",
"iss": "issuer",
"scopes": []interface{}{"s1", "s2"},
}, c)
}
}
assert.EqualError(t, tok.Claims(&testPrivRSAKey2.PublicKey), "square/go-jose: error in cryptographic primitive")
tok3, err := ParseSigned(invalidPayloadSignedToken)
if assert.NoError(t, err, "Error parsing signed token.") {
assert.Error(t, tok3.Claims(sharedKey, &Claims{}), "Expected unmarshaling claims to fail.")
}
_, err = ParseSigned(invalidPartsSignedToken)
assert.EqualError(t, err, "square/go-jose: compact JWS format must have three parts")
tok4, err := ParseEncrypted(hmacEncryptedToken)
if assert.NoError(t, err, "Error parsing encrypted token.") {
c := Claims{}
if assert.NoError(t, tok4.Claims(sharedEncryptionKey, &c)) {
assert.Equal(t, "foo", c.Subject)
}
}
assert.EqualError(t, tok4.Claims([]byte("invalid-secret-key")), "square/go-jose: error in cryptographic primitive")
tok5, err := ParseEncrypted(rsaEncryptedToken)
if assert.NoError(t, err, "Error parsing encrypted token.") {
c := make(map[string]interface{})
if assert.NoError(t, tok5.Claims(testPrivRSAKey1, &c)) {
assert.Equal(t, map[string]interface{}{
"sub": "subject",
"iss": "issuer",
"scopes": []interface{}{"s1", "s2"},
}, c)
}
}
assert.EqualError(t, tok5.Claims(testPrivRSAKey2), "square/go-jose: error in cryptographic primitive")
tok6, err := ParseEncrypted(invalidPayloadEncryptedToken)
if assert.NoError(t, err, "Error parsing encrypted token.") {
assert.Error(t, tok6.Claims(sharedEncryptionKey, &Claims{}))
}
_, err = ParseEncrypted(invalidPartsEncryptedToken)
assert.EqualError(t, err, "square/go-jose: compact JWE format must have five parts")
tok7, err := ParseSignedAndEncrypted(signedAndEncryptedToken)
if assert.NoError(t, err, "Error parsing signed-then-encrypted token.") {
c := make(map[string]interface{})
if nested, err := tok7.Decrypt(testPrivRSAKey1); assert.NoError(t, err) {
assert.NoError(t, nested.Claims(testPrivRSAKey1.Public(), &c))
assert.Equal(t, map[string]interface{}{
"sub": "subject",
"iss": "issuer",
"scopes": []interface{}{"s1", "s2"},
}, c)
assert.EqualError(t, nested.Claims(testPrivRSAKey2.Public()), "square/go-jose: error in cryptographic primitive")
}
}
_, err = tok7.Decrypt(testPrivRSAKey2)
assert.EqualError(t, err, "square/go-jose: error in cryptographic primitive")
_, err = ParseSignedAndEncrypted(invalidSignedAndEncryptedToken)
assert.EqualError(t, err, "square/go-jose/jwt: expected content type to be JWT (cty header)")
}
func BenchmarkDecodeSignedToken(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseSigned(hmacSignedToken)
}
}
func BenchmarkDecodeEncryptedHMACToken(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseEncrypted(hmacEncryptedToken)
}
}

View file

@ -1,92 +0,0 @@
/*-
* Copyright 2016 Zbigniew Mandziejewicz
* Copyright 2016 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 jwt
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestFieldsMatch(t *testing.T) {
c := Claims{
Issuer: "issuer",
Subject: "subject",
Audience: []string{"a1", "a2"},
ID: "42",
}
valid := []Expected{
{Issuer: "issuer"},
{Subject: "subject"},
{Audience: Audience{"a1", "a2"}},
{Audience: Audience{"a2", "a1"}},
{ID: "42"},
}
for _, v := range valid {
assert.NoError(t, c.Validate(v))
}
invalid := []struct {
Expected Expected
Error error
}{
{Expected{Issuer: "invalid-issuer"}, ErrInvalidIssuer},
{Expected{Subject: "invalid-subject"}, ErrInvalidSubject},
{Expected{Audience: Audience{"invalid-audience"}}, ErrInvalidAudience},
{Expected{ID: "invalid-id"}, ErrInvalidID},
}
for _, v := range invalid {
assert.Equal(t, v.Error, c.Validate(v.Expected))
}
}
func TestExpiryAndNotBefore(t *testing.T) {
now := time.Date(2016, 1, 1, 12, 0, 0, 0, time.UTC)
twelveHoursAgo := now.Add(-12 * time.Hour)
c := Claims{
IssuedAt: NewNumericDate(twelveHoursAgo),
NotBefore: NewNumericDate(twelveHoursAgo),
Expiry: NewNumericDate(now),
}
// expired - default leeway (1 minute)
assert.NoError(t, c.Validate(Expected{Time: now}))
err := c.Validate(Expected{Time: now.Add(2 * DefaultLeeway)})
if assert.Error(t, err) {
assert.Equal(t, err, ErrExpired)
}
// expired - no leeway
assert.NoError(t, c.ValidateWithLeeway(Expected{Time: now}, 0))
err = c.ValidateWithLeeway(Expected{Time: now.Add(1 * time.Second)}, 0)
if assert.Error(t, err) {
assert.Equal(t, err, ErrExpired)
}
// not before - default leeway (1 minute)
assert.NoError(t, c.Validate(Expected{Time: twelveHoursAgo}))
err = c.Validate(Expected{Time: twelveHoursAgo.Add(-2 * DefaultLeeway)})
if assert.Error(t, err) {
assert.Equal(t, err, ErrNotValidYet)
}
}

View file

@ -1,523 +0,0 @@
/*-
* 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 (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"fmt"
"io"
"reflect"
"testing"
"gopkg.in/square/go-jose.v2/json"
)
type staticNonceSource string
func (sns staticNonceSource) Nonce() (string, error) {
return string(sns), nil
}
func RoundtripJWS(sigAlg SignatureAlgorithm, serializer func(*JSONWebSignature) (string, error), corrupter func(*JSONWebSignature), signingKey interface{}, verificationKey interface{}, nonce string) error {
opts := &SignerOptions{}
if nonce != "" {
opts.NonceSource = staticNonceSource(nonce)
}
signer, err := NewSigner(SigningKey{Algorithm: sigAlg, Key: signingKey}, opts)
if err != nil {
return fmt.Errorf("error on new signer: %s", err)
}
input := []byte("Lorem ipsum dolor sit amet")
obj, err := signer.Sign(input)
if err != nil {
return fmt.Errorf("error on sign: %s", err)
}
msg, err := serializer(obj)
if err != nil {
return fmt.Errorf("error on serialize: %s", err)
}
obj, err = ParseSigned(msg)
if err != nil {
return fmt.Errorf("error on parse: %s", err)
}
// (Maybe) mangle the object
corrupter(obj)
output, err := obj.Verify(verificationKey)
if err != nil {
return fmt.Errorf("error on verify: %s", err)
}
// Check that verify works with embedded keys (if present)
for i, sig := range obj.Signatures {
if sig.Header.JSONWebKey != nil {
_, err = obj.Verify(sig.Header.JSONWebKey)
if err != nil {
return fmt.Errorf("error on verify with embedded key %d: %s", i, err)
}
}
// Check that the nonce correctly round-tripped (if present)
if sig.Header.Nonce != nonce {
return fmt.Errorf("Incorrect nonce returned: [%s]", sig.Header.Nonce)
}
}
if bytes.Compare(output, input) != 0 {
return fmt.Errorf("input/output do not match, got '%s', expected '%s'", output, input)
}
return nil
}
func TestRoundtripsJWS(t *testing.T) {
// Test matrix
sigAlgs := []SignatureAlgorithm{RS256, RS384, RS512, PS256, PS384, PS512, HS256, HS384, HS512, ES256, ES384, ES512, EdDSA}
serializers := []func(*JSONWebSignature) (string, error){
func(obj *JSONWebSignature) (string, error) { return obj.CompactSerialize() },
func(obj *JSONWebSignature) (string, error) { return obj.FullSerialize(), nil },
}
corrupter := func(obj *JSONWebSignature) {}
for _, alg := range sigAlgs {
signingKey, verificationKey := GenerateSigningTestKey(alg)
for i, serializer := range serializers {
err := RoundtripJWS(alg, serializer, corrupter, signingKey, verificationKey, "test_nonce")
if err != nil {
t.Error(err, alg, i)
}
}
}
}
func TestRoundtripsJWSCorruptSignature(t *testing.T) {
// Test matrix
sigAlgs := []SignatureAlgorithm{RS256, RS384, RS512, PS256, PS384, PS512, HS256, HS384, HS512, ES256, ES384, ES512, EdDSA}
serializers := []func(*JSONWebSignature) (string, error){
func(obj *JSONWebSignature) (string, error) { return obj.CompactSerialize() },
func(obj *JSONWebSignature) (string, error) { return obj.FullSerialize(), nil },
}
corrupters := []func(*JSONWebSignature){
func(obj *JSONWebSignature) {
// Changes bytes in signature
obj.Signatures[0].Signature[10]++
},
func(obj *JSONWebSignature) {
// Set totally invalid signature
obj.Signatures[0].Signature = []byte("###")
},
}
// Test all different configurations
for _, alg := range sigAlgs {
signingKey, verificationKey := GenerateSigningTestKey(alg)
for i, serializer := range serializers {
for j, corrupter := range corrupters {
err := RoundtripJWS(alg, serializer, corrupter, signingKey, verificationKey, "test_nonce")
if err == nil {
t.Error("failed to detect corrupt signature", err, alg, i, j)
}
}
}
}
}
func TestSignerWithBrokenRand(t *testing.T) {
sigAlgs := []SignatureAlgorithm{RS256, RS384, RS512, PS256, PS384, PS512}
serializer := func(obj *JSONWebSignature) (string, error) { return obj.CompactSerialize() }
corrupter := func(obj *JSONWebSignature) {}
// Break rand reader
readers := []func() io.Reader{
// Totally broken
func() io.Reader { return bytes.NewReader([]byte{}) },
// Not enough bytes
func() io.Reader { return io.LimitReader(rand.Reader, 20) },
}
defer resetRandReader()
for _, alg := range sigAlgs {
signingKey, verificationKey := GenerateSigningTestKey(alg)
for i, getReader := range readers {
randReader = getReader()
err := RoundtripJWS(alg, serializer, corrupter, signingKey, verificationKey, "test_nonce")
if err == nil {
t.Error("signer should fail if rand is broken", alg, i)
}
}
}
}
func TestJWSInvalidKey(t *testing.T) {
signingKey0, verificationKey0 := GenerateSigningTestKey(RS256)
_, verificationKey1 := GenerateSigningTestKey(ES256)
_, verificationKey2 := GenerateSigningTestKey(EdDSA)
signer, err := NewSigner(SigningKey{Algorithm: RS256, Key: signingKey0}, nil)
if err != nil {
panic(err)
}
input := []byte("Lorem ipsum dolor sit amet")
obj, err := signer.Sign(input)
if err != nil {
panic(err)
}
// Must work with correct key
_, err = obj.Verify(verificationKey0)
if err != nil {
t.Error("error on verify", err)
}
// Must not work with incorrect key
_, err = obj.Verify(verificationKey1)
if err == nil {
t.Error("verification should fail with incorrect key")
}
// Must not work with incorrect key
_, err = obj.Verify(verificationKey2)
if err == nil {
t.Error("verification should fail with incorrect key")
}
// Must not work with invalid key
_, err = obj.Verify("")
if err == nil {
t.Error("verification should fail with incorrect key")
}
}
func TestMultiRecipientJWS(t *testing.T) {
sharedKey := []byte{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
}
jwkSharedKey := JSONWebKey{
KeyID: "123",
Key: sharedKey,
}
signer, err := NewMultiSigner([]SigningKey{
{RS256, rsaTestKey},
{HS384, sharedKey},
{HS512, jwkSharedKey},
}, nil)
if err != nil {
t.Fatal("error creating signer: ", err)
}
input := []byte("Lorem ipsum dolor sit amet")
obj, err := signer.Sign(input)
if err != nil {
t.Fatal("error on sign: ", err)
}
_, err = obj.CompactSerialize()
if err == nil {
t.Fatal("message with multiple recipient was compact serialized")
}
msg := obj.FullSerialize()
obj, err = ParseSigned(msg)
if err != nil {
t.Fatal("error on parse: ", err)
}
i, _, output, err := obj.VerifyMulti(&rsaTestKey.PublicKey)
if err != nil {
t.Fatal("error on verify: ", err)
}
if i != 0 {
t.Fatal("signature index should be 0 for RSA key")
}
if bytes.Compare(output, input) != 0 {
t.Fatal("input/output do not match", output, input)
}
i, _, output, err = obj.VerifyMulti(sharedKey)
if err != nil {
t.Fatal("error on verify: ", err)
}
if i != 1 {
t.Fatal("signature index should be 1 for EC key")
}
if bytes.Compare(output, input) != 0 {
t.Fatal("input/output do not match", output, input)
}
}
func GenerateSigningTestKey(sigAlg SignatureAlgorithm) (sig, ver interface{}) {
switch sigAlg {
case EdDSA:
sig = ed25519PrivateKey
ver = ed25519PublicKey
case RS256, RS384, RS512, PS256, PS384, PS512:
sig = rsaTestKey
ver = &rsaTestKey.PublicKey
case HS256, HS384, HS512:
sig, _, _ = randomKeyGenerator{size: 16}.genKey()
ver = sig
case ES256:
key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
sig = key
ver = &key.PublicKey
case ES384:
key, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
sig = key
ver = &key.PublicKey
case ES512:
key, _ := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
sig = key
ver = &key.PublicKey
default:
panic("Must update test case")
}
return
}
func TestInvalidSignerAlg(t *testing.T) {
_, err := NewSigner(SigningKey{"XYZ", nil}, nil)
if err == nil {
t.Error("should not accept invalid algorithm")
}
_, err = NewSigner(SigningKey{"XYZ", []byte{}}, nil)
if err == nil {
t.Error("should not accept invalid algorithm")
}
}
func TestInvalidJWS(t *testing.T) {
signer, err := NewSigner(SigningKey{PS256, rsaTestKey}, nil)
if err != nil {
panic(err)
}
obj, err := signer.Sign([]byte("Lorem ipsum dolor sit amet"))
obj.Signatures[0].header = &rawHeader{}
obj.Signatures[0].header.set(headerCritical, []string{"TEST"})
_, err = obj.Verify(&rsaTestKey.PublicKey)
if err == nil {
t.Error("should not verify message with unknown crit header")
}
// Try without alg header
obj.Signatures[0].protected = &rawHeader{}
obj.Signatures[0].header = &rawHeader{}
_, err = obj.Verify(&rsaTestKey.PublicKey)
if err == nil {
t.Error("should not verify message with missing headers")
}
}
func TestSignerKid(t *testing.T) {
kid := "DEADBEEF"
payload := []byte("Lorem ipsum dolor sit amet")
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Error("problem generating test signing key", err)
}
basejwk := JSONWebKey{Key: key}
jsonbar, err := basejwk.MarshalJSON()
if err != nil {
t.Error("problem marshalling base JWK", err)
}
var jsonmsi map[string]interface{}
err = json.Unmarshal(jsonbar, &jsonmsi)
if err != nil {
t.Error("problem unmarshalling base JWK", err)
}
jsonmsi["kid"] = kid
jsonbar2, err := json.Marshal(jsonmsi)
if err != nil {
t.Error("problem marshalling kided JWK", err)
}
var jwk JSONWebKey
err = jwk.UnmarshalJSON(jsonbar2)
if err != nil {
t.Error("problem unmarshalling kided JWK", err)
}
signer, err := NewSigner(SigningKey{ES256, &jwk}, nil)
if err != nil {
t.Error("problem creating signer with *JSONWebKey", err)
}
signed, err := signer.Sign(payload)
serialized := signed.FullSerialize()
parsed, err := ParseSigned(serialized)
if err != nil {
t.Error("problem parsing signed object", err)
}
if parsed.Signatures[0].Header.KeyID != kid {
t.Error("KeyID did not survive trip")
}
signer, err = NewSigner(SigningKey{ES256, jwk}, nil)
if err != nil {
t.Error("problem creating signer with JSONWebKey", err)
}
}
func TestEmbedJwk(t *testing.T) {
var payload = []byte("Lorem ipsum dolor sit amet")
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Error("Failed to generate key")
}
signer, err := NewSigner(SigningKey{ES256, key}, &SignerOptions{EmbedJWK: true})
if err != nil {
t.Error("Failed to create signer")
}
object, err := signer.Sign(payload)
if err != nil {
t.Error("Failed to sign payload")
}
object, err = ParseSigned(object.FullSerialize())
if err != nil {
t.Error("Failed to parse jws")
}
jwk, err := object.Signatures[0].protected.getJWK()
if jwk == nil || err != nil {
t.Error("JWK isn't set in protected header")
}
// This time, sign and do not embed JWK in message
signer, err = NewSigner(SigningKey{ES256, key}, &SignerOptions{EmbedJWK: false})
object, err = signer.Sign(payload)
if err != nil {
t.Error("Failed to sign payload")
}
object, err = ParseSigned(object.FullSerialize())
if err != nil {
t.Error("Failed to parse jws")
}
jwk2, err := object.Signatures[0].protected.getJWK()
if err != nil {
t.Error("JWK is invalid in protected header")
}
if jwk2 != nil {
t.Error("JWK is set in protected header")
}
}
func TestSignerOptionsEd(t *testing.T) {
key, _ := GenerateSigningTestKey(EdDSA)
opts := &SignerOptions{
EmbedJWK: true,
}
opts.WithContentType("JWT")
opts.WithType("JWT")
sig, err := NewSigner(SigningKey{EdDSA, key}, opts)
if err != nil {
t.Error("Failed to create signer")
}
if !reflect.DeepEqual(*opts, sig.Options()) {
t.Error("Signer options do not match")
}
}
func TestSignerOptions(t *testing.T) {
key, _ := GenerateSigningTestKey(HS256)
opts := &SignerOptions{
EmbedJWK: true,
}
opts.WithContentType("JWT")
opts.WithType("JWT")
sig, err := NewSigner(SigningKey{HS256, key}, opts)
if err != nil {
t.Error("Failed to create signer")
}
if !reflect.DeepEqual(*opts, sig.Options()) {
t.Error("Signer options do not match")
}
}
// Test that extra headers are generated and parsed in a round trip.
func TestSignerExtraHeaderInclusion(t *testing.T) {
var payload = []byte("Lorem ipsum dolor sit amet")
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Error("Failed to generate key")
}
signer, err := NewSigner(SigningKey{ES256, key}, (&SignerOptions{}).WithContentType("foo/bar").WithHeader(HeaderKey("myCustomHeader"), "xyz"))
if err != nil {
t.Error("Failed to create signer", err)
}
object, err := signer.Sign(payload)
if err != nil {
t.Error("Failed to sign payload")
}
object, err = ParseSigned(object.FullSerialize())
if err != nil {
t.Error("Failed to parse jws")
}
correct := map[HeaderKey]interface{}{
HeaderContentType: "foo/bar",
HeaderKey("myCustomHeader"): "xyz",
}
if !reflect.DeepEqual(object.Signatures[0].Header.ExtraHeaders, correct) {
t.Errorf("Mismatch in extra headers: %#v", object.Signatures[0].Header.ExtraHeaders)
}
}

View file

@ -1,131 +0,0 @@
/*-
* 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 (
"bytes"
"crypto/cipher"
"crypto/rand"
"io"
"testing"
)
func TestInvalidSymmetricAlgorithms(t *testing.T) {
_, err := newSymmetricRecipient("XYZ", []byte{})
if err != ErrUnsupportedAlgorithm {
t.Error("should not accept invalid algorithm")
}
enc := &symmetricKeyCipher{}
_, err = enc.encryptKey([]byte{}, "XYZ")
if err != ErrUnsupportedAlgorithm {
t.Error("should not accept invalid algorithm")
}
}
func TestAeadErrors(t *testing.T) {
aead := &aeadContentCipher{
keyBytes: 16,
authtagBytes: 16,
getAead: func(key []byte) (cipher.AEAD, error) {
return nil, ErrCryptoFailure
},
}
parts, err := aead.encrypt([]byte{}, []byte{}, []byte{})
if err != ErrCryptoFailure {
t.Error("should handle aead failure")
}
_, err = aead.decrypt([]byte{}, []byte{}, parts)
if err != ErrCryptoFailure {
t.Error("should handle aead failure")
}
}
func TestInvalidKey(t *testing.T) {
gcm := newAESGCM(16).(*aeadContentCipher)
_, err := gcm.getAead([]byte{})
if err == nil {
t.Error("should not accept invalid key")
}
}
func TestStaticKeyGen(t *testing.T) {
key := make([]byte, 32)
io.ReadFull(rand.Reader, key)
gen := &staticKeyGenerator{key: key}
if gen.keySize() != len(key) {
t.Error("static key generator reports incorrect size")
}
generated, _, err := gen.genKey()
if err != nil {
t.Error("static key generator should always succeed", err)
}
if !bytes.Equal(generated, key) {
t.Error("static key generator returns different data")
}
}
func TestVectorsAESGCM(t *testing.T) {
// Source: http://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-29#appendix-A.1
plaintext := []byte{
84, 104, 101, 32, 116, 114, 117, 101, 32, 115, 105, 103, 110, 32,
111, 102, 32, 105, 110, 116, 101, 108, 108, 105, 103, 101, 110, 99,
101, 32, 105, 115, 32, 110, 111, 116, 32, 107, 110, 111, 119, 108,
101, 100, 103, 101, 32, 98, 117, 116, 32, 105, 109, 97, 103, 105,
110, 97, 116, 105, 111, 110, 46}
aad := []byte{
101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 83, 85, 48, 69,
116, 84, 48, 70, 70, 85, 67, 73, 115, 73, 109, 86, 117, 89, 121, 73,
54, 73, 107, 69, 121, 78, 84, 90, 72, 81, 48, 48, 105, 102, 81}
expectedCiphertext := []byte{
229, 236, 166, 241, 53, 191, 115, 196, 174, 43, 73, 109, 39, 122,
233, 96, 140, 206, 120, 52, 51, 237, 48, 11, 190, 219, 186, 80, 111,
104, 50, 142, 47, 167, 59, 61, 181, 127, 196, 21, 40, 82, 242, 32,
123, 143, 168, 226, 73, 216, 176, 144, 138, 247, 106, 60, 16, 205,
160, 109, 64, 63, 192}
expectedAuthtag := []byte{
92, 80, 104, 49, 133, 25, 161, 215, 173, 101, 219, 211, 136, 91, 210, 145}
// Mock random reader
randReader = bytes.NewReader([]byte{
177, 161, 244, 128, 84, 143, 225, 115, 63, 180, 3, 255, 107, 154,
212, 246, 138, 7, 110, 91, 112, 46, 34, 105, 47, 130, 203, 46, 122,
234, 64, 252, 227, 197, 117, 252, 2, 219, 233, 68, 180, 225, 77, 219})
defer resetRandReader()
enc := newAESGCM(32)
key, _, _ := randomKeyGenerator{size: 32}.genKey()
out, err := enc.encrypt(key, aad, plaintext)
if err != nil {
t.Error("Unable to encrypt:", err)
return
}
if bytes.Compare(out.ciphertext, expectedCiphertext) != 0 {
t.Error("Ciphertext did not match")
}
if bytes.Compare(out.tag, expectedAuthtag) != 0 {
t.Error("Auth tag did not match")
}
}

View file

@ -1,70 +0,0 @@
/*-
* 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/rand"
"encoding/base64"
"encoding/hex"
"math/big"
"regexp"
)
// Reset random reader to original value
func resetRandReader() {
randReader = rand.Reader
}
// Build big int from hex-encoded string. Strips whitespace (for testing).
func fromHexInt(base16 string) *big.Int {
re := regexp.MustCompile(`\s+`)
val, ok := new(big.Int).SetString(re.ReplaceAllString(base16, ""), 16)
if !ok {
panic("Invalid test data")
}
return val
}
// Build big int from base64-encoded string. Strips whitespace (for testing).
func fromBase64Int(encoded string) *big.Int {
re := regexp.MustCompile(`\s+`)
val, err := base64.RawURLEncoding.DecodeString(re.ReplaceAllString(encoded, ""))
if err != nil {
panic("Invalid test data: " + err.Error())
}
return new(big.Int).SetBytes(val)
}
// Decode hex-encoded string into byte array. Strips whitespace (for testing).
func fromHexBytes(base16 string) []byte {
re := regexp.MustCompile(`\s+`)
val, err := hex.DecodeString(re.ReplaceAllString(base16, ""))
if err != nil {
panic("Invalid test data")
}
return val
}
// Decode base64-encoded string into byte array. Strips whitespace (for testing).
func fromBase64Bytes(b64 string) []byte {
re := regexp.MustCompile(`\s+`)
val, err := base64.StdEncoding.DecodeString(re.ReplaceAllString(b64, ""))
if err != nil {
panic("Invalid test data")
}
return val
}