aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuraj Somorovsky <[email protected]>2016-09-17 14:44:40 +0200
committerJuraj Somorovsky <[email protected]>2016-09-30 00:57:29 +0200
commit863fc12c6ebcc96ed10a7c8896fea033a78fbb5d (patch)
tree129adf63325c4dd6b9ea58b5e397fe3aee28bb41
parentebe2f21dde0bd26261af633a96867df2372779cb (diff)
New TLS positive and negative tests.
TLS message parsing: - CertificateVerify - HelloVerify - ClientHello (with extensions) - ServerHello (with extensions) - NewSessionTicket - Alert TLS message processing: - HelloVerify TLS Policy tests Unit tests with TLS client authentication Added test_throws method that checks the correct exception message.
-rw-r--r--src/lib/tls/tls_extensions.h2
-rw-r--r--src/lib/tls/tls_messages.h12
-rw-r--r--src/tests/data/tls/alert.vec24
-rw-r--r--src/tests/data/tls/cert_verify.vec40
-rw-r--r--src/tests/data/tls/client_hello.vec68
-rw-r--r--src/tests/data/tls/hello_request.vec8
-rw-r--r--src/tests/data/tls/hello_verify.vec26
-rw-r--r--src/tests/data/tls/new_session_ticket.vec20
-rw-r--r--src/tests/data/tls/server_hello.vec48
-rw-r--r--src/tests/test_tls_messages.cpp203
-rw-r--r--src/tests/tests.cpp23
-rw-r--r--src/tests/tests.h3
-rw-r--r--src/tests/unit_tls.cpp14
-rw-r--r--src/tests/unit_tls_policy.cpp162
14 files changed, 642 insertions, 11 deletions
diff --git a/src/lib/tls/tls_extensions.h b/src/lib/tls/tls_extensions.h
index 4bd564a85..c270bf23a 100644
--- a/src/lib/tls/tls_extensions.h
+++ b/src/lib/tls/tls_extensions.h
@@ -366,7 +366,7 @@ class Encrypt_then_MAC final : public Extension
/**
* Represents a block of extensions in a hello message
*/
-class Extensions
+class BOTAN_DLL Extensions
{
public:
std::set<Handshake_Extension_Type> extension_types() const;
diff --git a/src/lib/tls/tls_messages.h b/src/lib/tls/tls_messages.h
index cf35053f2..698dbc99f 100644
--- a/src/lib/tls/tls_messages.h
+++ b/src/lib/tls/tls_messages.h
@@ -40,7 +40,7 @@ std::vector<byte> make_hello_random(RandomNumberGenerator& rng,
/**
* DTLS Hello Verify Request
*/
-class Hello_Verify_Request final : public Handshake_Message
+class BOTAN_DLL Hello_Verify_Request final : public Handshake_Message
{
public:
std::vector<byte> serialize() const override;
@@ -60,7 +60,7 @@ class Hello_Verify_Request final : public Handshake_Message
/**
* Client Hello Message
*/
-class Client_Hello final : public Handshake_Message
+class BOTAN_DLL Client_Hello final : public Handshake_Message
{
public:
class Settings
@@ -234,7 +234,7 @@ class Client_Hello final : public Handshake_Message
/**
* Server Hello Message
*/
-class Server_Hello final : public Handshake_Message
+class BOTAN_DLL Server_Hello final : public Handshake_Message
{
public:
class Settings
@@ -452,7 +452,7 @@ class Certificate_Req final : public Handshake_Message
/**
* Certificate Verify Message
*/
-class Certificate_Verify final : public Handshake_Message
+class BOTAN_DLL Certificate_Verify final : public Handshake_Message
{
public:
Handshake_Type type() const override { return CERTIFICATE_VERIFY; }
@@ -510,7 +510,7 @@ class Finished final : public Handshake_Message
/**
* Hello Request Message
*/
-class Hello_Request final : public Handshake_Message
+class BOTAN_DLL Hello_Request final : public Handshake_Message
{
public:
Handshake_Type type() const override { return HELLO_REQUEST; }
@@ -592,7 +592,7 @@ class Server_Hello_Done final : public Handshake_Message
/**
* New Session Ticket Message
*/
-class New_Session_Ticket final : public Handshake_Message
+class BOTAN_DLL New_Session_Ticket final : public Handshake_Message
{
public:
Handshake_Type type() const override { return NEW_SESSION_TICKET; }
diff --git a/src/tests/data/tls/alert.vec b/src/tests/data/tls/alert.vec
new file mode 100644
index 000000000..19ec8839b
--- /dev/null
+++ b/src/tests/data/tls/alert.vec
@@ -0,0 +1,24 @@
+# Alert message contains the following fields:
+# - Fatal (1 byte): 1=false, 2=true
+# - Type (1 byte)
+
+[alert]
+Buffer = 0130
+Exception =
+
+Buffer = 0230
+Exception =
+
+Buffer = 0231
+Exception =
+
+Buffer = 0030
+Protocol = 0303
+Exception = Invalid argument Decoding error: Alert: Bad code for alert level
+
+Buffer = 02
+Exception = Invalid argument Decoding error: Alert: Bad size 1 for alert message
+
+Buffer = 020101
+Exception = Invalid argument Decoding error: Alert: Bad size 3 for alert message
+
diff --git a/src/tests/data/tls/cert_verify.vec b/src/tests/data/tls/cert_verify.vec
new file mode 100644
index 000000000..f812d1c6a
--- /dev/null
+++ b/src/tests/data/tls/cert_verify.vec
@@ -0,0 +1,40 @@
+# Tests generated partially with openssl 1.0.2g
+# CertificateVerify message contains the following fields:
+# - SignatureAndHash Algorithm (2 bytes) [only in TLS 1.2]
+# - Certificate length (2 bytes)
+# - Certificate
+
+[cert_verify]
+Buffer = 06010080266481066a8431582157a9a591150d418b63d46154c4cd85bffcfdba8c7f6396f0ceb0402c2142c526a19659d58cd4111bf45f57a56e97d16eeecd350f6e9dc93662e4361053666e5a53c74fe11bd6cf86a9cf7a2488704c5121915820973280ed6afa3e8b79dfb799bddffb52caa2d1a0a895a0e7505d841a882bdd92ec9141
+Protocol = 0303
+Exception =
+
+Buffer = 008080c920a228dc3f32927fd8026a97fb8474603191a89c49aeeddd1b1caf7f28d6af7b9b7c0bc6b954e909f3d054eb3964d626402b7c932c019111bc854007c90c134d6adce505e5cd60292331f7645fba909017565fc60ee76a5eb6b6a89ab2a3d69be6c0e283ae5a84b1fc367c1a865c35dd8a1c93ac3d538d91a2d5128d8d52
+Protocol = 0302
+Exception =
+
+Buffer = 0080bb6b1df8c744f961ee3f5334448fac4af0f372763149972b88bec525a3196f87cf0204a50fd516b6808530252d1c6b79414b8b9194b3c5e2958adab5524bc124e16d9f3b05f5bf63c0b184709ce6586a0a4b267280b47576893406c381a401b10bcc5f111b14cd8ce889b5d48fbe47f465cf70bf23b71109f81d4574bbf6f93f
+Protocol = 0301
+Exception =
+
+Buffer = 0601000100
+Protocol = 0303
+Exception =
+
+#Incomplete algorithm
+Buffer = 06
+Protocol = 0303
+Exception = Invalid argument Decoding error: Invalid CertificateVerify: Expected 1 bytes remaining, only 0 left
+
+#Incomplete certificate
+Buffer = 0601000500
+Protocol = 0303
+Exception = Invalid argument Decoding error: Invalid CertificateVerify: Expected 5 bytes remaining, only 1 left
+
+Buffer = 000200
+Protocol = 0302
+Exception = Invalid argument Decoding error: Invalid CertificateVerify: Expected 2 bytes remaining, only 1 left
+
+Buffer = 000200
+Protocol = 0301
+Exception = Invalid argument Decoding error: Invalid CertificateVerify: Expected 2 bytes remaining, only 1 left \ No newline at end of file
diff --git a/src/tests/data/tls/client_hello.vec b/src/tests/data/tls/client_hello.vec
new file mode 100644
index 000000000..d629e3f6e
--- /dev/null
+++ b/src/tests/data/tls/client_hello.vec
@@ -0,0 +1,68 @@
+# Tests generated partially with openssl 1.0.2g/1.1.0a and TLS-Attacker
+# ClientHello message contains many fields, the following fields are checked:
+# - Protocol Version
+# - Extensions
+
+[client_hello]
+# no extension (empty renegotiation generated)
+Buffer = 030320f3dc33f90be6509e6133a1819f2b80fe6ccc6268d9195ca4ead7504ffe7e2a0000aac030c02cc028c024c014c00a00a500a300a1009f006b006a0069006800390038003700360088008700860085c032c02ec02ac026c00fc005009d003d00350084c02fc02bc027c023c013c00900a400a200a0009e00670040003f003e0033003200310030009a0099009800970045004400430042c031c02dc029c025c00ec004009c003c002f00960041c011c007c00cc00200050004c012c008001600130010000dc00dc003000a00ff01000000
+Protocol = 0303
+AdditionalData = FF01
+Exception =
+
+# with extensions: point formats, ec curves, session ticket, signature algorithms, heartbeat (point formats and heartbeat not supported, empty renegotiation generated)
+Buffer = 0303871e18983024eaee1be8ae6607d5ecad941d33fd7fc1d8554a9e1fbfda8d30880000aac030c02cc028c024c014c00a00a500a300a1009f006b006a0069006800390038003700360088008700860085c032c02ec02ac026c00fc005009d003d00350084c02fc02bc027c023c013c00900a400a200a0009e00670040003f003e0033003200310030009a0099009800970045004400430042c031c02dc029c025c00ec004009c003c002f00960041c011c007c00cc00200050004c012c008001600130010000dc00dc003000a00ff01000055000b000403000102000a001c001a00170019001c001b0018001a0016000e000d000b000c0009000a00230000000d0020001e060106020603050105020503040104020403030103020303020102020203000f000101
+Protocol = 0303
+AdditionalData = 000A000D0023FF01
+Exception =
+
+# with extensions: point formats, ec curves, session ticket, signature algorithms, heartbeat, Encrypt-then-MAC, Extended Master Secret (point formats and heartbeat not supported, empty renegotiation generated)
+Buffer = 0303e00da23523058b5dc9c445d97b2bb6315b019e97838ac4f16c23b2cb031b6a490000e2c0afc0adc030c02cc028c024c014c00ac0a3c09f00a500a300a1009f006b006a006900680039003800370036cca9cca8c077c073ccaa00c400c300c200c10088008700860085c032c02ec02ac026c00fc005c079c075c0a1c09d009d003d003500c00084c0aec0acc02fc02bc027c023c013c009c0a2c09e00a400a200a0009e00670040003f003e0033003200310030c076c07200be00bd00bc00bb009a0099009800970045004400430042c031c02dc029c025c00ec004c078c074c0a0c09c009c003c002f00ba009600410007c012c008001600130010000dc00dc003000a00ff0100005f000b000403000102000a001c001a00170019001c001b0018001a0016000e000d000b000c0009000a00230000000d00220020060106020603050105020503040104020403030103020303020102020203eded000f0001010016000000170000
+Protocol = 0303
+AdditionalData = 000A000D001600170023FF01
+Exception =
+
+# empty
+Buffer =
+Protocol = 0303
+Exception = Invalid argument Decoding error: Client_Hello: Packet corrupted
+
+Buffer = 00
+Protocol = 0303
+Exception = Invalid argument Decoding error: Client_Hello: Packet corrupted
+
+# Invalid cipher suite length (0xf0e2 instead of 0x00e2)
+Buffer = 0303e00da23523058b5dc9c445d97b2bb6315b019e97838ac4f16c23b2cb031b6a4900f0e2c0afc0adc030c02cc028c024c014c00ac0a3c09f00a500a300a1009f006b006a006900680039003800370036cca9cca8c077c073ccaa00c400c300c200c10088008700860085c032c02ec02ac026c00fc005c079c075c0a1c09d009d003d003500c00084c0aec0acc02fc02bc027c023c013c009c0a2c09e00a400a200a0009e00670040003f003e0033003200310030c076c07200be00bd00bc00bb009a0099009800970045004400430042c031c02dc029c025c00ec004c078c074c0a0c09c009c003c002f00ba009600410007c012c008001600130010000dc00dc003000a00ff01000000
+Protocol = 0303
+AdditionalData =
+Exception = Invalid argument Decoding error: Invalid ClientHello: Expected 61666 bytes remaining, only 230 left
+
+#invalid extensions length
+Buffer = 030320f3dc33f90be6509e6133a1819f2b80fe6ccc6268d9195ca4ead7504ffe7e2a0000aac030c02cc028c024c014c00a00a500a300a1009f006b006a0069006800390038003700360088008700860085c032c02ec02ac026c00fc005009d003d00350084c02fc02bc027c023c013c00900a400a200a0009e00670040003f003e0033003200310030009a0099009800970045004400430042c031c02dc029c025c00ec004009c003c002f00960041c011c007c00cc00200050004c012c008001600130010000dc00dc003000a00ff01000001
+Protocol = 0303
+Exception = Invalid argument Decoding error: Bad extension size
+
+#invalid extensions length 2
+Buffer = 030320f3dc33f90be6509e6133a1819f2b80fe6ccc6268d9195ca4ead7504ffe7e2a0000aac030c02cc028c024c014c00a00a500a300a1009f006b006a0069006800390038003700360088008700860085c032c02ec02ac026c00fc005009d003d00350084c02fc02bc027c023c013c00900a400a200a0009e00670040003f003e0033003200310030009a0099009800970045004400430042c031c02dc029c025c00ec004009c003c002f00960041c011c007c00cc00200050004c012c008001600130010000dc00dc003000a00ff010000010000
+Protocol = 0303
+Exception = Invalid argument Decoding error: Bad extension size
+
+#invalid length of the elliptic curve extension (0xf01c instead of 0x001c)
+Buffer = 0303871e18983024eaee1be8ae6607d5ecad941d33fd7fc1d8554a9e1fbfda8d30880000aac030c02cc028c024c014c00a00a500a300a1009f006b006a0069006800390038003700360088008700860085c032c02ec02ac026c00fc005009d003d00350084c02fc02bc027c023c013c00900a400a200a0009e00670040003f003e0033003200310030009a0099009800970045004400430042c031c02dc029c025c00ec004009c003c002f00960041c011c007c00cc00200050004c012c008001600130010000dc00dc003000a00ff01000055000b000403000102000af01c001a00170019001c001b0018001a0016000e000d000b000c0009000a00230000000d0020001e060106020603050105020503040104020403030103020303020102020203000f000101
+Protocol = 0303
+Exception = Invalid argument Decoding error: Inconsistent length field in elliptic curve list
+
+#invalid length of the elliptic curve extension (0xf01a instead of 0x001a)
+Buffer = 0303871e18983024eaee1be8ae6607d5ecad941d33fd7fc1d8554a9e1fbfda8d30880000aac030c02cc028c024c014c00a00a500a300a1009f006b006a0069006800390038003700360088008700860085c032c02ec02ac026c00fc005009d003d00350084c02fc02bc027c023c013c00900a400a200a0009e00670040003f003e0033003200310030009a0099009800970045004400430042c031c02dc029c025c00ec004009c003c002f00960041c011c007c00cc00200050004c012c008001600130010000dc00dc003000a00ff01000055000b000403000102000a001cf01a00170019001c001b0018001a0016000e000d000b000c0009000a00230000000d0020001e060106020603050105020503040104020403030103020303020102020203000f000101
+Protocol = 0303
+Exception = Invalid argument Decoding error: Inconsistent length field in elliptic curve list
+
+#invalid length of the session ticket extension
+Buffer = 0303871e18983024eaee1be8ae6607d5ecad941d33fd7fc1d8554a9e1fbfda8d30880000aac030c02cc028c024c014c00a00a500a300a1009f006b006a0069006800390038003700360088008700860085c032c02ec02ac026c00fc005009d003d00350084c02fc02bc027c023c013c00900a400a200a0009e00670040003f003e0033003200310030009a0099009800970045004400430042c031c02dc029c025c00ec004009c003c002f00960041c011c007c00cc00200050004c012c008001600130010000dc00dc003000a00ff01000055000b000403000102000a001c001a00170019001c001b0018001a0016000e000d000b000c0009000a002300ff000d0020001e060106020603050105020503040104020403030103020303020102020203000f000101
+Protocol = 0303
+Exception = Invalid argument Decoding error: Invalid ClientHello: Expected 255 bytes remaining, only 41 left
+
+#invalid length of the heartbeat extension
+Buffer = 0303871e18983024eaee1be8ae6607d5ecad941d33fd7fc1d8554a9e1fbfda8d30880000aac030c02cc028c024c014c00a00a500a300a1009f006b006a0069006800390038003700360088008700860085c032c02ec02ac026c00fc005009d003d00350084c02fc02bc027c023c013c00900a400a200a0009e00670040003f003e0033003200310030009a0099009800970045004400430042c031c02dc029c025c00ec004009c003c002f00960041c011c007c00cc00200050004c012c008001600130010000dc00dc003000a00ff01000055000b000403000102000a001c001a00170019001c001b0018001a0016000e000d000b000c0009000a00230000000d0020001e060106020603050105020503040104020403030103020303020102020203000f000201
+Protocol = 0303
+Exception = Invalid argument Decoding error: Invalid ClientHello: Expected 2 bytes remaining, only 1 left \ No newline at end of file
diff --git a/src/tests/data/tls/hello_request.vec b/src/tests/data/tls/hello_request.vec
new file mode 100644
index 000000000..3a7471ae4
--- /dev/null
+++ b/src/tests/data/tls/hello_request.vec
@@ -0,0 +1,8 @@
+# HelloRequest message does not contain any bytes
+
+[hello_request]
+Buffer =
+Exception =
+
+Buffer = 01
+Exception = Invalid argument Decoding error: Bad Hello_Request, has non-zero size
diff --git a/src/tests/data/tls/hello_verify.vec b/src/tests/data/tls/hello_verify.vec
new file mode 100644
index 000000000..f5db9e085
--- /dev/null
+++ b/src/tests/data/tls/hello_verify.vec
@@ -0,0 +1,26 @@
+# Tests generated partially with openssl 1.0.2g
+# HelloVerify message contains the following fields:
+# - Protocol version (2 bytes)
+# - Cookie length (1 byte)
+# - Cookie
+
+[hello_verify]
+Buffer = feff14925523e7539a13d9782af6d771b97d0032c61800
+Exception =
+
+# HelloVerify request has to contain at least 3 bytes
+Buffer = 0101
+Exception = Invalid argument Decoding error: Hello verify request too small
+
+# HelloVerify has to contain valid protocol version
+Buffer = 010100
+Exception = Invalid argument Decoding error: Unknown version from server in hello verify request
+
+# HelloVerify has to contain valid number of bytes
+Buffer = FEFD0000
+Exception = Invalid argument Decoding error: Bad length in hello verify request
+
+# HelloVerify has to contain valid number of bytes
+Buffer = FEFD0500
+Exception = Invalid argument Decoding error: Bad length in hello verify request
+
diff --git a/src/tests/data/tls/new_session_ticket.vec b/src/tests/data/tls/new_session_ticket.vec
new file mode 100644
index 000000000..22c03611e
--- /dev/null
+++ b/src/tests/data/tls/new_session_ticket.vec
@@ -0,0 +1,20 @@
+# NewSessionTicket message contains the following fields:
+# - lifetime (4 bytes)
+# - length (2 bytes)
+# - session ticket
+
+[new_session_ticket]
+Buffer = 000000000000
+Exception =
+
+Buffer = 00000000000100
+Exception =
+
+Buffer = 0000000000051122334455
+Exception =
+
+Buffer = 0001
+Exception = Invalid argument Decoding error: Session ticket message too short to be valid
+
+Buffer = 00010203000500
+Exception = Invalid argument Decoding error: Invalid SessionTicket: Expected 5 bytes remaining, only 1 left \ No newline at end of file
diff --git a/src/tests/data/tls/server_hello.vec b/src/tests/data/tls/server_hello.vec
new file mode 100644
index 000000000..64ec40b80
--- /dev/null
+++ b/src/tests/data/tls/server_hello.vec
@@ -0,0 +1,48 @@
+# Tests generated partially with openssl 1.0.2g
+# ServerHello message contains many fields, the following fields are checked:
+# - Protocol Version
+# - Cipher suite
+# - Extensions
+
+[server_hello]
+# correct, with session ticket and renegotiation info
+Buffer = 0303ffea0bcfba564a4ce177c6a444b0ebdff5629b277293c618c1125f231e8628dd00c030000016ff01000100000b00040300010200230000000f000101
+Protocol = 0303
+Ciphersuite = C030
+AdditionalData = 0023FF01
+Exception =
+
+# correct, with session ticket, extended master secret, and renegotiation info
+Buffer = 03019f9cafa88664d9095f85dd64a39e5dd5c09f5a4a5362938af3718ee4e818af6a00c03000001aff01000100000b00040300010200230000000f00010100170000
+Protocol = 0301
+Ciphersuite = C030
+AdditionalData = 00170023FF01
+Exception =
+
+# incorrect, corrupted
+Buffer =
+Protocol = 0303
+Ciphersuite = C030
+AdditionalData =
+Exception = Invalid argument Decoding error: Server_Hello: Packet corrupted
+
+# incorrect, corrupted
+Buffer = 00
+Protocol = 0303
+Ciphersuite = C030
+AdditionalData =
+Exception = Invalid argument Decoding error: Server_Hello: Packet corrupted
+
+# invalid extensions length
+Buffer = 03039f9cafa88664d9095f85dd64a39e5dd5c09f5a4a5362938af3718ee4e818af6a00c03000001cff01000100000b00040300010200230000000f00010100170000
+Protocol = 0303
+Ciphersuite = C030
+AdditionalData = 00170023FF01
+Exception = Invalid argument Decoding error: Bad extension size
+
+# invalid extension length
+Buffer = 03039f9cafa88664d9095f85dd64a39e5dd5c09f5a4a5362938af3718ee4e818af6a00c03000001aff01000100000b00040300010200230100000f00010100170000
+Protocol = 0303
+Ciphersuite = C030
+AdditionalData = 00170023FF01
+Exception = Invalid argument Decoding error: Invalid ServerHello: Expected 256 bytes remaining, only 9 left \ No newline at end of file
diff --git a/src/tests/test_tls_messages.cpp b/src/tests/test_tls_messages.cpp
new file mode 100644
index 000000000..da6e72f79
--- /dev/null
+++ b/src/tests/test_tls_messages.cpp
@@ -0,0 +1,203 @@
+/*
+* (C) 2016 Juraj Somorovsky
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "tests.h"
+
+#if defined(BOTAN_HAS_TLS)
+ #include <exception>
+ #include <botan/hex.h>
+ #include <botan/mac.h>
+ #include <botan/tls_ciphersuite.h>
+ #include <botan/tls_handshake_msg.h>
+ #include <botan/internal/tls_messages.h>
+#endif
+
+namespace Botan_Tests {
+
+namespace {
+
+#if defined(BOTAN_HAS_TLS)
+Test::Result test_hello_verify_request()
+ {
+ Test::Result result("hello_verify_request construction");
+
+ std::vector<byte> test_data;
+ std::vector<byte> key_data(32);
+ Botan::SymmetricKey sk(key_data);
+
+ // Compute cookie over an empty string with an empty test data
+ Botan::TLS::Hello_Verify_Request hfr(test_data, "", sk);
+
+ // Compute HMAC
+ std::unique_ptr<Botan::MessageAuthenticationCode> hmac(Botan::MessageAuthenticationCode::create("HMAC(SHA-256)"));
+ hmac->set_key(sk);
+ hmac->update_be(size_t(0));
+ hmac->update_be(size_t(0));
+ std::vector<byte> test = unlock(hmac->final());
+
+ result.test_eq("Cookie comparison", hfr.cookie(), test);
+ return result;
+ }
+
+class TLS_Message_Parsing_Test : public Text_Based_Test
+ {
+ public:
+ TLS_Message_Parsing_Test() :
+ Text_Based_Test("tls", {"Buffer", "Protocol", "Ciphersuite", "AdditionalData", "Exception"})
+ {}
+
+ Test::Result run_one_test(const std::string& algo, const VarMap& vars) override
+ {
+ const std::vector<uint8_t> buffer = get_req_bin(vars, "Buffer");
+ const std::vector<uint8_t> protocol = get_opt_bin(vars, "Protocol");
+ const std::vector<uint8_t> ciphersuite = get_opt_bin(vars, "Ciphersuite");
+ const std::string exception = get_req_str(vars, "Exception");
+ const bool is_positive_test = exception.empty();
+
+ Test::Result result(algo + " parsing");
+
+ if(is_positive_test)
+ {
+ try
+ {
+ if(algo == "cert_verify")
+ {
+ Botan::TLS::Protocol_Version pv(protocol[0], protocol[1]);
+ Botan::TLS::Certificate_Verify message(buffer, pv);
+ }
+ if(algo == "client_hello")
+ {
+ const std::string extensions = get_req_str(vars, "AdditionalData");
+ Botan::TLS::Protocol_Version pv(protocol[0], protocol[1]);
+ Botan::TLS::Client_Hello message(buffer);
+ result.test_eq("Protocol version", message.version().to_string(), pv.to_string());
+ std::vector<byte> buf;
+ for(Botan::TLS::Handshake_Extension_Type const& type : message.extension_types())
+ {
+ Botan::u16bit u16type = type;
+ buf.push_back(Botan::get_byte(0, u16type));
+ buf.push_back(Botan::get_byte(1, u16type));
+ }
+ result.test_eq("Hello extensions", Botan::hex_encode(buf), extensions);
+ }
+ else if(algo == "hello_verify")
+ {
+ Botan::TLS::Hello_Verify_Request message(buffer);
+ }
+ else if(algo == "hello_request")
+ {
+ Botan::TLS::Hello_Request message(buffer);
+ }
+ else if(algo == "new_session_ticket")
+ {
+ Botan::TLS::New_Session_Ticket message(buffer);
+ }
+ if(algo == "server_hello")
+ {
+ const std::string extensions = get_req_str(vars, "AdditionalData");
+ Botan::TLS::Protocol_Version pv(protocol[0], protocol[1]);
+ Botan::TLS::Ciphersuite cs = Botan::TLS::Ciphersuite::by_id(Botan::make_u16bit(ciphersuite[0], ciphersuite[1]));
+ Botan::TLS::Server_Hello message(buffer);
+ result.test_eq("Protocol version", message.version().to_string(), pv.to_string());
+ result.confirm("Ciphersuite", (message.ciphersuite() == cs.ciphersuite_code()));
+ std::vector<byte> buf;
+ for(Botan::TLS::Handshake_Extension_Type const& type : message.extension_types())
+ {
+ Botan::u16bit u16type = type;
+ buf.push_back(Botan::get_byte(0, u16type));
+ buf.push_back(Botan::get_byte(1, u16type));
+ }
+ result.test_eq("Hello extensions", Botan::hex_encode(buf), extensions);
+ }
+ else if(algo == "alert")
+ {
+ Botan::secure_vector<uint8_t> sb(buffer.begin(), buffer.end());
+ Botan::TLS::Alert message(sb);
+ result.test_lt("Alert type vectors result to UNKNOWN_CA or ACCESS_DENIED, which is shorter than 15",
+ message.type_string().size(), 15);
+ }
+ result.test_success("Correct parsing");
+ }
+ catch(std::exception& e)
+ {
+ result.test_failure(e.what());
+ }
+ }
+ else
+ {
+ if(algo == "cert_verify")
+ {
+ Botan::TLS::Protocol_Version pv(protocol[0], protocol[1]);
+ result.test_throws("invalid cert_verify input", exception, [&buffer, &pv]()
+ {
+ Botan::TLS::Certificate_Verify message(buffer, pv);
+ });
+ }
+ else if(algo == "client_hello")
+ {
+ result.test_throws("invalid client_hello input", exception, [&buffer]()
+ {
+ Botan::TLS::Client_Hello message(buffer);
+ });
+ }
+ else if(algo == "hello_verify")
+ {
+ result.test_throws("invalid hello_verify input", exception, [&buffer]()
+ {
+ Botan::TLS::Hello_Verify_Request message(buffer);
+ });
+ }
+ else if(algo == "hello_request")
+ {
+ result.test_throws("invalid hello_request input", exception, [&buffer]()
+ {
+ Botan::TLS::Hello_Request message(buffer);
+ });
+ }
+ else if(algo == "new_session_ticket")
+ {
+ result.test_throws("invalid new_session_ticket input", exception, [&buffer]()
+ {
+ Botan::TLS::New_Session_Ticket message(buffer);
+ });
+ }
+ else if(algo == "server_hello")
+ {
+ result.test_throws("invalid server_hello input", exception, [&buffer]()
+ {
+ Botan::TLS::Server_Hello message(buffer);
+ });
+ }
+ else if(algo == "alert")
+ {
+ result.test_throws("invalid alert input", exception, [&buffer]()
+ {
+ Botan::secure_vector<uint8_t> sb(buffer.begin(), buffer.end());
+ Botan::TLS::Alert message(sb);
+ });
+ }
+ }
+
+ return result;
+ }
+
+ std::vector<Test::Result> run_final_tests() override
+ {
+ std::vector<Test::Result> results;
+
+ results.push_back(test_hello_verify_request());
+
+ return results;
+ }
+ };
+
+BOTAN_REGISTER_TEST("tls_messages", TLS_Message_Parsing_Test);
+
+#endif
+
+}
+
+}
diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp
index b47f2a7ab..1bb8b7303 100644
--- a/src/tests/tests.cpp
+++ b/src/tests/tests.cpp
@@ -94,6 +94,29 @@ bool Test::Result::test_throws(const std::string& what, std::function<void ()> f
}
}
+bool Test::Result::test_throws(const std::string& what, const std::string& expected, std::function<void ()> fn)
+ {
+ try {
+ fn();
+ return test_failure(what + " failed to throw expected exception");
+ }
+ catch(std::exception& e)
+ {
+ if(expected == e.what())
+ {
+ return test_success(what + " threw exception " + e.what());
+ }
+ else
+ {
+ return test_failure(what + " failed to throw an exception with the expected text:\n Expected: " + expected + "\n Got: " + e.what());
+ }
+ }
+ catch(...)
+ {
+ return test_failure(what + " failed to throw an exception with the expected text:\n Expected: " + expected);
+ }
+ }
+
bool Test::Result::test_success(const std::string& note)
{
if(Test::log_success())
diff --git a/src/tests/tests.h b/src/tests/tests.h
index 1ceb24f48..fb8d357d4 100644
--- a/src/tests/tests.h
+++ b/src/tests/tests.h
@@ -291,6 +291,9 @@ class Test
}
bool test_throws(const std::string& what, std::function<void ()> fn);
+
+ bool test_throws(const std::string& what, const std::string& expected,
+ std::function<void ()> fn);
void set_ns_consumed(uint64_t ns) { m_ns_taken = ns; }
diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp
index 081b1038d..de54c9747 100644
--- a/src/tests/unit_tls.cpp
+++ b/src/tests/unit_tls.cpp
@@ -41,6 +41,7 @@ class Credentials_Manager_Test : public Botan::Credentials_Manager
{
std::unique_ptr<Botan::Certificate_Store> store(new Botan::Certificate_Store_In_Memory(m_ca_cert));
m_stores.push_back(std::move(store));
+ m_provides_client_certs = false;
}
std::vector<Botan::Certificate_Store*>
@@ -60,7 +61,7 @@ class Credentials_Manager_Test : public Botan::Credentials_Manager
{
std::vector<Botan::X509_Certificate> chain;
- if(type == "tls-server")
+ if(type == "tls-server" || (type == "tls-client" && m_provides_client_certs))
{
bool have_match = false;
for(size_t i = 0; i != cert_key_types.size(); ++i)
@@ -114,9 +115,10 @@ class Credentials_Manager_Test : public Botan::Credentials_Manager
Botan::X509_Certificate m_server_cert, m_ca_cert;
std::unique_ptr<Botan::Private_Key> m_key;
std::vector<std::unique_ptr<Botan::Certificate_Store>> m_stores;
+ bool m_provides_client_certs;
};
-Botan::Credentials_Manager* create_creds()
+Botan::Credentials_Manager* create_creds(bool client_type)
{
std::unique_ptr<Botan::Private_Key> ca_key(new Botan::RSA_PrivateKey(Test::rng(), 1024));
@@ -154,7 +156,9 @@ Botan::Credentials_Manager* create_creds()
start_time,
end_time);
- return new Credentials_Manager_Test(server_cert, ca_cert, server_key);
+ Credentials_Manager_Test* cmt (new Credentials_Manager_Test(server_cert, ca_cert, server_key));
+ cmt->m_provides_client_certs = client_type;
+ return cmt;
}
std::function<void (const byte[], size_t)> queue_inserter(std::vector<byte>& q)
@@ -782,7 +786,8 @@ class TLS_Unit_Tests : public Test
public:
std::vector<Test::Result> run() override
{
- std::unique_ptr<Botan::Credentials_Manager> basic_creds(create_creds());
+ std::unique_ptr<Botan::Credentials_Manager> basic_creds(create_creds(false));
+ std::unique_ptr<Botan::Credentials_Manager> basic_creds_with_client_cert(create_creds(true));
std::vector<Test::Result> results;
Test_Policy policy;
@@ -815,6 +820,7 @@ class TLS_Unit_Tests : public Test
results.push_back(test_tls_handshake(Botan::TLS::Protocol_Version::TLS_V12, *basic_creds, policy));
results.push_back(test_dtls_handshake(Botan::TLS::Protocol_Version::DTLS_V10, *basic_creds, policy));
results.push_back(test_dtls_handshake(Botan::TLS::Protocol_Version::DTLS_V12, *basic_creds, policy));
+ results.push_back(test_tls_handshake(Botan::TLS::Protocol_Version::TLS_V12, *basic_creds_with_client_cert, policy));
#if defined(BOTAN_HAS_AEAD_OCB)
policy.set("ciphers", "AES-128/OCB(12)");
diff --git a/src/tests/unit_tls_policy.cpp b/src/tests/unit_tls_policy.cpp
new file mode 100644
index 000000000..2e5b63f41
--- /dev/null
+++ b/src/tests/unit_tls_policy.cpp
@@ -0,0 +1,162 @@
+/*
+* TLS Policy tests
+*
+* (C) 2016 Juraj Somorovsky
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "tests.h"
+
+#if defined(BOTAN_HAS_TLS)
+ #include <botan/pubkey.h>
+ #include <botan/auto_rng.h>
+ #include <botan/oids.h>
+ #include <botan/tls_policy.h>
+#endif
+
+#if defined(BOTAN_HAS_RSA)
+ #include <botan/rsa.h>
+#endif
+
+#if defined(BOTAN_HAS_ECDH)
+ #include <botan/ecdh.h>
+#endif
+
+#if defined(BOTAN_HAS_ECDSA)
+ #include <botan/ecdsa.h>
+#endif
+
+#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
+ #include <botan/dh.h>
+#endif
+
+namespace Botan_Tests {
+
+namespace {
+
+#if defined(BOTAN_HAS_TLS)
+class TLS_Policy_Unit_Tests : public Test
+ {
+ public:
+ std::vector<Test::Result> run() override
+ {
+ std::vector<Test::Result> results;
+
+ results.push_back(test_peer_key_acceptable_rsa());
+ results.push_back(test_peer_key_acceptable_ecdh());
+ results.push_back(test_peer_key_acceptable_ecdsa());
+ results.push_back(test_peer_key_acceptable_dh());
+
+ return results;
+ }
+ private:
+ Test::Result test_peer_key_acceptable_rsa()
+ {
+ Test::Result result("TLS Policy RSA key verification");
+#if defined(BOTAN_HAS_RSA)
+ std::unique_ptr<Botan::Private_Key> rsa_key_1024 (new Botan::RSA_PrivateKey(Test::rng(), 1024));
+ Botan::TLS::Policy policy;
+
+ try
+ {
+ policy.check_peer_key_acceptable(*rsa_key_1024);
+ result.test_failure("Incorrectly accepting 1024 bit RSA keys");
+ }
+ catch(std::exception& e)
+ {
+ result.test_success("Correctly rejecting 1024 bit RSA keys");
+ }
+
+ std::unique_ptr<Botan::Private_Key> rsa_key_2048 (new Botan::RSA_PrivateKey(Test::rng(), 2048));
+ policy.check_peer_key_acceptable(*rsa_key_2048);
+ result.test_success("Correctly accepting 2048 bit RSA keys");
+#endif
+ return result;
+ }
+
+ Test::Result test_peer_key_acceptable_ecdh()
+ {
+ Test::Result result("TLS Policy ECDH key verification");
+#if defined(BOTAN_HAS_ECDH)
+ Botan::EC_Group group_192("secp192r1");
+ std::unique_ptr<Botan::Private_Key> ecdh_192 (new Botan::ECDH_PrivateKey(Test::rng(), group_192));
+
+ Botan::TLS::Policy policy;
+ try
+ {
+ policy.check_peer_key_acceptable(*ecdh_192);
+ result.test_failure("Incorrectly accepting 192 bit EC keys");
+ }
+ catch(std::exception& e)
+ {
+ result.test_success("Correctly rejecting 192 bit EC keys");
+ }
+
+ Botan::EC_Group group_256("secp256r1");
+ std::unique_ptr<Botan::Private_Key> ecdh_256 (new Botan::ECDH_PrivateKey(Test::rng(), group_256));
+ policy.check_peer_key_acceptable(*ecdh_256);
+ result.test_success("Correctly accepting 256 bit EC keys");
+#endif
+ return result;
+ }
+
+ Test::Result test_peer_key_acceptable_ecdsa()
+ {
+ Test::Result result("TLS Policy ECDSA key verification");
+#if defined(BOTAN_HAS_ECDSA)
+ Botan::EC_Group group_192("secp192r1");
+ std::unique_ptr<Botan::Private_Key> ecdsa_192 (new Botan::ECDSA_PrivateKey(Test::rng(), group_192));
+
+ Botan::TLS::Policy policy;
+ try
+ {
+ policy.check_peer_key_acceptable(*ecdsa_192);
+ result.test_failure("Incorrectly accepting 192 bit EC keys");
+ }
+ catch(std::exception& e)
+ {
+ result.test_success("Correctly rejecting 192 bit EC keys");
+ }
+
+ Botan::EC_Group group_256("secp256r1");
+ std::unique_ptr<Botan::Private_Key> ecdsa_256 (new Botan::ECDSA_PrivateKey(Test::rng(), group_256));
+ policy.check_peer_key_acceptable(*ecdsa_256);
+ result.test_success("Correctly accepting 256 bit EC keys");
+#endif
+ return result;
+ }
+
+ Test::Result test_peer_key_acceptable_dh()
+ {
+ Test::Result result("TLS Policy DH key verification");
+#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
+ const BigInt g("2");
+ const BigInt p("58458002095536094658683755258523362961421200751439456159756164191494576279467");
+ const Botan::DL_Group grp(p, g);
+ const Botan::BigInt x("46205663093589612668746163860870963912226379131190812163519349848291472898748");
+ std::unique_ptr<Botan::Private_Key> dhkey (new Botan::DH_PrivateKey(Test::rng(), grp, x));
+
+ Botan::TLS::Policy policy;
+ try
+ {
+ policy.check_peer_key_acceptable(*dhkey);
+ result.test_failure("Incorrectly accepting short bit DH keys");
+ }
+ catch(std::exception& e)
+ {
+ result.test_success("Correctly rejecting short bit DH keys");
+ }
+#endif
+ return result;
+ }
+
+ };
+
+BOTAN_REGISTER_TEST("tls_policy", TLS_Policy_Unit_Tests);
+
+#endif
+
+}
+
+}