diff options
-rw-r--r-- | src/build-data/cc/gcc.txt | 2 | ||||
-rw-r--r-- | src/tls/c_hello.cpp | 19 | ||||
-rw-r--r-- | src/tls/tls_extensions.cpp | 3 | ||||
-rw-r--r-- | src/tls/tls_extensions.h | 33 | ||||
-rw-r--r-- | src/tls/tls_messages.h | 32 | ||||
-rw-r--r-- | src/tls/tls_session.cpp | 91 | ||||
-rw-r--r-- | src/tls/tls_session.h | 14 |
7 files changed, 190 insertions, 4 deletions
diff --git a/src/build-data/cc/gcc.txt b/src/build-data/cc/gcc.txt index 3de85099c..6173f6271 100644 --- a/src/build-data/cc/gcc.txt +++ b/src/build-data/cc/gcc.txt @@ -13,7 +13,7 @@ add_lib_option -l lang_flags "-D_REENTRANT -Wno-long-long" warning_flags "-W -Wall" -maintainer_warning_flags "-Werror -Weffc++ -Wall -Wextra -Wstrict-aliasing -Wstrict-overflow=5 -Wcast-align -Wmissing-declarations -Wpointer-arith -Wcast-qual -Wold-style-cast" +maintainer_warning_flags "-Werror -Wall -Wextra -Wstrict-aliasing -Wstrict-overflow=5 -Wcast-align -Wmissing-declarations -Wpointer-arith -Wcast-qual -Wold-style-cast" lib_opt_flags "-O3" check_opt_flags "-O2" diff --git a/src/tls/c_hello.cpp b/src/tls/c_hello.cpp index 35389f37b..e0fce03b5 100644 --- a/src/tls/c_hello.cpp +++ b/src/tls/c_hello.cpp @@ -207,6 +207,10 @@ void Client_Hello::deserialize_sslv2(const MemoryRegion<byte>& buf) m_secure_renegotiation = value_exists(m_suites, static_cast<u16bit>(TLS_EMPTY_RENEGOTIATION_INFO_SCSV)); + + m_fragment_size = 0; + m_next_protocol = false; + m_supports_session_ticket = false; } /* @@ -300,6 +304,21 @@ void Client_Hello::deserialize(const MemoryRegion<byte>& buf) m_supported_algos.push_back(std::make_pair("SHA-1", "DSA")); m_supported_algos.push_back(std::make_pair("SHA-1", "ECDSA")); } + else if(Maximum_Fragment_Length* frag = dynamic_cast<Maximum_Fragment_Length*>(extn)) + { + m_fragment_size = frag->fragment_size(); + } + else if(Session_Ticket* ticket = dynamic_cast<Session_Ticket*>(extn)) + { + m_supports_session_ticket = true; + m_session_ticket = ticket->contents(); + } + else if(Renegotation_Extension* reneg = dynamic_cast<Renegotation_Extension*>(extn)) + { + // checked by TLS_Client / TLS_Server as they know the handshake state + m_secure_renegotiation = true; + m_renegotiation_info = reneg->renegotiation_info(); + } } if(value_exists(m_suites, static_cast<u16bit>(TLS_EMPTY_RENEGOTIATION_INFO_SCSV))) diff --git a/src/tls/tls_extensions.cpp b/src/tls/tls_extensions.cpp index 5d345cc9b..d0d5b2c62 100644 --- a/src/tls/tls_extensions.cpp +++ b/src/tls/tls_extensions.cpp @@ -42,6 +42,9 @@ Extension* make_extension(TLS_Data_Reader& reader, case TLSEXT_NEXT_PROTOCOL: return new Next_Protocol_Notification(reader, size); + case TLSEXT_SESSION_TICKET: + return new Session_Ticket(reader, size); + default: return 0; // not known } diff --git a/src/tls/tls_extensions.h b/src/tls/tls_extensions.h index 180216b8b..a9e85221e 100644 --- a/src/tls/tls_extensions.h +++ b/src/tls/tls_extensions.h @@ -1,6 +1,6 @@ /* * TLS Extensions -* (C) 2011 Jack Lloyd +* (C) 2011-2012 Jack Lloyd * * Released under the terms of the Botan license */ @@ -210,6 +210,37 @@ class Next_Protocol_Notification : public Extension std::vector<std::string> m_protocols; }; +class Session_Ticket : public TLS_Extension + { + public: + TLS_Handshake_Extension_Type type() const + { return TLSEXT_SESSION_TICKET; } + + const MemoryVector<byte>& contents() const { return m_contents; } + + /** + * Create empty extension, used by both client and server + */ + Session_Ticket() {} + + /** + * Extension with ticket, used by client + */ + Session_Ticket(const MemoryRegion<byte>& session_ticket) : + m_contents(session_ticket) {} + + /** + * Deserialize a session ticket + */ + Session_Ticket(const TLS_Data_Reader& reader, u16bit extension_size); + + MemoryVector<byte> serialize() const { return m_contents; } + + bool empty() const { return false; } + private: + MemoryVector<byte> m_contents; + }; + /** * Supported Elliptic Curves Extension (RFC 4492) */ diff --git a/src/tls/tls_messages.h b/src/tls/tls_messages.h index 513fdad70..617b03813 100644 --- a/src/tls/tls_messages.h +++ b/src/tls/tls_messages.h @@ -108,6 +108,11 @@ class Client_Hello : public Handshake_Message size_t fragment_size() const { return m_fragment_size; } + bool supports_session_ticket() const { return m_supports_session_ticket; } + + const MemoryRegion<byte>& session_ticket() const + { return m_session_ticket; } + Client_Hello(Record_Writer& writer, Handshake_Hash& hash, const Policy& policy, @@ -145,6 +150,9 @@ class Client_Hello : public Handshake_Message std::vector<std::pair<std::string, std::string> > m_supported_algos; std::vector<std::string> m_supported_curves; + + bool m_supports_session_ticket; + MemoryVector<byte> m_session_ticket; }; /** @@ -454,6 +462,30 @@ class Next_Protocol : public Handshake_Message std::string m_protocol; }; +class New_Session_Ticket : public Handshake_Message + { + public: + Handshake_Type type() const { return NEW_SESSION_TICKET; } + + static TLS_Session decrypt(const MemoryRegion<byte>& ctext, + const SymmetricKey& key, + const MemoryRegion<byte>& key_name); + + const MemoryVector<byte>& contents() const { return m_contents; } + + New_Session_Ticket(const TLS_Session& session_info, + const SymmetricKey& key, + const MemoryRegion<byte>& key_name, + RandomNumberGenerator& rng); + + New_Session_Ticket(const MemoryRegion<byte>& buf) { deserialize(buf); } + private: + MemoryVector<byte> serialize() const; + void deserialize(const MemoryRegion<byte>&); + + MemoryVector<byte> m_contents; + }; + } } diff --git a/src/tls/tls_session.cpp b/src/tls/tls_session.cpp index 320f3c004..f8e686a4a 100644 --- a/src/tls/tls_session.cpp +++ b/src/tls/tls_session.cpp @@ -1,6 +1,6 @@ /* * TLS Session State -* (C) 2011 Jack Lloyd +* (C) 2011-2012 Jack Lloyd * * Released under the terms of the Botan license */ @@ -11,6 +11,8 @@ #include <botan/asn1_str.h> #include <botan/pem.h> #include <botan/time.h> +#include <botan/lookup.h> +#include <memory> namespace Botan { @@ -128,4 +130,91 @@ std::string Session::PEM_encode() const } +MemoryVector<byte> +TLS_Session::encrypt(const SymmetricKey& master_key, + const MemoryRegion<byte>& key_name, + RandomNumberGenerator& rng) + { + if(key_name.size() != 16) + throw Encoding_Error("Bad length " + to_string(key_name.size()) + + " for key_name in TLS_Session::encrypt"); + + if(master_key.length() == 0) + throw Decoding_Error("TLS_Session master_key not set"); + + std::auto_ptr<KDF> kdf(get_kdf("KDF2(SHA-256)")); + + SymmetricKey aes_key = kdf->derive_key(16, master_key.bits_of(), + "session-ticket.cipher-key"); + + SymmetricKey hmac_key = kdf->derive_key(32, master_key.bits_of(), + "session-ticket.hmac-key"); + + InitializationVector aes_iv(rng, 16); + + std::auto_ptr<MessageAuthenticationCode> mac(get_mac("HMAC(SHA-256)")); + mac->set_key(hmac_key); + + Pipe pipe(get_cipher("AES-128/CBC", aes_key, aes_iv, ENCRYPTION)); + pipe.process_msg(BER_encode()); + MemoryVector<byte> ctext = pipe.read_all(0); + + MemoryVector<byte> out; + out += key_name; + out += aes_iv.bits_of(); + out += ctext; + + mac->update(out); + + out += mac->final(); + return out; + } + +TLS_Session TLS_Session::decrypt(const MemoryRegion<byte>& buf, + const SymmetricKey& master_key, + const MemoryRegion<byte>& key_name) + { + try + { + if(buf.size() < (16 + 16 + 32 + 1)) + throw Decoding_Error("Encrypted TLS_Session too short to be real"); + + if(master_key.length() == 0) + throw Decoding_Error("TLS_Session master_key not set"); + + if(key_name.size() != 16) + throw Decoding_Error("Bad length " + to_string(key_name.size()) + + " for key_name"); + + std::auto_ptr<KDF> kdf(get_kdf("KDF2(SHA-256)")); + + SymmetricKey hmac_key = kdf->derive_key(32, master_key.bits_of(), + "session-ticket.hmac-key"); + + std::auto_ptr<MessageAuthenticationCode> mac(get_mac("HMAC(SHA-256)")); + mac->set_key(hmac_key); + + mac->update(&buf[0], buf.size() - 32); + MemoryVector<byte> computed_mac = mac->final(); + + if(!same_mem(&buf[buf.size() - 32], &computed_mac[0], computed_mac.size())) + throw Decoding_Error("MAC verification failed"); + + SymmetricKey aes_key = kdf->derive_key(16, master_key.bits_of(), + "session-ticket.cipher-key"); + + InitializationVector aes_iv(&buf[16], 16); + + Pipe pipe(get_cipher("AES-128/CBC", aes_key, aes_iv, DECRYPTION)); + pipe.process_msg(&buf[16], buf.size() - (16 + 32)); + MemoryVector<byte> ber = pipe.read_all(); + + return TLS_Session(&ber[0], ber.size()); + } + catch(...) + { + throw Decoding_Error("Failed to decrypt encrypted session"); + } + } + } diff --git a/src/tls/tls_session.h b/src/tls/tls_session.h index 96b6d6daf..40aaee278 100644 --- a/src/tls/tls_session.h +++ b/src/tls/tls_session.h @@ -1,6 +1,6 @@ /* * TLS Session -* (C) 2011 Jack Lloyd +* (C) 2011-2012 Jack Lloyd * * Released under the terms of the Botan license */ @@ -13,6 +13,7 @@ #include <botan/tls_ciphersuite.h> #include <botan/tls_magic.h> #include <botan/secmem.h> +#include <botan/symkey.h> namespace Botan { @@ -71,6 +72,17 @@ class BOTAN_DLL Session SecureVector<byte> DER_encode() const; /** + * Encrypt a session (useful for serialization or session tickets) + */ + MemoryVector<byte> encrypt(const SymmetricKey& key, + const MemoryRegion<byte>& key_name, + RandomNumberGenerator& rng); + + static TLS_Session decrypt(const MemoryRegion<byte>& ctext, + const SymmetricKey& key, + const MemoryRegion<byte>& key_name); + + /** * Encode this session data for storage * @warning if the master secret is compromised so is the * session traffic |