mirror of
https://github.com/Luzifer/nginx-sso.git
synced 2024-12-21 05:11:17 +00:00
389 lines
9.4 KiB
Go
389 lines
9.4 KiB
Go
|
/*-
|
||
|
* Copyright 2014 Square Inc.
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package jose
|
||
|
|
||
|
import (
|
||
|
"crypto/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")
|
||
|
}
|
||
|
}
|