diff options
72 files changed, 2028 insertions, 1088 deletions
diff --git a/checks/bench.cpp b/checks/bench.cpp index b6bf93377..5faba00db 100644 --- a/checks/bench.cpp +++ b/checks/bench.cpp @@ -153,18 +153,6 @@ void report_results(const std::string& algo, std::cout << algo; -#if defined(__SUNPRO_CC) - #define REVERSE_ITERATOR_BUG 1 -#elif defined(__GNUC__) && __GNUC__ <= 3 - #define REVERSE_ITERATOR_BUG 1 -#elif defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ == 0) - #define REVERSE_ITERATOR_BUG 1 -#endif - -#ifndef REVERSE_ITERATOR_BUG - #define REVERSE_ITERATOR_BUG 0 -#endif - #if (defined(__GNUC__) && __GNUC__ <= 3) || defined(__SUNPRO_CC) // Work around GCC 3.x bug, reverse iterators don't work for(std::map<double, std::string>::const_iterator i = results.begin(); i != results.end(); ++i) diff --git a/checks/pk.cpp b/checks/pk.cpp index e11578523..e06efb3ea 100644 --- a/checks/pk.cpp +++ b/checks/pk.cpp @@ -14,6 +14,12 @@ #include <botan/botan.h> #include <botan/oids.h> +#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO) + #include <botan/x509_key.h> + #include <botan/pkcs8.h> + #include <botan/pubkey.h> +#endif + #if defined(BOTAN_HAS_RSA) #include <botan/rsa.h> #endif diff --git a/checks/pk_bench.cpp b/checks/pk_bench.cpp index 449ff7730..ab4702dba 100644 --- a/checks/pk_bench.cpp +++ b/checks/pk_bench.cpp @@ -10,6 +10,12 @@ #include <botan/oids.h> #include <map> +#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO) + #include <botan/x509_key.h> + #include <botan/pkcs8.h> + #include <botan/pubkey.h> +#endif + #if defined(BOTAN_HAS_RSA) #include <botan/rsa.h> #endif diff --git a/checks/validate.cpp b/checks/validate.cpp index 65317604e..2bb099030 100644 --- a/checks/validate.cpp +++ b/checks/validate.cpp @@ -110,6 +110,7 @@ bool keywrap_test(const char* key_str, bool ok = true; +#if defined(BOTAN_HAS_RFC3394_KEYWRAP) try { SymmetricKey key(key_str); @@ -140,6 +141,7 @@ bool keywrap_test(const char* key_str, { std::cout << e.what() << "\n"; } +#endif return ok; } @@ -339,7 +341,7 @@ u32bit do_validation_tests(const std::string& filename, if(should_pass) std::cout << "Testing " << algorithm << "..." << std::endl; else - std::cout << "Testing (expecing failure) " + std::cout << "Testing (expecting failure) " << algorithm << "..." << std::endl; #endif alg_count = 0; diff --git a/checks/validate.dat b/checks/validate.dat index 7b8588aac..f440bb293 100644 --- a/checks/validate.dat +++ b/checks/validate.dat @@ -4123,26 +4123,28 @@ F0E1D2C3B4A5968778695A4B3C2D1E0F00112233445566 FEDCBA9876543210:05044B62FA52D080:\ F0E1D2C3B4A5968778695A4B3C2D1E0F0011223344556677 -[Camellia] +[Camellia-128] # From RFC 3713 - 0123456789ABCDEFFEDCBA9876543210:67673138549669730857065648EABE43:\ 0123456789ABCDEFFEDCBA9876543210 -0123456789ABCDEFFEDCBA9876543210:B4993401B3E996F84EE5CEE7D79B09B9:\ -0123456789ABCDEFFEDCBA98765432100011223344556677 - -0123456789ABCDEFFEDCBA9876543210:9ACC237DFF16D76C20EF7C919E3A7509:\ -0123456789ABCDEFFEDCBA987654321000112233445566778899AABBCCDDEEFF - -# From NESSIE - +# Nessie 00000000000000000000000000000000:6C227F749319A3AA7DA235A9BBA05A2C:\ 80000000000000000000000000000000 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:25DD9EB9DD67FBC6E8431F56F4FBE651:\ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +[Camellia-192] +# From RFC 3713 +0123456789ABCDEFFEDCBA9876543210:B4993401B3E996F84EE5CEE7D79B09B9:\ +0123456789ABCDEFFEDCBA98765432100011223344556677 + +[Camellia-256] +# From RFC 3713 +0123456789ABCDEFFEDCBA9876543210:9ACC237DFF16D76C20EF7C919E3A7509:\ +0123456789ABCDEFFEDCBA987654321000112233445566778899AABBCCDDEEFF + # First one is from RFC 2144. The rest were done with OpenSSL and bits taken # from /dev/urandom [CAST-128] diff --git a/configure.py b/configure.py index 60a6b324a..31b55756d 100755 --- a/configure.py +++ b/configure.py @@ -45,20 +45,27 @@ def get_vc_revision(): try: mtn = subprocess.Popen(['mtn', 'automate', 'heads'], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + stderr=subprocess.PIPE, + universal_newlines=True) (stdout, stderr) = mtn.communicate() - if(stderr != ''): - logging.debug('Error getting rev from monotone - %s' % (stderr)) + if mtn.returncode != 0: + logging.debug('Error getting rev from monotone - %d (%s)' + % (mtn.returncode, stderr)) return 'unknown' - logging.debug('Monotone reported revision ' + stdout.strip()) + rev = str(stdout).strip() + logging.debug('Monotone reported revision %s' % (rev)) - return 'mtn:' + stdout.strip() + return 'mtn:' + rev except OSError as e: logging.debug('Error getting rev from monotone - %s' % (e[1])) return 'unknown' + except Exception as e: + logging.debug('Error getting rev from monotone - %s' % (e)) + return 'unknown' + class BuildConfigurationInformation(object): @@ -523,6 +530,7 @@ def force_to_dict(l): Represents the information about a particular module """ class ModuleInfo(object): + def __init__(self, infofile): lex_me_harder(infofile, self, @@ -535,21 +543,22 @@ class ModuleInfo(object): 'need_isa': None, 'mp_bits': 0 }) - if self.source == [] and \ - self.header_internal == [] and \ - self.header_public == []: - - for (dirpath, dirnames, filenames) in os.walk(self.lives_in): - if dirpath == self.lives_in: + def extract_files_matching(basedir, suffixes): + for (dirpath, dirnames, filenames) in os.walk(basedir): + if dirpath == basedir: for filename in filenames: if filename.startswith('.'): continue - if filename.endswith('.cpp') or \ - filename.endswith('.S'): - self.source.append(filename) - elif filename.endswith('.h'): - self.header_public.append(filename) + for suffix in suffixes: + if filename.endswith(suffix): + yield filename + + if self.source == []: + self.source = list(extract_files_matching(self.lives_in, ['.cpp', '.S'])) + + if self.header_internal == [] and self.header_public == []: + self.header_public = list(extract_files_matching(self.lives_in, ['.h'])) # Coerce to more useful types def convert_lib_list(l): @@ -1728,12 +1737,19 @@ def main(argv = None): def get_gcc_version(gcc_bin): try: - subproc_result = subprocess.Popen( + gcc_proc = subprocess.Popen( gcc_bin.split(' ') + ['-dumpversion'], stdout=subprocess.PIPE, - stderr=subprocess.PIPE).communicate() + stderr=subprocess.PIPE, + universal_newlines=True) + + (stdout, stderr) = gcc_proc.communicate() + + if gcc_proc.returncode != 0: + logging.warning("GCC returned non-zero result %s" % (stderr)) + return None - gcc_version = ''.join(map(str, subproc_result)).strip() + gcc_version = stdout.strip() logging.info('Detected gcc version %s' % (gcc_version)) return gcc_version diff --git a/doc/examples/asio_tls_server.cpp b/doc/examples/asio_tls_server.cpp index 55f29b336..e721d0455 100644 --- a/doc/examples/asio_tls_server.cpp +++ b/doc/examples/asio_tls_server.cpp @@ -186,6 +186,46 @@ class tls_server_session : public boost::enable_shared_from_this<tls_server_sess std::vector<byte> m_outbox; }; +class Session_Manager_Locked : public Botan::TLS::Session_Manager + { + public: + bool load_from_session_id(const Botan::MemoryRegion<byte>& session_id, + Botan::TLS::Session& session) + { + boost::lock_guard<boost::mutex> lock(m_mutex); + return m_session_manager.load_from_session_id(session_id, session); + } + + bool load_from_host_info(const std::string& hostname, Botan::u16bit port, + Botan::TLS::Session& session) + { + boost::lock_guard<boost::mutex> lock(m_mutex); + return m_session_manager.load_from_host_info(hostname, port, session); + }; + + void remove_entry(const Botan::MemoryRegion<byte>& session_id) + { + boost::lock_guard<boost::mutex> lock(m_mutex); + m_session_manager.remove_entry(session_id); + } + + void save(const Botan::TLS::Session& session) + { + boost::lock_guard<boost::mutex> lock(m_mutex); + m_session_manager.save(session); + } + + Botan::u32bit session_lifetime() const + { + return m_session_manager.session_lifetime(); + } + + private: + boost::mutex m_mutex; + Botan::TLS::Session_Manager_In_Memory m_session_manager; + + }; + class tls_server { public: @@ -242,7 +282,7 @@ class tls_server tcp::acceptor m_acceptor; Botan::AutoSeeded_RNG m_rng; - Botan::TLS::Session_Manager_In_Memory m_session_manager; + Session_Manager_Locked m_session_manager; Botan::TLS::Policy m_policy; Credentials_Manager_Simple m_creds; }; @@ -271,7 +311,7 @@ int main() std::cout << "Using " << num_threads << " threads\n"; - std::vector<boost::shared_ptr<boost::thread>> threads; + std::vector<boost::shared_ptr<boost::thread> > threads; for(size_t i = 0; i != num_threads; ++i) { diff --git a/doc/examples/credentials.h b/doc/examples/credentials.h index 8a0d47911..65d34aeee 100644 --- a/doc/examples/credentials.h +++ b/doc/examples/credentials.h @@ -6,6 +6,8 @@ #include <botan/x509self.h> #include <botan/rsa.h> #include <botan/dsa.h> +#include <botan/srp6.h> +#include <botan/srp6_files.h> #include <botan/ecdsa.h> #include <iostream> #include <fstream> @@ -25,6 +27,104 @@ class Credentials_Manager_Simple : public Botan::Credentials_Manager public: Credentials_Manager_Simple(Botan::RandomNumberGenerator& rng) : rng(rng) {} + std::string srp_identifier(const std::string& type, + const std::string& hostname) + { + if(type == "tls-client" && hostname == "srp-host") + return "user"; + return ""; + } + + bool attempt_srp(const std::string& type, + const std::string& hostname) + { + if(hostname == "srp-host") + return true; + return false; + } + + std::vector<Botan::X509_Certificate> + trusted_certificate_authorities(const std::string& type, + const std::string& hostname) + { + + std::vector<Botan::X509_Certificate> certs; + + try + { + Botan::X509_Certificate testca("testCA.crt"); + certs.push_back(testca); + } + + if(type == "tls-client" && hostname == "twitter.com") + { + Botan::X509_Certificate verisign("/usr/share/ca-certificates/mozilla/VeriSign_Class_3_Public_Primary_Certification_Authority_-_G5.crt"); + certs.push_back(verisign); + } + + return certs; + } + + void verify_certificate_chain( + const std::string& type, + const std::string& purported_hostname, + const std::vector<Botan::X509_Certificate>& cert_chain) + { + try + { + Botan::Credentials_Manager::verify_certificate_chain(type, + purported_hostname, + cert_chain); + } + catch(std::exception& e) + { + std::cout << "Certificate verification failed - " << e.what() << " - but will ignore\n"; + } + } + + std::string srp_password(const std::string& type, + const std::string& hostname, + const std::string& identifier) + { + if(type == "tls-client" && hostname == "localhost" && identifier == "user") + return "password"; + + return ""; + } + + bool srp_verifier(const std::string& type, + const std::string& context, + const std::string& identifier, + std::string& group_id, + Botan::BigInt& verifier, + Botan::MemoryRegion<Botan::byte>& salt, + bool generate_fake_on_unknown) + { + + std::string pass = srp_password("tls-client", context, identifier); + if(pass == "") + { + if(!generate_fake_on_unknown) + return false; + + pass.resize(16); + Botan::global_state().global_rng().randomize((Botan::byte*)&pass[0], pass.size()); + } + + group_id = "modp/srp/2048"; + + salt.resize(16); + Botan::global_state().global_rng().randomize(&salt[0], salt.size()); + + verifier = Botan::generate_srp6_verifier(identifier, + pass, + salt, + group_id, + "SHA-1"); + + return true; + } + std::string psk_identity_hint(const std::string&, const std::string&) { @@ -34,6 +134,7 @@ class Credentials_Manager_Simple : public Botan::Credentials_Manager std::string psk_identity(const std::string&, const std::string&, const std::string& identity_hint) { + //return "lloyd"; return "Client_identity"; } @@ -49,6 +150,8 @@ class Credentials_Manager_Simple : public Botan::Credentials_Manager if(identity == "Client_identity") return Botan::SymmetricKey("b5a72e1387552e6dc10766dc0eda12961f5b21e17f98ef4c41e6572e53bd7527"); + if(identity == "lloyd") + return Botan::SymmetricKey("85b3c1b7dc62b507636ac767999c9630"); throw Botan::Internal_Error("No PSK set for " + identity); } @@ -86,7 +189,7 @@ class Credentials_Manager_Simple : public Botan::Credentials_Manager opts.email = "root@" + hostname; opts.dns = hostname; - std::unique_ptr<Private_Key> key; + std::auto_ptr<Private_Key> key; if(key_type == "rsa") key.reset(new RSA_PrivateKey(rng, 1024)); else if(key_type == "dsa") @@ -129,6 +232,9 @@ class Credentials_Manager_Simple : public Botan::Credentials_Manager { const std::string hostname = (context == "" ? "localhost" : context); + if(hostname == "nosuchname") + return std::vector<Botan::X509_Certificate>(); + std::string key_name = ""; if(value_exists(cert_key_types, "RSA")) diff --git a/doc/examples/tls_client.cpp b/doc/examples/tls_client.cpp index 7c921ce53..a787af1fe 100644 --- a/doc/examples/tls_client.cpp +++ b/doc/examples/tls_client.cpp @@ -24,7 +24,7 @@ using namespace Botan; -using namespace std::placeholders; +using namespace std::tr1::placeholders; int connect_to_host(const std::string& host, u16bit port) { @@ -125,7 +125,7 @@ void doit(RandomNumberGenerator& rng, { int sockfd = connect_to_host(host, port); - TLS::Client client(std::bind(socket_write, sockfd, _1, _2), + TLS::Client client(std::tr1::bind(socket_write, sockfd, _1, _2), process_data, handshake_complete, session_manager, @@ -188,7 +188,16 @@ void doit(RandomNumberGenerator& rng, continue; } - client.send(buf, got); + if(got == 2 && (buf[0] == 'R' || buf[0] == 'r') && buf[1] == '\n') + { + std::cout << "Client initiated renegotiation\n"; + client.renegotiate((buf[0] == 'R')); + } + + if(buf[0] == 'H') + client.heartbeat(&buf[1], got-1); + else + client.send(buf, got); } } diff --git a/doc/examples/tls_server.cpp b/doc/examples/tls_server.cpp index 6bbcfd8b5..334d8f1fc 100644 --- a/doc/examples/tls_server.cpp +++ b/doc/examples/tls_server.cpp @@ -19,22 +19,11 @@ using namespace std::placeholders; #include <iostream> #include <memory> -bool handshake_complete(const TLS::Session& session) - { - printf("Handshake complete, protocol=%04X ciphersuite=%s compression=%d\n", - session.version(), session.ciphersuite().to_string().c_str(), - session.compression_method()); - - printf("Session id = %s\n", hex_encode(session.session_id()).c_str()); - printf("Master secret = %s\n", hex_encode(session.master_secret()).c_str()); - return true; - } - class Blocking_TLS_Server { public: - Blocking_TLS_Server(std::function<void (const byte[], size_t)> output_fn, - std::function<size_t (byte[], size_t)> input_fn, + Blocking_TLS_Server(std::tr1::function<void (const byte[], size_t)> output_fn, + std::tr1::function<size_t (byte[], size_t)> input_fn, std::vector<std::string>& protocols, TLS::Session_Manager& sessions, Credentials_Manager& creds, @@ -43,24 +32,47 @@ class Blocking_TLS_Server input_fn(input_fn), server( output_fn, - std::bind(&Blocking_TLS_Server::reader_fn, std::ref(*this), _1, _2, _3), - handshake_complete, + std::tr1::bind(&Blocking_TLS_Server::reader_fn, std::tr1::ref(*this), _1, _2, _3), + std::tr1::bind(&Blocking_TLS_Server::handshake_complete, std::tr1::ref(*this), _1), sessions, creds, policy, - rng), + rng, + protocols), exit(false) { read_loop(); } + bool handshake_complete(const TLS::Session& session) + { + std::cout << "Handshake complete: " + << session.version().to_string() << " " + << session.ciphersuite().to_string() << " " + << "SessionID: " << hex_encode(session.session_id()) << "\n"; + + if(session.srp_identifier() != "") + std::cout << "SRP identifier: " << session.srp_identifier() << "\n"; + + if(server.next_protocol() != "") + std::cout << "Next protocol: " << server.next_protocol() << "\n"; + + /* + std::vector<X509_Certificate> peer_certs = session.peer_certs(); + if(peer_certs.size()) + std::cout << peer_certs[0].to_string(); + */ + + return true; + } + size_t read(byte buf[], size_t buf_len) { size_t got = read_queue.read(buf, buf_len); while(!exit && !got) { - read_loop(5); // header size + read_loop(TLS::TLS_HEADER_SIZE); got = read_queue.read(buf, buf_len); } @@ -119,7 +131,7 @@ class Blocking_TLS_Server read_queue.write(buf, buf_len); } - std::function<size_t (byte[], size_t)> input_fn; + std::tr1::function<size_t (byte[], size_t)> input_fn; TLS::Server server; SecureQueue read_queue; bool exit; @@ -148,8 +160,14 @@ int main(int argc, char* argv[]) Credentials_Manager_Simple creds(rng); std::vector<std::string> protocols; - protocols.push_back("spdy/2"); - protocols.push_back("http/1.0"); + + /* + * These are the protocols we advertise to the client, but the + * client will send back whatever it actually plans on talking, + * which may or may not take into account what we advertise. + */ + protocols.push_back("echo/1.0"); + protocols.push_back("echo/1.1"); while(true) { @@ -161,8 +179,8 @@ int main(int argc, char* argv[]) printf("Got new connection\n"); Blocking_TLS_Server tls( - std::bind(&Socket::write, std::ref(sock), _1, _2), - std::bind(&Socket::read, std::ref(sock), _1, _2, true), + std::tr1::bind(&Socket::write, std::tr1::ref(sock), _1, _2), + std::tr1::bind(&Socket::read, std::tr1::ref(sock), _1, _2, true), protocols, sessions, creds, @@ -196,7 +214,9 @@ int main(int argc, char* argv[]) } if(line == "reneg\n") - tls.underlying().renegotiate(); + tls.underlying().renegotiate(false); + else if(line == "RENEG\n") + tls.underlying().renegotiate(true); line.clear(); } diff --git a/doc/log.txt b/doc/log.txt index 478b27a94..b1206637a 100644 --- a/doc/log.txt +++ b/doc/log.txt @@ -34,6 +34,9 @@ Version 1.10.2, Not Yet Released * Add Google's Native Client as an compile target +* The Qt mutex wrapper was broken and would not compile with any recent + version of Qt. It has been removed. + * If targetting GCC on a Windows system, configure.py will warn that likely you wanted to configure for either MinGW or Cygwin, not the generic Windows target which is oriented to Win32 plus the Visual diff --git a/doc/tls.txt b/doc/tls.txt index dd4fb1270..267fb6e62 100644 --- a/doc/tls.txt +++ b/doc/tls.txt @@ -7,14 +7,14 @@ SSL and TLS .. versionadded:: 1.10.2 Botan supports both client and server implementations of the SSL/TLS -protocols, including SSL v3, TLS v1.0, and TLS v1.1 (the insecure and -obsolete SSL v2 protocol is not supported, beyond processing SSL v2 -client hellos which some implementations send for backwards -compatability). - -The implementation uses ``std::tr1::function``, so it may not have -been compiled into the version you are using; you can test for the -feature macro ``BOTAN_HAS_TLS`` to check. +protocols, including SSL v3, TLS v1.0, TLS v1.1, and TLS v1.2 (the +insecure and obsolete SSL v2 protocol is not supported, beyond +processing SSL v2 client hellos which some clients still send for +backwards compatability with ancient servers). + +The implementation uses ``std::tr1::function`` for callbacks, so it +may not have been compiled into the version you are using; you can +test for the feature macro ``BOTAN_HAS_TLS`` to check. General TLS Interface ---------------------------------------- diff --git a/src/alloc/alloc_mmap/mmap_mem.cpp b/src/alloc/alloc_mmap/mmap_mem.cpp index bdc3fcab9..b90b6d5f7 100644 --- a/src/alloc/alloc_mmap/mmap_mem.cpp +++ b/src/alloc/alloc_mmap/mmap_mem.cpp @@ -128,15 +128,17 @@ void MemoryMapping_Allocator::dealloc_block(void* ptr, size_t n) const byte PATTERNS[] = { 0x00, 0xF5, 0x5A, 0xAF, 0x00 }; + // The char* casts are for Solaris, args are void* on most other systems + for(size_t i = 0; i != sizeof(PATTERNS); ++i) { std::memset(ptr, PATTERNS[i], n); - if(::msync((char*)ptr, n, MS_SYNC)) + if(::msync(static_cast<char*>(ptr), n, MS_SYNC)) throw MemoryMapping_Failed("Sync operation failed"); } - if(::munmap((char*)ptr, n)) + if(::munmap(static_cast<char*>(ptr), n)) throw MemoryMapping_Failed("Could not unmap file"); } diff --git a/src/alloc/secmem.h b/src/alloc/secmem.h index 6c8a75c44..884f2ebc0 100644 --- a/src/alloc/secmem.h +++ b/src/alloc/secmem.h @@ -59,14 +59,14 @@ class MemoryRegion const T* begin() const { return buf; } /** - * Get a pointer to the last element in the buffer. - * @return pointer to the last element in the buffer + * Get a pointer to one past the last element in the buffer. + * @return pointer to one past the last element in the buffer */ T* end() { return (buf + size()); } /** - * Get a constant pointer to the last element in the buffer. - * @return constant pointer to the last element in the buffer + * Get a const pointer to one past the last element in the buffer. + * @return const pointer to one past the last element in the buffer */ const T* end() const { return (buf + size()); } @@ -172,11 +172,12 @@ class MemoryRegion * Copy constructor * @param other the other region to copy */ - MemoryRegion(const MemoryRegion<T>& other) + MemoryRegion(const MemoryRegion<T>& other) : + buf(0), + used(0), + allocated(0), + alloc(other.alloc) { - buf = 0; - used = allocated = 0; - alloc = other.alloc; resize(other.size()); copy(&other[0], other.size()); } diff --git a/src/block/camellia/camellia.cpp b/src/block/camellia/camellia.cpp index 054558c35..2b4862efc 100644 --- a/src/block/camellia/camellia.cpp +++ b/src/block/camellia/camellia.cpp @@ -12,6 +12,8 @@ namespace Botan { namespace Camellia_F { +namespace { + u64bit F(u64bit v, u64bit K) { static const byte SBOX[256] = { @@ -101,101 +103,11 @@ u64bit left_rot_lo(u64bit h, u64bit l, size_t shift) return (h >> (64-shift)) | (l << shift); } -} - -/* -* Camellia Encryption -*/ -void Camellia::encrypt_n(const byte in[], byte out[], size_t blocks) const - { - using namespace Camellia_F; - - for(size_t i = 0; i != blocks; ++i) - { - u64bit D1 = load_be<u64bit>(in, 0); - u64bit D2 = load_be<u64bit>(in, 1); - - const u64bit* K = &SK[0]; - - D1 ^= *K++; - D2 ^= *K++; - - while(true) - { - D2 ^= F(D1, *K++); - D1 ^= F(D2, *K++); - D2 ^= F(D1, *K++); - D1 ^= F(D2, *K++); - D2 ^= F(D1, *K++); - D1 ^= F(D2, *K++); - - if(K == &SK[SK.size()-2]) - break; - - D1 = FL (D1, *K++); - D2 = FLINV(D2, *K++); - } - - D2 ^= *K++; - D1 ^= *K++; - - store_be(out, D2, D1); - - in += BLOCK_SIZE; - out += BLOCK_SIZE; - } - } - -/* -* Camellia Decryption -*/ -void Camellia::decrypt_n(const byte in[], byte out[], size_t blocks) const - { - using namespace Camellia_F; - - for(size_t i = 0; i != blocks; ++i) - { - u64bit D1 = load_be<u64bit>(in, 0); - u64bit D2 = load_be<u64bit>(in, 1); - - const u64bit* K = &SK[SK.size()-1]; - - D2 ^= *K--; - D1 ^= *K--; - - while(true) - { - D2 ^= F(D1, *K--); - D1 ^= F(D2, *K--); - D2 ^= F(D1, *K--); - D1 ^= F(D2, *K--); - D2 ^= F(D1, *K--); - D1 ^= F(D2, *K--); - - if(K == &SK[1]) - break; - - D1 = FL (D1, *K--); - D2 = FLINV(D2, *K--); - } - - D1 ^= *K--; - D2 ^= *K; - - store_be(out, D2, D1); - - in += BLOCK_SIZE; - out += BLOCK_SIZE; - } - } - /* * Camellia Key Schedule */ -void Camellia::key_schedule(const byte key[], size_t length) +void key_schedule(SecureVector<u64bit>& SK, const byte key[], size_t length) { - using namespace Camellia_F; - const u64bit Sigma1 = 0xA09E667F3BCC908B; const u64bit Sigma2 = 0xB67AE8584CAA73B2; const u64bit Sigma3 = 0xC6EF372FE94F82BE; @@ -308,4 +220,136 @@ void Camellia::key_schedule(const byte key[], size_t length) } } + +/* +* Camellia Encryption +*/ +void encrypt(const byte in[], byte out[], size_t blocks, const SecureVector<u64bit>& SK) + { + for(size_t i = 0; i != blocks; ++i) + { + u64bit D1 = load_be<u64bit>(in, 0); + u64bit D2 = load_be<u64bit>(in, 1); + + const u64bit* K = &SK[0]; + + D1 ^= *K++; + D2 ^= *K++; + + while(true) + { + D2 ^= F(D1, *K++); + D1 ^= F(D2, *K++); + D2 ^= F(D1, *K++); + D1 ^= F(D2, *K++); + D2 ^= F(D1, *K++); + D1 ^= F(D2, *K++); + + if(K == &SK[SK.size()-2]) + break; + + D1 = FL (D1, *K++); + D2 = FLINV(D2, *K++); + } + + D2 ^= *K++; + D1 ^= *K++; + + store_be(out, D2, D1); + + in += 16; + out += 16; + } + } + +/* +* Camellia Decryption +*/ +void decrypt(const byte in[], byte out[], size_t blocks, const SecureVector<u64bit>& SK) + { + for(size_t i = 0; i != blocks; ++i) + { + u64bit D1 = load_be<u64bit>(in, 0); + u64bit D2 = load_be<u64bit>(in, 1); + + const u64bit* K = &SK[SK.size()-1]; + + D2 ^= *K--; + D1 ^= *K--; + + while(true) + { + D2 ^= F(D1, *K--); + D1 ^= F(D2, *K--); + D2 ^= F(D1, *K--); + D1 ^= F(D2, *K--); + D2 ^= F(D1, *K--); + D1 ^= F(D2, *K--); + + if(K == &SK[1]) + break; + + D1 = FL (D1, *K--); + D2 = FLINV(D2, *K--); + } + + D1 ^= *K--; + D2 ^= *K; + + store_be(out, D2, D1); + + in += 16; + out += 16; + } + } + +} + +} + +void Camellia_128::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::encrypt(in, out, blocks, SK); + } + +void Camellia_192::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::encrypt(in, out, blocks, SK); + } + +void Camellia_256::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::encrypt(in, out, blocks, SK); + } + +void Camellia_128::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::decrypt(in, out, blocks, SK); + } + +void Camellia_192::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::decrypt(in, out, blocks, SK); + } + +void Camellia_256::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + Camellia_F::decrypt(in, out, blocks, SK); + } + +void Camellia_128::key_schedule(const byte key[], size_t length) + { + Camellia_F::key_schedule(SK, key, length); + } + +void Camellia_192::key_schedule(const byte key[], size_t length) + { + Camellia_F::key_schedule(SK, key, length); + } + +void Camellia_256::key_schedule(const byte key[], size_t length) + { + Camellia_F::key_schedule(SK, key, length); + } + } diff --git a/src/block/camellia/camellia.h b/src/block/camellia/camellia.h index aaf3ad9e3..9ce305983 100644 --- a/src/block/camellia/camellia.h +++ b/src/block/camellia/camellia.h @@ -13,17 +13,53 @@ namespace Botan { /** -* Camellia +* Camellia-128 +*/ +class BOTAN_DLL Camellia_128 : public Block_Cipher_Fixed_Params<16, 16> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { SK.clear(); } + std::string name() const { return "Camellia-128"; } + BlockCipher* clone() const { return new Camellia_128; } + private: + void key_schedule(const byte key[], size_t length); + + SecureVector<u64bit> SK; + }; + +/** +* Camellia-192 +*/ +class BOTAN_DLL Camellia_192 : public Block_Cipher_Fixed_Params<16, 24> + { + public: + void encrypt_n(const byte in[], byte out[], size_t blocks) const; + void decrypt_n(const byte in[], byte out[], size_t blocks) const; + + void clear() { SK.clear(); } + std::string name() const { return "Camellia-192"; } + BlockCipher* clone() const { return new Camellia_192; } + private: + void key_schedule(const byte key[], size_t length); + + SecureVector<u64bit> SK; + }; + +/** +* Camellia-256 */ -class BOTAN_DLL Camellia : public Block_Cipher_Fixed_Params<16, 16, 32, 8> +class BOTAN_DLL Camellia_256 : public Block_Cipher_Fixed_Params<16, 32> { public: void encrypt_n(const byte in[], byte out[], size_t blocks) const; void decrypt_n(const byte in[], byte out[], size_t blocks) const; void clear() { SK.clear(); } - std::string name() const { return "Camellia"; } - BlockCipher* clone() const { return new Camellia; } + std::string name() const { return "Camellia-256"; } + BlockCipher* clone() const { return new Camellia_256; } private: void key_schedule(const byte key[], size_t length); diff --git a/src/cert/cvc/cvc_req.h b/src/cert/cvc/cvc_req.h index 1e8cea7f8..ac4e22453 100644 --- a/src/cert/cvc/cvc_req.h +++ b/src/cert/cvc/cvc_req.h @@ -35,7 +35,7 @@ class BOTAN_DLL EAC1_1_Req : public EAC1_1_gen_CVC<EAC1_1_Req> EAC1_1_Req(DataSource& source); /** - * Construct a CVC request from a DER encoded CVC reqeust file. + * Construct a CVC request from a DER encoded CVC request file. * @param str the path to the DER encoded file */ EAC1_1_Req(const std::string& str); diff --git a/src/cert/x509cert/x509cert.cpp b/src/cert/x509cert/x509cert.cpp index dccb7b7be..4cff28c39 100644 --- a/src/cert/x509cert/x509cert.cpp +++ b/src/cert/x509cert/x509cert.cpp @@ -287,9 +287,22 @@ bool cert_subject_dns_match(const std::string& name, { for(size_t i = 0; i != cert_names.size(); ++i) { - // support basic wildcarding? - if(cert_names[i] == name) + const std::string cn = cert_names[i]; + + if(cn == name) return true; + + /* + * Possible wildcard match. We only support the most basic form of + * cert wildcarding ala RFC 2595 + */ + if(cn.size() > 2 && cn[0] == '*' && cn[1] == '.' && name.size() > cn.size()) + { + const std::string base = cn.substr(1, std::string::npos); + + if(name.compare(name.size() - base.size(), base.size(), base) == 0) + return true; + } } return false; @@ -299,6 +312,9 @@ bool cert_subject_dns_match(const std::string& name, bool X509_Certificate::matches_dns_name(const std::string& name) const { + if(name == "") + return false; + if(cert_subject_dns_match(name, subject_info("DNS"))) return true; diff --git a/src/constructs/srp6/srp6.cpp b/src/constructs/srp6/srp6.cpp index b2785e7f6..9ce0d18be 100644 --- a/src/constructs/srp6/srp6.cpp +++ b/src/constructs/srp6/srp6.cpp @@ -1,6 +1,6 @@ /* -* SRP-6a -* (C) 2011 Jack Lloyd +* SRP-6a (RFC 5054 compatatible) +* (C) 2011,2012 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -69,14 +69,37 @@ BigInt compute_x(const std::string& hash_id, } +std::string srp6_group_identifier(const BigInt& N, const BigInt& g) + { + /* + This function assumes that only one 'standard' SRP parameter set has + been defined for a particular bitsize. As of this writing that is the case. + */ + try + { + const std::string group_name = "modp/srp/" + to_string(N.bits()); + + DL_Group group(group_name); + + if(group.get_p() == N && group.get_g() == g) + return group_name; + + throw std::runtime_error("Unknown SRP params"); + } + catch(...) + { + throw Invalid_Argument("Bad SRP group parameters"); + } + } + std::pair<BigInt, SymmetricKey> -SRP6_Client_Session:: step1(const std::string& identifier, - const std::string& password, - const std::string& group_id, - const std::string& hash_id, - const MemoryRegion<byte>& salt, - const BigInt& B, - RandomNumberGenerator& rng) +srp6_client_agree(const std::string& identifier, + const std::string& password, + const std::string& group_id, + const std::string& hash_id, + const MemoryRegion<byte>& salt, + const BigInt& B, + RandomNumberGenerator& rng) { DL_Group group(group_id); const BigInt& g = group.get_g(); @@ -89,7 +112,7 @@ SRP6_Client_Session:: step1(const std::string& identifier, BigInt k = hash_seq(hash_id, p_bytes, p, g); - BigInt a(rng, p.bits() - 1); + BigInt a(rng, 256); BigInt A = power_mod(g, a, p); @@ -104,11 +127,11 @@ SRP6_Client_Session:: step1(const std::string& identifier, return std::make_pair(A, Sk); } -BigInt SRP6_Client_Session::generate_verifier(const std::string& identifier, - const std::string& password, - const MemoryRegion<byte>& salt, - const std::string& group_id, - const std::string& hash_id) +BigInt generate_srp6_verifier(const std::string& identifier, + const std::string& password, + const MemoryRegion<byte>& salt, + const std::string& group_id, + const std::string& hash_id) { const BigInt x = compute_x(hash_id, identifier, password, salt); @@ -129,7 +152,7 @@ BigInt SRP6_Server_Session::step1(const BigInt& v, BigInt k = hash_seq(hash_id, p_bytes, p, g); - BigInt b(rng, p.bits() - 1); + BigInt b(rng, 256); B = (v*k + power_mod(g, b, p)) % p; diff --git a/src/constructs/srp6/srp6.h b/src/constructs/srp6/srp6.h index 01bd2a4c7..4fd127c70 100644 --- a/src/constructs/srp6/srp6.h +++ b/src/constructs/srp6/srp6.h @@ -1,6 +1,6 @@ /* * SRP-6a (RFC 5054 compatatible) -* (C) 2011 Jack Lloyd +* (C) 2011,2012 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -17,44 +17,43 @@ namespace Botan { /** -* Represents a SRP-6a client session +* SRP6a Client side +* @param username the username we are attempting login for +* @param password the password we are attempting to use +* @param group_id specifies the shared SRP group +* @param hash_id specifies a secure hash function +* @param salt is the salt value sent by the server +* @param B is the server's public value +* @param rng is a random number generator +* +* @return (A,K) the client public key and the shared secret key */ -class BOTAN_DLL SRP6_Client_Session - { - public: +std::pair<BigInt,SymmetricKey> +BOTAN_DLL srp6_client_agree(const std::string& username, + const std::string& password, + const std::string& group_id, + const std::string& hash_id, + const MemoryRegion<byte>& salt, + const BigInt& B, + RandomNumberGenerator& rng); - /** - * Client side step 1 - * @param username the username we are attempting login for - * @param password the password we are attempting to use - * @param group_id specifies the shared SRP group - * @param hash_id specifies a secure hash function - * @param salt is the salt value sent by the server - * @param B is the server's public value - * @param rng is a random number generator - * - * @return (A,K) the client public key and the shared secret key - */ - std::pair<BigInt,SymmetricKey> step1(const std::string& username, - const std::string& password, - const std::string& group_id, - const std::string& hash_id, - const MemoryRegion<byte>& salt, - const BigInt& B, - RandomNumberGenerator& rng); +/** +* Generate a new SRP-6 verifier +* @param identifier a username or other client identifier +* @param password the secret used to authenticate user +* @param salt a randomly chosen value, at least 128 bits long +*/ +BigInt BOTAN_DLL generate_srp6_verifier(const std::string& identifier, + const std::string& password, + const MemoryRegion<byte>& salt, + const std::string& group_id, + const std::string& hash_id); - /** - * Generate a new SRP-6 verifier - * @param identifier a username or other client identifier - * @param password the secret used to authenticate user - * @param salt a randomly chosen value, at least 128 bits long - */ - static BigInt generate_verifier(const std::string& identifier, - const std::string& password, - const MemoryRegion<byte>& salt, - const std::string& group_id, - const std::string& hash_id); - }; +/** +* Return the group id for this SRP param set, or else thrown an +* exception +*/ +std::string BOTAN_DLL srp6_group_identifier(const BigInt& N, const BigInt& g); /** * Represents a SRP-6a server session diff --git a/src/constructs/srp6/srp6_files.cpp b/src/constructs/srp6/srp6_files.cpp index 2d685614f..bc321745f 100644 --- a/src/constructs/srp6/srp6_files.cpp +++ b/src/constructs/srp6/srp6_files.cpp @@ -51,7 +51,7 @@ SRP6_Authenticator_File::SRP6_Authenticator_File(const std::string& filename) bool SRP6_Authenticator_File::lookup_user(const std::string& username, BigInt& v, - MemoryVector<byte>& salt, + MemoryRegion<byte>& salt, std::string& group_id) const { std::map<std::string, SRP6_Data>::const_iterator i = entries.find(username); diff --git a/src/constructs/srp6/srp6_files.h b/src/constructs/srp6/srp6_files.h index 1def0fd51..4e3293423 100644 --- a/src/constructs/srp6/srp6_files.h +++ b/src/constructs/srp6/srp6_files.h @@ -17,7 +17,7 @@ namespace Botan { /** * A GnuTLS compatible SRP6 authenticator file */ -class SRP6_Authenticator_File +class BOTAN_DLL SRP6_Authenticator_File { public: /** @@ -28,7 +28,7 @@ class SRP6_Authenticator_File bool lookup_user(const std::string& username, BigInt& v, - MemoryVector<byte>& salt, + MemoryRegion<byte>& salt, std::string& group_id) const; private: struct SRP6_Data diff --git a/src/credentials/credentials_manager.cpp b/src/credentials/credentials_manager.cpp index ef5d44819..88b653df5 100644 --- a/src/credentials/credentials_manager.cpp +++ b/src/credentials/credentials_manager.cpp @@ -30,6 +30,12 @@ SymmetricKey Credentials_Manager::psk(const std::string&, throw Internal_Error("No PSK set for identity " + identity); } +bool Credentials_Manager::attempt_srp(const std::string&, + const std::string&) + { + return false; + } + std::string Credentials_Manager::srp_identifier(const std::string&, const std::string&) { @@ -46,8 +52,7 @@ std::string Credentials_Manager::srp_password(const std::string&, bool Credentials_Manager::srp_verifier(const std::string&, const std::string&, const std::string&, - BigInt&, - BigInt&, + std::string&, BigInt&, MemoryRegion<byte>&, bool) @@ -96,9 +101,10 @@ void Credentials_Manager::verify_certificate_chain( if(cert_chain.empty()) throw std::invalid_argument("Certificate chain was empty"); - if(!cert_chain[0].matches_dns_name(purported_hostname)) + if(purported_hostname != "" && !cert_chain[0].matches_dns_name(purported_hostname)) throw std::runtime_error("Certificate did not match hostname"); +#if 1 std::vector<X509_Certificate> CAs = trusted_certificate_authorities(type, purported_hostname); X509_Store store; @@ -110,11 +116,33 @@ void Credentials_Manager::verify_certificate_chain( X509_Code result = store.validate_cert(cert_chain[0], X509_Store::TLS_SERVER); - if(CAs.empty() && result == CERT_ISSUER_NOT_FOUND) - return; + if(CAs.empty()) + { + if(result == CERT_ISSUER_NOT_FOUND) + return; + if(result == CANNOT_ESTABLISH_TRUST) + return; + } if(result != VERIFIED) - throw std::runtime_error("Certificate did not validate"); + throw std::runtime_error("Certificate did not validate, code " + to_string(result)); +#else + + // New X.509 API + const Certificate_Store& CAs = + trusted_certificate_authorities(type, purported_hostname); + + Path_Validation_Result result = + x509_path_validate(cert_chain, + Path_Validation_Restrictions(), + store); + + if(!result.successful_validation()) + throw std::runtime_error("Certificate validation failure: " + result.as_string()); + + if(!CAs.certificate_known(result.trust_root()) + throw std::runtime_error("Certificate chain roots in unknown/untrusted CA"); +#endif } } diff --git a/src/credentials/credentials_manager.h b/src/credentials/credentials_manager.h index e1b4268e3..67da07eec 100644 --- a/src/credentials/credentials_manager.h +++ b/src/credentials/credentials_manager.h @@ -49,6 +49,12 @@ class BOTAN_DLL Credentials_Manager const std::string& identity); /** + * Return true if we should attempt SRP authentication + */ + virtual bool attempt_srp(const std::string& type, + const std::string& context); + + /** * @return identifier for client-side SRP auth, if available for this type/context. Should return empty string if password auth not desired/available. @@ -73,20 +79,21 @@ class BOTAN_DLL Credentials_Manager virtual bool srp_verifier(const std::string& type, const std::string& context, const std::string& identifier, - BigInt& group_prime, - BigInt& group_generator, + std::string& group_name, BigInt& verifier, MemoryRegion<byte>& salt, bool generate_fake_on_unknown); /** - * Return a cert chain we can use, ordered from leaf to root. - * Assumed that we can get the private key of the leaf with - * private_key_for + * Return a cert chain we can use, ordered from leaf to root, + * or else an empty vector. * - * @param cert_key_type is a set string representing the allowed - * key type ("RSA", "DSA", "ECDSA", etc) or empty if no - * preference. + * It is assumed that the caller can get the private key of the + * leaf with private_key_for + * + * @param cert_key_types specifies the key types desired ("RSA", + * "DSA", "ECDSA", etc), or empty if there + * is no preference by the caller. */ virtual std::vector<X509_Certificate> cert_chain( const std::vector<std::string>& cert_key_types, @@ -94,13 +101,14 @@ class BOTAN_DLL Credentials_Manager const std::string& context); /** - * Return a cert chain we can use, ordered from leaf to root. - * Assumed that we can get the private key of the leaf with - * private_key_for + * Return a cert chain we can use, ordered from leaf to root, + * or else an empty vector. + * + * It is assumed that the caller can get the private key of the + * leaf with private_key_for * - * @param cert_key_type is a set string representing the allowed - * key type ("RSA", "DSA", "ECDSA", etc) or empty if no - * preference. + * @param cert_key_type specifies the type of key requested + * ("RSA", "DSA", "ECDSA", etc) */ std::vector<X509_Certificate> cert_chain_single_type( const std::string& cert_key_type, diff --git a/src/credentials/info.txt b/src/credentials/info.txt index f6dcdd64d..689c4f1ae 100644 --- a/src/credentials/info.txt +++ b/src/credentials/info.txt @@ -1 +1,6 @@ define CREDENTIALS_MANAGER + +<requires> +x509cert +x509store +</requires> diff --git a/src/engine/asm_engine/asm_engine.h b/src/engine/asm_engine/asm_engine.h index bd82566d3..40fe5342f 100644 --- a/src/engine/asm_engine/asm_engine.h +++ b/src/engine/asm_engine/asm_engine.h @@ -23,7 +23,7 @@ class Assembler_Engine : public Engine BlockCipher* find_block_cipher(const SCAN_Name&, Algorithm_Factory&) const; - HashFunction* find_hash(const SCAN_Name& reqeust, + HashFunction* find_hash(const SCAN_Name& request, Algorithm_Factory&) const; }; diff --git a/src/engine/core_engine/core_engine.h b/src/engine/core_engine/core_engine.h index 5386991c3..983b75290 100644 --- a/src/engine/core_engine/core_engine.h +++ b/src/engine/core_engine/core_engine.h @@ -44,10 +44,10 @@ class Core_Engine : public Engine StreamCipher* find_stream_cipher(const SCAN_Name&, Algorithm_Factory&) const; - HashFunction* find_hash(const SCAN_Name& reqeust, + HashFunction* find_hash(const SCAN_Name& request, Algorithm_Factory&) const; - MessageAuthenticationCode* find_mac(const SCAN_Name& reqeust, + MessageAuthenticationCode* find_mac(const SCAN_Name& request, Algorithm_Factory&) const; PBKDF* find_pbkdf(const SCAN_Name& algo_spec, diff --git a/src/engine/core_engine/lookup_block.cpp b/src/engine/core_engine/lookup_block.cpp index c27a13237..c46d4f4cd 100644 --- a/src/engine/core_engine/lookup_block.cpp +++ b/src/engine/core_engine/lookup_block.cpp @@ -135,8 +135,12 @@ BlockCipher* Core_Engine::find_block_cipher(const SCAN_Name& request, #endif #if defined(BOTAN_HAS_CAMELLIA) - if(request.algo_name() == "Camellia") - return new Camellia; + if(request.algo_name() == "Camellia-128") + return new Camellia_128; + if(request.algo_name() == "Camellia-192") + return new Camellia_192; + if(request.algo_name() == "Camellia-256") + return new Camellia_256; #endif #if defined(BOTAN_HAS_CAST) diff --git a/src/engine/openssl/ossl_arc4.cpp b/src/engine/openssl/ossl_arc4.cpp index 799206ce1..6469d263a 100644 --- a/src/engine/openssl/ossl_arc4.cpp +++ b/src/engine/openssl/ossl_arc4.cpp @@ -71,7 +71,7 @@ void ARC4_OpenSSL::cipher(const byte in[], byte out[], size_t length) } /** -* Look for an OpenSSL-suported stream cipher (ARC4) +* Look for an OpenSSL-supported stream cipher (ARC4) */ StreamCipher* OpenSSL_Engine::find_stream_cipher(const SCAN_Name& request, diff --git a/src/engine/simd_engine/simd_engine.h b/src/engine/simd_engine/simd_engine.h index 73f7d2233..66c8886f1 100644 --- a/src/engine/simd_engine/simd_engine.h +++ b/src/engine/simd_engine/simd_engine.h @@ -23,7 +23,7 @@ class SIMD_Engine : public Engine BlockCipher* find_block_cipher(const SCAN_Name&, Algorithm_Factory&) const; - HashFunction* find_hash(const SCAN_Name& reqeust, + HashFunction* find_hash(const SCAN_Name& request, Algorithm_Factory&) const; }; diff --git a/src/libstate/init.cpp b/src/libstate/init.cpp index 5fd476994..6ab303909 100644 --- a/src/libstate/init.cpp +++ b/src/libstate/init.cpp @@ -22,7 +22,7 @@ void LibraryInitializer::initialize(const std::string&) /* This two stage initialization process is because Library_State's constructor will implicitly refer to global state through the - allocators and so for, so global_state() has to be a valid + allocators and so forth, so global_state() has to be a valid reference before initialize() can be called. Yeah, gross. */ Global_State_Management::set_global_state(new Library_State); diff --git a/src/libstate/policy.cpp b/src/libstate/policy.cpp index f91eed1d8..b1da22ce8 100644 --- a/src/libstate/policy.cpp +++ b/src/libstate/policy.cpp @@ -37,7 +37,19 @@ void set_default_oids(Library_State& config) add_oid(config, "1.3.6.1.4.1.3029.1.2.1", "ElGamal"); add_oid(config, "1.3.6.1.4.1.25258.1.1", "RW"); add_oid(config, "1.3.6.1.4.1.25258.1.2", "NR"); - add_oid(config, "1.2.840.10045.2.1", "ECDSA"); // X9.62 + + // X9.62 ecPublicKey, valid for ECDSA and ECDH (RFC 3279 sec 2.3.5) + add_oid(config, "1.2.840.10045.2.1", "ECDSA"); + + /* + * This is an OID defined for ECDH keys though rarely used for such. + * In this configuration it is accepted on decoding, but not used for + * encoding. You can enable it for encoding by calling + * global_state().set("str2oid", "ECDH", "1.3.132.1.12") + * from your application code. + */ + config.set("oid2str", "1.3.132.1.12", "ECDH"); + add_oid(config, "1.2.643.2.2.19", "GOST-34.10"); // RFC 4491 /* Ciphers */ @@ -325,6 +337,15 @@ void set_default_dl_groups(Library_State& config) "NgRlEbmT//////////8=" "-----END X942 DH PARAMETERS-----"); + config.set("dl", "modp/srp/1536", + "-----BEGIN DH PARAMETERS-----" + "MIHHAoHBAJ3vPK+5OSd6sfEqhheke7vbpR30maxMgL7uqWFLGcxNX09fVW4ny95R" + "xqlL5GB6KRVYkDug0PhDgLZVu5oi6NzfAop87Gfw0IE0sci5eYkUm2CeC+O6tj1H" + "VIOB28Wx/HZOP0tT3Z2hFYv9PiucjPVu3wGVOTSWJ9sv1T0kt8SGZXcuQ31sf4zk" + "QnNK98y3roN8Jkrjqb64f4ov6bi1KS5aAh//XpFHnoznoowkQsbzFRgPk0maI03P" + "duP+0TX5uwIBAg==" + "-----END DH PARAMETERS-----"); + config.set("dl", "modp/ietf/2048", "-----BEGIN X942 DH PARAMETERS-----" "MIICDAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" @@ -376,6 +397,19 @@ void set_default_dl_groups(Library_State& config) "JcFokFSdaWV//////////w==" "-----END X942 DH PARAMETERS-----"); + config.set("dl", "modp/srp/3072", + "-----BEGIN DH PARAMETERS-----" + "MIIBiAKCAYEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqTrS" + "yv//////////AgEF" + "-----END DH PARAMETERS-----"); + config.set("dl", "modp/ietf/4096", "-----BEGIN X942 DH PARAMETERS-----" "MIIEDAKCAgEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" @@ -402,6 +436,21 @@ void set_default_dl_groups(Library_State& config) "ydp1TEbH7uDDf9vuSFNgR6b6GuSaAxjM//////////8=" "-----END X942 DH PARAMETERS-----"); + config.set("dl", "modp/srp/4096", + "-----BEGIN DH PARAMETERS-----" + "MIICCAKCAgEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI" + "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O" + "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI" + "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0BjGZ//////////8CAQU=" + "-----END DH PARAMETERS-----"); + config.set("dl", "modp/ietf/6144", "-----BEGIN X942 DH PARAMETERS-----" "MIIGDAKCAwEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" @@ -439,6 +488,27 @@ void set_default_dl_groups(Library_State& config) "jzbmIBJ//////////wIBAg==" "-----END X942 DH PARAMETERS-----"); + config.set("dl", "modp/srp/6144", + "-----BEGIN DH PARAMETERS-----" + "MIIDCAKCAwEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI" + "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O" + "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI" + "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG" + "3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU" + "7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId" + "A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha" + "xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/" + "8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebcxA" + "JP//////////AgEF" + "-----END DH PARAMETERS-----"); + config.set("dl", "modp/ietf/8192", "-----BEGIN X942 DH PARAMETERS-----" "MIIIDAKCBAEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" @@ -486,6 +556,32 @@ void set_default_dl_groups(Library_State& config) "034BNyPKrHIjqzv01U8YKHE7K0pv5A+rdEBctziwZMBuzHbp7///////////AgEC" "-----END X942 DH PARAMETERS-----"); + config.set("dl", "modp/srp/8192", + "-----BEGIN DH PARAMETERS-----" + "MIIECAKCBAEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb" + "IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft" + "awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT" + "mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh" + "fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq" + "5RXSJhiY+gUQFXKOWoqqxC2tMxcNBFB6M6hVIavfHLpk7PuFBFjb7wqK6nFXXQYM" + "fbOXD4Wm4eTHq/WujNsJM9cejJTgSiVhnc7j0iYa0u5r8S/6BtmKCGTYdgJzPshq" + "ZFIfKxgXeyAMu+EXV3phXWx3CYjAutlG4gjiT6B05asxQ9tb/OD9EI5LgtEgqSEI" + "ARpyPBKnh+bXiHGaEL26WyaZwycYavTiPBqUaDS2FQvaJYPpyirUTOjbu8LbBN6O" + "+S6O/BQfvsqmKHxZR05rwF2ZspZPoJDDoiM7oYZRW+ftH2EpcM7i16+4G912IXBI" + "HNAGkSfVsFqpk7TqmI2P3cGG/7fckKbAj030Nck0AoSSNsP6tNJ8cCbB1NyyYCZG" + "3sl1HnY9uje9+P+UBq2eUw7l2zgvQTABrrBqU+2QJ9gxF5cnsIZaiRjaPtvrz5sU" + "7UTObLrO1Lsb238UR+bMJUszIFFRK9evQm+49AE3jNK/WYPKAcZLkuzwMuoV0XId" + "A/SC185udP721V5wL0aYDIK1qEAxkAscnlnnyX++x+jzI6l6fjbMiL4PHUW3/1ha" + "xUvUB7IrQVSqzI9tfr9I4dgUzF7SD4A34KeXFe7ym+MoBqHVi7fF2nb1UKo9ih+/" + "8OsZzLGjE9Vc2lbJ7C7yljI4f+jXbjwEaAQ+j2Y/SGDuEr8tWwt0dNbmlPkebb4R" + "WXSjkm8S/uXkOHd8tqky34zYvsTQc7kxujvIMraNndMAdB+nv4r8R+0ldvaTa6Qk" + "ZjqrY5xa5PVoNCO0dCvxyXgjjxbL451lLeP9uL78hIrZIiIuBKQDfAcT61eoGiPw" + "xzRz/GRs6jBrS8vIhi+Dhd36nUt/osCH6HloMwPtW906Bis89bOieKZtKhP4P0T4" + "Ld8xDuB0q2o2RZfomaAlXcFk8xzFCEaFHfmrSBld7X6hsdUQvX7nTXP682vDHs+i" + "aDWQRvTrh5+SQAlDi0gcbNeImgAu1e44K8kZDab8Am5HlVjkR1Z36aqeMFDidlaU" + "38gfVuiAuW5xYMmA3Zjt09///////////wIBEw==" + "-----END DH PARAMETERS-----"); + config.set("dl", "dsa/jce/512", "-----BEGIN DSA PARAMETERS-----" "MIGdAkEA/KaCzo4Syrom78z3EQ5SbbB4sF7ey80etKII864WF64B81uRpH5t9jQT" diff --git a/src/math/numbertheory/pow_mod.h b/src/math/numbertheory/pow_mod.h index 7ec237d72..9857c1833 100644 --- a/src/math/numbertheory/pow_mod.h +++ b/src/math/numbertheory/pow_mod.h @@ -61,7 +61,7 @@ class BOTAN_DLL Power_Mod Power_Mod(const BigInt& = 0, Usage_Hints = NO_HINTS); Power_Mod(const Power_Mod&); - ~Power_Mod(); + virtual ~Power_Mod(); private: mutable Modular_Exponentiator* core; Usage_Hints hints; diff --git a/src/pubkey/workfactor.cpp b/src/pubkey/workfactor.cpp index f3d5d164a..72ba75cf9 100644 --- a/src/pubkey/workfactor.cpp +++ b/src/pubkey/workfactor.cpp @@ -1,6 +1,6 @@ /* * Public Key Work Factor Functions -* (C) 1999-2007 Jack Lloyd +* (C) 1999-2007,2012 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -11,39 +11,40 @@ namespace Botan { -/* -* Choose the exponent size for a DL group -*/ size_t dl_work_factor(size_t bits) { -#if 0 /* - These values were taken from RFC 3526 + Based on GNFS work factors. Constant is 1.43 times the asymptotic + value; I'm not sure but I believe that came from a paper on 'real + world' runtimes, but I don't remember where now. + + Sample return values: + |512| -> 64 + |1024| -> 86 + |1536| -> 102 + |2048| -> 116 + |3072| -> 138 + |4096| -> 155 + |8192| -> 206 + + For DL algos, we use an exponent of twice the size of the result; + the assumption is that an arbitrary discrete log on a group of size + bits would take about 2^n effort, and thus using an exponent of + size 2^(2*n) implies that all available attacks are about as easy + (as e.g Pollard's kangaroo algorithm can compute the DL in sqrt(x) + operations) while minimizing the exponent size for performance + reasons. */ - if(bits <= 1536) - return 90; - else if(bits <= 2048) - return 110; - else if(bits <= 3072) - return 130; - else if(bits <= 4096) - return 150; - else if(bits <= 6144) - return 170; - else if(bits <= 8192) - return 190; - return 256; -#else - const double MIN_ESTIMATE = 64; - - const double log_x = bits / 1.44; + + const size_t MIN_WORKFACTOR = 64; + + // approximates natural logarithm of p + const double log_p = bits / 1.4426; const double strength = - 2.76 * std::pow(log_x, 1.0/3.0) * std::pow(std::log(log_x), 2.0/3.0); + 2.76 * std::pow(log_p, 1.0/3.0) * std::pow(std::log(log_p), 2.0/3.0); - return static_cast<size_t>(std::max(strength, MIN_ESTIMATE)); -#endif + return std::max(static_cast<size_t>(strength), MIN_WORKFACTOR); } - } diff --git a/src/pubkey/workfactor.h b/src/pubkey/workfactor.h index bd1a43298..179b580e7 100644 --- a/src/pubkey/workfactor.h +++ b/src/pubkey/workfactor.h @@ -13,7 +13,7 @@ namespace Botan { /** -* Estimate work factor +* Estimate work factor for discrete logarithm * @param prime_group_size size of the group in bits * @return estimated security level for this group */ diff --git a/src/tls/c_hello.cpp b/src/tls/c_hello.cpp index b08e1abe2..056a7550f 100644 --- a/src/tls/c_hello.cpp +++ b/src/tls/c_hello.cpp @@ -11,19 +11,20 @@ #include <botan/internal/tls_extensions.h> #include <botan/tls_record.h> #include <botan/internal/stl_util.h> -#include <chrono> +#include <botan/time.h> namespace Botan { namespace TLS { +enum { + TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF +}; + MemoryVector<byte> make_hello_random(RandomNumberGenerator& rng) { MemoryVector<byte> buf(32); - - const u32bit time32 = static_cast<u32bit>( - std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())); - + const u32bit time32 = system_time(); store_be(time32, buf); rng.randomize(&buf[4], buf.size() - 4); return buf; @@ -67,7 +68,7 @@ Client_Hello::Client_Hello(Record_Writer& writer, const std::string& srp_identifier) : m_version(policy.pref_version()), m_random(make_hello_random(rng)), - m_suites(policy.ciphersuite_list((srp_identifier != ""))), + m_suites(ciphersuite_list(policy, (srp_identifier != ""))), m_comp_methods(policy.compression()), m_hostname(hostname), m_srp_identifier(srp_identifier), @@ -76,7 +77,9 @@ Client_Hello::Client_Hello(Record_Writer& writer, m_secure_renegotiation(true), m_renegotiation_info(reneg_info), m_supported_curves(policy.allowed_ecc_curves()), - m_supports_session_ticket(true) + m_supports_session_ticket(true), + m_supports_heartbeats(true), + m_peer_can_send_heartbeats(true) { std::vector<std::string> hashes = policy.allowed_hashes(); std::vector<std::string> sigs = policy.allowed_signature_methods(); @@ -95,21 +98,25 @@ Client_Hello::Client_Hello(Record_Writer& writer, Handshake_Hash& hash, const Policy& policy, RandomNumberGenerator& rng, + const MemoryRegion<byte>& reneg_info, const Session& session, bool next_protocol) : m_version(session.version()), m_session_id(session.session_id()), m_random(make_hello_random(rng)), - m_suites(policy.ciphersuite_list(session.srp_identifier() != "")), + m_suites(ciphersuite_list(policy, (session.srp_identifier() != ""))), m_comp_methods(policy.compression()), m_hostname(session.sni_hostname()), m_srp_identifier(session.srp_identifier()), m_next_protocol(next_protocol), m_fragment_size(session.fragment_size()), m_secure_renegotiation(session.secure_renegotiation()), + m_renegotiation_info(reneg_info), m_supported_curves(policy.allowed_ecc_curves()), m_supports_session_ticket(true), - m_session_ticket(session.session_ticket()) + m_session_ticket(session.session_ticket()), + m_supports_heartbeats(true), + m_peer_can_send_heartbeats(true) { if(!value_exists(m_suites, session.ciphersuite_code())) m_suites.push_back(session.ciphersuite_code()); @@ -135,6 +142,8 @@ Client_Hello::Client_Hello(const MemoryRegion<byte>& buf, Handshake_Type type) m_next_protocol = false; m_secure_renegotiation = false; m_supports_session_ticket = false; + m_supports_heartbeats = false; + m_peer_can_send_heartbeats = false; m_fragment_size = 0; if(type == CLIENT_HELLO) @@ -167,28 +176,23 @@ MemoryVector<byte> Client_Hello::serialize() const Extensions extensions; - // Initial handshake - if(m_renegotiation_info.empty()) - { + if(m_secure_renegotiation) extensions.add(new Renegotation_Extension(m_renegotiation_info)); - extensions.add(new Server_Name_Indicator(m_hostname)); - extensions.add(new SRP_Identifier(m_srp_identifier)); - extensions.add(new Supported_Elliptic_Curves(m_supported_curves)); - if(m_version >= Protocol_Version::TLS_V12) - extensions.add(new Signature_Algorithms(m_supported_algos)); + extensions.add(new Session_Ticket(m_session_ticket)); - if(m_next_protocol) - extensions.add(new Next_Protocol_Notification()); + extensions.add(new Server_Name_Indicator(m_hostname)); + extensions.add(new SRP_Identifier(m_srp_identifier)); - extensions.add(new Session_Ticket(m_session_ticket)); - } - else - { - // renegotiation - extensions.add(new Renegotation_Extension(m_renegotiation_info)); - extensions.add(new Session_Ticket(m_session_ticket)); - } + extensions.add(new Supported_Elliptic_Curves(m_supported_curves)); + + if(m_version >= Protocol_Version::TLS_V12) + extensions.add(new Signature_Algorithms(m_supported_algos)); + + extensions.add(new Heartbeat_Support_Indicator(true)); + + if(m_renegotiation_info.empty() && m_next_protocol) + extensions.add(new Next_Protocol_Notification()); buf += extensions.serialize(); @@ -337,6 +341,12 @@ void Client_Hello::deserialize(const MemoryRegion<byte>& buf) m_session_ticket = ticket->contents(); } + if(Heartbeat_Support_Indicator* hb = extensions.get<Heartbeat_Support_Indicator>()) + { + m_supports_heartbeats = true; + m_peer_can_send_heartbeats = hb->peer_allowed_to_send(); + } + if(Renegotation_Extension* reneg = extensions.get<Renegotation_Extension>()) { // checked by TLS_Client / TLS_Server as they know the handshake state diff --git a/src/tls/c_kex.cpp b/src/tls/c_kex.cpp index 0e7eba23a..13925a482 100644 --- a/src/tls/c_kex.cpp +++ b/src/tls/c_kex.cpp @@ -15,6 +15,7 @@ #include <botan/dh.h> #include <botan/ecdh.h> #include <botan/rsa.h> +#include <botan/srp6.h> #include <botan/rng.h> #include <botan/loadstor.h> #include <memory> @@ -50,6 +51,7 @@ Client_Key_Exchange::Client_Key_Exchange(Record_Writer& writer, Handshake_State* state, Credentials_Manager& creds, const std::vector<X509_Certificate>& peer_certs, + const std::string& hostname, RandomNumberGenerator& rng) { const std::string kex_algo = state->suite.kex_algo(); @@ -147,8 +149,7 @@ Client_Key_Exchange::Client_Key_Exchange(Record_Writer& writer, const std::string name = Supported_Elliptic_Curves::curve_id_to_name(curve_id); if(name == "") - throw Decoding_Error("Server sent unknown named curve " + - std::to_string(curve_id)); + throw Decoding_Error("Server sent unknown named curve " + to_string(curve_id)); EC_Group group(name); @@ -172,6 +173,33 @@ Client_Key_Exchange::Client_Key_Exchange(Record_Writer& writer, append_tls_length_value(key_material, priv_key.public_value(), 1); } + else if(kex_algo == "SRP_SHA") + { + const BigInt N = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); + const BigInt g = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); + MemoryVector<byte> salt = reader.get_range<byte>(1, 1, 255); + const BigInt B = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); + + const std::string srp_group = srp6_group_identifier(N, g); + + const std::string srp_identifier = + creds.srp_identifier("tls-client", hostname); + + const std::string srp_password = + creds.srp_password("tls-client", hostname, srp_identifier); + + std::pair<BigInt, SymmetricKey> srp_vals = + srp6_client_agree(srp_identifier, + srp_password, + srp_group, + "SHA-1", + salt, + B, + rng); + + append_tls_length_value(key_material, BigInt::encode(srp_vals.first), 2); + pre_master = srp_vals.second.bits_of(); + } else { throw Internal_Error("Client_Key_Exchange: Unknown kex " + @@ -188,7 +216,7 @@ Client_Key_Exchange::Client_Key_Exchange(Record_Writer& writer, if(peer_certs.empty()) throw Internal_Error("No certificate and no server key exchange"); - std::unique_ptr<Public_Key> pub_key(peer_certs[0].subject_public_key()); + std::auto_ptr<Public_Key> pub_key(peer_certs[0].subject_public_key()); if(const RSA_PublicKey* rsa_pub = dynamic_cast<const RSA_PublicKey*>(pub_key.get())) { @@ -302,6 +330,12 @@ Client_Key_Exchange::Client_Key_Exchange(const MemoryRegion<byte>& contents, append_tls_length_value(pre_master, zeros, 2); append_tls_length_value(pre_master, psk.bits_of(), 2); } + else if(kex_algo == "SRP_SHA") + { + SRP6_Server_Session& srp = state->server_kex->server_srp_params(); + + pre_master = srp.step2(BigInt::decode(reader.get_range<byte>(2, 0, 65535))).bits_of(); + } else if(kex_algo == "DH" || kex_algo == "DHE_PSK" || kex_algo == "ECDH" || kex_algo == "ECDHE_PSK") { diff --git a/src/tls/cert_req.cpp b/src/tls/cert_req.cpp index df70cc43d..1b686c1c4 100644 --- a/src/tls/cert_req.cpp +++ b/src/tls/cert_req.cpp @@ -122,7 +122,7 @@ Certificate_Req::Certificate_Req(const MemoryRegion<byte>& buf, m_supported_algos.push_back(std::make_pair("SHA-1", "ECDSA")); } - u16bit purported_size = reader.get_u16bit(); + const u16bit purported_size = reader.get_u16bit(); if(reader.remaining_bytes() != purported_size) throw Decoding_Error("Inconsistent length in certificate request"); @@ -153,18 +153,20 @@ MemoryVector<byte> Certificate_Req::serialize() const append_tls_length_value(buf, cert_types, 1); if(!m_supported_algos.empty()) - { buf += Signature_Algorithms(m_supported_algos).serialize(); - } + + MemoryVector<byte> encoded_names; for(size_t i = 0; i != names.size(); ++i) { DER_Encoder encoder; encoder.encode(names[i]); - append_tls_length_value(buf, encoder.get_contents(), 2); + append_tls_length_value(encoded_names, encoder.get_contents(), 2); } + append_tls_length_value(buf, encoded_names, 2); + return buf; } diff --git a/src/tls/info.txt b/src/tls/info.txt index b19eedb20..3407aba32 100644 --- a/src/tls/info.txt +++ b/src/tls/info.txt @@ -1,5 +1,7 @@ define TLS +load_on auto + <comment> The TLS code is complex, new, and not yet reviewed, there may be serious bugs or security issues. @@ -8,6 +10,7 @@ serious bugs or security issues. <header:public> tls_alert.h tls_channel.h +tls_ciphersuite.h tls_client.h tls_exceptn.h tls_magic.h @@ -16,7 +19,6 @@ tls_record.h tls_server.h tls_session.h tls_session_manager.h -tls_ciphersuite.h tls_version.h </header:public> @@ -25,13 +27,13 @@ tls_extensions.h tls_handshake_hash.h tls_handshake_reader.h tls_handshake_state.h +tls_heartbeats.h tls_messages.h tls_reader.h tls_session_key.h </header:internal> <source> -tls_alert.cpp c_hello.cpp c_kex.cpp cert_req.cpp @@ -44,18 +46,21 @@ rec_wri.cpp s_hello.cpp s_kex.cpp session_ticket.cpp +tls_alert.cpp tls_channel.cpp +tls_ciphersuite.cpp tls_client.cpp tls_extensions.cpp tls_handshake_hash.cpp tls_handshake_reader.cpp tls_handshake_state.cpp +tls_heartbeats.cpp tls_policy.cpp tls_server.cpp tls_session.cpp tls_session_key.cpp tls_session_manager.cpp -tls_ciphersuite.cpp +tls_suite_info.cpp tls_version.cpp </source> @@ -63,6 +68,8 @@ tls_version.cpp aes arc4 asn1 +camellia +cbc credentials des dh @@ -80,6 +87,7 @@ prf_tls rng rsa seed +srp6 sha1 sha2_32 ssl3mac diff --git a/src/tls/rec_read.cpp b/src/tls/rec_read.cpp index bd6ae5af9..5d46ec1fa 100644 --- a/src/tls/rec_read.cpp +++ b/src/tls/rec_read.cpp @@ -216,10 +216,11 @@ size_t Record_Reader::add_input(const byte input_array[], size_t input_sz, if(m_readbuf[0] != CHANGE_CIPHER_SPEC && m_readbuf[0] != ALERT && m_readbuf[0] != HANDSHAKE && - m_readbuf[0] != APPLICATION_DATA) + m_readbuf[0] != APPLICATION_DATA && + m_readbuf[0] != HEARTBEAT) { throw Unexpected_Message( - "Unknown record type " + std::to_string(m_readbuf[0]) + " from counterparty"); + "Unknown record type " + to_string(m_readbuf[0]) + " from counterparty"); } const size_t record_len = make_u16bit(m_readbuf[3], m_readbuf[4]); diff --git a/src/tls/s_hello.cpp b/src/tls/s_hello.cpp index 7da9fdc57..1244dd2d8 100644 --- a/src/tls/s_hello.cpp +++ b/src/tls/s_hello.cpp @@ -21,47 +21,6 @@ namespace TLS { */ Server_Hello::Server_Hello(Record_Writer& writer, Handshake_Hash& hash, - Protocol_Version version, - const Client_Hello& c_hello, - const std::vector<std::string>& available_cert_types, - const Policy& policy, - bool have_session_ticket_key, - bool client_has_secure_renegotiation, - const MemoryRegion<byte>& reneg_info, - bool client_has_npn, - const std::vector<std::string>& next_protocols, - RandomNumberGenerator& rng) : - s_version(version), - m_session_id(rng.random_vec(32)), - s_random(make_hello_random(rng)), - m_fragment_size(c_hello.fragment_size()), - m_secure_renegotiation(client_has_secure_renegotiation), - m_renegotiation_info(reneg_info), - m_next_protocol(client_has_npn), - m_next_protocols(next_protocols), - m_supports_session_ticket(have_session_ticket_key && - c_hello.supports_session_ticket()) - { - suite = policy.choose_suite( - c_hello.ciphersuites(), - available_cert_types, - policy.choose_curve(c_hello.supported_ecc_curves()) != "", - false); - - if(suite == 0) - throw TLS_Exception(Alert::HANDSHAKE_FAILURE, - "Can't agree on a ciphersuite with client"); - - comp_method = policy.choose_compression(c_hello.compression_methods()); - - hash.update(writer.send(*this)); - } - -/* -* Create a new Server Hello message -*/ -Server_Hello::Server_Hello(Record_Writer& writer, - Handshake_Hash& hash, const MemoryRegion<byte>& session_id, Protocol_Version ver, u16bit ciphersuite, @@ -69,21 +28,24 @@ Server_Hello::Server_Hello(Record_Writer& writer, size_t max_fragment_size, bool client_has_secure_renegotiation, const MemoryRegion<byte>& reneg_info, - bool client_supports_session_tickets, + bool offer_session_ticket, bool client_has_npn, const std::vector<std::string>& next_protocols, + bool client_has_heartbeat, RandomNumberGenerator& rng) : - s_version(ver), + m_version(ver), m_session_id(session_id), - s_random(make_hello_random(rng)), - suite(ciphersuite), - comp_method(compression), + m_random(make_hello_random(rng)), + m_ciphersuite(ciphersuite), + m_comp_method(compression), m_fragment_size(max_fragment_size), m_secure_renegotiation(client_has_secure_renegotiation), m_renegotiation_info(reneg_info), m_next_protocol(client_has_npn), m_next_protocols(next_protocols), - m_supports_session_ticket(client_supports_session_tickets) + m_supports_session_ticket(offer_session_ticket), + m_supports_heartbeats(client_has_heartbeat), + m_peer_can_send_heartbeats(true) { hash.update(writer.send(*this)); } @@ -105,24 +67,24 @@ Server_Hello::Server_Hello(const MemoryRegion<byte>& buf) const byte major_version = reader.get_byte(); const byte minor_version = reader.get_byte(); - s_version = Protocol_Version(major_version, minor_version); + m_version = Protocol_Version(major_version, minor_version); - if(s_version != Protocol_Version::SSL_V3 && - s_version != Protocol_Version::TLS_V10 && - s_version != Protocol_Version::TLS_V11 && - s_version != Protocol_Version::TLS_V12) + if(m_version != Protocol_Version::SSL_V3 && + m_version != Protocol_Version::TLS_V10 && + m_version != Protocol_Version::TLS_V11 && + m_version != Protocol_Version::TLS_V12) { throw TLS_Exception(Alert::PROTOCOL_VERSION, "Server_Hello: Unsupported server version"); } - s_random = reader.get_fixed<byte>(32); + m_random = reader.get_fixed<byte>(32); m_session_id = reader.get_range<byte>(1, 0, 32); - suite = reader.get_u16bit(); + m_ciphersuite = reader.get_u16bit(); - comp_method = reader.get_byte(); + m_comp_method = reader.get_byte(); Extensions extensions(reader); @@ -145,6 +107,12 @@ Server_Hello::Server_Hello(const MemoryRegion<byte>& buf) throw Decoding_Error("TLS server sent non-empty session ticket extension"); m_supports_session_ticket = true; } + + if(Heartbeat_Support_Indicator* hb = extensions.get<Heartbeat_Support_Indicator>()) + { + m_supports_heartbeats = true; + m_peer_can_send_heartbeats = hb->peer_allowed_to_send(); + } } /* @@ -154,19 +122,22 @@ MemoryVector<byte> Server_Hello::serialize() const { MemoryVector<byte> buf; - buf.push_back(s_version.major_version()); - buf.push_back(s_version.minor_version()); - buf += s_random; + buf.push_back(m_version.major_version()); + buf.push_back(m_version.minor_version()); + buf += m_random; append_tls_length_value(buf, m_session_id, 1); - buf.push_back(get_byte(0, suite)); - buf.push_back(get_byte(1, suite)); + buf.push_back(get_byte(0, m_ciphersuite)); + buf.push_back(get_byte(1, m_ciphersuite)); - buf.push_back(comp_method); + buf.push_back(m_comp_method); Extensions extensions; + if(m_supports_heartbeats) + extensions.add(new Heartbeat_Support_Indicator(m_peer_can_send_heartbeats)); + if(m_secure_renegotiation) extensions.add(new Renegotation_Extension(m_renegotiation_info)); diff --git a/src/tls/s_kex.cpp b/src/tls/s_kex.cpp index 0890cac49..95518aa32 100644 --- a/src/tls/s_kex.cpp +++ b/src/tls/s_kex.cpp @@ -16,6 +16,7 @@ #include <botan/dh.h> #include <botan/ecdh.h> #include <botan/rsa.h> +#include <botan/srp6.h> #include <botan/oids.h> #include <memory> @@ -32,22 +33,22 @@ Server_Key_Exchange::Server_Key_Exchange(Record_Writer& writer, Credentials_Manager& creds, RandomNumberGenerator& rng, const Private_Key* signing_key) : - m_kex_key(0) + m_kex_key(0), m_srp_params(0) { + const std::string hostname = state->client_hello->sni_hostname(); const std::string kex_algo = state->suite.kex_algo(); if(kex_algo == "PSK" || kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK") { std::string identity_hint = - creds.psk_identity_hint("tls-server", - state->client_hello->sni_hostname()); + creds.psk_identity_hint("tls-server", hostname); append_tls_length_value(m_params, identity_hint, 2); } if(kex_algo == "DH" || kex_algo == "DHE_PSK") { - std::unique_ptr<DH_PrivateKey> dh(new DH_PrivateKey(rng, policy.dh_group())); + std::auto_ptr<DH_PrivateKey> dh(new DH_PrivateKey(rng, policy.dh_group())); append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_p()), 2); append_tls_length_value(m_params, BigInt::encode(dh->get_domain().get_g()), 2); @@ -70,7 +71,7 @@ Server_Key_Exchange::Server_Key_Exchange(Record_Writer& writer, EC_Group ec_group(curve_name); - std::unique_ptr<ECDH_PrivateKey> ecdh(new ECDH_PrivateKey(rng, ec_group)); + std::auto_ptr<ECDH_PrivateKey> ecdh(new ECDH_PrivateKey(rng, ec_group)); const std::string ecdh_domain_oid = ecdh->domain().get_oid(); const std::string domain = OIDS::lookup(OID(ecdh_domain_oid)); @@ -88,6 +89,35 @@ Server_Key_Exchange::Server_Key_Exchange(Record_Writer& writer, m_kex_key = ecdh.release(); } + else if(kex_algo == "SRP_SHA") + { + const std::string srp_identifier = state->client_hello->srp_identifier(); + + std::string group_id; + BigInt v; + MemoryVector<byte> salt; + + const bool found = creds.srp_verifier("tls-server", hostname, + srp_identifier, + group_id, v, salt, + policy.hide_unknown_users()); + + if(!found) + throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY, + "Unknown SRP user " + srp_identifier); + + m_srp_params = new SRP6_Server_Session; + + BigInt B = m_srp_params->step1(v, group_id, + "SHA-1", rng); + + DL_Group group(group_id); + + append_tls_length_value(m_params, BigInt::encode(group.get_p()), 2); + append_tls_length_value(m_params, BigInt::encode(group.get_g()), 2); + append_tls_length_value(m_params, salt, 1); + append_tls_length_value(m_params, BigInt::encode(B), 2); + } else if(kex_algo != "PSK") throw Internal_Error("Server_Key_Exchange: Unknown kex type " + kex_algo); @@ -116,7 +146,7 @@ Server_Key_Exchange::Server_Key_Exchange(const MemoryRegion<byte>& buf, const std::string& kex_algo, const std::string& sig_algo, Protocol_Version version) : - m_kex_key(0) + m_kex_key(0), m_srp_params(0) { if(buf.size() < 6) throw Decoding_Error("Server_Key_Exchange: Packet corrupted"); @@ -160,13 +190,27 @@ Server_Key_Exchange::Server_Key_Exchange(const MemoryRegion<byte>& buf, if(name == "") throw Decoding_Error("Server_Key_Exchange: Server sent unknown named curve " + - std::to_string(curve_id)); + to_string(curve_id)); m_params.push_back(curve_type); m_params.push_back(get_byte(0, curve_id)); m_params.push_back(get_byte(1, curve_id)); append_tls_length_value(m_params, ecdh_key, 1); } + else if(kex_algo == "SRP_SHA") + { + // 2 bigints (N,g) then salt, then server B + + const BigInt N = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); + const BigInt g = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); + MemoryVector<byte> salt = reader.get_range<byte>(1, 1, 255); + const BigInt B = BigInt::decode(reader.get_range<byte>(2, 1, 65535)); + + append_tls_length_value(m_params, BigInt::encode(N), 2); + append_tls_length_value(m_params, BigInt::encode(g), 2); + append_tls_length_value(m_params, salt, 1); + append_tls_length_value(m_params, BigInt::encode(B), 2); + } else if(kex_algo != "PSK") throw Decoding_Error("Server_Key_Exchange: Unsupported kex type " + kex_algo); @@ -182,6 +226,12 @@ Server_Key_Exchange::Server_Key_Exchange(const MemoryRegion<byte>& buf, } } +Server_Key_Exchange::~Server_Key_Exchange() + { + delete m_kex_key; + delete m_srp_params; + } + /** * Serialize a Server Key Exchange message @@ -211,7 +261,7 @@ MemoryVector<byte> Server_Key_Exchange::serialize() const bool Server_Key_Exchange::verify(const X509_Certificate& cert, Handshake_State* state) const { - std::unique_ptr<Public_Key> key(cert.subject_public_key()); + std::auto_ptr<Public_Key> key(cert.subject_public_key()); std::pair<std::string, Signature_Format> format = state->understand_sig_format(key.get(), m_hash_algo, m_sig_algo, false); @@ -230,6 +280,15 @@ const Private_Key& Server_Key_Exchange::server_kex_key() const BOTAN_ASSERT(m_kex_key, "Key is non-NULL"); return *m_kex_key; } + +// Only valid for SRP negotiation +SRP6_Server_Session& Server_Key_Exchange::server_srp_params() + { + BOTAN_ASSERT(m_srp_params, "SRP params are non-NULL"); + return *m_srp_params; + } +} + } } diff --git a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp index 175adad6c..aa9385d70 100644 --- a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp +++ b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp @@ -9,9 +9,9 @@ #include <botan/internal/assert.h> #include <botan/lookup.h> #include <botan/hex.h> +#include <botan/time.h> #include <botan/loadstor.h> #include <memory> -#include <chrono> #include <sqlite3.h> @@ -86,6 +86,38 @@ class sqlite3_statement {} } + std::pair<const byte*, size_t> get_blob(int column) + { + BOTAN_ASSERT(sqlite3_column_type(m_stmt, 0) == SQLITE_BLOB, + "Return value is a blob"); + + const void* session_blob = sqlite3_column_blob(m_stmt, column); + const int session_blob_size = sqlite3_column_bytes(m_stmt, column); + + BOTAN_ASSERT(session_blob_size >= 0, "Blob size is non-negative"); + + return std::make_pair(static_cast<const byte*>(session_blob), + static_cast<size_t>(session_blob_size)); + } + + size_t get_size_t(int column) + { + BOTAN_ASSERT(sqlite3_column_type(m_stmt, column) == SQLITE_INTEGER, + "Return count is an integer"); + + const int sessions_int = sqlite3_column_int(m_stmt, column); + + BOTAN_ASSERT(sessions_int >= 0, "Expected size_t is non-negative"); + + return static_cast<size_t>(sessions_int); + } + + void spin() + { + while(sqlite3_step(m_stmt) == SQLITE_ROW) + {} + } + int step() { return sqlite3_step(m_stmt); @@ -146,7 +178,7 @@ Session_Manager_SQLite::Session_Manager_SQLite(const std::string& passphrase, RandomNumberGenerator& rng, const std::string& db_filename, size_t max_sessions, - std::chrono::seconds session_lifetime) : + u32bit session_lifetime) : m_rng(rng), m_max_sessions(max_sessions), m_session_lifetime(session_lifetime) @@ -309,7 +341,7 @@ void Session_Manager_SQLite::save(const Session& session) " values(?1, ?2, ?3, ?4, ?5)"); stmt.bind(1, hex_encode(session.session_id())); - stmt.bind(2, std::chrono::system_clock::to_time_t(session.start_time())); + stmt.bind(2, session.start_time()); stmt.bind(3, session.sni_hostname()); stmt.bind(4, 0); stmt.bind(5, session.encrypt(m_session_key, m_rng)); @@ -323,8 +355,7 @@ void Session_Manager_SQLite::prune_session_cache() { sqlite3_statement remove_expired(m_db, "delete from tls_sessions where session_start <= ?1"); - remove_expired.bind(1, std::chrono::system_clock::to_time_t( - std::chrono::system_clock::now() - m_session_lifetime)); + remove_expired.bind(1, system_time() - m_session_lifetime); remove_expired.spin(); diff --git a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h index 1d12b71cd..57e5a58f6 100644 --- a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h +++ b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h @@ -5,8 +5,8 @@ * Released under the terms of the Botan license */ -#ifndef TLS_SQLITE_SESSION_MANAGER_H__ -#define TLS_SQLITE_SESSION_MANAGER_H__ +#ifndef BOTAN_TLS_SQLITE_SESSION_MANAGER_H__ +#define BOTAN_TLS_SQLITE_SESSION_MANAGER_H__ #include <botan/tls_session_manager.h> #include <botan/rng.h> @@ -36,7 +36,7 @@ class BOTAN_DLL Session_Manager_SQLite : public Session_Manager RandomNumberGenerator& rng, const std::string& db_filename, size_t max_sessions = 1000, - std::chrono::seconds session_lifetime = std::chrono::seconds(7200)); + u32bit session_lifetime = 7200); ~Session_Manager_SQLite(); @@ -49,6 +49,8 @@ class BOTAN_DLL Session_Manager_SQLite : public Session_Manager void remove_entry(const MemoryRegion<byte>& session_id); void save(const Session& session_data); + + u32bit session_lifetime() const { return m_session_lifetime; } private: Session_Manager_SQLite(const Session_Manager_SQLite&); Session_Manager_SQLite& operator=(const Session_Manager_SQLite&); @@ -58,7 +60,7 @@ class BOTAN_DLL Session_Manager_SQLite : public Session_Manager SymmetricKey m_session_key; RandomNumberGenerator& m_rng; size_t m_max_sessions; - std::chrono::seconds m_session_lifetime; + u32bit m_session_lifetime; class sqlite3* m_db; }; diff --git a/src/tls/tls_alert.cpp b/src/tls/tls_alert.cpp index 30c51d4c8..9b37a282f 100644 --- a/src/tls/tls_alert.cpp +++ b/src/tls/tls_alert.cpp @@ -90,14 +90,22 @@ std::string Alert::type_string() const case UNSUPPORTED_EXTENSION: return "unsupported_extension"; + case CERTIFICATE_UNOBTAINABLE: + return "certificate_unobtainable"; case UNRECOGNIZED_NAME: return "unrecognized_name"; - + case BAD_CERTIFICATE_STATUS_RESPONSE: + return "bad_certificate_status_response"; + case BAD_CERTIFICATE_HASH_VALUE: + return "bad_certificate_hash_value"; case UNKNOWN_PSK_IDENTITY: return "unknown_psk_identity"; case NULL_ALERT: - return ""; + return "none"; + + case HEARTBEAT_PAYLOAD: + return "heartbeat_payload"; } /* @@ -106,7 +114,7 @@ std::string Alert::type_string() const * compiler can warn us that it is not included in the switch * statement. */ - return "unrecognized_alert_" + std::to_string(type()); + return "unrecognized_alert_" + to_string(type()); } diff --git a/src/tls/tls_alert.h b/src/tls/tls_alert.h index 0446a8c30..3dfff3d29 100644 --- a/src/tls/tls_alert.h +++ b/src/tls/tls_alert.h @@ -22,37 +22,40 @@ class BOTAN_DLL Alert { public: enum Type { - CLOSE_NOTIFY = 0, - UNEXPECTED_MESSAGE = 10, - BAD_RECORD_MAC = 20, - DECRYPTION_FAILED = 21, - RECORD_OVERFLOW = 22, - DECOMPRESSION_FAILURE = 30, - HANDSHAKE_FAILURE = 40, - NO_CERTIFICATE = 41, // SSLv3 only - BAD_CERTIFICATE = 42, - UNSUPPORTED_CERTIFICATE = 43, - CERTIFICATE_REVOKED = 44, - CERTIFICATE_EXPIRED = 45, - CERTIFICATE_UNKNOWN = 46, - ILLEGAL_PARAMETER = 47, - UNKNOWN_CA = 48, - ACCESS_DENIED = 49, - DECODE_ERROR = 50, - DECRYPT_ERROR = 51, - EXPORT_RESTRICTION = 60, - PROTOCOL_VERSION = 70, - INSUFFICIENT_SECURITY = 71, - INTERNAL_ERROR = 80, - USER_CANCELED = 90, - NO_RENEGOTIATION = 100, - - UNSUPPORTED_EXTENSION = 110, - UNRECOGNIZED_NAME = 112, - - UNKNOWN_PSK_IDENTITY = 115, - - NULL_ALERT = 255 + CLOSE_NOTIFY = 0, + UNEXPECTED_MESSAGE = 10, + BAD_RECORD_MAC = 20, + DECRYPTION_FAILED = 21, + RECORD_OVERFLOW = 22, + DECOMPRESSION_FAILURE = 30, + HANDSHAKE_FAILURE = 40, + NO_CERTIFICATE = 41, // SSLv3 only + BAD_CERTIFICATE = 42, + UNSUPPORTED_CERTIFICATE = 43, + CERTIFICATE_REVOKED = 44, + CERTIFICATE_EXPIRED = 45, + CERTIFICATE_UNKNOWN = 46, + ILLEGAL_PARAMETER = 47, + UNKNOWN_CA = 48, + ACCESS_DENIED = 49, + DECODE_ERROR = 50, + DECRYPT_ERROR = 51, + EXPORT_RESTRICTION = 60, + PROTOCOL_VERSION = 70, + INSUFFICIENT_SECURITY = 71, + INTERNAL_ERROR = 80, + USER_CANCELED = 90, + NO_RENEGOTIATION = 100, + UNSUPPORTED_EXTENSION = 110, + CERTIFICATE_UNOBTAINABLE = 111, + UNRECOGNIZED_NAME = 112, + BAD_CERTIFICATE_STATUS_RESPONSE = 113, + BAD_CERTIFICATE_HASH_VALUE = 114, + UNKNOWN_PSK_IDENTITY = 115, + + NULL_ALERT = 255, + + HEARTBEAT_PAYLOAD = 256 }; /** diff --git a/src/tls/tls_channel.cpp b/src/tls/tls_channel.cpp index 736b37654..86d9db8bd 100644 --- a/src/tls/tls_channel.cpp +++ b/src/tls/tls_channel.cpp @@ -8,6 +8,7 @@ #include <botan/tls_channel.h> #include <botan/internal/tls_handshake_state.h> #include <botan/internal/tls_messages.h> +#include <botan/internal/tls_heartbeats.h> #include <botan/internal/assert.h> #include <botan/loadstor.h> @@ -15,15 +16,17 @@ namespace Botan { namespace TLS { -Channel::Channel(std::function<void (const byte[], size_t)> socket_output_fn, - std::function<void (const byte[], size_t, Alert)> proc_fn, - std::function<bool (const Session&)> handshake_complete) : +Channel::Channel(std::tr1::function<void (const byte[], size_t)> socket_output_fn, + std::tr1::function<void (const byte[], size_t, Alert)> proc_fn, + std::tr1::function<bool (const Session&)> handshake_complete) : proc_fn(proc_fn), handshake_fn(handshake_complete), writer(socket_output_fn), state(0), handshake_completed(false), - connection_closed(false) + connection_closed(false), + m_peer_supports_heartbeats(false), + m_heartbeat_sending_allowed(false) { } @@ -56,7 +59,30 @@ size_t Channel::received_data(const byte buf[], size_t buf_size) if(buf_size == 0 && needed != 0) return needed; // need more data to complete record - if(rec_type == APPLICATION_DATA) + if(rec_type == HANDSHAKE || rec_type == CHANGE_CIPHER_SPEC) + { + read_handshake(rec_type, record); + } + else if(rec_type == HEARTBEAT && m_peer_supports_heartbeats) + { + Heartbeat_Message heartbeat(record); + + const MemoryRegion<byte>& payload = heartbeat.payload(); + + if(heartbeat.is_request() && !state) + { + Heartbeat_Message response(Heartbeat_Message::RESPONSE, + payload, payload.size()); + + writer.send(HEARTBEAT, response.contents()); + } + else + { + // pass up to the application + proc_fn(&payload[0], payload.size(), Alert(Alert::HEARTBEAT_PAYLOAD)); + } + } + else if(rec_type == APPLICATION_DATA) { if(handshake_completed) { @@ -73,10 +99,6 @@ size_t Channel::received_data(const byte buf[], size_t buf_size) throw Unexpected_Message("Application data before handshake done"); } } - else if(rec_type == HANDSHAKE || rec_type == CHANGE_CIPHER_SPEC) - { - read_handshake(rec_type, record); - } else if(rec_type == ALERT) { Alert alert_msg(record); @@ -106,7 +128,7 @@ size_t Channel::received_data(const byte buf[], size_t buf_size) } else throw Unexpected_Message("Unknown TLS message type " + - std::to_string(rec_type) + " received"); + to_string(rec_type) + " received"); } return 0; // on a record boundary @@ -178,6 +200,20 @@ void Channel::read_handshake(byte rec_type, } } +void Channel::heartbeat(const byte payload[], size_t payload_size) + { + if(!is_active()) + throw std::runtime_error("Heartbeat cannot be sent on inactive TLS connection"); + + if(m_heartbeat_sending_allowed) + { + Heartbeat_Message heartbeat(Heartbeat_Message::REQUEST, + payload, payload_size); + + writer.send(HEARTBEAT, heartbeat.contents()); + } + } + void Channel::send(const byte buf[], size_t buf_size) { if(!is_active()) @@ -287,3 +323,5 @@ void Channel::Secure_Renegotiation_State::update(Finished* client_finished, } } + +} diff --git a/src/tls/tls_channel.h b/src/tls/tls_channel.h index 9ab89e5f7..257745d80 100644 --- a/src/tls/tls_channel.h +++ b/src/tls/tls_channel.h @@ -54,17 +54,31 @@ class BOTAN_DLL Channel /** * Attempt to renegotiate the session + * @param force_full_renegotiation if true, require a full renegotiation, + * otherwise allow session resumption */ - virtual void renegotiate() = 0; + virtual void renegotiate(bool force_full_renegotiation) = 0; + + /** + * Attempt to send a heartbeat message (if negotiated with counterparty) + * @param payload will be echoed back + * @param countents_size size of payload in bytes + */ + void heartbeat(const byte payload[], size_t payload_size); + + /** + * Attempt to send a heartbeat message (if negotiated with counterparty) + */ + void heartbeat() { heartbeat(0, 0); } /** * @return certificate chain of the peer (may be empty) */ std::vector<X509_Certificate> peer_cert_chain() const { return peer_certs; } - Channel(std::function<void (const byte[], size_t)> socket_output_fn, - std::function<void (const byte[], size_t, Alert)> proc_fn, - std::function<bool (const Session&)> handshake_complete); + Channel(std::tr1::function<void (const byte[], size_t)> socket_output_fn, + std::tr1::function<void (const byte[], size_t, Alert)> proc_fn, + std::tr1::function<bool (const Session&)> handshake_complete); virtual ~Channel(); protected: @@ -85,8 +99,8 @@ class BOTAN_DLL Channel virtual void alert_notify(const Alert& alert) = 0; - std::function<void (const byte[], size_t, Alert)> proc_fn; - std::function<bool (const Session&)> handshake_fn; + std::tr1::function<void (const byte[], size_t, Alert)> proc_fn; + std::tr1::function<bool (const Session&)> handshake_fn; Record_Writer writer; Record_Reader reader; @@ -130,6 +144,8 @@ class BOTAN_DLL Channel bool handshake_completed; bool connection_closed; + bool m_peer_supports_heartbeats; + bool m_heartbeat_sending_allowed; }; } diff --git a/src/tls/tls_ciphersuite.cpp b/src/tls/tls_ciphersuite.cpp index 89daaf679..798df0186 100644 --- a/src/tls/tls_ciphersuite.cpp +++ b/src/tls/tls_ciphersuite.cpp @@ -1,12 +1,11 @@ /* -* TLS Cipher Suites +* TLS Cipher Suite * (C) 2004-2010,2012 Jack Lloyd * * Released under the terms of the Botan license */ #include <botan/tls_ciphersuite.h> -#include <botan/tls_magic.h> #include <botan/parsing.h> #include <sstream> #include <stdexcept> @@ -15,246 +14,6 @@ namespace Botan { namespace TLS { -/** -* Convert an SSL/TLS ciphersuite to algorithm fields -*/ -Ciphersuite Ciphersuite::by_id(u16bit suite) - { - switch(static_cast<Ciphersuite_Code>(suite)) - { - // RSA ciphersuites - - case TLS_RSA_WITH_AES_128_CBC_SHA: - return Ciphersuite("RSA", "RSA", "SHA-1", "AES-128", 16); - - case TLS_RSA_WITH_AES_256_CBC_SHA: - return Ciphersuite("RSA", "RSA", "SHA-1", "AES-256", 32); - - case TLS_RSA_WITH_AES_128_CBC_SHA256: - return Ciphersuite("RSA", "RSA", "SHA-256", "AES-128", 16); - - case TLS_RSA_WITH_AES_256_CBC_SHA256: - return Ciphersuite("RSA", "RSA", "SHA-256", "AES-256", 32); - - case TLS_RSA_WITH_3DES_EDE_CBC_SHA: - return Ciphersuite("RSA", "RSA", "SHA-1", "3DES", 24); - - case TLS_RSA_WITH_RC4_128_SHA: - return Ciphersuite("RSA", "RSA", "SHA-1", "ARC4", 16); - - case TLS_RSA_WITH_RC4_128_MD5: - return Ciphersuite("RSA", "RSA", "MD5", "ARC4", 16); - - case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: - return Ciphersuite("RSA", "RSA", "SHA-1", "Camellia", 16); - - case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: - return Ciphersuite("RSA", "RSA", "SHA-1", "Camellia", 32); - - case TLS_RSA_WITH_SEED_CBC_SHA: - return Ciphersuite("RSA", "RSA", "SHA-1", "SEED", 16); - -#if defined(BOTAN_HAS_IDEA) - case TLS_RSA_WITH_IDEA_CBC_SHA: - return Ciphersuite("RSA", "RSA", "SHA-1", "IDEA", 16); -#endif - - // DH/DSS ciphersuites - - case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: - return Ciphersuite("DSA", "DH", "SHA-1", "AES-128", 16); - - case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: - return Ciphersuite("DSA", "DH", "SHA-1", "AES-256", 32); - - case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: - return Ciphersuite("DSA", "DH", "SHA-256", "AES-128", 16); - - case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: - return Ciphersuite("DSA", "DH", "SHA-256", "AES-256", 32); - - case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: - return Ciphersuite("DSA", "DH", "SHA-1", "3DES", 24); - - case TLS_DHE_DSS_WITH_RC4_128_SHA: - return Ciphersuite("DSA", "DH", "SHA-1", "ARC4", 16); - - case TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA: - return Ciphersuite("DSA", "DH", "SHA-1", "Camellia", 16); - - case TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA: - return Ciphersuite("DSA", "DH", "SHA-1", "Camellia", 32); - - case TLS_DHE_DSS_WITH_SEED_CBC_SHA: - return Ciphersuite("DSA", "DH", "SHA-1", "SEED", 16); - - // DH/RSA ciphersuites - - case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: - return Ciphersuite("RSA", "DH", "SHA-1", "AES-128", 16); - - case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: - return Ciphersuite("RSA", "DH", "SHA-1", "AES-256", 32); - - case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: - return Ciphersuite("RSA", "DH", "SHA-256", "AES-128", 16); - - case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: - return Ciphersuite("RSA", "DH", "SHA-256", "AES-256", 32); - - case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: - return Ciphersuite("RSA", "DH", "SHA-1", "3DES", 24); - - case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: - return Ciphersuite("RSA", "DH", "SHA-1", "Camellia", 16); - - case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: - return Ciphersuite("RSA", "DH", "SHA-1", "Camellia", 32); - - case TLS_DHE_RSA_WITH_SEED_CBC_SHA: - return Ciphersuite("RSA", "DH", "SHA-1", "SEED", 16); - - // ECDH/RSA ciphersuites - case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: - return Ciphersuite("RSA", "ECDH", "SHA-1", "AES-128", 16); - - case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: - return Ciphersuite("RSA", "ECDH", "SHA-1", "AES-256", 32); - - case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: - return Ciphersuite("RSA", "ECDH", "SHA-256", "AES-128", 16); - - case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: - return Ciphersuite("RSA", "ECDH", "SHA-384", "AES-256", 32); - - case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: - return Ciphersuite("RSA", "ECDH", "SHA-1", "3DES", 24); - - case TLS_ECDHE_RSA_WITH_RC4_128_SHA: - return Ciphersuite("RSA", "ECDH", "SHA-1", "ARC4", 16); - - // ECDH/ECDSA ciphersuites - - case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: - return Ciphersuite("ECDSA", "ECDH", "SHA-1", "AES-128", 16); - - case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: - return Ciphersuite("ECDSA", "ECDH", "SHA-1", "AES-256", 32); - - case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: - return Ciphersuite("ECDSA", "ECDH", "SHA-256", "AES-128", 16); - - case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: - return Ciphersuite("ECDSA", "ECDH", "SHA-384", "AES-256", 32); - - case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: - return Ciphersuite("ECDSA", "ECDH", "SHA-1", "ARC4", 16); - - case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: - return Ciphersuite("ECDSA", "ECDH", "SHA-1", "3DES", 24); - - // PSK ciphersuites - - case TLS_PSK_WITH_RC4_128_SHA: - return Ciphersuite("", "PSK", "SHA-1", "ARC4", 16); - - case TLS_PSK_WITH_3DES_EDE_CBC_SHA: - return Ciphersuite("", "PSK", "SHA-1", "3DES", 24); - - case TLS_PSK_WITH_AES_128_CBC_SHA: - return Ciphersuite("", "PSK", "SHA-1", "AES-128", 16); - - case TLS_PSK_WITH_AES_128_CBC_SHA256: - return Ciphersuite("", "PSK", "SHA-256", "AES-128", 16); - - case TLS_PSK_WITH_AES_256_CBC_SHA: - return Ciphersuite("", "PSK", "SHA-1", "AES-256", 32); - - case TLS_PSK_WITH_AES_256_CBC_SHA384: - return Ciphersuite("", "PSK", "SHA-384", "AES-256", 32); - - // PSK+DH ciphersuites - - case TLS_DHE_PSK_WITH_RC4_128_SHA: - return Ciphersuite("", "DHE_PSK", "SHA-1", "ARC4", 16); - - case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: - return Ciphersuite("", "DHE_PSK", "SHA-1", "3DES", 24); - - case TLS_DHE_PSK_WITH_AES_128_CBC_SHA: - return Ciphersuite("", "DHE_PSK", "SHA-1", "AES-128", 16); - - case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256: - return Ciphersuite("", "DHE_PSK", "SHA-256", "AES-128", 16); - - case TLS_DHE_PSK_WITH_AES_256_CBC_SHA: - return Ciphersuite("", "DHE_PSK", "SHA-1", "AES-256", 32); - - case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384: - return Ciphersuite("", "DHE_PSK", "SHA-384", "AES-256", 32); - - // PSK+ECDH ciphersuites - - case TLS_ECDHE_PSK_WITH_RC4_128_SHA: - return Ciphersuite("", "ECDHE_PSK", "SHA-1", "ARC4", 16); - - case TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA: - return Ciphersuite("", "ECDHE_PSK", "SHA-1", "3DES", 24); - - case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA: - return Ciphersuite("", "ECDHE_PSK", "SHA-1", "AES-128", 16); - - case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256: - return Ciphersuite("", "ECDHE_PSK", "SHA-256", "AES-128", 16); - - case TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA: - return Ciphersuite("", "ECDHE_PSK", "SHA-1", "AES-256", 32); - - case TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384: - return Ciphersuite("", "ECDHE_PSK", "SHA-384", "AES-256", 32); - - // SRP ciphersuites - - case TLS_SRP_SHA_WITH_AES_128_CBC_SHA: - return Ciphersuite("", "SRP", "SHA-1", "AES-128", 16); - - case TLS_SRP_SHA_WITH_AES_256_CBC_SHA: - return Ciphersuite("", "SRP", "SHA-1", "AES-256", 32); - - case TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA: - return Ciphersuite("", "SRP", "SHA-1", "3DES", 24); - - // SRP/RSA ciphersuites - - case TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA: - return Ciphersuite("RSA", "SRP", "SHA-1", "AES-128", 16); - - case TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: - return Ciphersuite("RSA", "SRP", "SHA-1", "AES-256", 32); - - case TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA: - return Ciphersuite("RSA", "SRP", "SHA-1", "3DES", 24); - - // SRP/DSA ciphersuites - - case TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA: - return Ciphersuite("DSA", "SRP", "SHA-1", "AES-128", 16); - - case TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA: - return Ciphersuite("DSA", "SRP", "SHA-1", "AES-256", 32); - - case TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA: - return Ciphersuite("DSA", "SRP", "SHA-1", "3DES", 24); - - // Signaling ciphersuite values - - case TLS_EMPTY_RENEGOTIATION_INFO_SCSV: - return Ciphersuite(); - } - - return Ciphersuite(); // some unknown ciphersuite - } - Ciphersuite Ciphersuite::by_name(const std::string& name) { for(size_t i = 0; i != 65536; ++i) @@ -271,6 +30,18 @@ Ciphersuite Ciphersuite::by_name(const std::string& name) return Ciphersuite(); // some unknown ciphersuite } +bool Ciphersuite::psk_ciphersuite() const + { + return (kex_algo() == "PSK" || + kex_algo() == "DHE_PSK" || + kex_algo() == "ECDHE_PSK"); + } + +bool Ciphersuite::ecc_ciphersuite() const + { + return (kex_algo() == "ECDH" || sig_algo() == "ECDSA"); + } + std::string Ciphersuite::to_string() const { if(m_cipher_keylen == 0) @@ -286,8 +57,6 @@ std::string Ciphersuite::to_string() const out << "DHE"; else if(kex_algo() == "ECDH") out << "ECDHE"; - else if(kex_algo() == "SRP") - out << "SRP_SHA"; else out << kex_algo(); @@ -310,7 +79,7 @@ std::string Ciphersuite::to_string() const if(cipher_algo() == "3DES") out << "3DES_EDE"; else if(cipher_algo() == "Camellia") - out << "CAMELLIA_" << std::to_string(8*cipher_keylen()); + out << "CAMELLIA_" << Botan::to_string(8*cipher_keylen()); else out << replace_char(cipher_algo(), '-', '_'); @@ -329,18 +98,7 @@ std::string Ciphersuite::to_string() const return out.str(); } -Ciphersuite::Ciphersuite(const std::string& sig_algo, - const std::string& kex_algo, - const std::string& mac_algo, - const std::string& cipher_algo, - size_t cipher_algo_keylen) : - m_sig_algo(sig_algo), - m_kex_algo(kex_algo), - m_mac_algo(mac_algo), - m_cipher_algo(cipher_algo), - m_cipher_keylen(cipher_algo_keylen) - { - } +} } diff --git a/src/tls/tls_ciphersuite.h b/src/tls/tls_ciphersuite.h index e5d8c967b..dcb4b6a6f 100644 --- a/src/tls/tls_ciphersuite.h +++ b/src/tls/tls_ciphersuite.h @@ -21,6 +21,9 @@ namespace TLS { class BOTAN_DLL Ciphersuite { public: + /** + * Convert an SSL/TLS ciphersuite to algorithm fields + */ static Ciphersuite by_id(u16bit suite); static Ciphersuite by_name(const std::string& name); @@ -30,6 +33,9 @@ class BOTAN_DLL Ciphersuite */ std::string to_string() const; + bool psk_ciphersuite() const; + bool ecc_ciphersuite() const; + std::string kex_algo() const { return m_kex_algo; } std::string sig_algo() const { return m_sig_algo; } @@ -46,7 +52,15 @@ class BOTAN_DLL Ciphersuite const std::string& kex_algo, const std::string& mac_algo, const std::string& cipher_algo, - size_t cipher_algo_keylen); + size_t cipher_algo_keylen) : + m_sig_algo(sig_algo), + m_kex_algo(kex_algo), + m_mac_algo(mac_algo), + m_cipher_algo(cipher_algo), + m_cipher_keylen(cipher_algo_keylen) + { + } + private: std::string m_sig_algo, m_kex_algo, m_mac_algo, m_cipher_algo; size_t m_cipher_keylen; diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp index 77e87e9bc..63d0ee148 100644 --- a/src/tls/tls_client.cpp +++ b/src/tls/tls_client.cpp @@ -18,20 +18,21 @@ namespace TLS { /* * TLS Client Constructor */ -Client::Client(std::function<void (const byte[], size_t)> output_fn, - std::function<void (const byte[], size_t, Alert)> proc_fn, - std::function<bool (const Session&)> handshake_fn, +Client::Client(std::tr1::function<void (const byte[], size_t)> output_fn, + std::tr1::function<void (const byte[], size_t, Alert)> proc_fn, + std::tr1::function<bool (const Session&)> handshake_fn, Session_Manager& session_manager, Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng, const std::string& hostname, - std::function<std::string (std::vector<std::string>)> next_protocol) : + std::tr1::function<std::string (std::vector<std::string>)> next_protocol) : Channel(output_fn, proc_fn, handshake_fn), policy(policy), rng(rng), session_manager(session_manager), - creds(creds) + creds(creds), + m_hostname(hostname) { writer.set_version(Protocol_Version::SSL_V3); @@ -56,6 +57,7 @@ Client::Client(std::function<void (const byte[], size_t)> output_fn, state->hash, policy, rng, + secure_renegotiation.for_client_hello(), session_info, send_npn_request); @@ -83,16 +85,42 @@ Client::Client(std::function<void (const byte[], size_t)> output_fn, /* * Send a new client hello to renegotiate */ -void Client::renegotiate() +void Client::renegotiate(bool force_full_renegotiation) { - if(state) - return; // currently in handshake + if(state && state->client_hello) + return; // currently in active handshake + delete state; state = new Handshake_State(new Stream_Handshake_Reader); + state->set_expected_next(SERVER_HELLO); - state->client_hello = new Client_Hello(writer, state->hash, policy, rng, - secure_renegotiation.for_client_hello()); + if(!force_full_renegotiation) + { + Session session_info; + if(session_manager.load_from_host_info(m_hostname, 0, session_info)) + { + state->client_hello = new Client_Hello( + writer, + state->hash, + policy, + rng, + secure_renegotiation.for_client_hello(), + session_info); + + state->resume_master_secret = session_info.master_secret(); + } + } + + if(!state->client_hello) + { + state->client_hello = new Client_Hello( + writer, + state->hash, + policy, + rng, + secure_renegotiation.for_client_hello()); + } secure_renegotiation.update(state->client_hello); } @@ -136,11 +164,7 @@ void Client::process_handshake_msg(Handshake_Type type, return; } - state->client_hello = new Client_Hello(writer, state->hash, policy, rng, - secure_renegotiation.for_client_hello()); - secure_renegotiation.update(state->client_hello); - - state->set_expected_next(SERVER_HELLO); + renegotiate(false); return; } @@ -188,6 +212,9 @@ void Client::process_handshake_msg(Handshake_Type type, secure_renegotiation.update(state->server_hello); + m_peer_supports_heartbeats = state->server_hello->supports_heartbeats(); + m_heartbeat_sending_allowed = state->server_hello->peer_can_send_heartbeats(); + state->suite = Ciphersuite::by_id(state->server_hello->ciphersuite()); const bool server_returned_same_session_id = @@ -241,8 +268,8 @@ void Client::process_handshake_msg(Handshake_Type type, ever sent. The server may or may not send a server kex, depending on if it has an identity hint for us. - DHE_PSK always sends a server key exchange for the DH - exchange portion. + (EC)DHE_PSK always sends a server key exchange for the + DH exchange portion. */ state->set_expected_next(SERVER_KEX); @@ -280,15 +307,14 @@ void Client::process_handshake_msg(Handshake_Type type, try { - const std::string hostname = state->client_hello->sni_hostname(); - creds.verify_certificate_chain("tls-client", hostname, peer_certs); + creds.verify_certificate_chain("tls-client", m_hostname, peer_certs); } catch(std::exception& e) { throw TLS_Exception(Alert::BAD_CERTIFICATE, e.what()); } - std::unique_ptr<Public_Key> peer_key(peer_certs[0].subject_public_key()); + std::auto_ptr<Public_Key> peer_key(peer_certs[0].subject_public_key()); if(peer_key->algo_name() != state->suite.sig_algo()) throw TLS_Exception(Alert::ILLEGAL_PARAMETER, @@ -330,7 +356,7 @@ void Client::process_handshake_msg(Handshake_Type type, std::vector<X509_Certificate> client_certs = creds.cert_chain(types, "tls-client", - state->client_hello->sni_hostname()); + m_hostname); state->client_certs = new Certificate(writer, state->hash, @@ -342,6 +368,7 @@ void Client::process_handshake_msg(Handshake_Type type, state, creds, peer_certs, + m_hostname, rng); state->keys = Session_Keys(state, @@ -354,7 +381,7 @@ void Client::process_handshake_msg(Handshake_Type type, Private_Key* private_key = creds.private_key_for(state->client_certs->cert_chain()[0], "tls-client", - state->client_hello->sni_hostname()); + m_hostname); state->client_verify = new Certificate_Verify(writer, state, @@ -437,7 +464,7 @@ void Client::process_handshake_msg(Handshake_Type type, state->server_hello->fragment_size(), peer_certs, session_ticket, - state->client_hello->sni_hostname(), + m_hostname, "" ); diff --git a/src/tls/tls_client.h b/src/tls/tls_client.h index cd972fa28..4efe2a2df 100644 --- a/src/tls/tls_client.h +++ b/src/tls/tls_client.h @@ -42,18 +42,18 @@ class BOTAN_DLL Client : public Channel * called with the list of protocols the server advertised; * the client should return the protocol it would like to use. */ - Client(std::function<void (const byte[], size_t)> socket_output_fn, - std::function<void (const byte[], size_t, Alert)> proc_fn, - std::function<bool (const Session&)> handshake_complete, + Client(std::tr1::function<void (const byte[], size_t)> socket_output_fn, + std::tr1::function<void (const byte[], size_t, Alert)> proc_fn, + std::tr1::function<bool (const Session&)> handshake_complete, Session_Manager& session_manager, Credentials_Manager& creds, const Policy& policy, RandomNumberGenerator& rng, const std::string& servername = "", - std::function<std::string (std::vector<std::string>)> next_protocol = - std::function<std::string (std::vector<std::string>)>()); + std::tr1::function<std::string (std::vector<std::string>)> next_protocol = + std::tr1::function<std::string (std::vector<std::string>)>()); - void renegotiate(); + void renegotiate(bool force_full_renegotiation); private: void process_handshake_msg(Handshake_Type type, const MemoryRegion<byte>& contents); @@ -64,6 +64,7 @@ class BOTAN_DLL Client : public Channel RandomNumberGenerator& rng; Session_Manager& session_manager; Credentials_Manager& creds; + const std::string m_hostname; }; } diff --git a/src/tls/tls_extensions.cpp b/src/tls/tls_extensions.cpp index c0de24bfe..f1361bbb9 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_HEARTBEAT_SUPPORT: + return new Heartbeat_Support_Indicator(reader, size); + case TLSEXT_SESSION_TICKET: return new Session_Ticket(reader, size); @@ -242,7 +245,7 @@ Maximum_Fragment_Length::Maximum_Fragment_Length(size_t max_fragment) else if(max_fragment == 4096) val = 4; else - throw std::invalid_argument("Bad setting " + std::to_string(max_fragment) + + throw std::invalid_argument("Bad setting " + to_string(max_fragment) + " for maximum fragment size"); } @@ -468,11 +471,16 @@ MemoryVector<byte> Signature_Algorithms::serialize() const for(size_t i = 0; i != m_supported_algos.size(); ++i) { - if(m_supported_algos[i].second == "") - continue; + try + { + const byte hash_code = hash_algo_code(m_supported_algos[i].first); + const byte sig_code = sig_algo_code(m_supported_algos[i].second); - buf.push_back(hash_algo_code(m_supported_algos[i].first)); - buf.push_back(sig_algo_code(m_supported_algos[i].second)); + buf.push_back(hash_code); + buf.push_back(sig_code); + } + catch(...) + {} } buf[0] = get_byte<u16bit>(0, buf.size()-2); diff --git a/src/tls/tls_extensions.h b/src/tls/tls_extensions.h index 6a97d2560..3fe3f7399 100644 --- a/src/tls/tls_extensions.h +++ b/src/tls/tls_extensions.h @@ -32,6 +32,7 @@ enum Handshake_Extension_Type { TLSEXT_EC_POINT_FORMATS = 11, TLSEXT_SRP_IDENTIFIER = 12, TLSEXT_SIGNATURE_ALGORITHMS = 13, + TLSEXT_HEARTBEAT_SUPPORT = 15, TLSEXT_SESSION_TICKET = 35, @@ -309,6 +310,32 @@ class Signature_Algorithms : public Extension }; /** +* Heartbeat Extension (RFC 6520) +*/ +class Heartbeat_Support_Indicator : public Extension + { + public: + static Handshake_Extension_Type static_type() + { return TLSEXT_HEARTBEAT_SUPPORT; } + + Handshake_Extension_Type type() const { return static_type(); } + + bool peer_allowed_to_send() const { return m_peer_allowed_to_send; } + + MemoryVector<byte> serialize() const; + + bool empty() const { return false; } + + Heartbeat_Support_Indicator(bool peer_allowed_to_send) : + m_peer_allowed_to_send(peer_allowed_to_send) {} + + Heartbeat_Support_Indicator(TLS_Data_Reader& reader, u16bit extension_size); + + private: + bool m_peer_allowed_to_send; + }; + +/** * Represents a block of extensions in a hello message */ class Extensions diff --git a/src/tls/tls_handshake_hash.cpp b/src/tls/tls_handshake_hash.cpp index a9bd8dccf..d0c74136b 100644 --- a/src/tls/tls_handshake_hash.cpp +++ b/src/tls/tls_handshake_hash.cpp @@ -35,7 +35,7 @@ SecureVector<byte> Handshake_Hash::final(Protocol_Version version, { Algorithm_Factory& af = global_state().algorithm_factory(); - std::unique_ptr<HashFunction> hash; + std::auto_ptr<HashFunction> hash; if(version == Protocol_Version::TLS_V10 || version == Protocol_Version::TLS_V11) { @@ -43,7 +43,7 @@ SecureVector<byte> Handshake_Hash::final(Protocol_Version version, } else if(version == Protocol_Version::TLS_V12) { - if(mac_algo == "SHA-1" || mac_algo == "SHA-256") + if(mac_algo == "MD5" || mac_algo == "SHA-1" || mac_algo == "SHA-256") hash.reset(af.make_hash_function("SHA-256")); else hash.reset(af.make_hash_function(mac_algo)); @@ -65,8 +65,8 @@ SecureVector<byte> Handshake_Hash::final_ssl3(const MemoryRegion<byte>& secret) Algorithm_Factory& af = global_state().algorithm_factory(); - std::unique_ptr<HashFunction> md5(af.make_hash_function("MD5")); - std::unique_ptr<HashFunction> sha1(af.make_hash_function("SHA-1")); + std::auto_ptr<HashFunction> md5(af.make_hash_function("MD5")); + std::auto_ptr<HashFunction> sha1(af.make_hash_function("SHA-1")); md5->update(data); sha1->update(data); diff --git a/src/tls/tls_handshake_state.cpp b/src/tls/tls_handshake_state.cpp index b34d8616d..1a55305e3 100644 --- a/src/tls/tls_handshake_state.cpp +++ b/src/tls/tls_handshake_state.cpp @@ -68,7 +68,7 @@ u32bit bitmask_for_handshake_type(Handshake_Type type) return 0; default: - throw Internal_Error("Unknown handshake type " + std::to_string(type)); + throw Internal_Error("Unknown handshake type " + to_string(type)); } return 0; @@ -104,6 +104,8 @@ Handshake_State::Handshake_State(Handshake_Reader* reader) hand_expecting_mask = 0; hand_received_mask = 0; + + allow_session_resumption = true; } void Handshake_State::set_version(const Protocol_Version& version) @@ -121,8 +123,8 @@ void Handshake_State::confirm_transition_to(Handshake_Type handshake_msg) if(!ok) throw Unexpected_Message("Unexpected state transition in handshake, got " + - std::to_string(handshake_msg) + " mask is " + - std::to_string(hand_expecting_mask)); + to_string(handshake_msg) + " mask is " + + to_string(hand_expecting_mask)); /* We don't know what to expect next, so force a call to set_expected_next; if it doesn't happen, the next transition @@ -143,6 +145,14 @@ bool Handshake_State::received_handshake_msg(Handshake_Type handshake_msg) const return (hand_received_mask & mask); } +std::string Handshake_State::srp_identifier() const + { + if(suite.valid() && suite.kex_algo() == "SRP_SHA") + return client_hello->srp_identifier(); + + return ""; + } + const MemoryRegion<byte>& Handshake_State::session_ticket() const { if(new_session_ticket && !new_session_ticket->ticket().empty()) @@ -163,8 +173,12 @@ KDF* Handshake_State::protocol_specific_prf() } else if(version() == Protocol_Version::TLS_V12) { - if(suite.mac_algo() == "SHA-1" || suite.mac_algo() == "SHA-256") + if(suite.mac_algo() == "MD5" || + suite.mac_algo() == "SHA-1" || + suite.mac_algo() == "SHA-256") + { return get_kdf("TLS-12-PRF(SHA-256)"); + } return get_kdf("TLS-12-PRF(" + suite.mac_algo() + ")"); } diff --git a/src/tls/tls_handshake_state.h b/src/tls/tls_handshake_state.h index d2f64c43b..ec4c2fea8 100644 --- a/src/tls/tls_handshake_state.h +++ b/src/tls/tls_handshake_state.h @@ -15,7 +15,20 @@ #include <botan/pubkey.h> #include <utility> -#include <functional> + +#if defined(BOTAN_USE_STD_TR1) + +#if defined(BOTAN_BUILD_COMPILER_IS_MSVC) + #include <functional> +#else + #include <tr1/functional> +#endif + +#elif defined(BOTAN_USE_BOOST_TR1) + #include <boost/tr1/functional.hpp> +#else + #error "No TR1 library defined for use" +#endif namespace Botan { @@ -51,6 +64,8 @@ class Handshake_State std::string& sig_algo, bool for_client_auth); + std::string srp_identifier() const; + KDF* protocol_specific_prf(); Protocol_Version version() const { return m_version; } @@ -86,10 +101,15 @@ class Handshake_State */ SecureVector<byte> resume_master_secret; + /* + * + */ + bool allow_session_resumption; + /** * Used by client using NPN */ - std::function<std::string (std::vector<std::string>)> client_npn_cb; + std::tr1::function<std::string (std::vector<std::string>)> client_npn_cb; Handshake_Reader* handshake_reader() { return m_handshake_reader; } private: diff --git a/src/tls/tls_heartbeats.cpp b/src/tls/tls_heartbeats.cpp new file mode 100644 index 000000000..a77d23534 --- /dev/null +++ b/src/tls/tls_heartbeats.cpp @@ -0,0 +1,78 @@ +/* +* TLS Heartbeats +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include <botan/internal/tls_heartbeats.h> +#include <botan/internal/tls_extensions.h> +#include <botan/internal/tls_reader.h> +#include <botan/tls_exceptn.h> + +namespace Botan { + +namespace TLS { + +Heartbeat_Message::Heartbeat_Message(const MemoryRegion<byte>& buf) + { + TLS_Data_Reader reader(buf); + + const byte type = reader.get_byte(); + + if(type != 1 && type != 2) + throw TLS_Exception(Alert::ILLEGAL_PARAMETER, + "Unknown heartbeat message type"); + + m_type = static_cast<Type>(type); + + m_payload = reader.get_range<byte>(2, 0, 16*1024); + + // padding follows and is ignored + } + +Heartbeat_Message::Heartbeat_Message(Type type, + const byte payload[], + size_t payload_len) : + m_type(type), + m_payload(payload, payload_len) + { + } + +MemoryVector<byte> Heartbeat_Message::contents() const + { + MemoryVector<byte> send_buf(3 + m_payload.size() + 16); + send_buf[0] = m_type; + send_buf[1] = get_byte<u16bit>(0, m_payload.size()); + send_buf[2] = get_byte<u16bit>(1, m_payload.size()); + copy_mem(&send_buf[3], &m_payload[0], m_payload.size()); + // leave padding as all zeros + + return send_buf; + } + +MemoryVector<byte> Heartbeat_Support_Indicator::serialize() const + { + MemoryVector<byte> heartbeat(1); + heartbeat[0] = (m_peer_allowed_to_send ? 1 : 2); + return heartbeat; + } + +Heartbeat_Support_Indicator::Heartbeat_Support_Indicator(TLS_Data_Reader& reader, + u16bit extension_size) + { + if(extension_size != 1) + throw Decoding_Error("Strange size for heartbeat extension"); + + const byte code = reader.get_byte(); + + if(code != 1 && code != 2) + throw TLS_Exception(Alert::ILLEGAL_PARAMETER, + "Unknown heartbeat code " + to_string(code)); + + m_peer_allowed_to_send = (code == 1); + } + +} + +} diff --git a/src/tls/tls_heartbeats.h b/src/tls/tls_heartbeats.h new file mode 100644 index 000000000..4fa49501b --- /dev/null +++ b/src/tls/tls_heartbeats.h @@ -0,0 +1,40 @@ +/* +* TLS Heartbeats +* (C) 2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_HEARTBEATS_H__ +#define BOTAN_TLS_HEARTBEATS_H__ + +#include <botan/secmem.h> + +namespace Botan { + +namespace TLS { + +class Heartbeat_Message + { + public: + enum Type { REQUEST = 1, RESPONSE = 2 }; + + MemoryVector<byte> contents() const; + + const MemoryRegion<byte>& payload() const { return m_payload; } + + bool is_request() const { return m_type == REQUEST; } + + Heartbeat_Message(const MemoryRegion<byte>& buf); + + Heartbeat_Message(Type type, const byte payload[], size_t payload_len); + private: + Type m_type; + MemoryVector<byte> m_payload; + }; + +} + +} + +#endif diff --git a/src/tls/tls_magic.h b/src/tls/tls_magic.h index 0e45407d3..2972321c9 100644 --- a/src/tls/tls_magic.h +++ b/src/tls/tls_magic.h @@ -32,7 +32,8 @@ enum Record_Type { CHANGE_CIPHER_SPEC = 20, ALERT = 21, HANDSHAKE = 22, - APPLICATION_DATA = 23 + APPLICATION_DATA = 23, + HEARTBEAT = 24, }; enum Handshake_Type { @@ -56,90 +57,6 @@ enum Handshake_Type { HANDSHAKE_NONE = 255 // Null value }; -enum Ciphersuite_Code { - 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_CAMELLIA_128_CBC_SHA = 0x0041, - TLS_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0084, - TLS_RSA_WITH_SEED_CBC_SHA = 0x0096, - TLS_RSA_WITH_IDEA_CBC_SHA = 0x0007, - - 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_CAMELLIA_128_CBC_SHA = 0x0044, - TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0087, - TLS_DHE_DSS_WITH_SEED_CBC_SHA = 0x0099, - TLS_DHE_DSS_WITH_RC4_128_SHA = 0x0066, - - 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_CAMELLIA_128_CBC_SHA = 0x0045, - TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0088, - 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, - - TLS_PSK_WITH_RC4_128_SHA = 0x008A, - TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008B, - TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C, - TLS_PSK_WITH_AES_256_CBC_SHA = 0x008D, - TLS_PSK_WITH_AES_128_CBC_SHA256 = 0x00AE, - TLS_PSK_WITH_AES_256_CBC_SHA384 = 0x00AF, - - TLS_DHE_PSK_WITH_RC4_128_SHA = 0x008E, - TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = 0x008F, - TLS_DHE_PSK_WITH_AES_128_CBC_SHA = 0x0090, - TLS_DHE_PSK_WITH_AES_256_CBC_SHA = 0x0091, - TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = 0x00B2, - TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = 0x00B3, - - TLS_ECDHE_PSK_WITH_RC4_128_SHA = 0xC033, - TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA = 0xC034, - TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = 0xC035, - TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = 0xC036, - TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = 0xC037, - TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 = 0xC038, - - TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = 0xC01A, - TLS_SRP_SHA_WITH_AES_128_CBC_SHA = 0xC01D, - TLS_SRP_SHA_WITH_AES_256_CBC_SHA = 0xC020, - - TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = 0xC01C, - TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = 0xC01F, - TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = 0xC022, - - TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = 0xC01B, - TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = 0xC01E, - TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = 0xC021, - - /* signalling values that cannot be negotiated */ - TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF -}; - enum Compression_Method { NO_COMPRESSION = 0x00, DEFLATE_COMPRESSION = 0x01 diff --git a/src/tls/tls_messages.h b/src/tls/tls_messages.h index 2f8af5fd2..d9146dda1 100644 --- a/src/tls/tls_messages.h +++ b/src/tls/tls_messages.h @@ -21,6 +21,7 @@ namespace Botan { class Credentials_Manager; +class SRP6_Server_Session; namespace TLS { @@ -72,15 +73,10 @@ class Client_Hello : public Handshake_Message { public: Handshake_Type type() const { return CLIENT_HELLO; } + Protocol_Version version() const { return m_version; } - const MemoryVector<byte>& session_id() const { return m_session_id; } - std::vector<byte> session_id_vector() const - { - std::vector<byte> v; - v.insert(v.begin(), &m_session_id[0], &m_session_id[m_session_id.size()]); - return v; - } + const MemoryVector<byte>& session_id() const { return m_session_id; } const std::vector<std::pair<std::string, std::string> >& supported_algos() const { return m_supported_algos; } @@ -113,6 +109,10 @@ class Client_Hello : public Handshake_Message const MemoryRegion<byte>& session_ticket() const { return m_session_ticket; } + bool supports_heartbeats() const { return m_supports_heartbeats; } + + bool peer_can_send_heartbeats() const { return m_peer_can_send_heartbeats; } + Client_Hello(Record_Writer& writer, Handshake_Hash& hash, const Policy& policy, @@ -126,6 +126,7 @@ class Client_Hello : public Handshake_Message Handshake_Hash& hash, const Policy& policy, RandomNumberGenerator& rng, + const MemoryRegion<byte>& reneg_info, const Session& resumed_session, bool next_protocol = false); @@ -154,6 +155,9 @@ class Client_Hello : public Handshake_Message bool m_supports_session_ticket; MemoryVector<byte> m_session_ticket; + + bool m_supports_heartbeats; + bool m_peer_can_send_heartbeats; }; /** @@ -163,17 +167,16 @@ class Server_Hello : public Handshake_Message { public: Handshake_Type type() const { return SERVER_HELLO; } - Protocol_Version version() { return s_version; } + + Protocol_Version version() { return m_version; } + + const MemoryVector<byte>& random() const { return m_random; } + const MemoryVector<byte>& session_id() const { return m_session_id; } - u16bit ciphersuite() const { return suite; } - byte compression_method() const { return comp_method; } - std::vector<byte> session_id_vector() const - { - std::vector<byte> v; - v.insert(v.begin(), &m_session_id[0], &m_session_id[m_session_id.size()]); - return v; - } + u16bit ciphersuite() const { return m_ciphersuite; } + + byte compression_method() const { return m_comp_method; } bool secure_renegotiation() const { return m_secure_renegotiation; } @@ -189,20 +192,9 @@ class Server_Hello : public Handshake_Message const MemoryVector<byte>& renegotiation_info() { return m_renegotiation_info; } - const MemoryVector<byte>& random() const { return s_random; } + bool supports_heartbeats() const { return m_supports_heartbeats; } - Server_Hello(Record_Writer& writer, - Handshake_Hash& hash, - Protocol_Version version, - const Client_Hello& other, - const std::vector<std::string>& available_cert_types, - const Policy& policies, - bool have_session_ticket_key, - bool client_has_secure_renegotiation, - const MemoryRegion<byte>& reneg_info, - bool client_has_npn, - const std::vector<std::string>& next_protocols, - RandomNumberGenerator& rng); + bool peer_can_send_heartbeats() const { return m_peer_can_send_heartbeats; } Server_Hello(Record_Writer& writer, Handshake_Hash& hash, @@ -213,19 +205,20 @@ class Server_Hello : public Handshake_Message size_t max_fragment_size, bool client_has_secure_renegotiation, const MemoryRegion<byte>& reneg_info, - bool client_supports_session_tickets, + bool offer_session_ticket, bool client_has_npn, const std::vector<std::string>& next_protocols, + bool client_has_heartbeat, RandomNumberGenerator& rng); Server_Hello(const MemoryRegion<byte>& buf); private: MemoryVector<byte> serialize() const; - Protocol_Version s_version; - MemoryVector<byte> m_session_id, s_random; - u16bit suite; - byte comp_method; + Protocol_Version m_version; + MemoryVector<byte> m_session_id, m_random; + u16bit m_ciphersuite; + byte m_comp_method; size_t m_fragment_size; bool m_secure_renegotiation; @@ -234,6 +227,9 @@ class Server_Hello : public Handshake_Message bool m_next_protocol; std::vector<std::string> m_next_protocols; bool m_supports_session_ticket; + + bool m_supports_heartbeats; + bool m_peer_can_send_heartbeats; }; /** @@ -251,6 +247,7 @@ class Client_Key_Exchange : public Handshake_Message Handshake_State* state, Credentials_Manager& creds, const std::vector<X509_Certificate>& peer_certs, + const std::string& hostname, RandomNumberGenerator& rng); Client_Key_Exchange(const MemoryRegion<byte>& buf, @@ -408,6 +405,9 @@ class Server_Key_Exchange : public Handshake_Message // Only valid for certain kex types const Private_Key& server_kex_key() const; + // Only valid for SRP negotiation + SRP6_Server_Session& server_srp_params(); + Server_Key_Exchange(Record_Writer& writer, Handshake_State* state, const Policy& policy, @@ -420,11 +420,12 @@ class Server_Key_Exchange : public Handshake_Message const std::string& sig_alg, Protocol_Version version); - ~Server_Key_Exchange() { delete m_kex_key; } + ~Server_Key_Exchange(); private: MemoryVector<byte> serialize() const; Private_Key* m_kex_key; + SRP6_Server_Session* m_srp_params; MemoryVector<byte> m_params; @@ -479,7 +480,7 @@ class New_Session_Ticket : public Handshake_Message New_Session_Ticket(Record_Writer& writer, Handshake_Hash& hash, const MemoryRegion<byte>& ticket, - u32bit lifetime = 0); + u32bit lifetime); New_Session_Ticket(Record_Writer& writer, Handshake_Hash& hash); diff --git a/src/tls/tls_policy.cpp b/src/tls/tls_policy.cpp index 1ab55f7c6..f240bebac 100644 --- a/src/tls/tls_policy.cpp +++ b/src/tls/tls_policy.cpp @@ -11,8 +11,6 @@ #include <botan/tls_exceptn.h> #include <botan/internal/stl_util.h> -#include <assert.h> - namespace Botan { namespace TLS { @@ -25,8 +23,8 @@ std::vector<std::string> Policy::allowed_ciphers() const allowed.push_back("AES-128"); allowed.push_back("3DES"); allowed.push_back("ARC4"); - - // Note that Camellia, SEED and IDEA are not included by default + //allowed.push_back("Camellia"); + //allowed.push_back("SEED"); return allowed; } @@ -40,7 +38,7 @@ std::vector<std::string> Policy::allowed_hashes() const allowed.push_back("SHA-256"); allowed.push_back("SHA-224"); allowed.push_back("SHA-1"); - // Note that MD5 is not included by default + //allowed.push_back("MD5"); return allowed; } @@ -49,13 +47,14 @@ std::vector<std::string> Policy::allowed_key_exchange_methods() const { std::vector<std::string> allowed; - //allowed.push_back("SRP"); + allowed.push_back("SRP_SHA"); //allowed.push_back("ECDHE_PSK"); //allowed.push_back("DHE_PSK"); //allowed.push_back("PSK"); + allowed.push_back("ECDH"); allowed.push_back("DH"); - allowed.push_back("RSA"); // RSA via server cert + allowed.push_back("RSA"); return allowed; } @@ -67,7 +66,7 @@ std::vector<std::string> Policy::allowed_signature_methods() const allowed.push_back("ECDSA"); allowed.push_back("RSA"); allowed.push_back("DSA"); - allowed.push_back(""); + //allowed.push_back(""); return allowed; } @@ -89,6 +88,40 @@ std::vector<std::string> Policy::allowed_ecc_curves() const return curves; } +/* +* Choose an ECC curve to use +*/ +std::string Policy::choose_curve(const std::vector<std::string>& curve_names) const + { + const std::vector<std::string> our_curves = allowed_ecc_curves(); + + for(size_t i = 0; i != our_curves.size(); ++i) + if(value_exists(curve_names, our_curves[i])) + return our_curves[i]; + + return ""; // no shared curve + } + +DL_Group Policy::dh_group() const + { + return DL_Group("modp/ietf/2048"); + } + +/* +* Return allowed compression algorithms +*/ +std::vector<byte> Policy::compression() const + { + std::vector<byte> algs; + algs.push_back(NO_COMPRESSION); + return algs; + } + +u32bit Policy::session_ticket_lifetime() const + { + return 86400; // 1 day + } + Protocol_Version Policy::min_version() const { return Protocol_Version::SSL_V3; @@ -173,21 +206,13 @@ class Ciphersuite_Preference_Ordering } -std::vector<u16bit> Policy::ciphersuite_list(bool have_srp) const +std::vector<u16bit> ciphersuite_list(const Policy& policy, + bool have_srp) { - std::vector<std::string> ciphers = allowed_ciphers(); - std::vector<std::string> hashes = allowed_hashes(); - std::vector<std::string> kex = allowed_key_exchange_methods(); - std::vector<std::string> sigs = allowed_signature_methods(); - - if(!have_srp) - { - std::vector<std::string>::iterator i = - std::find(kex.begin(), kex.end(), "SRP"); - - if(i != kex.end()) - kex.erase(i); - } + const std::vector<std::string> ciphers = policy.allowed_ciphers(); + const std::vector<std::string> hashes = policy.allowed_hashes(); + const std::vector<std::string> kex = policy.allowed_key_exchange_methods(); + const std::vector<std::string> sigs = policy.allowed_signature_methods(); Ciphersuite_Preference_Ordering order(ciphers, hashes, kex, sigs); @@ -201,13 +226,27 @@ std::vector<u16bit> Policy::ciphersuite_list(bool have_srp) const if(!suite.valid()) continue; // not a ciphersuite we know, skip - if(value_exists(ciphers, suite.cipher_algo()) && - value_exists(hashes, suite.mac_algo()) && - value_exists(kex, suite.kex_algo()) && - value_exists(sigs, suite.sig_algo())) + if(!have_srp && suite.kex_algo() == "SRP_SHA") + continue; + + if(!value_exists(kex, suite.kex_algo())) + continue; // unsupported key exchange + + if(!value_exists(ciphers, suite.cipher_algo())) + continue; // unsupported cipher + + if(!value_exists(hashes, suite.mac_algo())) + continue; // unsupported MAC algo + + if(!value_exists(sigs, suite.sig_algo())) { - ciphersuites[suite] = i; + // allow if it's an empty sig algo and we want to use PSK + if(suite.sig_algo() != "" || !suite.psk_ciphersuite()) + continue; } + + // OK, allow it: + ciphersuites[suite] = i; } std::vector<u16bit> ciphersuite_codes; @@ -221,79 +260,6 @@ std::vector<u16bit> Policy::ciphersuite_list(bool have_srp) const return ciphersuite_codes; } -/* -* Return allowed compression algorithms -*/ -std::vector<byte> Policy::compression() const - { - std::vector<byte> algs; - algs.push_back(NO_COMPRESSION); - return algs; - } - -/* -* Choose an ECC curve to use -*/ -std::string Policy::choose_curve(const std::vector<std::string>& curve_names) const - { - std::vector<std::string> our_curves = allowed_ecc_curves(); - - for(size_t i = 0; i != our_curves.size(); ++i) - if(value_exists(curve_names, our_curves[i])) - return our_curves[i]; - - return ""; // no shared curve - } - -/* -* Choose which ciphersuite to use -*/ -u16bit Policy::choose_suite(const std::vector<u16bit>& client_suites, - const std::vector<std::string>& available_cert_types, - bool have_shared_ecc_curve, - bool have_srp) const - { - std::vector<u16bit> ciphersuites = ciphersuite_list(have_srp); - - for(size_t i = 0; i != ciphersuites.size(); ++i) - { - const u16bit suite_id = ciphersuites[i]; - Ciphersuite suite = Ciphersuite::by_id(suite_id); - - if(!have_shared_ecc_curve) - { - if(suite.kex_algo() == "ECDH" || suite.sig_algo() == "ECDSA") - continue; - } - - if(suite.sig_algo() != "" && - !value_exists(available_cert_types, suite.sig_algo())) - { - continue; - } - - if(value_exists(client_suites, suite_id)) - return suite_id; - } - - return 0; // no shared cipersuite - } - -/* -* Choose which compression algorithm to use -*/ -byte Policy::choose_compression(const std::vector<byte>& c_comp) const - { - std::vector<byte> s_comp = compression(); - - for(size_t i = 0; i != s_comp.size(); ++i) - for(size_t j = 0; j != c_comp.size(); ++j) - if(s_comp[i] == c_comp[j]) - return s_comp[i]; - - return NO_COMPRESSION; - } - } } diff --git a/src/tls/tls_policy.h b/src/tls/tls_policy.h index f53b9bab6..c3a0fc29e 100644 --- a/src/tls/tls_policy.h +++ b/src/tls/tls_policy.h @@ -82,19 +82,26 @@ class BOTAN_DLL Policy /** * Return the group to use for ephemeral Diffie-Hellman key agreement */ - virtual DL_Group dh_group() const { return DL_Group("modp/ietf/1536"); } + virtual DL_Group dh_group() const; /** * If this function returns false, unknown SRP/PSK identifiers * will be rejected with an unknown_psk_identifier alert as soon * as the non-existence is identified. Otherwise, a false * identifier value will be used and the protocol allowed to - * proceed, causing the login to eventually fail without + * proceed, causing the handshake to eventually fail without * revealing that the username does not exist on this system. */ virtual bool hide_unknown_users() const { return false; } /** + * Return the allowed lifetime of a session ticket. If 0, session + * tickets do not expire until the session ticket key rolls over. + * Expired session tickets cannot be used to resume a session. + */ + virtual u32bit session_ticket_lifetime() const; + + /** * @return the minimum version that we are willing to negotiate */ virtual Protocol_Version min_version() const; @@ -104,21 +111,15 @@ class BOTAN_DLL Policy */ virtual Protocol_Version pref_version() const; - /** - * Return allowed ciphersuites, in order of preference - */ - std::vector<u16bit> ciphersuite_list(bool have_srp) const; - - u16bit choose_suite(const std::vector<u16bit>& client_suites, - const std::vector<std::string>& available_cert_types, - bool have_shared_ecc_curve, - bool have_srp) const; - - byte choose_compression(const std::vector<byte>& client_algos) const; - virtual ~Policy() {} }; +/** +* Return allowed ciphersuites, in order of preference +*/ +std::vector<u16bit> ciphersuite_list(const Policy& policy, + bool have_srp); + } } diff --git a/src/tls/tls_record.h b/src/tls/tls_record.h index b966e3c72..680ec8f7b 100644 --- a/src/tls/tls_record.h +++ b/src/tls/tls_record.h @@ -22,6 +22,16 @@ namespace Botan { namespace TLS { +#elif defined(BOTAN_USE_BOOST_TR1) + #include <boost/tr1/functional.hpp> +#else + #error "No TR1 library defined for use" +#endif + +namespace Botan { + +namespace TLS { + class Session_Keys; /** @@ -33,6 +43,9 @@ class BOTAN_DLL Record_Writer void send(byte type, const byte input[], size_t length); void send(byte type, byte val) { send(type, &val, 1); } + void send(byte type, const MemoryRegion<byte>& input) + { send(type, &input[0], input.size()); } + MemoryVector<byte> send(class Handshake_Message& msg); void send_alert(const Alert& alert); @@ -48,7 +61,7 @@ class BOTAN_DLL Record_Writer void set_maximum_fragment_size(size_t max_fragment); - Record_Writer(std::function<void (const byte[], size_t)> output_fn); + Record_Writer(std::tr1::function<void (const byte[], size_t)> output_fn); ~Record_Writer() { delete m_mac; } private: @@ -57,7 +70,7 @@ class BOTAN_DLL Record_Writer void send_record(byte type, const byte input[], size_t length); - std::function<void (const byte[], size_t)> m_output_fn; + std::tr1::function<void (const byte[], size_t)> m_output_fn; MemoryVector<byte> m_writebuf; diff --git a/src/tls/tls_server.cpp b/src/tls/tls_server.cpp index 3b4a526cc..9da4ca3b8 100644 --- a/src/tls/tls_server.cpp +++ b/src/tls/tls_server.cpp @@ -21,7 +21,8 @@ namespace { bool check_for_resume(Session& session_info, Session_Manager& session_manager, Credentials_Manager& credentials, - Client_Hello* client_hello) + Client_Hello* client_hello, + u32bit session_ticket_lifetime) { const MemoryVector<byte>& client_session_id = client_hello->session_id(); const MemoryVector<byte>& session_ticket = client_hello->session_ticket(); @@ -43,6 +44,10 @@ bool check_for_resume(Session& session_info, session_info = Session::decrypt( session_ticket, credentials.psk("tls-server", "session-ticket", "")); + + if(session_ticket_lifetime && + session_info.session_age() > session_ticket_lifetime) + return false; // ticket has expired } catch(...) { @@ -81,6 +86,79 @@ bool check_for_resume(Session& session_info, return true; } +/* +* Choose which ciphersuite to use +*/ +u16bit choose_ciphersuite( + const Policy& policy, + Credentials_Manager& creds, + const std::map<std::string, std::vector<X509_Certificate> >& cert_chains, + const Client_Hello* client_hello) + { + const bool have_srp = creds.attempt_srp("tls-server", + client_hello->sni_hostname()); + + const std::vector<u16bit> client_suites = client_hello->ciphersuites(); + const std::vector<u16bit> server_suites = ciphersuite_list(policy, have_srp); + + if(server_suites.empty()) + throw Internal_Error("Policy forbids us from negotiating any ciphersuite"); + + const bool have_shared_ecc_curve = + (policy.choose_curve(client_hello->supported_ecc_curves()) != ""); + + // Ordering by our preferences rather than by clients + for(size_t i = 0; i != server_suites.size(); ++i) + { + const u16bit suite_id = server_suites[i]; + + if(!value_exists(client_suites, suite_id)) + continue; + + Ciphersuite suite = Ciphersuite::by_id(suite_id); + + if(!have_shared_ecc_curve && suite.ecc_ciphersuite()) + continue; + + if(cert_chains.count(suite.sig_algo()) == 0) + continue; + + /* + The client may offer SRP cipher suites in the hello message but + omit the SRP extension. If the server would like to select an + SRP cipher suite in this case, the server SHOULD return a fatal + "unknown_psk_identity" alert immediately after processing the + client hello message. + - RFC 5054 section 2.5.1.2 + */ + if(suite.kex_algo() == "SRP_SHA" && client_hello->srp_identifier() == "") + throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY, + "Client wanted SRP but did not send username"); + + return suite_id; + } + + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Can't agree on a ciphersuite with client"); + } + + +/* +* Choose which compression algorithm to use +*/ +byte choose_compression(const Policy& policy, + const std::vector<byte>& c_comp) + { + std::vector<byte> s_comp = policy.compression(); + + for(size_t i = 0; i != s_comp.size(); ++i) + for(size_t j = 0; j != c_comp.size(); ++j) + if(s_comp[i] == c_comp[j]) + return s_comp[i]; + + return NO_COMPRESSION; + } + std::map<std::string, std::vector<X509_Certificate> > get_server_certs(const std::string& hostname, Credentials_Manager& creds) @@ -106,9 +184,9 @@ get_server_certs(const std::string& hostname, /* * TLS Server Constructor */ -Server::Server(std::function<void (const byte[], size_t)> output_fn, - std::function<void (const byte[], size_t, Alert)> proc_fn, - std::function<bool (const Session&)> handshake_fn, +Server::Server(std::tr1::function<void (const byte[], size_t)> output_fn, + std::tr1::function<void (const byte[], size_t, Alert)> proc_fn, + std::tr1::function<bool (const Session&)> handshake_fn, Session_Manager& session_manager, Credentials_Manager& creds, const Policy& policy, @@ -126,12 +204,14 @@ Server::Server(std::function<void (const byte[], size_t)> output_fn, /* * Send a hello request to the client */ -void Server::renegotiate() +void Server::renegotiate(bool force_full_renegotiation) { if(state) return; // currently in handshake state = new Handshake_State(new Stream_Handshake_Reader); + + state->allow_session_resumption = !force_full_renegotiation; state->set_expected_next(CLIENT_HELLO); Hello_Request hello_req(writer); } @@ -193,7 +273,8 @@ void Server::process_handshake_msg(Handshake_Type type, { state->client_hello = new Client_Hello(contents, type); - m_hostname = state->client_hello->sni_hostname(); + if(state->client_hello->sni_hostname() != "") + m_hostname = state->client_hello->sni_hostname(); Protocol_Version client_version = state->client_hello->version(); @@ -208,14 +289,20 @@ void Server::process_handshake_msg(Handshake_Type type, secure_renegotiation.update(state->client_hello); + m_peer_supports_heartbeats = state->client_hello->supports_heartbeats(); + m_heartbeat_sending_allowed = state->client_hello->peer_can_send_heartbeats(); + writer.set_version(state->version()); reader.set_version(state->version()); Session session_info; - const bool resuming = check_for_resume(session_info, - session_manager, - creds, - state->client_hello); + const bool resuming = + state->allow_session_resumption && + check_for_resume(session_info, + session_manager, + creds, + state->client_hello, + policy.session_ticket_lifetime()); bool have_session_ticket_key = false; @@ -240,11 +327,16 @@ void Server::process_handshake_msg(Handshake_Type type, session_info.fragment_size(), secure_renegotiation.supported(), secure_renegotiation.for_server_hello(), - state->client_hello->supports_session_ticket() && have_session_ticket_key, + (state->client_hello->supports_session_ticket() && + state->client_hello->session_ticket().empty() && + have_session_ticket_key), state->client_hello->next_protocol_notification(), m_possible_protocols, + state->client_hello->supports_heartbeats(), rng); + secure_renegotiation.update(state->server_hello); + if(session_info.fragment_size()) { reader.set_maximum_fragment_size(session_info.fragment_size()); @@ -257,13 +349,12 @@ void Server::process_handshake_msg(Handshake_Type type, if(!handshake_fn(session_info)) { - if(state->server_hello->supports_session_ticket()) + session_manager.remove_entry(session_info.session_id()); + + if(state->server_hello->supports_session_ticket()) // send an empty ticket state->new_session_ticket = new New_Session_Ticket(writer, state->hash); - else - session_manager.remove_entry(session_info.session_id()); } - // FIXME: should only send a new ticket if we need too (eg old session) if(state->server_hello->supports_session_ticket() && !state->new_session_ticket) { try @@ -272,7 +363,8 @@ void Server::process_handshake_msg(Handshake_Type type, state->new_session_ticket = new New_Session_Ticket(writer, state->hash, - session_info.encrypt(ticket_key, rng)); + session_info.encrypt(ticket_key, rng), + policy.session_ticket_lifetime()); } catch(...) {} @@ -301,29 +393,24 @@ void Server::process_handshake_msg(Handshake_Type type, cert_chains = get_server_certs("", creds); } - std::vector<std::string> available_cert_types; - - for(std::map<std::string, std::vector<X509_Certificate> >::const_iterator i = cert_chains.begin(); - i != cert_chains.end(); ++i) - { - if(!i->second.empty()) - available_cert_types.push_back(i->first); - } - state->server_hello = new Server_Hello( writer, state->hash, + rng.random_vec(32), // new session ID state->version(), - *(state->client_hello), - available_cert_types, - policy, - have_session_ticket_key, + choose_ciphersuite(policy, creds, cert_chains, state->client_hello), + choose_compression(policy, state->client_hello->compression_methods()), + state->client_hello->fragment_size(), secure_renegotiation.supported(), secure_renegotiation.for_server_hello(), + state->client_hello->supports_session_ticket() && have_session_ticket_key, state->client_hello->next_protocol_notification(), m_possible_protocols, + state->client_hello->supports_heartbeats(), rng); + secure_renegotiation.update(state->server_hello); + if(state->client_hello->fragment_size()) { reader.set_maximum_fragment_size(state->client_hello->fragment_size()); @@ -381,8 +468,6 @@ void Server::process_handshake_msg(Handshake_Type type, state->set_expected_next(CERTIFICATE); } - secure_renegotiation.update(state->server_hello); - /* * If the client doesn't have a cert they want to use they are * allowed to send either an empty cert message or proceed @@ -397,11 +482,6 @@ void Server::process_handshake_msg(Handshake_Type type, { state->client_certs = new Certificate(contents); - // Is this allowed by the protocol? - if(state->client_certs->count() > 1) - throw TLS_Exception(Alert::CERTIFICATE_UNKNOWN, - "Client sent more than one certificate"); - state->set_expected_next(CLIENT_KEX); } else if(type == CLIENT_KEX) @@ -419,11 +499,10 @@ void Server::process_handshake_msg(Handshake_Type type, { state->client_verify = new Certificate_Verify(contents, state->version()); - const std::vector<X509_Certificate>& client_certs = - state->client_certs->cert_chain(); + peer_certs = state->client_certs->cert_chain(); const bool sig_valid = - state->client_verify->verify(client_certs[0], state); + state->client_verify->verify(peer_certs[0], state); state->hash.update(type, contents); @@ -437,7 +516,7 @@ void Server::process_handshake_msg(Handshake_Type type, try { - creds.verify_certificate_chain("tls-server", "", client_certs); + creds.verify_certificate_chain("tls-server", "", peer_certs); } catch(std::exception& e) { @@ -492,7 +571,7 @@ void Server::process_handshake_msg(Handshake_Type type, peer_certs, MemoryVector<byte>(), m_hostname, - "" + state->srp_identifier() ); if(handshake_fn(session_info)) @@ -505,7 +584,8 @@ void Server::process_handshake_msg(Handshake_Type type, state->new_session_ticket = new New_Session_Ticket(writer, state->hash, - session_info.encrypt(ticket_key, rng)); + session_info.encrypt(ticket_key, rng), + policy.session_ticket_lifetime()); } catch(...) {} } @@ -522,9 +602,6 @@ void Server::process_handshake_msg(Handshake_Type type, state->server_hello->compression_method()); state->server_finished = new Finished(writer, state, SERVER); - - if(state->client_certs && state->client_verify) - peer_certs = state->client_certs->cert_chain(); } secure_renegotiation.update(state->client_finished, diff --git a/src/tls/tls_server.h b/src/tls/tls_server.h index a90982066..6ade91afc 100644 --- a/src/tls/tls_server.h +++ b/src/tls/tls_server.h @@ -26,9 +26,9 @@ class BOTAN_DLL Server : public Channel /** * Server initialization */ - Server(std::function<void (const byte[], size_t)> socket_output_fn, - std::function<void (const byte[], size_t, Alert)> proc_fn, - std::function<bool (const Session&)> handshake_complete, + Server(std::tr1::function<void (const byte[], size_t)> socket_output_fn, + std::tr1::function<void (const byte[], size_t, Alert)> proc_fn, + std::tr1::function<bool (const Session&)> handshake_complete, Session_Manager& session_manager, Credentials_Manager& creds, const Policy& policy, @@ -36,7 +36,7 @@ class BOTAN_DLL Server : public Channel const std::vector<std::string>& protocols = std::vector<std::string>()); - void renegotiate(); + void renegotiate(bool force_full_renegotiation); /** * Return the server name indicator, if sent by the client diff --git a/src/tls/tls_session.cpp b/src/tls/tls_session.cpp index cec1c87ae..0e8bf3051 100644 --- a/src/tls/tls_session.cpp +++ b/src/tls/tls_session.cpp @@ -10,6 +10,7 @@ #include <botan/ber_dec.h> #include <botan/asn1_str.h> #include <botan/pem.h> +#include <botan/time.h> #include <botan/lookup.h> #include <botan/loadstor.h> #include <memory> @@ -30,7 +31,7 @@ Session::Session(const MemoryRegion<byte>& session_identifier, const MemoryRegion<byte>& ticket, const std::string& sni_hostname, const std::string& srp_identifier) : - m_start_time(std::chrono::system_clock::now()), + m_start_time(system_time()), m_identifier(session_identifier), m_session_ticket(ticket), m_master_secret(master_secret), @@ -63,13 +64,11 @@ Session::Session(const byte ber[], size_t ber_len) MemoryVector<byte> peer_cert_bits; - size_t start_time = 0; - BER_Decoder(ber, ber_len) .start_cons(SEQUENCE) .decode_and_check(static_cast<size_t>(TLS_SESSION_PARAM_STRUCT_VERSION), "Unknown version in session structure") - .decode_integer_type(start_time) + .decode_integer_type(m_start_time) .decode_integer_type(major_version) .decode_integer_type(minor_version) .decode(m_identifier, OCTET_STRING) @@ -87,7 +86,6 @@ Session::Session(const byte ber[], size_t ber_len) .verify_end(); m_version = Protocol_Version(major_version, minor_version); - m_start_time = std::chrono::system_clock::from_time_t(start_time); m_sni_hostname = sni_hostname_str.value(); m_srp_identifier = srp_identifier_str.value(); m_connection_side = static_cast<Connection_Side>(side_code); @@ -110,7 +108,7 @@ SecureVector<byte> Session::DER_encode() const return DER_Encoder() .start_cons(SEQUENCE) .encode(static_cast<size_t>(TLS_SESSION_PARAM_STRUCT_VERSION)) - .encode(static_cast<size_t>(std::chrono::system_clock::to_time_t(m_start_time))) + .encode(static_cast<size_t>(m_start_time)) .encode(static_cast<size_t>(m_version.major_version())) .encode(static_cast<size_t>(m_version.minor_version())) .encode(m_identifier, OCTET_STRING) @@ -133,6 +131,11 @@ std::string Session::PEM_encode() const return PEM_Code::encode(this->DER_encode(), "SSL SESSION"); } +u32bit Session::session_age() const + { + return (system_time() - m_start_time); + } + namespace { const u32bit SESSION_CRYPTO_MAGIC = 0x571B0E4E; @@ -152,7 +155,7 @@ MemoryVector<byte> Session::encrypt(const SymmetricKey& master_key, RandomNumberGenerator& rng) const { - std::unique_ptr<KDF> kdf(get_kdf(SESSION_CRYPTO_KDF)); + std::auto_ptr<KDF> kdf(get_kdf(SESSION_CRYPTO_KDF)); SymmetricKey cipher_key = kdf->derive_key(CIPHER_KEY_LENGTH, @@ -166,7 +169,7 @@ Session::encrypt(const SymmetricKey& master_key, InitializationVector cipher_iv(rng, 16); - std::unique_ptr<MessageAuthenticationCode> mac(get_mac(SESSION_CRYPTO_MAC)); + std::auto_ptr<MessageAuthenticationCode> mac(get_mac(SESSION_CRYPTO_MAC)); mac->set_key(mac_key); Pipe pipe(get_cipher(SESSION_CRYPTO_CIPHER, cipher_key, cipher_iv, ENCRYPTION)); @@ -200,14 +203,14 @@ Session Session::decrypt(const byte buf[], size_t buf_len, if(load_be<u32bit>(buf, 0) != SESSION_CRYPTO_MAGIC) throw Decoding_Error("Unknown header value in encrypted session"); - std::unique_ptr<KDF> kdf(get_kdf(SESSION_CRYPTO_KDF)); + std::auto_ptr<KDF> kdf(get_kdf(SESSION_CRYPTO_KDF)); SymmetricKey mac_key = kdf->derive_key(MAC_KEY_LENGTH, master_key.bits_of(), "tls.session.mac-key"); - std::unique_ptr<MessageAuthenticationCode> mac(get_mac(SESSION_CRYPTO_MAC)); + std::auto_ptr<MessageAuthenticationCode> mac(get_mac(SESSION_CRYPTO_MAC)); mac->set_key(mac_key); mac->update(&buf[0], buf_len - MAC_OUTPUT_LENGTH); diff --git a/src/tls/tls_session.h b/src/tls/tls_session.h index 8fc048c75..290ee6dcc 100644 --- a/src/tls/tls_session.h +++ b/src/tls/tls_session.h @@ -5,8 +5,8 @@ * Released under the terms of the Botan license */ -#ifndef TLS_SESSION_STATE_H__ -#define TLS_SESSION_STATE_H__ +#ifndef BOTAN_TLS_SESSION_STATE_H__ +#define BOTAN_TLS_SESSION_STATE_H__ #include <botan/x509cert.h> #include <botan/tls_version.h> @@ -14,7 +14,6 @@ #include <botan/tls_magic.h> #include <botan/secmem.h> #include <botan/symkey.h> -#include <chrono> namespace Botan { @@ -31,7 +30,7 @@ class BOTAN_DLL Session * Uninitialized session */ Session() : - m_start_time(std::chrono::system_clock::time_point::min()), + m_start_time(0), m_version(), m_ciphersuite(0), m_compression_method(0), @@ -175,8 +174,12 @@ class BOTAN_DLL Session /** * Get the time this session began (seconds since Epoch) */ - std::chrono::system_clock::time_point start_time() const - { return m_start_time; } + u64bit start_time() const { return m_start_time; } + + /** + * Return how long this session has existed (in seconds) + */ + u32bit session_age() const; /** * Return the session ticket the server gave us @@ -186,7 +189,7 @@ class BOTAN_DLL Session private: enum { TLS_SESSION_PARAM_STRUCT_VERSION = 0x2994e300 }; - std::chrono::system_clock::time_point m_start_time; + u64bit m_start_time; MemoryVector<byte> m_identifier; MemoryVector<byte> m_session_ticket; // only used by client side diff --git a/src/tls/tls_session_manager.cpp b/src/tls/tls_session_manager.cpp index 4c6bc1a47..69823e8bd 100644 --- a/src/tls/tls_session_manager.cpp +++ b/src/tls/tls_session_manager.cpp @@ -20,7 +20,7 @@ bool Session_Manager_In_Memory::load_from_session_str( auto i = sessions.find(session_str); - if(i == sessions.end()) + if(i == m_sessions.end()) return false; // if session has expired, remove it @@ -28,7 +28,7 @@ bool Session_Manager_In_Memory::load_from_session_str( if(i->second.start_time() + session_lifetime < now) { - sessions.erase(i); + m_sessions.erase(i); return false; } @@ -75,8 +75,8 @@ void Session_Manager_In_Memory::remove_entry( auto i = sessions.find(hex_encode(session_id)); - if(i != sessions.end()) - sessions.erase(i); + if(i != m_sessions.end()) + m_sessions.erase(i); } void Session_Manager_In_Memory::save(const Session& session) @@ -89,8 +89,8 @@ void Session_Manager_In_Memory::save(const Session& session) This removes randomly based on ordering of session ids. Instead, remove oldest first? */ - while(sessions.size() >= max_sessions) - sessions.erase(sessions.begin()); + while(m_sessions.size() >= m_max_sessions) + m_sessions.erase(m_sessions.begin()); } const std::string session_id_str = hex_encode(session.session_id()); diff --git a/src/tls/tls_session_manager.h b/src/tls/tls_session_manager.h index 4152f2392..8a4f31b78 100644 --- a/src/tls/tls_session_manager.h +++ b/src/tls/tls_session_manager.h @@ -5,8 +5,8 @@ * Released under the terms of the Botan license */ -#ifndef TLS_SESSION_MANAGER_H__ -#define TLS_SESSION_MANAGER_H__ +#ifndef BOTAN_TLS_SESSION_MANAGER_H__ +#define BOTAN_TLS_SESSION_MANAGER_H__ #include <botan/tls_session.h> #include <mutex> @@ -65,6 +65,13 @@ class BOTAN_DLL Session_Manager */ virtual void save(const Session& session) = 0; + /** + * Return the allowed lifetime of a session; beyond this time, + * sessions are not resumed. Returns 0 if unknown/no explicit + * expiration policy. + */ + virtual u32bit session_lifetime() const = 0; + virtual ~Session_Manager() {} }; @@ -82,9 +89,9 @@ class BOTAN_DLL Session_Manager_In_Memory : public Session_Manager * seconds have elapsed from initial handshake. */ Session_Manager_In_Memory(size_t max_sessions = 1000, - std::chrono::seconds session_lifetime = std::chrono::seconds(7200)) : - max_sessions(max_sessions), - session_lifetime(session_lifetime) + u32bit session_lifetime = 7200) : + m_max_sessions(max_sessions), + m_session_lifetime(session_lifetime) {} bool load_from_session_id(const MemoryRegion<byte>& session_id, @@ -97,17 +104,18 @@ class BOTAN_DLL Session_Manager_In_Memory : public Session_Manager void save(const Session& session_data); + u32bit session_lifetime() const { return m_session_lifetime; } + private: bool load_from_session_str(const std::string& session_str, Session& session); - std::mutex mutex; + size_t m_max_sessions; - size_t max_sessions; - std::chrono::seconds session_lifetime; + u32bit m_session_lifetime; - std::map<std::string, Session> sessions; // hex(session_id) -> session - std::map<std::string, std::string> host_sessions; + std::map<std::string, Session> m_sessions; // hex(session_id) -> session + std::map<std::string, std::string> m_host_sessions; }; } diff --git a/src/tls/tls_suite_info.cpp b/src/tls/tls_suite_info.cpp new file mode 100644 index 000000000..997bda428 --- /dev/null +++ b/src/tls/tls_suite_info.cpp @@ -0,0 +1,317 @@ +/* +* TLS Cipher Suite +* (C) 2004-2010,2012 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include <botan/tls_ciphersuite.h> + +namespace Botan { + +namespace TLS { + +Ciphersuite Ciphersuite::by_id(u16bit suite) + { + // Automatically generated by a Python script from the IANA values + + switch(suite) + { + case 0x0013: // DHE_DSS_WITH_3DES_EDE_CBC_SHA + return Ciphersuite("DSA", "DH", "SHA-1", "3DES", 24); + + case 0x0032: // DHE_DSS_WITH_AES_128_CBC_SHA + return Ciphersuite("DSA", "DH", "SHA-1", "AES-128", 16); + + case 0x0040: // DHE_DSS_WITH_AES_128_CBC_SHA256 + return Ciphersuite("DSA", "DH", "SHA-256", "AES-128", 16); + + case 0x0038: // DHE_DSS_WITH_AES_256_CBC_SHA + return Ciphersuite("DSA", "DH", "SHA-1", "AES-256", 32); + + case 0x006A: // DHE_DSS_WITH_AES_256_CBC_SHA256 + return Ciphersuite("DSA", "DH", "SHA-256", "AES-256", 32); + + case 0x0044: // DHE_DSS_WITH_CAMELLIA_128_CBC_SHA + return Ciphersuite("DSA", "DH", "SHA-1", "Camellia-128", 16); + + case 0x00BD: // DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite("DSA", "DH", "SHA-256", "Camellia-128", 16); + + case 0x0087: // DHE_DSS_WITH_CAMELLIA_256_CBC_SHA + return Ciphersuite("DSA", "DH", "SHA-1", "Camellia-256", 32); + + case 0x00C3: // DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 + return Ciphersuite("DSA", "DH", "SHA-256", "Camellia-256", 32); + + case 0x0066: // DHE_DSS_WITH_RC4_128_SHA + return Ciphersuite("DSA", "DH", "SHA-1", "ARC4", 16); + + case 0x0099: // DHE_DSS_WITH_SEED_CBC_SHA + return Ciphersuite("DSA", "DH", "SHA-1", "SEED", 16); + + case 0x008F: // DHE_PSK_WITH_3DES_EDE_CBC_SHA + return Ciphersuite("", "DHE_PSK", "SHA-1", "3DES", 24); + + case 0x0090: // DHE_PSK_WITH_AES_128_CBC_SHA + return Ciphersuite("", "DHE_PSK", "SHA-1", "AES-128", 16); + + case 0x00B2: // DHE_PSK_WITH_AES_128_CBC_SHA256 + return Ciphersuite("", "DHE_PSK", "SHA-256", "AES-128", 16); + + case 0x0091: // DHE_PSK_WITH_AES_256_CBC_SHA + return Ciphersuite("", "DHE_PSK", "SHA-1", "AES-256", 32); + + case 0x00B3: // DHE_PSK_WITH_AES_256_CBC_SHA384 + return Ciphersuite("", "DHE_PSK", "SHA-384", "AES-256", 32); + + case 0xC096: // DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite("", "DHE_PSK", "SHA-256", "Camellia-128", 16); + + case 0xC097: // DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + return Ciphersuite("", "DHE_PSK", "SHA-384", "Camellia-256", 32); + + case 0x008E: // DHE_PSK_WITH_RC4_128_SHA + return Ciphersuite("", "DHE_PSK", "SHA-1", "ARC4", 16); + + case 0x0016: // DHE_RSA_WITH_3DES_EDE_CBC_SHA + return Ciphersuite("RSA", "DH", "SHA-1", "3DES", 24); + + case 0x0033: // DHE_RSA_WITH_AES_128_CBC_SHA + return Ciphersuite("RSA", "DH", "SHA-1", "AES-128", 16); + + case 0x0067: // DHE_RSA_WITH_AES_128_CBC_SHA256 + return Ciphersuite("RSA", "DH", "SHA-256", "AES-128", 16); + + case 0x0039: // DHE_RSA_WITH_AES_256_CBC_SHA + return Ciphersuite("RSA", "DH", "SHA-1", "AES-256", 32); + + case 0x006B: // DHE_RSA_WITH_AES_256_CBC_SHA256 + return Ciphersuite("RSA", "DH", "SHA-256", "AES-256", 32); + + case 0x0045: // DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + return Ciphersuite("RSA", "DH", "SHA-1", "Camellia-128", 16); + + case 0x00BE: // DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite("RSA", "DH", "SHA-256", "Camellia-128", 16); + + case 0x0088: // DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + return Ciphersuite("RSA", "DH", "SHA-1", "Camellia-256", 32); + + case 0x00C4: // DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + return Ciphersuite("RSA", "DH", "SHA-256", "Camellia-256", 32); + + case 0x009A: // DHE_RSA_WITH_SEED_CBC_SHA + return Ciphersuite("RSA", "DH", "SHA-1", "SEED", 16); + + case 0x001B: // DH_anon_WITH_3DES_EDE_CBC_SHA + return Ciphersuite("", "DH", "SHA-1", "3DES", 24); + + case 0x0034: // DH_anon_WITH_AES_128_CBC_SHA + return Ciphersuite("", "DH", "SHA-1", "AES-128", 16); + + case 0x006C: // DH_anon_WITH_AES_128_CBC_SHA256 + return Ciphersuite("", "DH", "SHA-256", "AES-128", 16); + + case 0x003A: // DH_anon_WITH_AES_256_CBC_SHA + return Ciphersuite("", "DH", "SHA-1", "AES-256", 32); + + case 0x006D: // DH_anon_WITH_AES_256_CBC_SHA256 + return Ciphersuite("", "DH", "SHA-256", "AES-256", 32); + + case 0x0046: // DH_anon_WITH_CAMELLIA_128_CBC_SHA + return Ciphersuite("", "DH", "SHA-1", "Camellia-128", 16); + + case 0x00BF: // DH_anon_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite("", "DH", "SHA-256", "Camellia-128", 16); + + case 0x0089: // DH_anon_WITH_CAMELLIA_256_CBC_SHA + return Ciphersuite("", "DH", "SHA-1", "Camellia-256", 32); + + case 0x00C5: // DH_anon_WITH_CAMELLIA_256_CBC_SHA256 + return Ciphersuite("", "DH", "SHA-256", "Camellia-256", 32); + + case 0x0018: // DH_anon_WITH_RC4_128_MD5 + return Ciphersuite("", "DH", "MD5", "ARC4", 16); + + case 0x009B: // DH_anon_WITH_SEED_CBC_SHA + return Ciphersuite("", "DH", "SHA-1", "SEED", 16); + + case 0xC008: // ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + return Ciphersuite("ECDSA", "ECDH", "SHA-1", "3DES", 24); + + case 0xC009: // ECDHE_ECDSA_WITH_AES_128_CBC_SHA + return Ciphersuite("ECDSA", "ECDH", "SHA-1", "AES-128", 16); + + case 0xC023: // ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + return Ciphersuite("ECDSA", "ECDH", "SHA-256", "AES-128", 16); + + case 0xC00A: // ECDHE_ECDSA_WITH_AES_256_CBC_SHA + return Ciphersuite("ECDSA", "ECDH", "SHA-1", "AES-256", 32); + + case 0xC024: // ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + return Ciphersuite("ECDSA", "ECDH", "SHA-384", "AES-256", 32); + + case 0xC072: // ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite("ECDSA", "ECDH", "SHA-256", "Camellia-128", 16); + + case 0xC073: // ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + return Ciphersuite("ECDSA", "ECDH", "SHA-384", "Camellia-256", 32); + + case 0xC007: // ECDHE_ECDSA_WITH_RC4_128_SHA + return Ciphersuite("ECDSA", "ECDH", "SHA-1", "ARC4", 16); + + case 0xC034: // ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + return Ciphersuite("", "ECDHE_PSK", "SHA-1", "3DES", 24); + + case 0xC035: // ECDHE_PSK_WITH_AES_128_CBC_SHA + return Ciphersuite("", "ECDHE_PSK", "SHA-1", "AES-128", 16); + + case 0xC037: // ECDHE_PSK_WITH_AES_128_CBC_SHA256 + return Ciphersuite("", "ECDHE_PSK", "SHA-256", "AES-128", 16); + + case 0xC036: // ECDHE_PSK_WITH_AES_256_CBC_SHA + return Ciphersuite("", "ECDHE_PSK", "SHA-1", "AES-256", 32); + + case 0xC038: // ECDHE_PSK_WITH_AES_256_CBC_SHA384 + return Ciphersuite("", "ECDHE_PSK", "SHA-384", "AES-256", 32); + + case 0xC09A: // ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite("", "ECDHE_PSK", "SHA-256", "Camellia-128", 16); + + case 0xC09B: // ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + return Ciphersuite("", "ECDHE_PSK", "SHA-384", "Camellia-256", 32); + + case 0xC033: // ECDHE_PSK_WITH_RC4_128_SHA + return Ciphersuite("", "ECDHE_PSK", "SHA-1", "ARC4", 16); + + case 0xC012: // ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + return Ciphersuite("RSA", "ECDH", "SHA-1", "3DES", 24); + + case 0xC013: // ECDHE_RSA_WITH_AES_128_CBC_SHA + return Ciphersuite("RSA", "ECDH", "SHA-1", "AES-128", 16); + + case 0xC027: // ECDHE_RSA_WITH_AES_128_CBC_SHA256 + return Ciphersuite("RSA", "ECDH", "SHA-256", "AES-128", 16); + + case 0xC014: // ECDHE_RSA_WITH_AES_256_CBC_SHA + return Ciphersuite("RSA", "ECDH", "SHA-1", "AES-256", 32); + + case 0xC028: // ECDHE_RSA_WITH_AES_256_CBC_SHA384 + return Ciphersuite("RSA", "ECDH", "SHA-384", "AES-256", 32); + + case 0xC076: // ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite("RSA", "ECDH", "SHA-256", "Camellia-128", 16); + + case 0xC077: // ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + return Ciphersuite("RSA", "ECDH", "SHA-384", "Camellia-256", 32); + + case 0xC011: // ECDHE_RSA_WITH_RC4_128_SHA + return Ciphersuite("RSA", "ECDH", "SHA-1", "ARC4", 16); + + case 0xC017: // ECDH_anon_WITH_3DES_EDE_CBC_SHA + return Ciphersuite("", "ECDH", "SHA-1", "3DES", 24); + + case 0xC018: // ECDH_anon_WITH_AES_128_CBC_SHA + return Ciphersuite("", "ECDH", "SHA-1", "AES-128", 16); + + case 0xC019: // ECDH_anon_WITH_AES_256_CBC_SHA + return Ciphersuite("", "ECDH", "SHA-1", "AES-256", 32); + + case 0xC016: // ECDH_anon_WITH_RC4_128_SHA + return Ciphersuite("", "ECDH", "SHA-1", "ARC4", 16); + + case 0x008B: // PSK_WITH_3DES_EDE_CBC_SHA + return Ciphersuite("", "PSK", "SHA-1", "3DES", 24); + + case 0x008C: // PSK_WITH_AES_128_CBC_SHA + return Ciphersuite("", "PSK", "SHA-1", "AES-128", 16); + + case 0x00AE: // PSK_WITH_AES_128_CBC_SHA256 + return Ciphersuite("", "PSK", "SHA-256", "AES-128", 16); + + case 0x008D: // PSK_WITH_AES_256_CBC_SHA + return Ciphersuite("", "PSK", "SHA-1", "AES-256", 32); + + case 0x00AF: // PSK_WITH_AES_256_CBC_SHA384 + return Ciphersuite("", "PSK", "SHA-384", "AES-256", 32); + + case 0xC094: // PSK_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite("", "PSK", "SHA-256", "Camellia-128", 16); + + case 0xC095: // PSK_WITH_CAMELLIA_256_CBC_SHA384 + return Ciphersuite("", "PSK", "SHA-384", "Camellia-256", 32); + + case 0x008A: // PSK_WITH_RC4_128_SHA + return Ciphersuite("", "PSK", "SHA-1", "ARC4", 16); + + case 0x000A: // RSA_WITH_3DES_EDE_CBC_SHA + return Ciphersuite("RSA", "RSA", "SHA-1", "3DES", 24); + + case 0x002F: // RSA_WITH_AES_128_CBC_SHA + return Ciphersuite("RSA", "RSA", "SHA-1", "AES-128", 16); + + case 0x003C: // RSA_WITH_AES_128_CBC_SHA256 + return Ciphersuite("RSA", "RSA", "SHA-256", "AES-128", 16); + + case 0x0035: // RSA_WITH_AES_256_CBC_SHA + return Ciphersuite("RSA", "RSA", "SHA-1", "AES-256", 32); + + case 0x003D: // RSA_WITH_AES_256_CBC_SHA256 + return Ciphersuite("RSA", "RSA", "SHA-256", "AES-256", 32); + + case 0x0041: // RSA_WITH_CAMELLIA_128_CBC_SHA + return Ciphersuite("RSA", "RSA", "SHA-1", "Camellia-128", 16); + + case 0x00BA: // RSA_WITH_CAMELLIA_128_CBC_SHA256 + return Ciphersuite("RSA", "RSA", "SHA-256", "Camellia-128", 16); + + case 0x0084: // RSA_WITH_CAMELLIA_256_CBC_SHA + return Ciphersuite("RSA", "RSA", "SHA-1", "Camellia-256", 32); + + case 0x00C0: // RSA_WITH_CAMELLIA_256_CBC_SHA256 + return Ciphersuite("RSA", "RSA", "SHA-256", "Camellia-256", 32); + + case 0x0004: // RSA_WITH_RC4_128_MD5 + return Ciphersuite("RSA", "RSA", "MD5", "ARC4", 16); + + case 0x0005: // RSA_WITH_RC4_128_SHA + return Ciphersuite("RSA", "RSA", "SHA-1", "ARC4", 16); + + case 0x0096: // RSA_WITH_SEED_CBC_SHA + return Ciphersuite("RSA", "RSA", "SHA-1", "SEED", 16); + + case 0xC01C: // SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA + return Ciphersuite("DSA", "SRP_SHA", "SHA-1", "3DES", 24); + + case 0xC01F: // SRP_SHA_DSS_WITH_AES_128_CBC_SHA + return Ciphersuite("DSA", "SRP_SHA", "SHA-1", "AES-128", 16); + + case 0xC022: // SRP_SHA_DSS_WITH_AES_256_CBC_SHA + return Ciphersuite("DSA", "SRP_SHA", "SHA-1", "AES-256", 32); + + case 0xC01B: // SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA + return Ciphersuite("RSA", "SRP_SHA", "SHA-1", "3DES", 24); + + case 0xC01E: // SRP_SHA_RSA_WITH_AES_128_CBC_SHA + return Ciphersuite("RSA", "SRP_SHA", "SHA-1", "AES-128", 16); + + case 0xC021: // SRP_SHA_RSA_WITH_AES_256_CBC_SHA + return Ciphersuite("RSA", "SRP_SHA", "SHA-1", "AES-256", 32); + + case 0xC01A: // SRP_SHA_WITH_3DES_EDE_CBC_SHA + return Ciphersuite("", "SRP_SHA", "SHA-1", "3DES", 24); + + case 0xC01D: // SRP_SHA_WITH_AES_128_CBC_SHA + return Ciphersuite("", "SRP_SHA", "SHA-1", "AES-128", 16); + + case 0xC020: // SRP_SHA_WITH_AES_256_CBC_SHA + return Ciphersuite("", "SRP_SHA", "SHA-1", "AES-256", 32); + } + + return Ciphersuite(); // some unknown ciphersuite + } + +} + +} diff --git a/src/utils/dyn_load/dyn_load.h b/src/utils/dyn_load/dyn_load.h index b37a52e84..4d5cfb296 100644 --- a/src/utils/dyn_load/dyn_load.h +++ b/src/utils/dyn_load/dyn_load.h @@ -59,6 +59,9 @@ class Dynamically_Loaded_Library } private: + Dynamically_Loaded_Library(const Dynamically_Loaded_Library&); + Dynamically_Loaded_Library& operator=(const Dynamically_Loaded_Library&); + std::string lib_name; void* lib; }; |