aboutsummaryrefslogtreecommitdiffstats
path: root/src/ssl
diff options
context:
space:
mode:
authorlloyd <[email protected]>2010-04-28 22:31:20 +0000
committerlloyd <[email protected]>2010-04-28 22:31:20 +0000
commit0f47cb60e703ca2de56286f07b4c9d91c7bba071 (patch)
tree5304fd84516c79f55e213755b2b2b99e6e65c9e0 /src/ssl
parent6eec50d372143afcb3188f21d0991ace3e0d5e9e (diff)
parent50fc7b15553d888d95bee72972e53eae27a82c1f (diff)
propagate from branch 'net.randombit.botan' (head a5f25a3b954f24c5d07fa0dab6c4d76f63767165)
to branch 'net.randombit.botan.c++0x' (head a365694b70b4b84ca713272d56d496acca351cb5)
Diffstat (limited to 'src/ssl')
-rw-r--r--src/ssl/c_kex.cpp4
-rw-r--r--src/ssl/hello.cpp39
-rw-r--r--src/ssl/rec_read.cpp29
-rw-r--r--src/ssl/tls_client.cpp21
-rw-r--r--src/ssl/tls_magic.h90
-rw-r--r--src/ssl/tls_messages.h19
-rw-r--r--src/ssl/tls_policy.cpp29
-rw-r--r--src/ssl/tls_server.cpp29
-rw-r--r--src/ssl/tls_suites.cpp286
-rw-r--r--src/ssl/tls_suites.h16
10 files changed, 458 insertions, 104 deletions
diff --git a/src/ssl/c_kex.cpp b/src/ssl/c_kex.cpp
index e09e18ce1..db2198627 100644
--- a/src/ssl/c_kex.cpp
+++ b/src/ssl/c_kex.cpp
@@ -67,9 +67,7 @@ Client_Key_Exchange::Client_Key_Exchange(const MemoryRegion<byte>& contents,
{
include_length = true;
- if(using_version == SSL_V3 &&
- (suite.kex_type() == CipherSuite::NO_KEX ||
- suite.kex_type() == CipherSuite::RSA_KEX))
+ if(using_version == SSL_V3 && (suite.kex_type() == TLS_ALGO_KEYEXCH_RSA))
include_length = false;
deserialize(contents);
diff --git a/src/ssl/hello.cpp b/src/ssl/hello.cpp
index a23d51c24..5b3c32278 100644
--- a/src/ssl/hello.cpp
+++ b/src/ssl/hello.cpp
@@ -106,6 +106,40 @@ SecureVector<byte> Client_Hello::serialize() const
return buf;
}
+void Client_Hello::deserialize_sslv2(const MemoryRegion<byte>& buf)
+ {
+ if(buf.size() < 12 || buf[0] != 1)
+ throw Decoding_Error("Client_Hello: SSLv2 hello corrupted");
+
+ const u32bit cipher_spec_len = make_u16bit(buf[3], buf[4]);
+ const u32bit sess_id_len = make_u16bit(buf[5], buf[6]);
+ const u32bit challenge_len = make_u16bit(buf[7], buf[8]);
+
+ const u32bit expected_size =
+ (9 + sess_id_len + cipher_spec_len + challenge_len);
+
+ if(buf.size() != expected_size)
+ throw Decoding_Error("Client_Hello: SSLv2 hello corrupted");
+
+ if(sess_id_len != 0 || cipher_spec_len % 3 != 0 ||
+ (challenge_len < 16 || challenge_len > 32))
+ {
+ throw Decoding_Error("Client_Hello: SSLv2 hello corrupted");
+ }
+
+ for(u32bit i = 9; i != 9 + cipher_spec_len; i += 3)
+ {
+ if(buf[i] != 0) // a SSLv2 cipherspec; ignore it
+ continue;
+
+ suites.push_back(make_u16bit(buf[i+1], buf[i+2]));
+ }
+
+ c_version = static_cast<Version_Code>(make_u16bit(buf[1], buf[2]));
+
+ c_random.set(&buf[9+cipher_spec_len+sess_id_len], challenge_len);
+ }
+
/**
* Deserialize a Client Hello message
*/
@@ -207,6 +241,11 @@ Server_Hello::Server_Hello(RandomNumberGenerator& rng,
}
suite = policy->choose_suite(c_hello.ciphersuites(), have_rsa, have_dsa);
+
+ if(suite == 0)
+ throw TLS_Exception(PROTOCOL_VERSION,
+ "Can't agree on a ciphersuite with client");
+
comp_algo = policy->choose_compression(c_hello.compression_algos());
s_version = ver;
diff --git a/src/ssl/rec_read.cpp b/src/ssl/rec_read.cpp
index 8f8e5dc1e..f07744c2a 100644
--- a/src/ssl/rec_read.cpp
+++ b/src/ssl/rec_read.cpp
@@ -124,6 +124,35 @@ u32bit Record_Reader::get_record(byte& msg_type,
*/
input_queue.peek(header, sizeof(header));
+ // SSLv2-format client hello?
+ if(header[0] & 0x80 && header[2] == 1 && header[3] == 3)
+ {
+ u32bit record_len = make_u16bit(header[0], header[1]) & 0x7FFF;
+
+ if(have_in_queue < record_len + 2)
+ return (record_len + 2 - have_in_queue);
+
+ msg_type = HANDSHAKE;
+ output.resize(record_len + 4);
+
+ input_queue.read(&output[2], record_len + 2);
+ output[0] = CLIENT_HELLO_SSLV2;
+ output[1] = 0;
+ output[2] = header[0] & 0x7F;
+ output[3] = header[1];
+
+ return 0;
+ }
+
+ if(header[0] != CHANGE_CIPHER_SPEC &&
+ header[0] != ALERT &&
+ header[0] != HANDSHAKE &&
+ header[0] != APPLICATION_DATA)
+ {
+ throw TLS_Exception(UNEXPECTED_MESSAGE,
+ "Record_Reader: Unknown record type");
+ }
+
const u16bit version = make_u16bit(header[1], header[2]);
const u16bit record_len = make_u16bit(header[3], header[4]);
diff --git a/src/ssl/tls_client.cpp b/src/ssl/tls_client.cpp
index fbad1f838..8a4275d93 100644
--- a/src/ssl/tls_client.cpp
+++ b/src/ssl/tls_client.cpp
@@ -123,6 +123,7 @@ TLS_Client::~TLS_Client()
*/
void TLS_Client::initialize()
{
+ std::string error_str;
Alert_Type error_type = NO_ALERT_TYPE;
try {
@@ -133,10 +134,12 @@ void TLS_Client::initialize()
}
catch(TLS_Exception& e)
{
+ error_str = e.what();
error_type = e.type();
}
catch(std::exception& e)
{
+ error_str = e.what();
error_type = HANDSHAKE_FAILURE;
}
@@ -157,7 +160,7 @@ void TLS_Client::initialize()
state = 0;
}
- throw Stream_IO_Error("TLS_Client: Handshake failed");
+ throw Stream_IO_Error("TLS_Client: Handshake failed: " + error_str);
}
}
@@ -360,6 +363,8 @@ void TLS_Client::read_handshake(byte rec_type,
void TLS_Client::process_handshake_msg(Handshake_Type type,
const MemoryRegion<byte>& contents)
{
+ rng.add_entropy(&contents[0], contents.size());
+
if(type == HELLO_REQUEST)
{
if(state == 0)
@@ -419,7 +424,7 @@ void TLS_Client::process_handshake_msg(Handshake_Type type,
{
client_check_state(type, state);
- if(state->suite.sig_type() == CipherSuite::NO_SIG)
+ if(state->suite.sig_type() == TLS_ALGO_SIGNER_ANON)
throw Unexpected_Message("Recived certificate from anonymous server");
state->server_certs = new Certificate(contents);
@@ -445,8 +450,8 @@ void TLS_Client::process_handshake_msg(Handshake_Type type,
throw TLS_Exception(UNSUPPORTED_CERTIFICATE,
"Unknown key type recieved in server kex");
- if((is_dsa && state->suite.sig_type() != CipherSuite::DSA_SIG) ||
- (is_rsa && state->suite.sig_type() != CipherSuite::RSA_SIG))
+ if((is_dsa && state->suite.sig_type() != TLS_ALGO_SIGNER_DSA) ||
+ (is_rsa && state->suite.sig_type() != TLS_ALGO_SIGNER_RSA))
throw TLS_Exception(ILLEGAL_PARAMETER,
"Certificate key type did not match ciphersuite");
}
@@ -454,7 +459,7 @@ void TLS_Client::process_handshake_msg(Handshake_Type type,
{
client_check_state(type, state);
- if(state->suite.kex_type() == CipherSuite::NO_KEX)
+ if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_NOKEX)
throw Unexpected_Message("Unexpected key exchange from server");
state->server_kex = new Server_Key_Exchange(contents);
@@ -474,12 +479,12 @@ void TLS_Client::process_handshake_msg(Handshake_Type type,
throw TLS_Exception(HANDSHAKE_FAILURE,
"Unknown key type recieved in server kex");
- if((is_dh && state->suite.kex_type() != CipherSuite::DH_KEX) ||
- (is_rsa && state->suite.kex_type() != CipherSuite::RSA_KEX))
+ if((is_dh && state->suite.kex_type() != TLS_ALGO_KEYEXCH_DH) ||
+ (is_rsa && state->suite.kex_type() != TLS_ALGO_KEYEXCH_RSA))
throw TLS_Exception(ILLEGAL_PARAMETER,
"Certificate key type did not match ciphersuite");
- if(state->suite.sig_type() != CipherSuite::NO_SIG)
+ if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON)
{
if(!state->server_kex->verify(peer_certs[0],
state->client_hello->random(),
diff --git a/src/ssl/tls_magic.h b/src/ssl/tls_magic.h
index a6ca1f8d6..93b56d96d 100644
--- a/src/ssl/tls_magic.h
+++ b/src/ssl/tls_magic.h
@@ -1,6 +1,6 @@
/**
-* SSL/TLS Protocol Constants
-* (C) 2004-2006 Jack Lloyd
+* SSL/TLS Protocol Constants
+* (C) 2004-2010 Jack Lloyd
*
* Released under the terms of the Botan license
*/
@@ -40,6 +40,7 @@ enum Record_Type {
enum Handshake_Type {
HELLO_REQUEST = 0,
CLIENT_HELLO = 1,
+ CLIENT_HELLO_SSLV2 = 255, // not a wire value
SERVER_HELLO = 2,
CERTIFICATE = 11,
SERVER_KEX = 12,
@@ -96,19 +97,75 @@ enum Certificate_Type {
};
enum Ciphersuite_Code {
- RSA_RC4_MD5 = 0x0004,
- RSA_RC4_SHA = 0x0005,
- RSA_3DES_SHA = 0x000A,
- RSA_AES128_SHA = 0x002F,
- RSA_AES256_SHA = 0x0035,
-
- DHE_RSA_3DES_SHA = 0x0016,
- DHE_RSA_AES128_SHA = 0x0033,
- DHE_RSA_AES256_SHA = 0x0039,
-
- DHE_DSS_3DES_SHA = 0x0013,
- DHE_DSS_AES128_SHA = 0x0032,
- DHE_DSS_AES256_SHA = 0x0038
+ TLS_RSA_WITH_RC4_128_MD5 = 0x0004,
+ TLS_RSA_WITH_RC4_128_SHA = 0x0005,
+
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A,
+
+ TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F,
+ TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035,
+ TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C,
+ TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D,
+ TLS_RSA_WITH_SEED_CBC_SHA = 0x0096,
+
+ TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013,
+ TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032,
+ TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038,
+ TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040,
+ TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x006A,
+ TLS_DHE_DSS_WITH_SEED_CBC_SHA = 0x0099,
+
+ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016,
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033,
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039,
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067,
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B,
+ TLS_DHE_RSA_WITH_SEED_CBC_SHA = 0x009A,
+
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007,
+ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024,
+
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011,
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028
+};
+
+/*
+* Form of the ciphersuites broken down by field instead of
+* being randomly assigned codepoints.
+*/
+enum TLS_Ciphersuite_Algos {
+ TLS_ALGO_SIGNER_MASK = 0xFF000000,
+ TLS_ALGO_SIGNER_ANON = 0x01000000,
+ TLS_ALGO_SIGNER_RSA = 0x02000000,
+ TLS_ALGO_SIGNER_DSA = 0x03000000,
+ TLS_ALGO_SIGNER_ECDSA = 0x04000000,
+
+ TLS_ALGO_KEYEXCH_MASK = 0x00FF0000,
+ TLS_ALGO_KEYEXCH_NOKEX = 0x00010000,
+ TLS_ALGO_KEYEXCH_RSA = 0x00020000,
+ TLS_ALGO_KEYEXCH_DH = 0x00030000,
+ TLS_ALGO_KEYEXCH_ECDH = 0x00040000,
+
+ TLS_ALGO_MAC_MASK = 0x0000FF00,
+ TLS_ALGO_MAC_MD5 = 0x00000100,
+ TLS_ALGO_MAC_SHA1 = 0x00000200,
+ TLS_ALGO_MAC_SHA256 = 0x00000300,
+ TLS_ALGO_MAC_SHA384 = 0x00000400,
+
+ TLS_ALGO_CIPHER_MASK = 0x000000FF,
+ TLS_ALGO_CIPHER_RC4_128 = 0x00000001,
+ TLS_ALGO_CIPHER_3DES_CBC = 0x00000002,
+ TLS_ALGO_CIPHER_AES128_CBC = 0x00000003,
+ TLS_ALGO_CIPHER_AES256_CBC = 0x00000004,
+ TLS_ALGO_CIPHER_SEED_CBC = 0x00000005
};
enum Compression_Algo {
@@ -122,6 +179,9 @@ enum TLS_Handshake_Extension_Type {
TLSEXT_TRUSTED_CA_KEYS = 3,
TLSEXT_TRUNCATED_HMAC = 4,
+ TLSEXT_USABLE_ELLIPTIC_CURVES = 10,
+ TLSEXT_EC_POINT_FORMATS = 11,
+
TLSEXT_CERTIFICATE_TYPES = 9,
TLSEXT_SESSION_TICKET = 35,
};
diff --git a/src/ssl/tls_messages.h b/src/ssl/tls_messages.h
index 1f72c05f7..5c0c06c88 100644
--- a/src/ssl/tls_messages.h
+++ b/src/ssl/tls_messages.h
@@ -43,11 +43,11 @@ class BOTAN_DLL Client_Hello : public HandshakeMessage
public:
Handshake_Type type() const { return CLIENT_HELLO; }
Version_Code version() const { return c_version; }
- SecureVector<byte> session_id() const { return sess_id; }
+ const SecureVector<byte>& session_id() const { return sess_id; }
std::vector<u16bit> ciphersuites() const { return suites; }
std::vector<byte> compression_algos() const { return comp_algos; }
- SecureVector<byte> random() const { return c_random; }
+ const SecureVector<byte>& random() const { return c_random; }
std::string hostname() const { return requested_hostname; }
@@ -56,10 +56,19 @@ class BOTAN_DLL Client_Hello : public HandshakeMessage
Client_Hello(RandomNumberGenerator& rng,
Record_Writer&, const TLS_Policy*, HandshakeHash&);
- Client_Hello(const MemoryRegion<byte>& buf) { deserialize(buf); }
+ Client_Hello(const MemoryRegion<byte>& buf,
+ Handshake_Type type)
+ {
+ if(type == CLIENT_HELLO)
+ deserialize(buf);
+ else
+ deserialize_sslv2(buf);
+ }
+
private:
SecureVector<byte> serialize() const;
void deserialize(const MemoryRegion<byte>&);
+ void deserialize_sslv2(const MemoryRegion<byte>&);
Version_Code c_version;
SecureVector<byte> sess_id, c_random;
@@ -216,11 +225,11 @@ class BOTAN_DLL Server_Hello : public HandshakeMessage
public:
Handshake_Type type() const { return SERVER_HELLO; }
Version_Code version() { return s_version; }
- SecureVector<byte> session_id() const { return sess_id; }
+ const SecureVector<byte>& session_id() const { return sess_id; }
u16bit ciphersuite() const { return suite; }
byte compression_algo() const { return comp_algo; }
- SecureVector<byte> random() const { return s_random; }
+ const SecureVector<byte>& random() const { return s_random; }
Server_Hello(RandomNumberGenerator& rng,
Record_Writer&, const TLS_Policy*,
diff --git a/src/ssl/tls_policy.cpp b/src/ssl/tls_policy.cpp
index 6138ae193..57fcdb5cc 100644
--- a/src/ssl/tls_policy.cpp
+++ b/src/ssl/tls_policy.cpp
@@ -1,6 +1,6 @@
/**
-* Policies
-* (C) 2004-2006 Jack Lloyd
+* Policies for TLS
+* (C) 2004-2010 Jack Lloyd
*
* Released under the terms of the Botan license
*/
@@ -29,25 +29,28 @@ std::vector<u16bit> TLS_Policy::suite_list(bool use_rsa,
if(use_edh_dsa)
{
- suites.push_back(DHE_DSS_AES256_SHA);
- suites.push_back(DHE_DSS_AES128_SHA);
- suites.push_back(DHE_DSS_3DES_SHA);
+ suites.push_back(TLS_DHE_DSS_WITH_AES_256_CBC_SHA);
+ suites.push_back(TLS_DHE_DSS_WITH_AES_128_CBC_SHA);
+ suites.push_back(TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA);
+ suites.push_back(TLS_DHE_DSS_WITH_SEED_CBC_SHA);
}
if(use_edh_rsa)
{
- suites.push_back(DHE_RSA_AES256_SHA);
- suites.push_back(DHE_RSA_AES128_SHA);
- suites.push_back(DHE_RSA_3DES_SHA);
+ suites.push_back(TLS_DHE_RSA_WITH_AES_256_CBC_SHA);
+ suites.push_back(TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
+ suites.push_back(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA);
+ suites.push_back(TLS_DHE_RSA_WITH_SEED_CBC_SHA);
}
if(use_rsa)
{
- suites.push_back(RSA_AES256_SHA);
- suites.push_back(RSA_AES128_SHA);
- suites.push_back(RSA_3DES_SHA);
- suites.push_back(RSA_RC4_SHA);
- suites.push_back(RSA_RC4_MD5);
+ suites.push_back(TLS_RSA_WITH_AES_256_CBC_SHA);
+ suites.push_back(TLS_RSA_WITH_AES_128_CBC_SHA);
+ suites.push_back(TLS_RSA_WITH_3DES_EDE_CBC_SHA);
+ suites.push_back(TLS_RSA_WITH_SEED_CBC_SHA);
+ suites.push_back(TLS_RSA_WITH_RC4_128_SHA);
+ suites.push_back(TLS_RSA_WITH_RC4_128_MD5);
}
if(suites.size() == 0)
diff --git a/src/ssl/tls_server.cpp b/src/ssl/tls_server.cpp
index 47902a71c..a4cfcf7de 100644
--- a/src/ssl/tls_server.cpp
+++ b/src/ssl/tls_server.cpp
@@ -43,7 +43,7 @@ void server_check_state(Handshake_Type new_msg, Handshake_State* state)
Unexpected_Message("State transition error from " + err) {}
};
- if(new_msg == CLIENT_HELLO)
+ if(new_msg == CLIENT_HELLO || new_msg == CLIENT_HELLO_SSLV2)
{
if(state->server_hello)
throw State_Transition_Error("ClientHello");
@@ -325,23 +325,30 @@ void TLS_Server::read_handshake(byte rec_type,
void TLS_Server::process_handshake_msg(Handshake_Type type,
const MemoryRegion<byte>& contents)
{
+ rng.add_entropy(&contents[0], contents.size());
+
if(state == 0)
throw Unexpected_Message("Unexpected handshake message");
if(type != HANDSHAKE_CCS && type != FINISHED)
{
- state->hash.update(static_cast<byte>(type));
- u32bit record_length = contents.size();
- for(u32bit j = 0; j != 3; j++)
- state->hash.update(get_byte(j+1, record_length));
+
+ if(type != CLIENT_HELLO_SSLV2)
+ {
+ state->hash.update(static_cast<byte>(type));
+ u32bit record_length = contents.size();
+ for(u32bit j = 0; j != 3; j++)
+ state->hash.update(get_byte(j+1, record_length));
+ }
+
state->hash.update(contents);
}
- if(type == CLIENT_HELLO)
+ if(type == CLIENT_HELLO || type == CLIENT_HELLO_SSLV2)
{
server_check_state(type, state);
- state->client_hello = new Client_Hello(contents);
+ state->client_hello = new Client_Hello(contents, type);
client_requested_hostname = state->client_hello->hostname();
@@ -358,7 +365,7 @@ void TLS_Server::process_handshake_msg(Handshake_Type type,
state->suite = CipherSuite(state->server_hello->ciphersuite());
- if(state->suite.sig_type() != CipherSuite::NO_SIG)
+ if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON)
{
// FIXME: should choose certs based on sig type
state->server_certs = new Certificate(writer, cert_chain,
@@ -366,14 +373,14 @@ void TLS_Server::process_handshake_msg(Handshake_Type type,
}
state->kex_priv = PKCS8::copy_key(*private_key, rng);
- if(state->suite.kex_type() != CipherSuite::NO_KEX)
+ if(state->suite.kex_type() != TLS_ALGO_KEYEXCH_NOKEX)
{
- if(state->suite.kex_type() == CipherSuite::RSA_KEX)
+ if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_RSA)
{
state->kex_priv = new RSA_PrivateKey(rng,
policy->rsa_export_keysize());
}
- else if(state->suite.kex_type() == CipherSuite::DH_KEX)
+ else if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_DH)
{
state->kex_priv = new DH_PrivateKey(rng, policy->dh_group());
}
diff --git a/src/ssl/tls_suites.cpp b/src/ssl/tls_suites.cpp
index a168dac0a..ccc4ab502 100644
--- a/src/ssl/tls_suites.cpp
+++ b/src/ssl/tls_suites.cpp
@@ -1,40 +1,254 @@
/**
-* TLS Cipher Suites
-* (C) 2004-2006 Jack Lloyd
+* TLS Cipher Suites
+* (C) 2004-2010 Jack Lloyd
*
* Released under the terms of the Botan license
*/
#include <botan/tls_suites.h>
#include <botan/tls_exceptn.h>
-#include <botan/parsing.h>
-#include <vector>
-#include <string>
namespace Botan {
-namespace {
-
/**
-* Convert an SSL/TLS ciphersuite to a string
+* Convert an SSL/TLS ciphersuite to algorithm fields
*/
-std::string lookup_ciphersuite(u16bit suite)
+TLS_Ciphersuite_Algos CipherSuite::lookup_ciphersuite(u16bit suite)
{
- if(suite == RSA_RC4_MD5) return "RSA/NONE/ARC4/16/MD5";
- if(suite == RSA_RC4_SHA) return "RSA/NONE/ARC4/16/SHA1";
- if(suite == RSA_3DES_SHA) return "RSA/NONE/3DES/24/SHA1";
- if(suite == RSA_AES128_SHA) return "RSA/NONE/AES/16/SHA1";
- if(suite == RSA_AES256_SHA) return "RSA/NONE/AES/32/SHA1";
+ if(suite == TLS_RSA_WITH_RC4_128_MD5)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_NOKEX |
+ TLS_ALGO_MAC_MD5 |
+ TLS_ALGO_CIPHER_RC4_128);
+
+ if(suite == TLS_RSA_WITH_RC4_128_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_NOKEX |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_RC4_128);
+
+ if(suite == TLS_RSA_WITH_3DES_EDE_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_NOKEX |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_3DES_CBC);
+
+ if(suite == TLS_RSA_WITH_AES_128_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_NOKEX |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_AES128_CBC);
+
+ if(suite == TLS_RSA_WITH_AES_256_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_NOKEX |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_AES256_CBC);
+
+ if(suite == TLS_RSA_WITH_SEED_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_NOKEX |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_SEED_CBC);
+
+ if(suite == TLS_RSA_WITH_AES_128_CBC_SHA256)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_NOKEX |
+ TLS_ALGO_MAC_SHA256 |
+ TLS_ALGO_CIPHER_AES128_CBC);
+
+ if(suite == TLS_RSA_WITH_AES_256_CBC_SHA256)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_NOKEX |
+ TLS_ALGO_MAC_SHA256 |
+ TLS_ALGO_CIPHER_AES256_CBC);
+
+ if(suite == TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA |
+ TLS_ALGO_KEYEXCH_DH |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_3DES_CBC);
+
+ if(suite == TLS_DHE_DSS_WITH_AES_128_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA |
+ TLS_ALGO_KEYEXCH_DH |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_AES128_CBC);
+
+ if(suite == TLS_DHE_DSS_WITH_SEED_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA |
+ TLS_ALGO_KEYEXCH_DH |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_SEED_CBC);
+
+ if(suite == TLS_DHE_DSS_WITH_AES_256_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA |
+ TLS_ALGO_KEYEXCH_DH |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_AES256_CBC);
+
+ if(suite == TLS_DHE_DSS_WITH_AES_128_CBC_SHA256)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA |
+ TLS_ALGO_KEYEXCH_DH |
+ TLS_ALGO_MAC_SHA256 |
+ TLS_ALGO_CIPHER_AES128_CBC);
+
+ if(suite == TLS_DHE_DSS_WITH_AES_256_CBC_SHA256)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA |
+ TLS_ALGO_KEYEXCH_DH |
+ TLS_ALGO_MAC_SHA256 |
+ TLS_ALGO_CIPHER_AES256_CBC);
+
+ if(suite == TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_DH |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_3DES_CBC);
+
+ if(suite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_DH |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_AES128_CBC);
+
+ if(suite == TLS_DHE_DSS_WITH_SEED_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_DH |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_SEED_CBC);
+
+ if(suite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_DH |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_AES256_CBC);
+
+ if(suite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA256)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_DH |
+ TLS_ALGO_MAC_SHA256 |
+ TLS_ALGO_CIPHER_AES128_CBC);
+
+ if(suite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA256)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_DH |
+ TLS_ALGO_MAC_SHA256 |
+ TLS_ALGO_CIPHER_AES256_CBC);
+
+ if(suite == TLS_ECDHE_ECDSA_WITH_RC4_128_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
+ TLS_ALGO_KEYEXCH_ECDH |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_RC4_128);
+
+ if(suite == TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
+ TLS_ALGO_KEYEXCH_ECDH |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_3DES_CBC);
+
+ if(suite == TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
+ TLS_ALGO_KEYEXCH_ECDH |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_AES128_CBC);
+
+ if(suite == TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
+ TLS_ALGO_KEYEXCH_ECDH |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_AES256_CBC);
- if(suite == DHE_RSA_3DES_SHA) return "RSA/DH/3DES/24/SHA1";
- if(suite == DHE_RSA_AES128_SHA) return "RSA/DH/AES/16/SHA1";
- if(suite == DHE_RSA_AES256_SHA) return "RSA/DH/AES/32/SHA1";
+ if(suite == TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
+ TLS_ALGO_KEYEXCH_ECDH |
+ TLS_ALGO_MAC_SHA256 |
+ TLS_ALGO_CIPHER_AES128_CBC);
- if(suite == DHE_DSS_3DES_SHA) return "DSA/DH/3DES/24/SHA1";
- if(suite == DHE_DSS_AES128_SHA) return "DSA/DH/AES/16/SHA1";
- if(suite == DHE_DSS_AES256_SHA) return "DSA/DH/AES/32/SHA1";
+ if(suite == TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
+ TLS_ALGO_KEYEXCH_ECDH |
+ TLS_ALGO_MAC_SHA384 |
+ TLS_ALGO_CIPHER_AES256_CBC);
- return "";
+ if(suite == TLS_ECDHE_RSA_WITH_RC4_128_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_ECDH |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_RC4_128);
+
+ if(suite == TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_ECDH |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_3DES_CBC);
+
+ if(suite == TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_ECDH |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_AES128_CBC);
+
+ if(suite == TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
+ TLS_ALGO_KEYEXCH_ECDH |
+ TLS_ALGO_MAC_SHA1 |
+ TLS_ALGO_CIPHER_AES256_CBC);
+
+ if(suite == TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
+ TLS_ALGO_KEYEXCH_ECDH |
+ TLS_ALGO_MAC_SHA256 |
+ TLS_ALGO_CIPHER_AES128_CBC);
+
+ if(suite == TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384)
+ return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
+ TLS_ALGO_KEYEXCH_ECDH |
+ TLS_ALGO_MAC_SHA384 |
+ TLS_ALGO_CIPHER_AES256_CBC);
+
+ return TLS_Ciphersuite_Algos(0);
+ }
+
+namespace {
+
+std::pair<std::string, u32bit> cipher_code_to_name(TLS_Ciphersuite_Algos algo)
+ {
+ if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_RC4_128)
+ return std::make_pair("RC4", 128);
+
+ if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_3DES_CBC)
+ return std::make_pair("3DES", 24);
+
+ if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_AES128_CBC)
+ return std::make_pair("AES-128", 16);
+
+ if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_AES256_CBC)
+ return std::make_pair("AES-256", 32);
+
+ if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_SEED_CBC)
+ return std::make_pair("SEED", 16);
+
+ throw TLS_Exception(INTERNAL_ERROR,
+ "CipherSuite: Unknown cipher type " + to_string(algo));
+ }
+
+std::string mac_code_to_name(TLS_Ciphersuite_Algos algo)
+ {
+ if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_MD5)
+ return "MD5";
+
+ if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_SHA1)
+ return "SHA-1";
+
+ if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_SHA256)
+ return "SHA-256";
+
+ if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_SHA384)
+ return "SHA-384";
+
+ throw TLS_Exception(INTERNAL_ERROR,
+ "CipherSuite: Unknown MAC type " + to_string(algo));
}
}
@@ -47,31 +261,21 @@ CipherSuite::CipherSuite(u16bit suite_code)
if(suite_code == 0)
return;
- std::string suite_string = lookup_ciphersuite(suite_code);
+ TLS_Ciphersuite_Algos algos = lookup_ciphersuite(suite_code);
+
+ if(algos == 0)
+ throw Invalid_Argument("Unknown ciphersuite: " + to_string(suite_code));
- if(suite_string == "")
- throw Invalid_Argument("Unknown ciphersuite: " +
- std::to_string(suite_code));
+ sig_algo = TLS_Ciphersuite_Algos(algos & TLS_ALGO_SIGNER_MASK);
- std::vector<std::string> suite_info = split_on(suite_string, '/');
+ kex_algo = TLS_Ciphersuite_Algos(algos & TLS_ALGO_KEYEXCH_MASK);
- if(suite_info[0] == "RSA") sig_algo = RSA_SIG;
- else if(suite_info[0] == "DSA") sig_algo = DSA_SIG;
- else if(suite_info[0] == "NONE") sig_algo = NO_SIG;
- else
- throw TLS_Exception(INTERNAL_ERROR,
- "CipherSuite: Unknown sig type " + suite_info[0]);
+ std::pair<std::string, u32bit> cipher_info = cipher_code_to_name(algos);
- if(suite_info[1] == "DH") kex_algo = DH_KEX;
- else if(suite_info[1] == "RSA") kex_algo = RSA_KEX;
- else if(suite_info[1] == "NONE") kex_algo = NO_KEX;
- else
- throw TLS_Exception(INTERNAL_ERROR,
- "CipherSuite: Unknown kex type " + suite_info[1]);
+ cipher = cipher_info.first;
+ cipher_key_length = cipher_info.second;
- cipher = suite_info[2];
- cipher_key_length = to_u32bit(suite_info[3]);
- mac = suite_info[4];
+ mac = mac_code_to_name(algos);
}
}
diff --git a/src/ssl/tls_suites.h b/src/ssl/tls_suites.h
index b7008e8db..fa015c28f 100644
--- a/src/ssl/tls_suites.h
+++ b/src/ssl/tls_suites.h
@@ -1,6 +1,6 @@
/**
-* Cipher Suites
-* (C) 2004-2006 Jack Lloyd
+* Cipher Suites
+* (C) 2004-2010 Jack Lloyd
*
* Released under the terms of the Botan license
*/
@@ -9,6 +9,7 @@
#define BOTAN_TLS_CIPHERSUITES_H__
#include <botan/types.h>
+#include <botan/tls_magic.h>
#include <string>
namespace Botan {
@@ -19,20 +20,19 @@ namespace Botan {
class BOTAN_DLL CipherSuite
{
public:
- enum Kex_Type { NO_KEX, RSA_KEX, DH_KEX };
- enum Sig_Type { NO_SIG, RSA_SIG, DSA_SIG };
+ static TLS_Ciphersuite_Algos lookup_ciphersuite(u16bit suite);
std::string cipher_algo() const { return cipher; }
std::string mac_algo() const { return mac; }
u32bit cipher_keylen() const { return cipher_key_length; }
- Kex_Type kex_type() const { return kex_algo; }
- Sig_Type sig_type() const { return sig_algo; }
+
+ TLS_Ciphersuite_Algos kex_type() const { return kex_algo; }
+ TLS_Ciphersuite_Algos sig_type() const { return sig_algo; }
CipherSuite(u16bit = 0);
private:
- Kex_Type kex_algo;
- Sig_Type sig_algo;
+ TLS_Ciphersuite_Algos kex_algo, sig_algo;
std::string cipher, mac;
u32bit cipher_key_length;
};