Skip to content

Commit

Permalink
require: finish package uapolicy
Browse files Browse the repository at this point in the history
  • Loading branch information
magiconair committed Dec 16, 2024
1 parent adebbd5 commit 4270340
Showing 1 changed file with 60 additions and 153 deletions.
213 changes: 60 additions & 153 deletions uapolicy/securitypolicy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
package uapolicy

import (
"bytes"
"crypto"
"crypto/rand"
"crypto/rsa"
Expand All @@ -30,26 +29,16 @@ func TestGenerateKeysLength(t *testing.T) {
localNonce := make([]byte, 32)
remoteNonce := make([]byte, 32)
_, err := rand.Read(localNonce)
if err != nil {
t.Fatalf("Could not generate local nonce")
}
require.NoError(t, err, "Could not generate local nonce")

_, err = rand.Read(remoteNonce)
if err != nil {
t.Fatalf("Could not generate remote nonce")
}
require.NoError(t, err, "Could not generate remote nonce")

hmac := &HMAC{Hash: crypto.SHA256, Secret: remoteNonce}
keys := generateKeys(hmac, localNonce, 32, 32, 16)
if len(keys.signing) != 32 {
t.Errorf("Signing Key Invalid Length\n")
}
if len(keys.encryption) != 32 {
t.Errorf("Encryption Key Invalid Length\n")
}
if len(keys.iv) != 16 {
t.Errorf("Encryption IV Invalid Length\n")
}
require.Equal(t, 32, len(keys.signing), "Signing Key Invalid Length")
require.Equal(t, 32, len(keys.encryption), "Encryption Key Invalid Length")
require.Equal(t, 16, len(keys.iv), "Encryption IV Invalid Length")
}

func TestGenerateKeys(t *testing.T) {
Expand All @@ -70,27 +59,15 @@ func TestGenerateKeys(t *testing.T) {

localHmac := &HMAC{Hash: crypto.SHA1, Secret: localNonce}
keys := generateKeys(localHmac, remoteNonce, 16, 16, 16)
if got, want := keys.signing, localKeys.signing; !bytes.Equal(got, want) {
t.Errorf("local signing key generation failed:\ngot %#v want %#v\n", got, want)
}
if got, want := keys.encryption, localKeys.encryption; !bytes.Equal(got, want) {
t.Errorf("local encryption key generation failed:\ngot %#v want %#v\n", got, want)
}
if got, want := keys.iv, localKeys.iv; !bytes.Equal(got, want) {
t.Errorf("local iv key generation failed:\ngot %#v want %#v\n", got, want)
}
require.Equal(t, localKeys.signing, keys.signing, "local signing key generation failed")
require.Equal(t, localKeys.encryption, keys.encryption, "local encryption key generation failed")
require.Equal(t, localKeys.iv, keys.iv, "local iv key generation failed")

remoteHmac := &HMAC{Hash: crypto.SHA1, Secret: remoteNonce}
keys = generateKeys(remoteHmac, localNonce, 16, 16, 16)
if got, want := keys.signing, remoteKeys.signing; !bytes.Equal(got, want) {
t.Errorf("remote signing key generation failed:\ngot %#v want %#v\n", got, want)
}
if got, want := keys.encryption, remoteKeys.encryption; !bytes.Equal(got, want) {
t.Errorf("remote encryption key generation failed:\ngot %#v want %#v\n", got, want)
}
if got, want := keys.iv, remoteKeys.iv; !bytes.Equal(got, want) {
t.Errorf("remote iv key generation failed:\ngot %#v want %#v\n", got, want)
}
require.Equal(t, remoteKeys.signing, keys.signing, "remote signing key generation failed")
require.Equal(t, remoteKeys.encryption, keys.encryption, "remote encryption key generation failed")
require.Equal(t, remoteKeys.iv, keys.iv, "remote iv key generation failed")
}

// Test all supported encryption algorithms. Because the majority of the algorithms
Expand All @@ -101,9 +78,7 @@ func TestGenerateKeys(t *testing.T) {
func TestEncryptionAlgorithms(t *testing.T) {
payload := make([]byte, 5000)
_, err := rand.Read(payload)
if err != nil {
t.Fatalf("could not generate random payload")
}
require.NoError(t, err, "could not generate random payload")

payloadRef := make([]byte, len(payload))
copy(payloadRef, payload)
Expand All @@ -112,53 +87,39 @@ func TestEncryptionAlgorithms(t *testing.T) {
// This won't be the case forever and will be too small for future algorithms
// and the test will need to be able to input keys of varying size
localKey, err := generatePrivateKey(2048)
if err != nil {
t.Fatalf("Unable to generate local private key\n")
}
require.NoError(t, err, "Unable to generate local private key")

remoteKey, err := generatePrivateKey(2048)
if err != nil {
t.Fatalf("Unable to generate remote private key\n")
}
require.NoError(t, err, "Unable to generate remote private key")

for uri, p := range policies {
t.Run(uri, func(t *testing.T) {
localAsymmetric, err := p.asymmetric(localKey, &remoteKey.PublicKey)
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)

makeNonce := func(n int) []byte {
t.Helper()
if n == 0 {
return nil
}
b := make([]byte, n)
if _, err = rand.Read(b); err != nil {
t.Fatalf("could not generate nonce")
}
_, err = rand.Read(b)
require.NoError(t, err, "could not generate nonce")
return b
}

nonceLength := localAsymmetric.NonceLength()
localNonce, remoteNonce := makeNonce(nonceLength), makeNonce(nonceLength)
if nonceLength == 0 && uri != ua.SecurityPolicyURINone {
t.Fatalf("client nonce length zero")
}
require.False(t, nonceLength == 0 && uri != ua.SecurityPolicyURINone, "client nonce length zero")

localSymmetric, err := p.symmetric(localNonce, remoteNonce)
if err != nil {
t.Fatalf("failed local Symmetric: %s", err)
}
require.NoError(t, err, "failed local Symmetric: %s", err)

remoteSymmetric, err := p.symmetric(remoteNonce, localNonce)
if err != nil {
t.Fatalf("failed remote Symmetric: %s", err)
}
require.NoError(t, err, "failed remote Symmetric: %s", err)

remoteAsymmetric, err := p.asymmetric(remoteKey, &localKey.PublicKey)
if err != nil {
t.Fatalf("failed remote Asymmetric: %s", err)
}
require.NoError(t, err, "failed remote Asymmetric: %s", err)

// Symmetric Algorithm
plaintext := make([]byte, len(payload))
Expand All @@ -172,82 +133,57 @@ func TestEncryptionAlgorithms(t *testing.T) {
copy(paddedPlaintext, plaintext)

symCiphertext, err := localSymmetric.Encrypt(paddedPlaintext)
if err != nil {
t.Fatalf("failed to encrypt Symmetric: %s", err)
}
require.NoError(t, err, "failed to encrypt Symmetric: %s", err)

symDeciphered, err := remoteSymmetric.Decrypt(symCiphertext)
if err != nil {
t.Fatalf("failed to decrypt Symmetric: %s", err)
}
require.NoError(t, err, "failed to decrypt Symmetric: %s", err)

symDeciphered = symDeciphered[:len(symDeciphered)-padSize] // Trim off padding
if got, want := symDeciphered, plaintext; !bytes.Equal(got, want) {
t.Errorf("symmetric encryption failed:\ngot %#v want %#v\n", got, want)
}
require.Equal(t, plaintext, symDeciphered, "symmetric encryption failed")

// Modify the plaintext and detect if the decrypted message changes; if it does,
// our byte slices are referencing the same data and the previous test may have
// been a false positive
paddedPlaintext[4] = 0xff ^ paddedPlaintext[4]
if got, want := symDeciphered, payloadRef; !bytes.Equal(got, want) {
t.Errorf("symmetric input corruption detected:\ngot %#v want %#v\n", got, want)
}
require.Equal(t, payloadRef, symDeciphered, "symmetric input corruption detected")

symSignature, err := localSymmetric.Signature(paddedPlaintext)
if err != nil {
t.Errorf("symmetric signature generation failed")
}
require.NoError(t, err, "symmetric signature generation failed")

err = remoteSymmetric.VerifySignature(paddedPlaintext, symSignature)
if err != nil {
t.Errorf("symmetric signature validation failed")
}
require.NoError(t, err, "symmetric signature validation failed")

// Asymmetric Algorithm
asymCiphertext, err := localAsymmetric.Encrypt(plaintext)
if err != nil {
t.Fatalf("failed to encrypt Asymmetric: %s", err)
}
require.NoError(t, err, "failed to encrypt Asymmetric: %s", err)

asymDeciphered, err := remoteAsymmetric.Decrypt(asymCiphertext)
if err != nil {
t.Fatalf("failed to decrypt Asymmetric: %s", err)
}
if got, want := asymDeciphered, plaintext; !bytes.Equal(got, want) {
t.Errorf("asymmetric encryption failed:\ngot %#v want %#v\n", got, want)
}
require.NoError(t, err, "failed to decrypt Asymmetric: %s", err)

require.Equal(t, plaintext, asymDeciphered, "asymmetric encryption failed")

paddedPlaintext[4] = 0xff ^ paddedPlaintext[4]
if got, want := asymDeciphered, payloadRef; !bytes.Equal(got, want) {
t.Errorf("asymmetric input corruption detected:\ngot %#v want %#v\n", got, want)
}
require.Equal(t, payloadRef, asymDeciphered, "asymmetric input corruption detected")

asymSignature, err := localAsymmetric.Signature(plaintext)
if err != nil {
t.Errorf("asymmetric signature generation failed\n")
}
require.NoError(t, err, "asymmetric signature generation failed")

err = remoteAsymmetric.VerifySignature(plaintext, asymSignature)
if err != nil {
t.Errorf("asymmetric signature validation failed\n")
}
require.NoError(t, err, "asymmetric signature validation failed")
})
}
}

func TestMissingKey(t *testing.T) {
payload := make([]byte, 5000)
_, err := rand.Read(payload)
if err != nil {
t.Fatalf("could not generate random payload")
}
require.NoError(t, err, "could not generate random payload")

payloadRef := make([]byte, len(payload))
copy(payloadRef, payload)

key, err := generatePrivateKey(2048)
if err != nil {
t.Fatalf("Unable to generate private key\n")
}
require.NoError(t, err, "Unable to generate private key")

for uri, p := range policies {
if uri == ua.SecurityPolicyURINone {
Expand All @@ -256,87 +192,58 @@ func TestMissingKey(t *testing.T) {

t.Run(uri, func(t *testing.T) {
encryptOnly, err := p.asymmetric(nil, &key.PublicKey)
if err != nil {
t.Fatalf("failed to create encrypt-only asymmetric algorithms: %s", err)
}
require.NoError(t, err, "failed to create encrypt-only asymmetric algorithms")

decryptOnly, err := p.asymmetric(key, nil)
if err != nil {
t.Fatalf("failed to create decrypt-only asymmetric algorithms: %s", err)
}
require.NoError(t, err, "failed to create decrypt-only asymmetric algorithms")

ciphertext, err := encryptOnly.Encrypt(payload)
if err != nil {
t.Fatalf("failed to encrypt with encrypt-only policy: %s", err)
}
require.NoError(t, err, "failed to encrypt with encrypt-only policy")

signature, err := decryptOnly.Signature(payload)
if err != nil {
t.Fatalf("decrypt-only algorithm failed to generate signature: %s", err)
}
require.NoError(t, err, "decrypt-only algorithm failed to generate signature")

err = encryptOnly.VerifySignature(payload, signature)
if err != nil {
t.Fatalf("failed to verify signature with encrypt-only algorithm: %s", err)
}
require.NoError(t, err, "failed to verify signature with encrypt-only algorithm")

plaintext, err := decryptOnly.Decrypt(ciphertext)
if err != nil {
t.Fatalf("failed to decrypt with decrypt-only algorithm: %s", err)
}
require.NoError(t, err, "failed to decrypt with decrypt-only algorithm")

if got, want := plaintext, payloadRef; !bytes.Equal(got, want) {
t.Errorf("decryption failed:\ngot %#v want %#v\n", got, want)
}
require.Equal(t, payloadRef, plaintext, "decryption failed")

_, err = encryptOnly.Decrypt(ciphertext)
if err == nil {
t.Fatal("encrypt-only algorithm decrypted block without error - should be impossible")
}
require.Error(t, err, "encrypt-only algorithm decrypted block without error - should be impossible")

_, err = encryptOnly.Signature(payload)
if err == nil {
t.Fatalf("encrypt-only algorithm generated a signature without error - should be impossible")
}
require.Error(t, err, "encrypt-only algorithm generated a signature without error - should be impossible")

_, err = decryptOnly.Encrypt(payload)
if err == nil {
t.Fatal("decrypt-only algorithm encrypted block without error - should be impossible")
}
require.Error(t, err, "decrypt-only algorithm encrypted block without error - should be impossible")

err = decryptOnly.VerifySignature(payload, signature)
if err == nil {
t.Fatalf("decrypt-only algorithm verified a signature without error - should be impossible")
}

require.Error(t, err, "decrypt-only algorithm verified a signature without error - should be impossible")
})

}
}

func TestZeroStruct(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Error("panicked while checking zero value of struct", r)
}
}()

ze := &EncryptionAlgorithm{}

const payload string = "The quick brown fox jumps over the lazy dog."
plaintext := []byte(payload)

// Call all the methods and make sure they don't panic due to nil pointers
_ = ze.BlockSize()
_ = ze.PlaintextBlockSize()
_, _ = ze.Encrypt(plaintext)
_, _ = ze.Decrypt(plaintext)
_, _ = ze.Signature(plaintext)
_ = ze.VerifySignature(plaintext, plaintext)
_ = ze.NonceLength()
_ = ze.SignatureLength()
_ = ze.EncryptionURI()
_ = ze.SignatureURI()
require.NotPanics(t, func() { ze.BlockSize() })
require.NotPanics(t, func() { ze.PlaintextBlockSize() })
require.NotPanics(t, func() { ze.Encrypt(plaintext) })
require.NotPanics(t, func() { ze.Decrypt(plaintext) })
require.NotPanics(t, func() { ze.Signature(plaintext) })
require.NotPanics(t, func() { ze.VerifySignature(plaintext, plaintext) })
require.NotPanics(t, func() { ze.NonceLength() })
require.NotPanics(t, func() { ze.SignatureLength() })
require.NotPanics(t, func() { ze.EncryptionURI() })
require.NotPanics(t, func() { ze.SignatureURI() })
}

func generatePrivateKey(bitSize int) (*rsa.PrivateKey, error) {
Expand Down

0 comments on commit 4270340

Please sign in to comment.