| /*- |
| * 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/elliptic" |
| "crypto/rand" |
| "crypto/rsa" |
| "errors" |
| "io" |
| "testing" |
| ) |
| |
| 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") |
| } |
| } |