Skip to content

Commit

Permalink
add evil twin tests
Browse files Browse the repository at this point in the history
Construct some simple RPKI hierarchies and try every possible object
insertion order to see if it's possible for a valid object with an
evil parent to ever be considered invalid.

addresses [bgpsecurity#29]
  • Loading branch information
rhansen committed Feb 18, 2016
1 parent 74671c7 commit 162eb00
Show file tree
Hide file tree
Showing 24 changed files with 483 additions and 0 deletions.
84 changes: 84 additions & 0 deletions mk/rpki.mk
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,90 @@ clean-local: clean-roa-ee-munge
clean-roa-ee-munge:
rm -rf tests/subsystem/roa-ee-munge/roa-ee-munge.tap.cache

######################################################################
## evil twin tests
######################################################################
EVIL_TWIN_TESTS = \
tests/subsystem/evil-twin/evil-twin-ca-invalid-1.tap \
tests/subsystem/evil-twin/evil-twin-ca-invalid-2.tap \
tests/subsystem/evil-twin/evil-twin-ca-valid-1.tap \
tests/subsystem/evil-twin/evil-twin-ca-valid-2.tap \
tests/subsystem/evil-twin/evil-twin-ee-invalid.tap \
tests/subsystem/evil-twin/evil-twin-ee-valid.tap
TESTS += ${EVIL_TWIN_TESTS}
EXTRA_DIST += ${EVIL_TWIN_TESTS}
check_SCRIPTS += \
tests/subsystem/evil-twin/evil-twin-common.sh
tests/subsystem/evil-twin/evil-twin-common.sh: \
tests/subsystem/evil-twin/evil-twin-common.sh.in
MK_SUBST_FILES += \
tests/subsystem/evil-twin/evil-twin-common.sh
CERTS += \
tests/subsystem/evil-twin/ta-good.cer \
tests/subsystem/evil-twin/ta-evil.cer \
tests/subsystem/evil-twin/ca-good.cer \
tests/subsystem/evil-twin/ca-evil-invalid.cer \
tests/subsystem/evil-twin/ca-evil-valid.cer \
tests/subsystem/evil-twin/test1-ca.cer \
tests/subsystem/evil-twin/test2-ee.cer \
tests/subsystem/evil-twin/ee-good.cer \
tests/subsystem/evil-twin/ee-evil-invalid.cer \
tests/subsystem/evil-twin/ee-evil-valid.cer
ROAS += \
tests/subsystem/evil-twin/test2-ee.roa \
tests/subsystem/evil-twin/ee-good.roa \
tests/subsystem/evil-twin/ee-evil-invalid.roa \
tests/subsystem/evil-twin/ee-evil-valid.roa
tests/subsystem/evil-twin/ta-good.cer: \
tests/subsystem/evil-twin/ta-good.options \
tests/subsystem/evil-twin/ta-good.key
tests/subsystem/evil-twin/ta-evil.cer: \
tests/subsystem/evil-twin/ta-evil.options \
tests/subsystem/evil-twin/ta-evil.key
tests/subsystem/evil-twin/ca-good.cer: \
tests/subsystem/evil-twin/ca-good.options \
tests/subsystem/evil-twin/ca-good.key
tests/subsystem/evil-twin/ca-evil-invalid.cer: \
tests/subsystem/evil-twin/ca-evil-invalid.options \
tests/subsystem/evil-twin/ca-evil-invalid.key
tests/subsystem/evil-twin/ca-evil-valid.cer: \
tests/subsystem/evil-twin/ca-evil-valid.options \
tests/subsystem/evil-twin/ca-evil-valid.key
tests/subsystem/evil-twin/test1-ca.cer: \
tests/subsystem/evil-twin/test1-ca.options \
tests/subsystem/evil-twin/test1-ca.key
tests/subsystem/evil-twin/test2-ee.cer: \
tests/subsystem/evil-twin/test2-ee.options \
tests/subsystem/evil-twin/test2-ee.key
tests/subsystem/evil-twin/test2-ee.roa: \
tests/subsystem/evil-twin/test2-ee.cer \
tests/subsystem/evil-twin/test2-ee.key \
tests/subsystem/evil-twin/test2-ee.roa.options
tests/subsystem/evil-twin/ee-good.cer: \
tests/subsystem/evil-twin/ee-good.options \
tests/subsystem/evil-twin/ee-good.key
tests/subsystem/evil-twin/ee-good.roa: \
tests/subsystem/evil-twin/ee-good.cer \
tests/subsystem/evil-twin/ee-good.key \
tests/subsystem/evil-twin/ee-good.roa.options
tests/subsystem/evil-twin/ee-evil-invalid.cer: \
tests/subsystem/evil-twin/ee-evil-invalid.options \
tests/subsystem/evil-twin/ee-evil-invalid.key
tests/subsystem/evil-twin/ee-evil-invalid.roa: \
tests/subsystem/evil-twin/ee-evil-invalid.cer \
tests/subsystem/evil-twin/ee-evil-invalid.key \
tests/subsystem/evil-twin/ee-evil-invalid.roa.options
tests/subsystem/evil-twin/ee-evil-valid.cer: \
tests/subsystem/evil-twin/ee-evil-valid.options \
tests/subsystem/evil-twin/ee-evil-valid.key
tests/subsystem/evil-twin/ee-evil-valid.roa: \
tests/subsystem/evil-twin/ee-evil-valid.cer \
tests/subsystem/evil-twin/ee-evil-valid.key \
tests/subsystem/evil-twin/ee-evil-valid.roa.options
clean-local: clean-evil-twin
clean-evil-twin:
rm -rf ${EVIL_TWIN_TESTS:=.cache}

######################################################################
## chaser
######################################################################
Expand Down
5 changes: 5 additions & 0 deletions tests/subsystem/evil-twin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/*.cache/
/*.cer
/*.key
/*.roa
/evil-twin-common.sh
21 changes: 21 additions & 0 deletions tests/subsystem/evil-twin/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
This directory contains tests for vulnerabilities to the "evil twin"
attack.

The goal of the evil twin attack is to make a good object look bad.
The malicious CA signs and publishes a certificate that reuses the
public key, subject, and SKI from a victim certificate. This new
certificate (the "evil twin" certificate) is either:

* invalid because it uses resources not held by the malicious CA, or

* valid but not a valid parent of the objects signed by the victim
certificate because the objects signed by the victim certificate
have resources outside of the evil twin certificate.

Either way, if the RP software is buggy and considers the evil twin to
be the parent of objects that were actually signed by the victim
(because the subject, SKI, and public keys match), those good objects
would be incorrectly invalidated.

The test scripts in this directory use different toy hierarchies to
cover a wide range of scenarios.
12 changes: 12 additions & 0 deletions tests/subsystem/evil-twin/ca-evil-invalid.options
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
type=CA
issuer=ta-evil
subject=ca-good
aia=rsync://invalid/
sia=r:rsync://invalid/,m:rsync://invalid/invalid.mft
ipv4=0.0.0.0/16
ipv6=::/32
as=1-63
selfsigned=false
parentcertfile=tests/subsystem/evil-twin/ta-evil.cer
parentkeyfile=tests/subsystem/evil-twin/ta-evil.key
subjkeyfile=tests/subsystem/evil-twin/ca-good.key
12 changes: 12 additions & 0 deletions tests/subsystem/evil-twin/ca-evil-valid.options
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
type=CA
issuer=ta-evil
subject=ca-good
aia=rsync://invalid/
sia=r:rsync://invalid/,m:rsync://invalid/invalid.mft
ipv4=1.0.0.0/16
ipv6=1::/32
as=128-191
selfsigned=false
parentcertfile=tests/subsystem/evil-twin/ta-evil.cer
parentkeyfile=tests/subsystem/evil-twin/ta-evil.key
subjkeyfile=tests/subsystem/evil-twin/ca-good.key
12 changes: 12 additions & 0 deletions tests/subsystem/evil-twin/ca-good.options
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
type=CA
issuer=ta-good
subject=ca-good
aia=rsync://invalid/
sia=r:rsync://invalid/,m:rsync://invalid/invalid.mft
ipv4=0.0.0.0/16
ipv6=::/32
as=1-63
selfsigned=false
parentcertfile=tests/subsystem/evil-twin/ta-good.cer
parentkeyfile=tests/subsystem/evil-twin/ta-good.key
subjkeyfile=tests/subsystem/evil-twin/ca-good.key
12 changes: 12 additions & 0 deletions tests/subsystem/evil-twin/ee-evil-invalid.options
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
type=EE
issuer=ta-evil
subject=ee-good
aia=rsync://invalid/
sia=s:rsync://invalid/
ipv4=0.0.0.0/24
ipv6=::/48
as=1-31
selfsigned=false
parentcertfile=tests/subsystem/evil-twin/ta-evil.cer
parentkeyfile=tests/subsystem/evil-twin/ta-evil.key
subjkeyfile=tests/subsystem/evil-twin/ee-good.key
3 changes: 3 additions & 0 deletions tests/subsystem/evil-twin/ee-evil-invalid.roa.options
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
roaipv4=0.0.0.0/25
roaipv6=::/64
asid=1
12 changes: 12 additions & 0 deletions tests/subsystem/evil-twin/ee-evil-valid.options
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
type=EE
issuer=ta-evil
subject=ee-good
aia=rsync://invalid/
sia=s:rsync://invalid/
ipv4=1.0.0.0/24
ipv6=1::/48
as=128-159
selfsigned=false
parentcertfile=tests/subsystem/evil-twin/ta-evil.cer
parentkeyfile=tests/subsystem/evil-twin/ta-evil.key
subjkeyfile=tests/subsystem/evil-twin/ee-good.key
3 changes: 3 additions & 0 deletions tests/subsystem/evil-twin/ee-evil-valid.roa.options
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
roaipv4=0.0.0.0/25
roaipv6=::/64
asid=1
12 changes: 12 additions & 0 deletions tests/subsystem/evil-twin/ee-good.options
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
type=EE
issuer=ta-good
subject=ee-good
aia=rsync://invalid/
sia=s:rsync://invalid/
ipv4=0.0.0.0/24
ipv6=::/48
as=1-31
selfsigned=false
parentcertfile=tests/subsystem/evil-twin/ta-good.cer
parentkeyfile=tests/subsystem/evil-twin/ta-good.key
subjkeyfile=tests/subsystem/evil-twin/ee-good.key
3 changes: 3 additions & 0 deletions tests/subsystem/evil-twin/ee-good.roa.options
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
roaipv4=0.0.0.0/25
roaipv6=::/64
asid=1
40 changes: 40 additions & 0 deletions tests/subsystem/evil-twin/evil-twin-ca-invalid-1.tap
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/bin/sh

# This scenario uses the following forest:
#
#
# Good TA (valid) Evil TA (valid)
# IPv4: 0.0.0.0/8 IPv4: 1.0.0.0/8
# IPv6: ::/16 IPv6: 1::/16
# AS: 1-127 AS: 128-255
# | |
# | |
# Good CA (valid) Evil CA (invalid, this is the "evil twin" of Good CA)
# IPv4: 0.0.0.0/16 IPv4: 0.0.0.0/16 (outside of issuer resoures)
# IPv6: ::/32 IPv6: ::/32 (outside of issuer resources)
# AS: 1-63 AS: 1-63 (outside of issuer resources)
# |
# |
# Test1 CA (valid)
# IPv4: 0.0.0.0/24
# IPv6: ::/48
# AS: 1-31
#
# The five objects above are added to the database one at a time. To
# ensure that the order in which the objects are added does not affect
# the outcome, all permutations are tried (the database is scrubbed
# between permutations). The result looks like this:
#
# 1. ta-good.cer ta-evil.cer ca-good.cer ca-evil.cer test1-ca.cer
# 2. ta-good.cer ta-evil.cer ca-good.cer test1-ca.cer ca-evil.cer
# 3. ta-good.cer ta-evil.cer ca-evil.cer ca-good.cer test1-ca.cer
# 4. ta-good.cer ta-evil.cer ca-evil.cer test1-ca.cer ca-good.cer
# ...
# 120. test1-ca.cer ca-evil.cer ca-good.cer ta-evil.cer ta-good.cer

. "${TESTS_BUILDDIR}"/evil-twin-common.sh || exit 1

files="ta-good.cer ta-evil.cer ca-good.cer ca-evil-invalid.cer test1-ca.cer"
exp="ta-good.cer ta-evil.cer ca-good.cer test1-ca.cer"

run_tests "${files}" "${exp}"
32 changes: 32 additions & 0 deletions tests/subsystem/evil-twin/evil-twin-ca-invalid-2.tap
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/sh

# This scenario is the same as evil-twin-ca-invalid-1 except the Test1
# CA certificate is replaced by a ROA:
#
# Good TA (valid) Evil TA (valid)
# IPv4: 0.0.0.0/8 IPv4: 1.0.0.0/8
# IPv6: ::/16 IPv6: 1::/16
# AS: 1-127 AS: 128-255
# | |
# | |
# Good CA (valid) Evil CA (invalid, this is the "evil twin" of Good CA)
# IPv4: 0.0.0.0/16 IPv4: 0.0.0.0/16 (outside of issuer resoures)
# IPv6: ::/32 IPv6: ::/32 (outside of issuer resources)
# AS: 1-63 AS: 1-63 (outside of issuer resources)
# |
# |
# Test2 ROA (valid)
# IPv4: 0.0.0.0/25
# IPv6: ::/64
# AS: 1
# via Test2 EE (valid):
# IPv4: 0.0.0.0/24
# IPv6: ::/48
# AS: 1-31

. "${TESTS_BUILDDIR}"/evil-twin-common.sh || exit 1

files="ta-good.cer ta-evil.cer ca-good.cer ca-evil-invalid.cer test2-ee.roa"
exp="ta-good.cer ta-evil.cer ca-good.cer test2-ee.roa test2-ee.roa.cer"

run_tests "${files}" "${exp}"
48 changes: 48 additions & 0 deletions tests/subsystem/evil-twin/evil-twin-ca-valid-1.tap
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/sh

# This scenario is the same as evil-twin-ca-invalid-1 except the Evil
# CA certificate has its resources altered to be valid:
#
# Good TA (valid) Evil TA (valid)
# IPv4: 0.0.0.0/8 IPv4: 1.0.0.0/8
# IPv6: ::/16 IPv6: 1::/16
# AS: 1-127 AS: 128-255
# | |
# | |
# Good CA (valid) Evil CA (valid, this is the "evil twin" of Good CA)
# IPv4: 0.0.0.0/16 IPv4: 1.0.0.0/16 (modified resources to be valid)
# IPv6: ::/32 IPv6: 1::/32 (modified resources to be valid)
# AS: 1-63 AS: 128-191 (modified resources to be valid)
# |
# |
# Test1 CA (valid)
# IPv4: 0.0.0.0/24
# IPv6: ::/48
# AS: 1-31

. "${TESTS_BUILDDIR}"/evil-twin-common.sh || exit 1

files="ta-good.cer ta-evil.cer ca-good.cer ca-evil-valid.cer test1-ca.cer"
exp=${files}

# override testcase() to set xfail for cases that are known to fail
testcase() {
pass=true
# if the evil hierarchy is completely added before the test CA, or
# if the entire evil hierarchy and the test CA are added before
# the good hierarchy is completely added, then it will fail.
# stated another way, if the good hierarchy and test CA are added
# before the bad hierarchy is completely added, then it will pass.
case $(printf " %s " $4) in
*evil*evil*" test1-ca.cer "*) pass=false;;
*evil*" test1-ca.cer "*evil*good*) pass=false;;
*" test1-ca.cer "*evil*evil*good*) pass=false;;
esac
if "${pass}"; then
t4s_testcase "$@"
else
t4s_testcase --xfail "see ticket #29" "$@"
fi
}

run_tests "${files}" "${exp}"
52 changes: 52 additions & 0 deletions tests/subsystem/evil-twin/evil-twin-ca-valid-2.tap
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/bin/sh

# This scenario is the same as evil-twin-ca-valid-1 except the Test1
# CA certificate is replaced with a ROA as in evil-twin-ca-invalid-2:
#
# Good TA (valid) Evil TA (valid)
# IPv4: 0.0.0.0/8 IPv4: 1.0.0.0/8
# IPv6: ::/16 IPv6: 1::/16
# AS: 1-127 AS: 128-255
# | |
# | |
# Good CA (valid) Evil CA (valid, this is the "evil twin" of Good CA)
# IPv4: 0.0.0.0/16 IPv4: 1.0.0.0/16 (modified resources to be valid)
# IPv6: ::/32 IPv6: 1::/32 (modified resources to be valid)
# AS: 1-63 AS: 128-191 (modified resources to be valid)
# |
# |
# Test2 ROA (valid)
# IPv4: 0.0.0.0/25
# IPv6: ::/64
# AS: 1
# via Test2 EE (valid):
# IPv4: 0.0.0.0/24
# IPv6: ::/48
# AS: 1-31

. "${TESTS_BUILDDIR}"/evil-twin-common.sh || exit 1

files="ta-good.cer ta-evil.cer ca-good.cer ca-evil-valid.cer test2-ee.roa"
exp=${files}" test2-ee.roa.cer"

# override testcase() to set xfail for cases that are known to fail
testcase() {
pass=true
# if the evil hierarchy is completely added before the test ROA,
# or if the entire evil hierarchy and the test ROA are added
# before the good hierarchy is completely added, then it will fail
# stated another way, if the good hierarchy and test ROA are added
# before the bad hierarchy is completely added, then it will pass.
case $(printf " %s " $4) in
*evil*evil*" test2-ee.roa "*) pass=false;;
*evil*" test2-ee.roa "*evil*good*) pass=false;;
*" test2-ee.roa "*evil*evil*good*) pass=false;;
esac
if "${pass}"; then
t4s_testcase "$@"
else
t4s_testcase --xfail "see ticket #29" "$@"
fi
}

run_tests "${files}" "${exp}"
13 changes: 13 additions & 0 deletions tests/subsystem/evil-twin/evil-twin-common.sh.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@SETUP_ENVIRONMENT@

t4s_setup

u=${TESTS_TOP_SRCDIR}/tests/util.sh
. "${u}" || t4s_bailout "unable to load ${u}"

cd "${TESTS_BUILDDIR}" || t4s_bailout "unable to cd to ${TESTS_BUILDDIR}"

run_tests() {
test_perms "${0##*/}".cache "$@"
t4s_done
}
Loading

0 comments on commit 162eb00

Please sign in to comment.