aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlloyd <lloyd@randombit.net>2012-04-25 13:48:08 +0000
committerlloyd <lloyd@randombit.net>2012-04-25 13:48:08 +0000
commitb72a44475d06263e1492f8913310b5f29515cba6 (patch)
tree680752dbd43999cea16851b9c196046d9e5fbd7f
parentedca5f211722ea6b9d99b8b5fce4603a1b9b422d (diff)
parentf14a9fdee7902ba1a4c962cfbabe29d5146e7c55 (diff)
propagate from branch 'net.randombit.botan.tls-state-machine' (head a4741cd07f50a9e1b29b0dd97c6fb8697c038ade)
to branch 'net.randombit.botan.cxx11' (head 116e5ff139c07000be431e07d3472cc8f3919b91)
-rw-r--r--checks/bench.cpp12
-rw-r--r--checks/pk.cpp6
-rw-r--r--checks/pk_bench.cpp6
-rw-r--r--checks/validate.cpp4
-rw-r--r--checks/validate.dat22
-rwxr-xr-xconfigure.py54
-rw-r--r--doc/examples/asio_tls_server.cpp44
-rw-r--r--doc/examples/credentials.h108
-rw-r--r--doc/examples/tls_client.cpp15
-rw-r--r--doc/examples/tls_server.cpp66
-rw-r--r--doc/log.txt3
-rw-r--r--doc/tls.txt16
-rw-r--r--src/alloc/alloc_mmap/mmap_mem.cpp6
-rw-r--r--src/alloc/secmem.h17
-rw-r--r--src/block/camellia/camellia.cpp226
-rw-r--r--src/block/camellia/camellia.h44
-rw-r--r--src/cert/cvc/cvc_req.h2
-rw-r--r--src/cert/x509cert/x509cert.cpp20
-rw-r--r--src/constructs/srp6/srp6.cpp55
-rw-r--r--src/constructs/srp6/srp6.h71
-rw-r--r--src/constructs/srp6/srp6_files.cpp2
-rw-r--r--src/constructs/srp6/srp6_files.h4
-rw-r--r--src/credentials/credentials_manager.cpp40
-rw-r--r--src/credentials/credentials_manager.h36
-rw-r--r--src/credentials/info.txt5
-rw-r--r--src/engine/asm_engine/asm_engine.h2
-rw-r--r--src/engine/core_engine/core_engine.h4
-rw-r--r--src/engine/core_engine/lookup_block.cpp8
-rw-r--r--src/engine/openssl/ossl_arc4.cpp2
-rw-r--r--src/engine/simd_engine/simd_engine.h2
-rw-r--r--src/libstate/init.cpp2
-rw-r--r--src/libstate/policy.cpp98
-rw-r--r--src/math/numbertheory/pow_mod.h2
-rw-r--r--src/pubkey/workfactor.cpp55
-rw-r--r--src/pubkey/workfactor.h2
-rw-r--r--src/tls/c_hello.cpp64
-rw-r--r--src/tls/c_kex.cpp40
-rw-r--r--src/tls/cert_req.cpp10
-rw-r--r--src/tls/info.txt14
-rw-r--r--src/tls/rec_read.cpp5
-rw-r--r--src/tls/s_hello.cpp93
-rw-r--r--src/tls/s_kex.cpp75
-rw-r--r--src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp41
-rw-r--r--src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h10
-rw-r--r--src/tls/tls_alert.cpp14
-rw-r--r--src/tls/tls_alert.h65
-rw-r--r--src/tls/tls_channel.cpp58
-rw-r--r--src/tls/tls_channel.h28
-rw-r--r--src/tls/tls_ciphersuite.cpp272
-rw-r--r--src/tls/tls_ciphersuite.h16
-rw-r--r--src/tls/tls_client.cpp73
-rw-r--r--src/tls/tls_client.h13
-rw-r--r--src/tls/tls_extensions.cpp18
-rw-r--r--src/tls/tls_extensions.h27
-rw-r--r--src/tls/tls_handshake_hash.cpp8
-rw-r--r--src/tls/tls_handshake_state.cpp22
-rw-r--r--src/tls/tls_handshake_state.h24
-rw-r--r--src/tls/tls_heartbeats.cpp78
-rw-r--r--src/tls/tls_heartbeats.h40
-rw-r--r--src/tls/tls_magic.h87
-rw-r--r--src/tls/tls_messages.h73
-rw-r--r--src/tls/tls_policy.cpp166
-rw-r--r--src/tls/tls_policy.h29
-rw-r--r--src/tls/tls_record.h17
-rw-r--r--src/tls/tls_server.cpp167
-rw-r--r--src/tls/tls_server.h8
-rw-r--r--src/tls/tls_session.cpp23
-rw-r--r--src/tls/tls_session.h17
-rw-r--r--src/tls/tls_session_manager.cpp12
-rw-r--r--src/tls/tls_session_manager.h28
-rw-r--r--src/tls/tls_suite_info.cpp317
-rw-r--r--src/utils/dyn_load/dyn_load.h3
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;
};