aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/algo_base/algo_base.h7
-rw-r--r--src/algo_base/symkey.cpp13
-rw-r--r--src/algo_base/symkey.h29
-rw-r--r--src/algo_factory/algo_cache.h52
-rw-r--r--src/algo_factory/algo_factory.cpp15
-rw-r--r--src/algo_factory/algo_factory.h3
-rw-r--r--src/algo_factory/info.txt1
-rw-r--r--src/alloc/alloc_mmap/mmap_mem.cpp2
-rw-r--r--src/alloc/alloc_mmap/mmap_mem.h4
-rw-r--r--src/alloc/mem_pool/info.txt4
-rw-r--r--src/alloc/mem_pool/mem_pool.cpp27
-rw-r--r--src/alloc/mem_pool/mem_pool.h9
-rw-r--r--src/alloc/secmem.h36
-rw-r--r--src/alloc/system_alloc/defalloc.h5
-rw-r--r--src/asn1/asn1_alt.cpp27
-rw-r--r--src/asn1/asn1_int.cpp4
-rw-r--r--src/asn1/asn1_obj.h3
-rw-r--r--src/asn1/asn1_oid.cpp2
-rw-r--r--src/asn1/asn1_str.cpp2
-rw-r--r--src/asn1/asn1_tm.cpp54
-rw-r--r--src/asn1/ber_dec.cpp29
-rw-r--r--src/asn1/ber_dec.h67
-rw-r--r--src/asn1/der_enc.cpp2
-rw-r--r--src/asn1/x509_dn.cpp70
-rw-r--r--src/benchmark/benchmark.cpp77
-rw-r--r--src/benchmark/benchmark.h5
-rw-r--r--src/block/des/desx.cpp4
-rw-r--r--src/block/lion/lion.cpp6
-rw-r--r--src/block/misty1/misty1.cpp2
-rw-r--r--src/block/rc2/rc2.cpp2
-rw-r--r--src/block/rc5/rc5.cpp4
-rw-r--r--src/block/safer/safer_sk.cpp2
-rw-r--r--src/block/serpent/serpent.cpp3
-rw-r--r--src/block/square/square.cpp7
-rw-r--r--src/build-data/cc/clang.txt2
-rw-r--r--src/build-data/cc/compaq.txt26
-rw-r--r--src/build-data/cc/gcc.txt18
-rw-r--r--src/build-data/cc/icc.txt4
-rw-r--r--src/build-data/cc/kai.txt27
-rw-r--r--src/build-data/cc/mipspro.txt39
-rw-r--r--src/build-data/cc/sgipro64.txt27
-rw-r--r--src/build-data/os/windows.txt5
-rw-r--r--src/cert/cvc/asn1_eac_tm.cpp114
-rw-r--r--src/cert/cvc/cvc_self.cpp34
-rw-r--r--src/cert/cvc/eac_asn_obj.h62
-rw-r--r--src/cert/cvc/info.txt1
-rw-r--r--src/cert/pkcs10/pkcs10.cpp2
-rw-r--r--src/cert/x509ca/x509_ca.cpp11
-rw-r--r--src/cert/x509ca/x509_ca.h6
-rw-r--r--src/cert/x509cert/x509_obj.cpp2
-rw-r--r--src/cert/x509cert/x509cert.cpp119
-rw-r--r--src/cert/x509cert/x509cert.h12
-rw-r--r--src/cert/x509crl/crl_ent.cpp3
-rw-r--r--src/cert/x509crl/x509_crl.cpp2
-rw-r--r--src/cert/x509self/x509opt.cpp8
-rw-r--r--src/cert/x509self/x509self.cpp4
-rw-r--r--src/cert/x509store/x509stor.cpp36
-rw-r--r--src/cert/x509store/x509stor.h20
-rw-r--r--src/cms/cms_dalg.cpp7
-rw-r--r--src/cms/cms_ealg.cpp4
-rw-r--r--src/codec/pem/pem.cpp13
-rw-r--r--src/codec/pem/pem.h58
-rw-r--r--src/constructs/rfc3394/rfc3394.cpp4
-rw-r--r--src/constructs/srp6/srp6.cpp8
-rw-r--r--src/constructs/tss/tss.cpp2
-rw-r--r--src/credentials/credentials_manager.cpp149
-rw-r--r--src/credentials/credentials_manager.h153
-rw-r--r--src/credentials/info.txt6
-rw-r--r--src/engine/dyn_engine/dyn_engine.cpp2
-rw-r--r--src/engine/openssl/ossl_arc4.cpp2
-rw-r--r--src/entropy/hres_timer/hres_timer.cpp6
-rw-r--r--src/entropy/proc_walk/es_ftw.cpp6
-rw-r--r--src/filters/bzip2/bzip2.cpp2
-rw-r--r--src/filters/codec_filt/b64_filt.cpp4
-rw-r--r--src/filters/codec_filt/hex_filt.cpp4
-rw-r--r--src/filters/data_snk.h6
-rw-r--r--src/filters/data_src.h5
-rw-r--r--src/filters/filter.h6
-rw-r--r--src/filters/modes/cfb/cfb.cpp20
-rw-r--r--src/filters/modes/cts/cts.cpp10
-rw-r--r--src/filters/modes/eax/eax.cpp2
-rw-r--r--src/filters/modes/eax/eax_dec.cpp6
-rw-r--r--src/filters/modes/xts/xts.cpp32
-rw-r--r--src/filters/pipe.cpp7
-rw-r--r--src/filters/pipe.h14
-rw-r--r--src/filters/secqueue.cpp5
-rw-r--r--src/filters/secqueue.h2
-rw-r--r--src/filters/zlib/zlib.cpp33
-rw-r--r--src/filters/zlib/zlib.h16
-rw-r--r--src/hash/gost_3411/gost_3411.cpp6
-rw-r--r--src/hash/keccak/keccak.cpp4
-rw-r--r--src/hash/md2/md2.cpp6
-rw-r--r--src/hash/mdx_hash/mdx_hash.cpp4
-rw-r--r--src/hash/par_hash/par_hash.cpp51
-rw-r--r--src/hash/skein/skein_512.cpp11
-rw-r--r--src/hash/tiger/tiger.cpp7
-rw-r--r--src/kdf/prf_tls/info.txt1
-rw-r--r--src/kdf/prf_tls/prf_tls.cpp11
-rw-r--r--src/libstate/get_enc.cpp20
-rw-r--r--src/libstate/global_rng.cpp21
-rw-r--r--src/libstate/global_state.cpp2
-rw-r--r--src/libstate/info.txt2
-rw-r--r--src/libstate/init.cpp35
-rw-r--r--src/libstate/libstate.cpp85
-rw-r--r--src/libstate/libstate.h41
-rw-r--r--src/mac/cmac/cmac.cpp4
-rw-r--r--src/mac/hmac/hmac.h2
-rw-r--r--src/mac/ssl3mac/ssl3_mac.cpp5
-rw-r--r--src/math/bigint/big_code.cpp4
-rw-r--r--src/math/bigint/bigint.cpp26
-rw-r--r--src/math/bigint/bigint.h29
-rw-r--r--src/math/ec_gfp/point_gfp.h31
-rw-r--r--src/math/numbertheory/dsa_gen.cpp8
-rw-r--r--src/math/numbertheory/make_prm.cpp4
-rw-r--r--src/math/numbertheory/numthry.cpp2
-rw-r--r--src/mutex/info.txt5
-rw-r--r--src/mutex/mutex.h71
-rw-r--r--src/mutex/noop_mutex/info.txt9
-rw-r--r--src/mutex/noop_mutex/mux_noop.cpp50
-rw-r--r--src/mutex/noop_mutex/mux_noop.h26
-rw-r--r--src/mutex/pthreads/info.txt29
-rw-r--r--src/mutex/pthreads/mux_pthr.cpp58
-rw-r--r--src/mutex/pthreads/mux_pthr.h26
-rw-r--r--src/mutex/win32_crit_section/info.txt15
-rw-r--r--src/mutex/win32_crit_section/mux_win32.cpp34
-rw-r--r--src/mutex/win32_crit_section/mux_win32.h26
-rw-r--r--src/passhash/bcrypt/bcrypt.cpp9
-rw-r--r--src/passhash/passhash9/passhash9.cpp3
-rw-r--r--src/pbkdf/pbkdf2/pbkdf2.cpp2
-rw-r--r--src/pbkdf/pgps2k/pgp_s2k.cpp2
-rw-r--r--src/pk_pad/eme1/eme1.cpp6
-rw-r--r--src/pk_pad/eme_pkcs/eme_pkcs.cpp2
-rw-r--r--src/pk_pad/emsa2/emsa2.cpp2
-rw-r--r--src/pk_pad/emsa3/emsa3.cpp4
-rw-r--r--src/pk_pad/emsa4/emsa4.cpp6
-rw-r--r--src/pubkey/dl_group/dl_group.cpp8
-rw-r--r--src/pubkey/dlies/dlies.cpp4
-rw-r--r--src/pubkey/dsa/dsa.cpp20
-rw-r--r--src/pubkey/ec_group/ec_group.h4
-rw-r--r--src/pubkey/nr/nr.cpp6
-rw-r--r--src/pubkey/pkcs8.cpp56
-rw-r--r--src/pubkey/pkcs8.h24
-rw-r--r--src/pubkey/pubkey.cpp4
-rw-r--r--src/pubkey/rsa/rsa.cpp6
-rw-r--r--src/pubkey/rw/rw.cpp2
-rw-r--r--src/rng/hmac_rng/hmac_rng.cpp5
-rw-r--r--src/rng/randpool/randpool.cpp6
-rw-r--r--src/selftest/selftest.cpp3
-rw-r--r--src/ssl/c_kex.cpp165
-rw-r--r--src/ssl/cert_req.cpp151
-rw-r--r--src/ssl/cert_ver.cpp98
-rw-r--r--src/ssl/finished.cpp100
-rw-r--r--src/ssl/hello.cpp331
-rw-r--r--src/ssl/info.txt71
-rw-r--r--src/ssl/rec_read.cpp260
-rw-r--r--src/ssl/rec_wri.cpp270
-rw-r--r--src/ssl/s_kex.cpp180
-rw-r--r--src/ssl/tls_alerts.h54
-rw-r--r--src/ssl/tls_client.cpp586
-rw-r--r--src/ssl/tls_client.h73
-rw-r--r--src/ssl/tls_connection.h36
-rw-r--r--src/ssl/tls_handshake_hash.cpp70
-rw-r--r--src/ssl/tls_magic.h192
-rw-r--r--src/ssl/tls_messages.h297
-rw-r--r--src/ssl/tls_policy.cpp118
-rw-r--r--src/ssl/tls_policy.h63
-rw-r--r--src/ssl/tls_record.h117
-rw-r--r--src/ssl/tls_server.cpp494
-rw-r--r--src/ssl/tls_server.h77
-rw-r--r--src/ssl/tls_session_key.cpp170
-rw-r--r--src/ssl/tls_session_key.h52
-rw-r--r--src/ssl/tls_state.cpp59
-rw-r--r--src/ssl/tls_state.h53
-rw-r--r--src/ssl/tls_suites.cpp281
-rw-r--r--src/ssl/tls_suites.h42
-rw-r--r--src/stream/arc4/arc4.cpp2
-rw-r--r--src/stream/ctr/ctr.cpp4
-rw-r--r--src/stream/ofb/ofb.cpp2
-rw-r--r--src/tls/c_hello.cpp394
-rw-r--r--src/tls/c_kex.cpp393
-rw-r--r--src/tls/cert_req.cpp241
-rw-r--r--src/tls/cert_ver.cpp117
-rw-r--r--src/tls/finished.cpp104
-rw-r--r--src/tls/hello_verify.cpp61
-rw-r--r--src/tls/info.txt95
-rw-r--r--src/tls/next_protocol.cpp55
-rw-r--r--src/tls/rec_read.cpp353
-rw-r--r--src/tls/rec_wri.cpp317
-rw-r--r--src/tls/s_hello.cpp186
-rw-r--r--src/tls/s_kex.cpp292
-rw-r--r--src/tls/session_ticket.cpp57
-rw-r--r--src/tls/sessions_sqlite/info.txt11
-rw-r--r--src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp350
-rw-r--r--src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h71
-rw-r--r--src/tls/tls_alert.cpp122
-rw-r--r--src/tls/tls_alert.h100
-rw-r--r--src/tls/tls_channel.cpp326
-rw-r--r--src/tls/tls_channel.h155
-rw-r--r--src/tls/tls_ciphersuite.cpp104
-rw-r--r--src/tls/tls_ciphersuite.h73
-rw-r--r--src/tls/tls_client.cpp486
-rw-r--r--src/tls/tls_client.h74
-rw-r--r--src/tls/tls_exceptn.h (renamed from src/ssl/tls_exceptn.h)14
-rw-r--r--src/tls/tls_extensions.cpp524
-rw-r--r--src/tls/tls_extensions.h381
-rw-r--r--src/tls/tls_handshake_hash.cpp103
-rw-r--r--src/tls/tls_handshake_hash.h (renamed from src/ssl/tls_handshake_hash.h)23
-rw-r--r--src/tls/tls_handshake_reader.cpp66
-rw-r--r--src/tls/tls_handshake_reader.h58
-rw-r--r--src/tls/tls_handshake_state.cpp330
-rw-r--r--src/tls/tls_handshake_state.h112
-rw-r--r--src/tls/tls_heartbeats.cpp78
-rw-r--r--src/tls/tls_heartbeats.h40
-rw-r--r--src/tls/tls_magic.h69
-rw-r--r--src/tls/tls_messages.h500
-rw-r--r--src/tls/tls_policy.cpp265
-rw-r--r--src/tls/tls_policy.h127
-rw-r--r--src/tls/tls_reader.h (renamed from src/ssl/tls_reader.h)51
-rw-r--r--src/tls/tls_record.h136
-rw-r--r--src/tls/tls_server.cpp620
-rw-r--r--src/tls/tls_server.h74
-rw-r--r--src/tls/tls_session.cpp251
-rw-r--r--src/tls/tls_session.h217
-rw-r--r--src/tls/tls_session_key.cpp89
-rw-r--r--src/tls/tls_session_key.h52
-rw-r--r--src/tls/tls_session_manager.cpp106
-rw-r--r--src/tls/tls_session_manager.h127
-rw-r--r--src/tls/tls_suite_info.cpp317
-rw-r--r--src/tls/tls_version.cpp33
-rw-r--r--src/tls/tls_version.h87
-rw-r--r--src/utils/assert.cpp2
-rw-r--r--src/utils/assert.h10
-rw-r--r--src/utils/calendar.cpp52
-rw-r--r--src/utils/calendar.h (renamed from src/utils/time.h)22
-rw-r--r--src/utils/charset.cpp2
-rw-r--r--src/utils/datastor/datastor.cpp41
-rw-r--r--src/utils/datastor/datastor.h17
-rw-r--r--src/utils/exceptn.h4
-rw-r--r--src/utils/info.txt6
-rw-r--r--src/utils/parsing.cpp93
-rw-r--r--src/utils/parsing.h30
-rw-r--r--src/utils/rounding.h18
-rw-r--r--src/utils/stl_util.h63
-rw-r--r--src/utils/time.cpp125
-rw-r--r--src/utils/types.h10
-rw-r--r--src/utils/ui.cpp36
-rw-r--r--src/utils/ui.h37
-rw-r--r--src/wrap/python/core.cpp2
-rw-r--r--src/wrap/python/filter.cpp14
-rw-r--r--src/wrap/python/python_botan.h3
250 files changed, 10928 insertions, 6226 deletions
diff --git a/src/algo_base/algo_base.h b/src/algo_base/algo_base.h
index 813216a36..f757a9a83 100644
--- a/src/algo_base/algo_base.h
+++ b/src/algo_base/algo_base.h
@@ -19,7 +19,6 @@ namespace Botan {
class BOTAN_DLL Algorithm
{
public:
-
/**
* Zeroize internal state
*/
@@ -31,10 +30,10 @@ class BOTAN_DLL Algorithm
virtual std::string name() const = 0;
Algorithm() {}
+ Algorithm(const Algorithm&) = delete;
+ Algorithm& operator=(const Algorithm&) = delete;
+
virtual ~Algorithm() {}
- private:
- Algorithm(const Algorithm&) {}
- Algorithm& operator=(const Algorithm&) { return (*this); }
};
}
diff --git a/src/algo_base/symkey.cpp b/src/algo_base/symkey.cpp
index 56648d9c5..5509b83bc 100644
--- a/src/algo_base/symkey.cpp
+++ b/src/algo_base/symkey.cpp
@@ -26,7 +26,7 @@ OctetString::OctetString(RandomNumberGenerator& rng,
/*
* Create an OctetString from a hex string
*/
-void OctetString::change(const std::string& hex_string)
+OctetString::OctetString(const std::string& hex_string)
{
bits.resize(1 + hex_string.length() / 2);
bits.resize(hex_decode(&bits[0], hex_string));
@@ -35,10 +35,13 @@ void OctetString::change(const std::string& hex_string)
/*
* Create an OctetString from a byte string
*/
-void OctetString::change(const byte in[], size_t n)
+OctetString::OctetString(const byte in[], size_t n)
+ {
+ bits.assign(in, in + n);
+ }
+
+OctetString::OctetString(const MemoryRegion<byte>& b) : bits(b)
{
- bits.resize(n);
- bits.copy(in, n);
}
/*
@@ -125,7 +128,7 @@ OctetString operator+(const OctetString& k1, const OctetString& k2)
OctetString operator^(const OctetString& k1, const OctetString& k2)
{
SecureVector<byte> ret(std::max(k1.length(), k2.length()));
- ret.copy(k1.begin(), k1.length());
+ copy_mem(&ret[0], k1.begin(), k1.length());
xor_buf(ret, k2.begin(), k2.length());
return OctetString(ret);
}
diff --git a/src/algo_base/symkey.h b/src/algo_base/symkey.h
index 6735b2b87..2ccc0b883 100644
--- a/src/algo_base/symkey.h
+++ b/src/algo_base/symkey.h
@@ -57,23 +57,10 @@ class BOTAN_DLL OctetString
void set_odd_parity();
/**
- * Change the contents of this octet string
- * @param hex_string a hex encoded bytestring
- */
- void change(const std::string& hex_string);
-
- /**
- * Change the contents of this octet string
- * @param in the input
- * @param length of in in bytes
- */
- void change(const byte in[], size_t length);
-
- /**
- * Change the contents of this octet string
- * @param in the input
+ * Create a new OctetString
+ * @param str is a hex encoded string
*/
- void change(const MemoryRegion<byte>& in) { bits = in; }
+ OctetString(const std::string& str = "");
/**
* Create a new random OctetString
@@ -84,22 +71,16 @@ class BOTAN_DLL OctetString
/**
* Create a new OctetString
- * @param str is a hex encoded string
- */
- OctetString(const std::string& str = "") { change(str); }
-
- /**
- * Create a new OctetString
* @param in is an array
* @param len is the length of in in bytes
*/
- OctetString(const byte in[], size_t len) { change(in, len); }
+ OctetString(const byte in[], size_t len);
/**
* Create a new OctetString
* @param in a bytestring
*/
- OctetString(const MemoryRegion<byte>& in) { change(in); }
+ OctetString(const MemoryRegion<byte>& in);
private:
SecureVector<byte> bits;
};
diff --git a/src/algo_factory/algo_cache.h b/src/algo_factory/algo_cache.h
index 25f2db023..3a792c994 100644
--- a/src/algo_factory/algo_cache.h
+++ b/src/algo_factory/algo_cache.h
@@ -8,8 +8,9 @@
#ifndef BOTAN_ALGORITHM_CACHE_TEMPLATE_H__
#define BOTAN_ALGORITHM_CACHE_TEMPLATE_H__
-#include <botan/internal/mutex.h>
+#include <botan/types.h>
#include <botan/internal/stl_util.h>
+#include <mutex>
#include <string>
#include <vector>
#include <map>
@@ -67,21 +68,12 @@ class Algorithm_Cache
*/
void clear_cache();
- /**
- * Constructor
- * @param m a mutex to serialize internal access
- */
- Algorithm_Cache(Mutex* m) : mutex(m) {}
- ~Algorithm_Cache() { clear_cache(); delete mutex; }
+ ~Algorithm_Cache() { clear_cache(); }
private:
- typedef typename std::map<std::string, std::map<std::string, T*> >::iterator
- algorithms_iterator;
-
- typedef typename std::map<std::string, T*>::iterator provider_iterator;
+ typename std::map<std::string, std::map<std::string, T*> >::const_iterator
+ find_algorithm(const std::string& algo_spec);
- algorithms_iterator find_algorithm(const std::string& algo_spec);
-
- Mutex* mutex;
+ std::mutex mutex;
std::map<std::string, std::string> aliases;
std::map<std::string, std::string> pref_providers;
std::map<std::string, std::map<std::string, T*> > algorithms;
@@ -92,16 +84,15 @@ class Algorithm_Cache
* Assumes object lock is held
*/
template<typename T>
-typename Algorithm_Cache<T>::algorithms_iterator
+typename std::map<std::string, std::map<std::string, T*> >::const_iterator
Algorithm_Cache<T>::find_algorithm(const std::string& algo_spec)
{
- algorithms_iterator algo = algorithms.find(algo_spec);
+ auto algo = algorithms.find(algo_spec);
// Not found? Check if a known alias
if(algo == algorithms.end())
{
- std::map<std::string, std::string>::const_iterator alias =
- aliases.find(algo_spec);
+ auto alias = aliases.find(algo_spec);
if(alias != aliases.end())
algo = algorithms.find(alias->second);
@@ -117,16 +108,16 @@ template<typename T>
const T* Algorithm_Cache<T>::get(const std::string& algo_spec,
const std::string& requested_provider)
{
- Mutex_Holder lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
- algorithms_iterator algo = find_algorithm(algo_spec);
+ auto algo = find_algorithm(algo_spec);
if(algo == algorithms.end()) // algo not found at all (no providers)
return 0;
// If a provider is requested specifically, return it or fail entirely
if(requested_provider != "")
{
- provider_iterator prov = algo->second.find(requested_provider);
+ auto prov = algo->second.find(requested_provider);
if(prov != algo->second.end())
return prov->second;
return 0;
@@ -138,7 +129,7 @@ const T* Algorithm_Cache<T>::get(const std::string& algo_spec,
const std::string pref_provider = search_map(pref_providers, algo_spec);
- for(provider_iterator i = algo->second.begin(); i != algo->second.end(); ++i)
+ for(auto i = algo->second.begin(); i != algo->second.end(); ++i)
{
const std::string prov_name = i->first;
const size_t prov_weight = static_provider_weight(prov_name);
@@ -147,7 +138,7 @@ const T* Algorithm_Cache<T>::get(const std::string& algo_spec,
if(prov_name == pref_provider)
return i->second;
- if(prototype == 0 || prov_weight > prototype_prov_weight)
+ if(prototype == nullptr || prov_weight > prototype_prov_weight)
{
prototype = i->second;
prototype_provider = i->first;
@@ -169,7 +160,7 @@ void Algorithm_Cache<T>::add(T* algo,
if(!algo)
return;
- Mutex_Holder lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
if(algo->name() != requested_name &&
aliases.find(requested_name) == aliases.end())
@@ -189,15 +180,14 @@ void Algorithm_Cache<T>::add(T* algo,
template<typename T> std::vector<std::string>
Algorithm_Cache<T>::providers_of(const std::string& algo_name)
{
- Mutex_Holder lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
std::vector<std::string> providers;
- algorithms_iterator algo = find_algorithm(algo_name);
-
+ auto algo = find_algorithm(algo_name);
if(algo != algorithms.end())
{
- provider_iterator provider = algo->second.begin();
+ auto provider = algo->second.begin();
while(provider != algo->second.end())
{
@@ -216,7 +206,7 @@ template<typename T>
void Algorithm_Cache<T>::set_preferred_provider(const std::string& algo_spec,
const std::string& provider)
{
- Mutex_Holder lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
pref_providers[algo_spec] = provider;
}
@@ -227,11 +217,11 @@ void Algorithm_Cache<T>::set_preferred_provider(const std::string& algo_spec,
template<typename T>
void Algorithm_Cache<T>::clear_cache()
{
- algorithms_iterator algo = algorithms.begin();
+ auto algo = algorithms.begin();
while(algo != algorithms.end())
{
- provider_iterator provider = algo->second.begin();
+ auto provider = algo->second.begin();
while(provider != algo->second.end())
{
diff --git a/src/algo_factory/algo_factory.cpp b/src/algo_factory/algo_factory.cpp
index 3d640ab8a..9e4f78569 100644
--- a/src/algo_factory/algo_factory.cpp
+++ b/src/algo_factory/algo_factory.cpp
@@ -94,13 +94,13 @@ const T* factory_prototype(const std::string& algo_spec,
/*
* Setup caches
*/
-Algorithm_Factory::Algorithm_Factory(Mutex_Factory& mf)
+Algorithm_Factory::Algorithm_Factory()
{
- block_cipher_cache = new Algorithm_Cache<BlockCipher>(mf.make());
- stream_cipher_cache = new Algorithm_Cache<StreamCipher>(mf.make());
- hash_cache = new Algorithm_Cache<HashFunction>(mf.make());
- mac_cache = new Algorithm_Cache<MessageAuthenticationCode>(mf.make());
- pbkdf_cache = new Algorithm_Cache<PBKDF>(mf.make());
+ block_cipher_cache = new Algorithm_Cache<BlockCipher>();
+ stream_cipher_cache = new Algorithm_Cache<StreamCipher>();
+ hash_cache = new Algorithm_Cache<HashFunction>();
+ mac_cache = new Algorithm_Cache<MessageAuthenticationCode>();
+ pbkdf_cache = new Algorithm_Cache<PBKDF>();
}
/*
@@ -114,7 +114,8 @@ Algorithm_Factory::~Algorithm_Factory()
delete mac_cache;
delete pbkdf_cache;
- std::for_each(engines.begin(), engines.end(), del_fun<Engine>());
+ for(auto i = engines.begin(); i != engines.end(); ++i)
+ delete *i;
}
void Algorithm_Factory::clear_caches()
diff --git a/src/algo_factory/algo_factory.h b/src/algo_factory/algo_factory.h
index b9f15757d..1bec2adf7 100644
--- a/src/algo_factory/algo_factory.h
+++ b/src/algo_factory/algo_factory.h
@@ -26,7 +26,6 @@ class PBKDF;
template<typename T> class Algorithm_Cache;
class Engine;
-class Mutex_Factory;
/**
* Algorithm Factory
@@ -38,7 +37,7 @@ class BOTAN_DLL Algorithm_Factory
* Constructor
* @param mf a mutex factory
*/
- Algorithm_Factory(Mutex_Factory& mf);
+ Algorithm_Factory();
/**
* Destructor
diff --git a/src/algo_factory/info.txt b/src/algo_factory/info.txt
index eae4b3934..236fdda0e 100644
--- a/src/algo_factory/info.txt
+++ b/src/algo_factory/info.txt
@@ -20,6 +20,5 @@ block
engine
hash
mac
-mutex
stream
</requires>
diff --git a/src/alloc/alloc_mmap/mmap_mem.cpp b/src/alloc/alloc_mmap/mmap_mem.cpp
index 17c189e9b..b90b6d5f7 100644
--- a/src/alloc/alloc_mmap/mmap_mem.cpp
+++ b/src/alloc/alloc_mmap/mmap_mem.cpp
@@ -123,7 +123,7 @@ void* MemoryMapping_Allocator::alloc_block(size_t n)
*/
void MemoryMapping_Allocator::dealloc_block(void* ptr, size_t n)
{
- if(ptr == 0)
+ if(ptr == nullptr)
return;
const byte PATTERNS[] = { 0x00, 0xF5, 0x5A, 0xAF, 0x00 };
diff --git a/src/alloc/alloc_mmap/mmap_mem.h b/src/alloc/alloc_mmap/mmap_mem.h
index fa4e5e715..c9983ed23 100644
--- a/src/alloc/alloc_mmap/mmap_mem.h
+++ b/src/alloc/alloc_mmap/mmap_mem.h
@@ -21,10 +21,6 @@ namespace Botan {
class MemoryMapping_Allocator : public Pooling_Allocator
{
public:
- /**
- * @param mutex used for internal locking
- */
- MemoryMapping_Allocator(Mutex* mutex) : Pooling_Allocator(mutex) {}
std::string type() const { return "mmap"; }
private:
void* alloc_block(size_t);
diff --git a/src/alloc/mem_pool/info.txt b/src/alloc/mem_pool/info.txt
index 5097c325f..f87ea4c4c 100644
--- a/src/alloc/mem_pool/info.txt
+++ b/src/alloc/mem_pool/info.txt
@@ -6,7 +6,3 @@ mem_pool.cpp
<header:internal>
mem_pool.h
</header:internal>
-
-<requires>
-mutex
-</requires>
diff --git a/src/alloc/mem_pool/mem_pool.cpp b/src/alloc/mem_pool/mem_pool.cpp
index f32eb9604..770622149 100644
--- a/src/alloc/mem_pool/mem_pool.cpp
+++ b/src/alloc/mem_pool/mem_pool.cpp
@@ -46,7 +46,7 @@ byte* Pooling_Allocator::Memory_Block::alloc(size_t n)
if(n == BITMAP_SIZE)
{
if(bitmap)
- return 0;
+ return nullptr;
else
{
bitmap = ~bitmap;
@@ -69,7 +69,7 @@ byte* Pooling_Allocator::Memory_Block::alloc(size_t n)
}
if(bitmap & mask)
- return 0;
+ return nullptr;
bitmap |= mask;
return buffer + offset * BLOCK_SIZE;
@@ -96,7 +96,7 @@ void Pooling_Allocator::Memory_Block::free(void* ptr, size_t blocks)
/*
* Pooling_Allocator Constructor
*/
-Pooling_Allocator::Pooling_Allocator(Mutex* m) : mutex(m)
+Pooling_Allocator::Pooling_Allocator()
{
last_used = blocks.begin();
}
@@ -106,7 +106,6 @@ Pooling_Allocator::Pooling_Allocator(Mutex* m) : mutex(m)
*/
Pooling_Allocator::~Pooling_Allocator()
{
- delete mutex;
if(blocks.size())
throw Invalid_State("Pooling_Allocator: Never released memory");
}
@@ -116,7 +115,7 @@ Pooling_Allocator::~Pooling_Allocator()
*/
void Pooling_Allocator::destroy()
{
- Mutex_Holder lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
blocks.clear();
@@ -133,7 +132,7 @@ void* Pooling_Allocator::allocate(size_t n)
const size_t BITMAP_SIZE = Memory_Block::bitmap_size();
const size_t BLOCK_SIZE = Memory_Block::block_size();
- Mutex_Holder lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
if(n <= BITMAP_SIZE * BLOCK_SIZE)
{
@@ -167,10 +166,10 @@ void Pooling_Allocator::deallocate(void* ptr, size_t n)
const size_t BITMAP_SIZE = Memory_Block::bitmap_size();
const size_t BLOCK_SIZE = Memory_Block::block_size();
- if(ptr == 0 && n == 0)
+ if(ptr == nullptr && n == 0)
return;
- Mutex_Holder lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
if(n > BITMAP_SIZE * BLOCK_SIZE)
dealloc_block(ptr, n);
@@ -178,8 +177,8 @@ void Pooling_Allocator::deallocate(void* ptr, size_t n)
{
const size_t block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE;
- std::vector<Memory_Block>::iterator i =
- std::lower_bound(blocks.begin(), blocks.end(), Memory_Block(ptr));
+ auto i = std::lower_bound(blocks.begin(), blocks.end(),
+ Memory_Block(ptr));
if(i == blocks.end() || !i->contains(ptr, block_no))
throw Invalid_State("Pointer released to the wrong allocator");
@@ -194,9 +193,9 @@ void Pooling_Allocator::deallocate(void* ptr, size_t n)
byte* Pooling_Allocator::allocate_blocks(size_t n)
{
if(blocks.empty())
- return 0;
+ return nullptr;
- std::vector<Memory_Block>::iterator i = last_used;
+ auto i = last_used;
do
{
@@ -213,7 +212,7 @@ byte* Pooling_Allocator::allocate_blocks(size_t n)
}
while(i != last_used);
- return 0;
+ return nullptr;
}
/*
@@ -233,7 +232,7 @@ void Pooling_Allocator::get_more_core(size_t in_bytes)
const size_t to_allocate = in_blocks * TOTAL_BLOCK_SIZE;
void* ptr = alloc_block(to_allocate);
- if(ptr == 0)
+ if(ptr == nullptr)
throw Memory_Exhaustion();
allocated.push_back(std::make_pair(ptr, to_allocate));
diff --git a/src/alloc/mem_pool/mem_pool.h b/src/alloc/mem_pool/mem_pool.h
index 28d4dd903..f2225e573 100644
--- a/src/alloc/mem_pool/mem_pool.h
+++ b/src/alloc/mem_pool/mem_pool.h
@@ -10,7 +10,7 @@
#include <botan/allocate.h>
#include <botan/exceptn.h>
-#include <botan/internal/mutex.h>
+#include <mutex>
#include <utility>
#include <vector>
@@ -27,10 +27,7 @@ class Pooling_Allocator : public Allocator
void destroy();
- /**
- * @param mutex used for internal locking
- */
- Pooling_Allocator(Mutex* mutex);
+ Pooling_Allocator();
~Pooling_Allocator();
private:
void get_more_core(size_t);
@@ -69,7 +66,7 @@ class Pooling_Allocator : public Allocator
std::vector<Memory_Block> blocks;
std::vector<Memory_Block>::iterator last_used;
std::vector<std::pair<void*, size_t> > allocated;
- Mutex* mutex;
+ std::mutex mutex;
};
}
diff --git a/src/alloc/secmem.h b/src/alloc/secmem.h
index 884f2ebc0..e6b2b71ec 100644
--- a/src/alloc/secmem.h
+++ b/src/alloc/secmem.h
@@ -117,23 +117,16 @@ class MemoryRegion
* @param in the array to copy the contents from
* @param n the length of in
*/
+
void copy(const T in[], size_t n)
{
copy_mem(buf, in, std::min(n, size()));
}
- /**
- * Copy the contents of an array of objects of type T into this buffer.
- * The former contents of *this are discarded.
- * The length of *this must be at least n, otherwise memory errors occur.
- * @param off the offset position inside this buffer to start inserting
- * the copied bytes
- * @param in the array to copy the contents from
- * @param n the length of in
- */
- void copy(size_t off, const T in[], size_t n)
+ void assign(const T* start, const T* end)
{
- copy_mem(buf + off, in, std::min(n, size() - off));
+ resize(end - start);
+ copy_mem(buf, start, (end - start));
}
/**
@@ -370,6 +363,27 @@ class SecureVector : public MemoryRegion<T>
};
template<typename T>
+size_t buffer_insert(MemoryRegion<T>& buf,
+ size_t buf_offset,
+ const T input[],
+ size_t input_length)
+ {
+ const size_t to_copy = std::min(input_length, buf.size() - buf_offset);
+ copy_mem(&buf[buf_offset], input, to_copy);
+ return to_copy;
+ }
+
+template<typename T>
+size_t buffer_insert(MemoryRegion<T>& buf,
+ size_t buf_offset,
+ const MemoryRegion<T>& input)
+ {
+ const size_t to_copy = std::min(input.size(), buf.size() - buf_offset);
+ copy_mem(&buf[buf_offset], &input[0], to_copy);
+ return to_copy;
+ }
+
+template<typename T>
MemoryRegion<T>& operator+=(MemoryRegion<T>& out,
const MemoryRegion<T>& in)
{
diff --git a/src/alloc/system_alloc/defalloc.h b/src/alloc/system_alloc/defalloc.h
index 6fba0e511..c4b90d081 100644
--- a/src/alloc/system_alloc/defalloc.h
+++ b/src/alloc/system_alloc/defalloc.h
@@ -30,11 +30,6 @@ class Malloc_Allocator : public Allocator
class Locking_Allocator : public Pooling_Allocator
{
public:
- /**
- * @param mutex used for internal locking
- */
- Locking_Allocator(Mutex* mutex) : Pooling_Allocator(mutex) {}
-
std::string type() const { return "locking"; }
private:
void* alloc_block(size_t);
diff --git a/src/asn1/asn1_alt.cpp b/src/asn1/asn1_alt.cpp
index 2d8e3a1d2..1a5c699cd 100644
--- a/src/asn1/asn1_alt.cpp
+++ b/src/asn1/asn1_alt.cpp
@@ -58,9 +58,8 @@ void AlternativeName::add_attribute(const std::string& type,
if(type == "" || str == "")
return;
- typedef std::multimap<std::string, std::string>::iterator iter;
- std::pair<iter, iter> range = alt_info.equal_range(type);
- for(iter j = range.first; j != range.second; ++j)
+ auto range = alt_info.equal_range(type);
+ for(auto j = range.first; j != range.second; ++j)
if(j->second == str)
return;
@@ -101,13 +100,11 @@ std::multimap<std::string, std::string> AlternativeName::contents() const
{
std::multimap<std::string, std::string> names;
- typedef std::multimap<std::string, std::string>::const_iterator rdn_iter;
- for(rdn_iter j = alt_info.begin(); j != alt_info.end(); ++j)
- multimap_insert(names, j->first, j->second);
+ for(auto i = alt_info.begin(); i != alt_info.end(); ++i)
+ multimap_insert(names, i->first, i->second);
- typedef std::multimap<OID, ASN1_String>::const_iterator on_iter;
- for(on_iter j = othernames.begin(); j != othernames.end(); ++j)
- multimap_insert(names, OIDS::lookup(j->first), j->second.value());
+ for(auto i = othernames.begin(); i != othernames.end(); ++i)
+ multimap_insert(names, OIDS::lookup(i->first), i->second.value());
return names;
}
@@ -129,19 +126,18 @@ void encode_entries(DER_Encoder& encoder,
const std::multimap<std::string, std::string>& attr,
const std::string& type, ASN1_Tag tagging)
{
- typedef std::multimap<std::string, std::string>::const_iterator iter;
+ auto range = attr.equal_range(type);
- std::pair<iter, iter> range = attr.equal_range(type);
- for(iter j = range.first; j != range.second; ++j)
+ for(auto i = range.first; i != range.second; ++i)
{
if(type == "RFC822" || type == "DNS" || type == "URI")
{
- ASN1_String asn1_string(j->second, IA5_STRING);
+ ASN1_String asn1_string(i->second, IA5_STRING);
encoder.add_object(tagging, CONTEXT_SPECIFIC, asn1_string.iso_8859());
}
else if(type == "IP")
{
- const u32bit ip = string_to_ipv4(j->second);
+ const u32bit ip = string_to_ipv4(i->second);
byte ip_buf[4] = { 0 };
store_be(ip, ip_buf);
encoder.add_object(tagging, CONTEXT_SPECIFIC, ip_buf, 4);
@@ -163,8 +159,7 @@ void AlternativeName::encode_into(DER_Encoder& der) const
encode_entries(der, alt_info, "URI", ASN1_Tag(6));
encode_entries(der, alt_info, "IP", ASN1_Tag(7));
- std::multimap<OID, ASN1_String>::const_iterator i;
- for(i = othernames.begin(); i != othernames.end(); ++i)
+ for(auto i = othernames.begin(); i != othernames.end(); ++i)
{
der.start_explicit(0)
.encode(i->first)
diff --git a/src/asn1/asn1_int.cpp b/src/asn1/asn1_int.cpp
index 75cb1f90c..bb4a3ecf7 100644
--- a/src/asn1/asn1_int.cpp
+++ b/src/asn1/asn1_int.cpp
@@ -20,11 +20,11 @@ BER_Decoding_Error::BER_Decoding_Error(const std::string& str) :
Decoding_Error("BER: " + str) {}
BER_Bad_Tag::BER_Bad_Tag(const std::string& str, ASN1_Tag tag) :
- BER_Decoding_Error(str + ": " + to_string(tag)) {}
+ BER_Decoding_Error(str + ": " + std::to_string(tag)) {}
BER_Bad_Tag::BER_Bad_Tag(const std::string& str,
ASN1_Tag tag1, ASN1_Tag tag2) :
- BER_Decoding_Error(str + ": " + to_string(tag1) + "/" + to_string(tag2)) {}
+ BER_Decoding_Error(str + ": " + std::to_string(tag1) + "/" + std::to_string(tag2)) {}
namespace ASN1 {
diff --git a/src/asn1/asn1_obj.h b/src/asn1/asn1_obj.h
index 692a6fde6..3cd8422e6 100644
--- a/src/asn1/asn1_obj.h
+++ b/src/asn1/asn1_obj.h
@@ -15,6 +15,7 @@
#include <botan/alg_id.h>
#include <vector>
#include <map>
+#include <chrono>
namespace Botan {
@@ -53,7 +54,7 @@ class BOTAN_DLL X509_Time : public ASN1_Object
void set_to(const std::string&);
void set_to(const std::string&, ASN1_Tag);
- X509_Time(u64bit);
+ X509_Time(const std::chrono::system_clock::time_point& time);
X509_Time(const std::string& = "");
X509_Time(const std::string&, ASN1_Tag);
private:
diff --git a/src/asn1/asn1_oid.cpp b/src/asn1/asn1_oid.cpp
index ae3d48ce2..750eb90f7 100644
--- a/src/asn1/asn1_oid.cpp
+++ b/src/asn1/asn1_oid.cpp
@@ -52,7 +52,7 @@ std::string OID::as_string() const
std::string oid_str;
for(size_t i = 0; i != id.size(); ++i)
{
- oid_str += to_string(id[i]);
+ oid_str += std::to_string(id[i]);
if(i != id.size() - 1)
oid_str += '.';
}
diff --git a/src/asn1/asn1_str.cpp b/src/asn1/asn1_str.cpp
index b28f36d90..44db189f9 100644
--- a/src/asn1/asn1_str.cpp
+++ b/src/asn1/asn1_str.cpp
@@ -77,7 +77,7 @@ ASN1_String::ASN1_String(const std::string& str, ASN1_Tag t) : tag(t)
tag != UTF8_STRING &&
tag != BMP_STRING)
throw Invalid_Argument("ASN1_String: Unknown string type " +
- to_string(tag));
+ std::to_string(tag));
}
/*
diff --git a/src/asn1/asn1_tm.cpp b/src/asn1/asn1_tm.cpp
index a059e0528..b8095a41c 100644
--- a/src/asn1/asn1_tm.cpp
+++ b/src/asn1/asn1_tm.cpp
@@ -10,7 +10,7 @@
#include <botan/ber_dec.h>
#include <botan/charset.h>
#include <botan/parsing.h>
-#include <botan/time.h>
+#include <botan/calendar.h>
namespace Botan {
@@ -23,11 +23,11 @@ X509_Time::X509_Time(const std::string& time_str)
}
/*
-* Create an X509_Time
+* Create a X509_Time from a time point
*/
-X509_Time::X509_Time(u64bit timer)
+X509_Time::X509_Time(const std::chrono::system_clock::time_point& time)
{
- calendar_point cal = calendar_value(timer);
+ calendar_point cal = calendar_value(time);
year = cal.year;
month = cal.month;
@@ -98,7 +98,7 @@ void X509_Time::set_to(const std::string& time_str)
void X509_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag)
{
if(spec_tag != GENERALIZED_TIME && spec_tag != UTC_TIME)
- throw Invalid_Argument("X509_Time: Invalid tag " + to_string(spec_tag));
+ throw Invalid_Argument("X509_Time: Invalid tag " + std::to_string(spec_tag));
if(spec_tag == GENERALIZED_TIME && t_spec.size() != 13 && t_spec.size() != 15)
throw Invalid_Argument("Invalid GeneralizedTime: " + t_spec);
@@ -182,24 +182,30 @@ std::string X509_Time::as_string() const
if(time_is_set() == false)
throw Invalid_State("X509_Time::as_string: No time set");
- std::string asn1rep;
- if(tag == GENERALIZED_TIME)
- asn1rep = to_string(year, 4);
- else if(tag == UTC_TIME)
+ u32bit full_year = year;
+
+ if(tag == UTC_TIME)
{
if(year < 1950 || year >= 2050)
throw Encoding_Error("X509_Time: The time " + readable_string() +
" cannot be encoded as a UTCTime");
- u32bit asn1year = (year >= 2000) ? (year - 2000) : (year - 1900);
- asn1rep = to_string(asn1year, 2);
+
+ full_year = (year >= 2000) ? (year - 2000) : (year - 1900);
}
- else
- throw Invalid_Argument("X509_Time: Invalid tag " + to_string(tag));
- asn1rep += to_string(month, 2) + to_string(day, 2);
- asn1rep += to_string(hour, 2) + to_string(minute, 2) + to_string(second, 2);
- asn1rep += "Z";
- return asn1rep;
+ std::string repr = std::to_string(full_year*10000000000 +
+ month*100000000 +
+ day*1000000 +
+ hour*10000 +
+ minute*100 +
+ second) + "Z";
+
+ u32bit desired_size = (tag == UTC_TIME) ? 13 : 15;
+
+ while(repr.size() < desired_size)
+ repr = "0" + repr;
+
+ return repr;
}
/*
@@ -218,14 +224,12 @@ std::string X509_Time::readable_string() const
if(time_is_set() == false)
throw Invalid_State("X509_Time::readable_string: No time set");
- std::string readable;
- readable += to_string(year, 4) + "/";
- readable += to_string(month ) + "/";
- readable += to_string(day ) + " ";
- readable += to_string(hour ) + ":";
- readable += to_string(minute, 2) + ":";
- readable += to_string(second, 2) + " UTC";
- return readable;
+ std::string output(24, 0);
+
+ std::sprintf(&output[0], "%04d/%02d/%02d %02d:%02d:%02d UTC",
+ year, month, day, hour, minute, second);
+
+ return output;
}
/*
diff --git a/src/asn1/ber_dec.cpp b/src/asn1/ber_dec.cpp
index b31c7b903..3754bb158 100644
--- a/src/asn1/ber_dec.cpp
+++ b/src/asn1/ber_dec.cpp
@@ -141,7 +141,11 @@ size_t find_eoc(DataSource* ber)
void BER_Object::assert_is_a(ASN1_Tag type_tag, ASN1_Tag class_tag)
{
if(this->type_tag != type_tag || this->class_tag != class_tag)
- throw BER_Decoding_Error("Tag mismatch when decoding");
+ throw BER_Decoding_Error("Tag mismatch when decoding got " +
+ std::to_string(this->type_tag) + "/" +
+ std::to_string(this->class_tag) + " expected " +
+ std::to_string(type_tag) + "/" +
+ std::to_string(class_tag));
}
/*
@@ -400,6 +404,29 @@ BER_Decoder& BER_Decoder::decode(size_t& out,
}
/*
+* Decode a small BER encoded INTEGER
+*/
+u64bit BER_Decoder::decode_constrained_integer(ASN1_Tag type_tag,
+ ASN1_Tag class_tag,
+ size_t T_bytes)
+ {
+ if(T_bytes > 8)
+ throw BER_Decoding_Error("Can't decode small integer over 8 bytes");
+
+ BigInt integer;
+ decode(integer, type_tag, class_tag);
+
+ if(integer.bits() > 8*T_bytes)
+ throw BER_Decoding_Error("Decoded integer value larger than expected");
+
+ u64bit out = 0;
+ for(size_t i = 0; i != 8; ++i)
+ out = (out << 8) | integer.byte_at(7-i);
+
+ return out;
+ }
+
+/*
* Decode a BER encoded INTEGER
*/
BER_Decoder& BER_Decoder::decode(BigInt& out,
diff --git a/src/asn1/ber_dec.h b/src/asn1/ber_dec.h
index 5f79d3fc1..87039ed93 100644
--- a/src/asn1/ber_dec.h
+++ b/src/asn1/ber_dec.h
@@ -20,33 +20,61 @@ class BOTAN_DLL BER_Decoder
{
public:
BER_Object get_next_object();
- void push_back(const BER_Object&);
+ void push_back(const BER_Object& obj);
bool more_items() const;
BER_Decoder& verify_end();
BER_Decoder& discard_remaining();
- BER_Decoder start_cons(ASN1_Tag, ASN1_Tag = UNIVERSAL);
+ BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag = UNIVERSAL);
BER_Decoder& end_cons();
- BER_Decoder& raw_bytes(MemoryRegion<byte>&);
+ BER_Decoder& raw_bytes(MemoryRegion<byte>& v);
BER_Decoder& decode_null();
- BER_Decoder& decode(bool&);
- BER_Decoder& decode(size_t&);
- BER_Decoder& decode(class BigInt&);
- BER_Decoder& decode(MemoryRegion<byte>&, ASN1_Tag);
+ BER_Decoder& decode(bool& v);
+ BER_Decoder& decode(size_t& v);
+ BER_Decoder& decode(class BigInt& v);
+ BER_Decoder& decode(MemoryRegion<byte>& v, ASN1_Tag type_tag);
- BER_Decoder& decode(bool&, ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC);
- BER_Decoder& decode(size_t&, ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC);
- BER_Decoder& decode(class BigInt&,
- ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC);
- BER_Decoder& decode(MemoryRegion<byte>&, ASN1_Tag,
- ASN1_Tag, ASN1_Tag = CONTEXT_SPECIFIC);
+ BER_Decoder& decode(bool& v,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC);
- BER_Decoder& decode(class ASN1_Object&);
+ BER_Decoder& decode(size_t& v,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC);
- BER_Decoder& decode_octet_string_bigint(class BigInt&);
+ BER_Decoder& decode(class BigInt& v,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC);
+
+ BER_Decoder& decode(MemoryRegion<byte>& v,
+ ASN1_Tag real_type,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC);
+
+ BER_Decoder& decode(class ASN1_Object& obj);
+
+ BER_Decoder& decode_octet_string_bigint(class BigInt& b);
+
+ u64bit decode_constrained_integer(ASN1_Tag type_tag,
+ ASN1_Tag class_tag,
+ size_t T_bytes);
+
+ template<typename T> BER_Decoder& decode_integer_type(T& out)
+ {
+ return decode_integer_type<T>(out, INTEGER, UNIVERSAL);
+ }
+
+ template<typename T>
+ BER_Decoder& decode_integer_type(T& out,
+ ASN1_Tag type_tag,
+ ASN1_Tag class_tag = CONTEXT_SPECIFIC)
+ {
+ out = decode_constrained_integer(type_tag, class_tag, sizeof(out));
+ return (*this);
+ }
template<typename T>
BER_Decoder& decode_optional(T& out,
@@ -71,8 +99,11 @@ class BOTAN_DLL BER_Decoder
return (*this);
}
- BER_Decoder& decode_optional_string(MemoryRegion<byte>&,
- ASN1_Tag, u16bit);
+ BER_Decoder& decode_optional_string(MemoryRegion<byte>& out,
+ ASN1_Tag real_type,
+ u16bit type_no);
+
+ BER_Decoder& operator=(const BER_Decoder&) = delete;
BER_Decoder(DataSource&);
BER_Decoder(const byte[], size_t);
@@ -80,8 +111,6 @@ class BOTAN_DLL BER_Decoder
BER_Decoder(const BER_Decoder&);
~BER_Decoder();
private:
- BER_Decoder& operator=(const BER_Decoder&) { return (*this); }
-
BER_Decoder* parent;
DataSource* source;
BER_Object pushed;
diff --git a/src/asn1/der_enc.cpp b/src/asn1/der_enc.cpp
index a14b3c5e2..d19e434f0 100644
--- a/src/asn1/der_enc.cpp
+++ b/src/asn1/der_enc.cpp
@@ -24,7 +24,7 @@ SecureVector<byte> encode_tag(ASN1_Tag type_tag, ASN1_Tag class_tag)
{
if((class_tag | 0xE0) != 0xE0)
throw Encoding_Error("DER_Encoder: Invalid class tag " +
- to_string(class_tag));
+ std::to_string(class_tag));
SecureVector<byte> encoded_tag;
if(type_tag <= 30)
diff --git a/src/asn1/x509_dn.cpp b/src/asn1/x509_dn.cpp
index f91303296..984645cfe 100644
--- a/src/asn1/x509_dn.cpp
+++ b/src/asn1/x509_dn.cpp
@@ -26,9 +26,8 @@ X509_DN::X509_DN()
*/
X509_DN::X509_DN(const std::multimap<OID, std::string>& args)
{
- std::multimap<OID, std::string>::const_iterator j;
- for(j = args.begin(); j != args.end(); ++j)
- add_attribute(j->first, j->second);
+ for(auto i = args.begin(); i != args.end(); ++i)
+ add_attribute(i->first, i->second);
}
/*
@@ -36,9 +35,8 @@ X509_DN::X509_DN(const std::multimap<OID, std::string>& args)
*/
X509_DN::X509_DN(const std::multimap<std::string, std::string>& args)
{
- std::multimap<std::string, std::string>::const_iterator j;
- for(j = args.begin(); j != args.end(); ++j)
- add_attribute(OIDS::lookup(j->first), j->second);
+ for(auto i = args.begin(); i != args.end(); ++i)
+ add_attribute(OIDS::lookup(i->first), i->second);
}
/*
@@ -59,11 +57,9 @@ void X509_DN::add_attribute(const OID& oid, const std::string& str)
if(str == "")
return;
- typedef std::multimap<OID, ASN1_String>::iterator rdn_iter;
-
- std::pair<rdn_iter, rdn_iter> range = dn_info.equal_range(oid);
- for(rdn_iter j = range.first; j != range.second; ++j)
- if(j->second.value() == str)
+ auto range = dn_info.equal_range(oid);
+ for(auto i = range.first; i != range.second; ++i)
+ if(i->second.value() == str)
return;
multimap_insert(dn_info, oid, ASN1_String(str));
@@ -75,11 +71,9 @@ void X509_DN::add_attribute(const OID& oid, const std::string& str)
*/
std::multimap<OID, std::string> X509_DN::get_attributes() const
{
- typedef std::multimap<OID, ASN1_String>::const_iterator rdn_iter;
-
std::multimap<OID, std::string> retval;
- for(rdn_iter j = dn_info.begin(); j != dn_info.end(); ++j)
- multimap_insert(retval, j->first, j->second.value());
+ for(auto i = dn_info.begin(); i != dn_info.end(); ++i)
+ multimap_insert(retval, i->first, i->second.value());
return retval;
}
@@ -88,11 +82,9 @@ std::multimap<OID, std::string> X509_DN::get_attributes() const
*/
std::multimap<std::string, std::string> X509_DN::contents() const
{
- typedef std::multimap<OID, ASN1_String>::const_iterator rdn_iter;
-
std::multimap<std::string, std::string> retval;
- for(rdn_iter j = dn_info.begin(); j != dn_info.end(); ++j)
- multimap_insert(retval, OIDS::lookup(j->first), j->second.value());
+ for(auto i = dn_info.begin(); i != dn_info.end(); ++i)
+ multimap_insert(retval, OIDS::lookup(i->first), i->second.value());
return retval;
}
@@ -101,14 +93,13 @@ std::multimap<std::string, std::string> X509_DN::contents() const
*/
std::vector<std::string> X509_DN::get_attribute(const std::string& attr) const
{
- typedef std::multimap<OID, ASN1_String>::const_iterator rdn_iter;
-
const OID oid = OIDS::lookup(deref_info_field(attr));
- std::pair<rdn_iter, rdn_iter> range = dn_info.equal_range(oid);
+
+ auto range = dn_info.equal_range(oid);
std::vector<std::string> values;
- for(rdn_iter j = range.first; j != range.second; ++j)
- values.push_back(j->second.value());
+ for(auto i = range.first; i != range.second; ++i)
+ values.push_back(i->second.value());
return values;
}
@@ -142,15 +133,13 @@ std::string X509_DN::deref_info_field(const std::string& info)
*/
bool operator==(const X509_DN& dn1, const X509_DN& dn2)
{
- typedef std::multimap<OID, std::string>::const_iterator rdn_iter;
-
- std::multimap<OID, std::string> attr1 = dn1.get_attributes();
- std::multimap<OID, std::string> attr2 = dn2.get_attributes();
+ auto attr1 = dn1.get_attributes();
+ auto attr2 = dn2.get_attributes();
if(attr1.size() != attr2.size()) return false;
- rdn_iter p1 = attr1.begin();
- rdn_iter p2 = attr2.begin();
+ auto p1 = attr1.begin();
+ auto p2 = attr2.begin();
while(true)
{
@@ -180,18 +169,15 @@ bool operator!=(const X509_DN& dn1, const X509_DN& dn2)
*/
bool operator<(const X509_DN& dn1, const X509_DN& dn2)
{
- typedef std::multimap<OID, std::string>::const_iterator rdn_iter;
-
- std::multimap<OID, std::string> attr1 = dn1.get_attributes();
- std::multimap<OID, std::string> attr2 = dn2.get_attributes();
+ auto attr1 = dn1.get_attributes();
+ auto attr2 = dn2.get_attributes();
if(attr1.size() < attr2.size()) return true;
if(attr1.size() > attr2.size()) return false;
- for(rdn_iter p1 = attr1.begin(); p1 != attr1.end(); ++p1)
+ for(auto p1 = attr1.begin(); p1 != attr1.end(); ++p1)
{
- std::multimap<OID, std::string>::const_iterator p2;
- p2 = attr2.find(p1->first);
+ auto p2 = attr2.find(p1->first);
if(p2 == attr2.end()) return false;
if(p1->second > p2->second) return false;
if(p1->second < p2->second) return true;
@@ -209,8 +195,6 @@ void do_ava(DER_Encoder& encoder,
ASN1_Tag string_type, const std::string& oid_str,
bool must_exist = false)
{
- typedef std::multimap<OID, std::string>::const_iterator rdn_iter;
-
const OID oid = OIDS::lookup(oid_str);
const bool exists = (dn_info.find(oid) != dn_info.end());
@@ -218,14 +202,14 @@ void do_ava(DER_Encoder& encoder,
throw Encoding_Error("X509_DN: No entry for " + oid_str);
if(!exists) return;
- std::pair<rdn_iter, rdn_iter> range = dn_info.equal_range(oid);
+ auto range = dn_info.equal_range(oid);
- for(rdn_iter j = range.first; j != range.second; ++j)
+ for(auto i = range.first; i != range.second; ++i)
{
encoder.start_cons(SET)
.start_cons(SEQUENCE)
.encode(oid)
- .encode(ASN1_String(j->second, string_type))
+ .encode(ASN1_String(i->second, string_type))
.end_cons()
.end_cons();
}
@@ -238,7 +222,7 @@ void do_ava(DER_Encoder& encoder,
*/
void X509_DN::encode_into(DER_Encoder& der) const
{
- std::multimap<OID, std::string> dn_info = get_attributes();
+ auto dn_info = get_attributes();
der.start_cons(SEQUENCE);
diff --git a/src/benchmark/benchmark.cpp b/src/benchmark/benchmark.cpp
index dbccd45c1..a9b84f252 100644
--- a/src/benchmark/benchmark.cpp
+++ b/src/benchmark/benchmark.cpp
@@ -1,6 +1,6 @@
/*
* Runtime benchmarking
-* (C) 2008 Jack Lloyd
+* (C) 2008-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
@@ -11,33 +11,40 @@
#include <botan/stream_cipher.h>
#include <botan/hash.h>
#include <botan/mac.h>
-#include <botan/time.h>
#include <memory>
+#include <vector>
+#include <chrono>
namespace Botan {
namespace {
+typedef std::chrono::high_resolution_clock benchmark_clock;
+
/**
* Benchmark Buffered_Computation (hash or MAC)
*/
std::pair<u64bit, u64bit> bench_buf_comp(Buffered_Computation* buf_comp,
- u64bit nanoseconds_max,
+ std::chrono::nanoseconds max_time,
const byte buf[], size_t buf_len)
{
u64bit reps = 0;
- u64bit nanoseconds_used = 0;
- while(nanoseconds_used < nanoseconds_max)
+ std::chrono::nanoseconds time_used(0);
+
+ while(time_used < max_time)
{
- const u64bit start = get_nanoseconds_clock();
+ auto start = benchmark_clock::now();
buf_comp->update(buf, buf_len);
- nanoseconds_used += get_nanoseconds_clock() - start;
+ time_used += std::chrono::duration_cast<std::chrono::nanoseconds>(benchmark_clock::now() - start);
++reps;
}
- return std::make_pair(reps * buf_len, nanoseconds_used);
+ u64bit ns_taken =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(time_used).count();
+
+ return std::make_pair(reps * buf_len, ns_taken);
}
/**
@@ -45,27 +52,32 @@ std::pair<u64bit, u64bit> bench_buf_comp(Buffered_Computation* buf_comp,
*/
std::pair<u64bit, u64bit>
bench_block_cipher(BlockCipher* block_cipher,
- u64bit nanoseconds_max,
+ std::chrono::nanoseconds max_time,
byte buf[], size_t buf_len)
{
const size_t in_blocks = buf_len / block_cipher->block_size();
u64bit reps = 0;
- u64bit nanoseconds_used = 0;
+
+ std::chrono::nanoseconds time_used(0);
block_cipher->set_key(buf, block_cipher->maximum_keylength());
- while(nanoseconds_used < nanoseconds_max)
+ while(time_used < max_time)
{
- const u64bit start = get_nanoseconds_clock();
+ auto start = benchmark_clock::now();
block_cipher->encrypt_n(buf, buf, in_blocks);
- nanoseconds_used += get_nanoseconds_clock() - start;
+ time_used += std::chrono::duration_cast<std::chrono::nanoseconds>(benchmark_clock::now() - start);
+ //time_used += benchmark_clock::now() - start;
++reps;
}
+ u64bit ns_taken =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(time_used).count();
+
return std::make_pair(reps * in_blocks * block_cipher->block_size(),
- nanoseconds_used);
+ ns_taken);
}
/**
@@ -73,24 +85,28 @@ bench_block_cipher(BlockCipher* block_cipher,
*/
std::pair<u64bit, u64bit>
bench_stream_cipher(StreamCipher* stream_cipher,
- u64bit nanoseconds_max,
+ std::chrono::nanoseconds max_time,
byte buf[], size_t buf_len)
{
u64bit reps = 0;
- u64bit nanoseconds_used = 0;
stream_cipher->set_key(buf, stream_cipher->maximum_keylength());
- while(nanoseconds_used < nanoseconds_max)
+ std::chrono::nanoseconds time_used(0);
+
+ while(time_used < max_time)
{
- const u64bit start = get_nanoseconds_clock();
+ auto start = benchmark_clock::now();
stream_cipher->cipher1(buf, buf_len);
- nanoseconds_used += get_nanoseconds_clock() - start;
+ time_used += benchmark_clock::now() - start;
++reps;
}
- return std::make_pair(reps * buf_len, nanoseconds_used);
+ u64bit ns_taken =
+ std::chrono::duration_cast<std::chrono::nanoseconds>(time_used).count();
+
+ return std::make_pair(reps * buf_len, ns_taken);
}
/**
@@ -98,10 +114,10 @@ bench_stream_cipher(StreamCipher* stream_cipher,
*/
std::pair<u64bit, u64bit>
bench_hash(HashFunction* hash,
- u64bit nanoseconds_max,
+ std::chrono::nanoseconds max_time,
const byte buf[], size_t buf_len)
{
- return bench_buf_comp(hash, nanoseconds_max, buf, buf_len);
+ return bench_buf_comp(hash, max_time, buf, buf_len);
}
/**
@@ -109,11 +125,11 @@ bench_hash(HashFunction* hash,
*/
std::pair<u64bit, u64bit>
bench_mac(MessageAuthenticationCode* mac,
- u64bit nanoseconds_max,
+ std::chrono::nanoseconds max_time,
const byte buf[], size_t buf_len)
{
mac->set_key(buf, mac->maximum_keylength());
- return bench_buf_comp(mac, nanoseconds_max, buf, buf_len);
+ return bench_buf_comp(mac, max_time, buf, buf_len);
}
}
@@ -122,7 +138,7 @@ std::map<std::string, double>
algorithm_benchmark(const std::string& name,
Algorithm_Factory& af,
RandomNumberGenerator& rng,
- u32bit milliseconds,
+ std::chrono::milliseconds milliseconds,
size_t buf_size)
{
std::vector<std::string> providers = af.providers_of(name);
@@ -131,8 +147,7 @@ algorithm_benchmark(const std::string& name,
if(providers.empty()) // no providers, nothing to do
return all_results;
- const u64bit ns_per_provider =
- (static_cast<u64bit>(milliseconds) * 1000 * 1000) / providers.size();
+ std::chrono::nanoseconds ns_per_provider = milliseconds / providers.size();
std::vector<byte> buf(buf_size * 1024);
rng.randomize(&buf[0], buf.size());
@@ -146,7 +161,7 @@ algorithm_benchmark(const std::string& name,
if(const BlockCipher* proto =
af.prototype_block_cipher(name, provider))
{
- std::auto_ptr<BlockCipher> block_cipher(proto->clone());
+ std::unique_ptr<BlockCipher> block_cipher(proto->clone());
results = bench_block_cipher(block_cipher.get(),
ns_per_provider,
&buf[0], buf.size());
@@ -154,7 +169,7 @@ algorithm_benchmark(const std::string& name,
else if(const StreamCipher* proto =
af.prototype_stream_cipher(name, provider))
{
- std::auto_ptr<StreamCipher> stream_cipher(proto->clone());
+ std::unique_ptr<StreamCipher> stream_cipher(proto->clone());
results = bench_stream_cipher(stream_cipher.get(),
ns_per_provider,
&buf[0], buf.size());
@@ -162,14 +177,14 @@ algorithm_benchmark(const std::string& name,
else if(const HashFunction* proto =
af.prototype_hash_function(name, provider))
{
- std::auto_ptr<HashFunction> hash(proto->clone());
+ std::unique_ptr<HashFunction> hash(proto->clone());
results = bench_hash(hash.get(), ns_per_provider,
&buf[0], buf.size());
}
else if(const MessageAuthenticationCode* proto =
af.prototype_mac(name, provider))
{
- std::auto_ptr<MessageAuthenticationCode> mac(proto->clone());
+ std::unique_ptr<MessageAuthenticationCode> mac(proto->clone());
results = bench_mac(mac.get(), ns_per_provider,
&buf[0], buf.size());
}
diff --git a/src/benchmark/benchmark.h b/src/benchmark/benchmark.h
index c47fdc166..17df85e4e 100644
--- a/src/benchmark/benchmark.h
+++ b/src/benchmark/benchmark.h
@@ -1,6 +1,6 @@
/*
* Runtime benchmarking
-* (C) 2008 Jack Lloyd
+* (C) 2008-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
@@ -12,6 +12,7 @@
#include <botan/rng.h>
#include <map>
#include <string>
+#include <chrono>
namespace Botan {
@@ -28,7 +29,7 @@ std::map<std::string, double>
BOTAN_DLL algorithm_benchmark(const std::string& name,
Algorithm_Factory& af,
RandomNumberGenerator& rng,
- u32bit milliseconds,
+ std::chrono::milliseconds milliseconds,
size_t buf_size);
}
diff --git a/src/block/des/desx.cpp b/src/block/des/desx.cpp
index b92011e56..7f68e406a 100644
--- a/src/block/des/desx.cpp
+++ b/src/block/des/desx.cpp
@@ -47,9 +47,9 @@ void DESX::decrypt_n(const byte in[], byte out[], size_t blocks) const
*/
void DESX::key_schedule(const byte key[], size_t)
{
- K1.copy(key, 8);
+ K1.assign(key, key + 8);
des.set_key(key + 8, 8);
- K2.copy(key + 16, 8);
+ K2.assign(key + 16, key + 24);
}
}
diff --git a/src/block/lion/lion.cpp b/src/block/lion/lion.cpp
index 46308e428..4a9e8b901 100644
--- a/src/block/lion/lion.cpp
+++ b/src/block/lion/lion.cpp
@@ -72,8 +72,8 @@ void Lion::key_schedule(const byte key[], size_t length)
{
clear();
- key1.copy(key, length / 2);
- key2.copy(key + length / 2, length / 2);
+ key1.assign(key, key + (length / 2));
+ key2.assign(key + (length / 2), key + length);
}
/*
@@ -83,7 +83,7 @@ std::string Lion::name() const
{
return "Lion(" + hash->name() + "," +
cipher->name() + "," +
- to_string(BLOCK_SIZE) + ")";
+ std::to_string(BLOCK_SIZE) + ")";
}
/*
diff --git a/src/block/misty1/misty1.cpp b/src/block/misty1/misty1.cpp
index 36c25a814..77d1047b1 100644
--- a/src/block/misty1/misty1.cpp
+++ b/src/block/misty1/misty1.cpp
@@ -255,7 +255,7 @@ MISTY1::MISTY1(size_t rounds) : EK(100), DK(100)
{
if(rounds != 8)
throw Invalid_Argument("MISTY1: Invalid number of rounds: "
- + to_string(rounds));
+ + std::to_string(rounds));
}
}
diff --git a/src/block/rc2/rc2.cpp b/src/block/rc2/rc2.cpp
index 97ca5d577..071e4e209 100644
--- a/src/block/rc2/rc2.cpp
+++ b/src/block/rc2/rc2.cpp
@@ -125,7 +125,7 @@ void RC2::key_schedule(const byte key[], size_t length)
0xFE, 0x7F, 0xC1, 0xAD };
SecureVector<byte> L(128);
- L.copy(key, length);
+ copy_mem(&L[0], key, length);
for(size_t i = length; i != 128; ++i)
L[i] = TABLE[(L[i-1] + L[i-length]) % 256];
diff --git a/src/block/rc5/rc5.cpp b/src/block/rc5/rc5.cpp
index cfcc4cb64..981f73564 100644
--- a/src/block/rc5/rc5.cpp
+++ b/src/block/rc5/rc5.cpp
@@ -116,7 +116,7 @@ void RC5::key_schedule(const byte key[], size_t length)
*/
std::string RC5::name() const
{
- return "RC5(" + to_string(get_rounds()) + ")";
+ return "RC5(" + std::to_string(get_rounds()) + ")";
}
/*
@@ -126,7 +126,7 @@ RC5::RC5(size_t rounds)
{
if(rounds < 8 || rounds > 32 || (rounds % 4 != 0))
throw Invalid_Argument("RC5: Invalid number of rounds " +
- to_string(rounds));
+ std::to_string(rounds));
S.resize(2*rounds + 2);
}
diff --git a/src/block/safer/safer_sk.cpp b/src/block/safer/safer_sk.cpp
index a3a6cefd8..5275a0781 100644
--- a/src/block/safer/safer_sk.cpp
+++ b/src/block/safer/safer_sk.cpp
@@ -230,7 +230,7 @@ void SAFER_SK::key_schedule(const byte key[], size_t)
*/
std::string SAFER_SK::name() const
{
- return "SAFER-SK(" + to_string(get_rounds()) + ")";
+ return "SAFER-SK(" + std::to_string(get_rounds()) + ")";
}
/*
diff --git a/src/block/serpent/serpent.cpp b/src/block/serpent/serpent.cpp
index b3cf0f6c9..b1e632c29 100644
--- a/src/block/serpent/serpent.cpp
+++ b/src/block/serpent/serpent.cpp
@@ -387,7 +387,8 @@ void Serpent::key_schedule(const byte key[], size_t length)
SBoxE8(W[120],W[121],W[122],W[123]); SBoxE7(W[124],W[125],W[126],W[127]);
SBoxE6(W[128],W[129],W[130],W[131]); SBoxE5(W[132],W[133],W[134],W[135]);
SBoxE4(W[136],W[137],W[138],W[139]);
- round_key.copy(&W[8], 132);
+
+ round_key.assign(&W[8], &W[140]);
}
}
diff --git a/src/block/square/square.cpp b/src/block/square/square.cpp
index cd1865582..ff98c040e 100644
--- a/src/block/square/square.cpp
+++ b/src/block/square/square.cpp
@@ -160,6 +160,9 @@ void Square::key_schedule(const byte key[], size_t)
transform(&XEK[4*i]);
}
+ ME.resize(16);
+ MD.resize(16);
+
for(size_t i = 0; i != 4; ++i)
for(size_t j = 0; j != 4; ++j)
{
@@ -169,8 +172,8 @@ void Square::key_schedule(const byte key[], size_t)
MD[4*i+j+16] = get_byte(j, XEK[i ]);
}
- EK.copy(&XEK[4], 28);
- DK.copy(&XDK[4], 28);
+ EK.assign(&XEK[4], &XEK[36]);
+ DK.assign(&XDK[4], &XDK[36]);
}
/*
diff --git a/src/build-data/cc/clang.txt b/src/build-data/cc/clang.txt
index e5d52db3d..8860a30ba 100644
--- a/src/build-data/cc/clang.txt
+++ b/src/build-data/cc/clang.txt
@@ -10,7 +10,7 @@ add_include_dir_option -I
add_lib_dir_option -L
add_lib_option -l
-lang_flags "-D_REENTRANT -ansi -Wno-long-long"
+lang_flags "-D_REENTRANT -std=c++0x"
warning_flags "-W -Wall"
makefile_style unix
diff --git a/src/build-data/cc/compaq.txt b/src/build-data/cc/compaq.txt
deleted file mode 100644
index 7e7f1ea56..000000000
--- a/src/build-data/cc/compaq.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-macro_name COMPAQ
-
-binary_name cxx
-
-compile_option "-c "
-output_to_option "-o "
-add_include_dir_option -I
-add_lib_dir_option -L
-add_lib_option -l
-
-# -O3 and up seem to be unhappy with Botan
-lib_opt_flags "-O2"
-check_opt_flags "-O2"
-debug_flags -g
-no_debug_flags ""
-lang_flags "-std ansi -D__USE_STD_IOSTREAM"
-
-makefile_style unix
-
-<so_link_flags>
-default -> "$(CXX) -shared -soname $(SONAME)"
-</so_link_flags>
-
-<mach_opt>
-alpha -> "-arch=SUBMODEL" alpha-
-</mach_opt>
diff --git a/src/build-data/cc/gcc.txt b/src/build-data/cc/gcc.txt
index 6173f6271..d22ae6202 100644
--- a/src/build-data/cc/gcc.txt
+++ b/src/build-data/cc/gcc.txt
@@ -1,8 +1,6 @@
macro_name GCC
-binary_name g++
-
-has_tr1 yes
+binary_name g++-4.6.0
compile_option "-c "
output_to_option "-o "
@@ -10,7 +8,7 @@ add_include_dir_option -I
add_lib_dir_option -L
add_lib_option -l
-lang_flags "-D_REENTRANT -Wno-long-long"
+lang_flags "-D_REENTRANT -std=c++0x"
warning_flags "-W -Wall"
maintainer_warning_flags "-Werror -Wall -Wextra -Wstrict-aliasing -Wstrict-overflow=5 -Wcast-align -Wmissing-declarations -Wpointer-arith -Wcast-qual -Wold-style-cast"
@@ -90,18 +88,16 @@ x86_64 -> "-march=SUBMODEL -momit-leaf-frame-pointer"
# The 'linking' bit means "use this for both compiling *and* linking"
<mach_abi_linking>
-x86_64 -> "-m64"
+all -> "-pthread"
+
mips64 -> "-mabi=64"
s390 -> "-m31"
s390x -> "-m64"
sparc32 -> "-m32 -mno-app-regs"
sparc64 -> "-m64 -mno-app-regs"
ppc64 -> "-m64"
+x86_64 -> "-m64"
-# This should probably be used on most/all targets, but the docs are unclear
-openbsd -> "-pthread"
-freebsd -> "-pthread"
-dragonfly -> "-pthread"
-netbsd -> "-pthread -D_NETBSD_SOURCE"
-qnx -> "-fexceptions -D_QNX_SOURCE"
+netbsd -> "-D_NETBSD_SOURCE"
+qnx -> "-fexceptions -D_QNX_SOURCE"
</mach_abi_linking>
diff --git a/src/build-data/cc/icc.txt b/src/build-data/cc/icc.txt
index 28c1a2816..e11875cb1 100644
--- a/src/build-data/cc/icc.txt
+++ b/src/build-data/cc/icc.txt
@@ -2,8 +2,6 @@ macro_name INTEL
binary_name icpc
-has_tr1 yes
-
compile_option "-c "
output_to_option "-o "
add_include_dir_option -I
@@ -14,7 +12,7 @@ lib_opt_flags "-O2 -ip -unroll"
check_opt_flags "-O2"
debug_flags -g
no_debug_flags "-fomit-frame-pointer"
-lang_flags ""
+lang_flags "-std=c++0x"
warning_flags "-w1"
shared_flags "-fPIC"
diff --git a/src/build-data/cc/kai.txt b/src/build-data/cc/kai.txt
deleted file mode 100644
index 2d9c0cd65..000000000
--- a/src/build-data/cc/kai.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-macro_name KAI
-
-binary_name KCC
-
-compile_option "-c "
-output_to_option "-o "
-add_include_dir_option -I
-add_lib_dir_option -L
-add_lib_option -l
-
-ar_command "KCC -o"
-
-lib_opt_flags "+K3 --inline_auto_space_time=65 --abstract_pointer"
-check_opt_flags "+K3"
-lang_flags "-D__KAI_STRICT"
-debug_flags -g
-no_debug_flags ""
-
-makefile_style unix
-
-<so_link_flags>
-default -> "$(CXX) --soname $(SONAME)"
-</so_link_flags>
-
-<mach_abi_linking>
-all -> "--one_per"
-</mach_abi_linking>
diff --git a/src/build-data/cc/mipspro.txt b/src/build-data/cc/mipspro.txt
deleted file mode 100644
index 28b47b30d..000000000
--- a/src/build-data/cc/mipspro.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-macro_name MIPSPRO
-
-binary_name CC
-
-compile_option "-c "
-output_to_option "-o "
-add_include_dir_option -I
-add_lib_dir_option -L
-add_lib_option -l
-
-lib_opt_flags "-O3 -OPT:alias=TYPED"
-check_opt_flags "-O3 -OPT:alias=TYPED"
-debug_flags "-g3"
-no_debug_flags ""
-shared_flags "-KPIC"
-lang_flags "-ansi -LANG:ansi-for-init-scope=ON"
-# Disabled, because, while my code is fine, it warns about a lot of it's own
-# headers <g>
-#warning_flags "-fullwarn"
-
-makefile_style unix
-
-<so_link_flags>
-default -> "$(CXX) -shared -Wl,-soname,$(SONAME)"
-</so_link_flags>
-
-<mach_opt>
-mips32 -> "-mips1"
-mips64 -> "-mips3"
-
-mips64-r5000 -> "-mips4 -r5000"
-mips64-r8000 -> "-mips4 -r8000"
-mips64-r10000 -> "-mips4 -r10000"
-</mach_opt>
-
-<mach_abi_linking>
-mips32 -> "-n32"
-mips64 -> "-64"
-</mach_abi_linking>
diff --git a/src/build-data/cc/sgipro64.txt b/src/build-data/cc/sgipro64.txt
deleted file mode 100644
index e6a58f16d..000000000
--- a/src/build-data/cc/sgipro64.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-macro_name SGI_PRO64
-
-binary_name sgiCC
-
-compile_option "-c "
-output_to_option "-o "
-add_include_dir_option -I
-add_lib_dir_option -L
-add_lib_option -l
-
-lib_opt_flags "-O3 -OPT:alias=TYPED"
-check_opt_flags "-O3 -OPT:alias=TYPED"
-debug_flags "-g3"
-no_debug_flags ""
-shared_flags "-KPIC"
-lang_flags "-ansi -LANG:ansi-for-init-scope=ON"
-warning_flags "-Wall -W"
-
-makefile_style unix
-
-<so_link_flags>
-default -> "$(CXX) -shared -Wl,-soname,$(SONAME)"
-</so_link_flags>
-
-<mach_opt>
-
-</mach_opt>
diff --git a/src/build-data/os/windows.txt b/src/build-data/os/windows.txt
index 2f344e33c..30a6b77f8 100644
--- a/src/build-data/os/windows.txt
+++ b/src/build-data/os/windows.txt
@@ -11,10 +11,11 @@ install_cmd_data "copy"
install_cmd_exec "copy"
<target_features>
-win32_virtual_lock
-win32_get_systemtime
gmtime_s
loadlibrary
+win32_get_systemtime
+win32_query_perf_counter
+win32_virtual_lock
</target_features>
<aliases>
diff --git a/src/cert/cvc/asn1_eac_tm.cpp b/src/cert/cvc/asn1_eac_tm.cpp
index db5d2fbaf..12221b582 100644
--- a/src/cert/cvc/asn1_eac_tm.cpp
+++ b/src/cert/cvc/asn1_eac_tm.cpp
@@ -1,7 +1,7 @@
/*
* EAC Time Types
* (C) 2007 FlexSecure GmbH
-* 2008 Jack Lloyd
+* 2008-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
@@ -12,7 +12,7 @@
#include <botan/charset.h>
#include <botan/parsing.h>
#include <botan/internal/rounding.h>
-#include <botan/time.h>
+#include <botan/calendar.h>
namespace Botan {
@@ -22,7 +22,7 @@ SecureVector<byte> enc_two_digit(u32bit in)
{
SecureVector<byte> result;
in %= 100;
- if (in < 10)
+ if(in < 10)
result.push_back(0x00);
else
{
@@ -51,9 +51,10 @@ u32bit dec_two_digit(byte b1, byte b2)
/*
* Create an EAC_Time
*/
-EAC_Time::EAC_Time(u64bit timer, ASN1_Tag t) : tag(t)
+EAC_Time::EAC_Time(const std::chrono::system_clock::time_point& time,
+ ASN1_Tag t) : tag(t)
{
- calendar_point cal = calendar_value(timer);
+ calendar_point cal = calendar_value(time);
year = cal.year;
month = cal.month;
@@ -67,6 +68,7 @@ EAC_Time::EAC_Time(const std::string& t_spec, ASN1_Tag t) : tag(t)
{
set_to(t_spec);
}
+
/*
* Create an EAC_Time
*/
@@ -80,7 +82,7 @@ EAC_Time::EAC_Time(u32bit y, u32bit m, u32bit d, ASN1_Tag t) :
*/
void EAC_Time::set_to(const std::string& time_str)
{
- if (time_str == "")
+ if(time_str == "")
{
year = month = day = 0;
return;
@@ -89,28 +91,28 @@ void EAC_Time::set_to(const std::string& time_str)
std::vector<std::string> params;
std::string current;
- for (u32bit j = 0; j != time_str.size(); ++j)
+ for(u32bit j = 0; j != time_str.size(); ++j)
{
- if (Charset::is_digit(time_str[j]))
+ if(Charset::is_digit(time_str[j]))
current += time_str[j];
else
{
- if (current != "")
+ if(current != "")
params.push_back(current);
current.clear();
}
}
- if (current != "")
+ if(current != "")
params.push_back(current);
- if (params.size() != 3)
+ if(params.size() != 3)
throw Invalid_Argument("Invalid time specification " + time_str);
year = to_u32bit(params[0]);
month = to_u32bit(params[1]);
day = to_u32bit(params[2]);
- if (!passes_sanity_check())
+ if(!passes_sanity_check())
throw Invalid_Argument("Invalid time specification " + time_str);
}
@@ -129,15 +131,10 @@ void EAC_Time::encode_into(DER_Encoder& der) const
*/
std::string EAC_Time::as_string() const
{
- if (time_is_set() == false)
+ if(time_is_set() == false)
throw Invalid_State("EAC_Time::as_string: No time set");
- std::string asn1rep;
- asn1rep = to_string(year, 2);
-
- asn1rep += to_string(month, 2) + to_string(day, 2);
-
- return asn1rep;
+ return std::to_string(year * 10000 + month * 100 + day);
}
/*
@@ -153,15 +150,14 @@ bool EAC_Time::time_is_set() const
*/
std::string EAC_Time::readable_string() const
{
- if (time_is_set() == false)
+ if(time_is_set() == false)
throw Invalid_State("EAC_Time::readable_string: No time set");
- std::string readable;
- readable += to_string(year, 2) + "/";
- readable += to_string(month, 2) + "/";
- readable += to_string(day, 2) + " ";
+ std::string output(11, 0);
- return readable;
+ std::sprintf(&output[0], "%04d/%02d/%02d", year, month, day);
+
+ return output;
}
/*
@@ -169,11 +165,11 @@ std::string EAC_Time::readable_string() const
*/
bool EAC_Time::passes_sanity_check() const
{
- if (year < 2000 || year > 2099)
+ if(year < 2000 || year > 2099)
return false;
- if (month == 0 || month > 12)
+ if(month == 0 || month > 12)
return false;
- if (day == 0 || day > 31)
+ if(day == 0 || day > 31)
return false;
return true;
@@ -182,11 +178,11 @@ bool EAC_Time::passes_sanity_check() const
/*
* modification functions
*/
-
void EAC_Time::add_years(u32bit years)
{
year += years;
}
+
void EAC_Time::add_months(u32bit months)
{
year += months/12;
@@ -198,23 +194,22 @@ void EAC_Time::add_months(u32bit months)
}
}
-
/*
* Compare this time against another
*/
s32bit EAC_Time::cmp(const EAC_Time& other) const
{
- if (time_is_set() == false)
+ if(time_is_set() == false)
throw Invalid_State("EAC_Time::cmp: No time set");
const s32bit EARLIER = -1, LATER = 1, SAME_TIME = 0;
- if (year < other.year) return EARLIER;
- if (year > other.year) return LATER;
- if (month < other.month) return EARLIER;
- if (month > other.month) return LATER;
- if (day < other.day) return EARLIER;
- if (day > other.day) return LATER;
+ if(year < other.year) return EARLIER;
+ if(year > other.year) return LATER;
+ if(month < other.month) return EARLIER;
+ if(month > other.month) return LATER;
+ if(day < other.day) return EARLIER;
+ if(day > other.day) return LATER;
return SAME_TIME;
}
@@ -283,21 +278,6 @@ void EAC_Time::decode_from(BER_Decoder& source)
}
-u32bit EAC_Time::get_year() const
- {
- return year;
- }
-
-u32bit EAC_Time::get_month() const
- {
- return month;
- }
-
-u32bit EAC_Time::get_day() const
- {
- return day;
- }
-
/*
* make the value an octet string for encoding
*/
@@ -310,34 +290,4 @@ SecureVector<byte> EAC_Time::encoded_eac_time() const
return result;
}
-ASN1_Ced::ASN1_Ced(std::string const& str) :
- EAC_Time(str, ASN1_Tag(37))
- {}
-
-ASN1_Ced::ASN1_Ced(u64bit val) :
- EAC_Time(val, ASN1_Tag(37))
- {}
-
-ASN1_Ced::ASN1_Ced(EAC_Time const& other) :
- EAC_Time(other.get_year(),
- other.get_month(),
- other.get_day(),
- ASN1_Tag(37))
- {}
-
-ASN1_Cex::ASN1_Cex(std::string const& str) :
- EAC_Time(str, ASN1_Tag(36))
- {}
-
-ASN1_Cex::ASN1_Cex(u64bit val) :
- EAC_Time(val, ASN1_Tag(36))
- {}
-
-ASN1_Cex::ASN1_Cex(EAC_Time const& other) :
- EAC_Time(other.get_year(),
- other.get_month(),
- other.get_day(),
- ASN1_Tag(36))
- {}
-
}
diff --git a/src/cert/cvc/cvc_self.cpp b/src/cert/cvc/cvc_self.cpp
index 662a1d2be..61a1e7b64 100644
--- a/src/cert/cvc/cvc_self.cpp
+++ b/src/cert/cvc/cvc_self.cpp
@@ -8,7 +8,6 @@
#include <botan/cvc_self.h>
#include <botan/ecc_key.h>
#include <botan/point_gfp.h>
-#include <botan/time.h>
#include <botan/oids.h>
#include <sstream>
#include <memory>
@@ -164,6 +163,7 @@ EAC1_1_ADO create_ado_req(Private_Key const& key,
{
throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
}
+
std::string padding_and_hash = padding_and_hash_from_oid(req.signature_algorithm().oid);
PK_Signer signer(*priv_key, padding_and_hash);
SecureVector<byte> tbs_bits = req.BER_encode();
@@ -193,9 +193,8 @@ EAC1_1_CVC create_cvca(Private_Key const& key,
}
EAC1_1_CVC_Options opts;
opts.car = car;
- const u64bit current_time = system_time();
- opts.ced = ASN1_Ced(current_time);
+ opts.ced = ASN1_Ced(std::chrono::system_clock::now());
opts.cex = ASN1_Cex(opts.ced);
opts.cex.add_months(cvca_validity_months);
opts.holder_auth_templ = (CVCA | (iris * IRIS) | (fingerpr * FINGERPRINT));
@@ -210,12 +209,12 @@ EAC1_1_CVC link_cvca(EAC1_1_CVC const& signer,
EAC1_1_CVC const& signee,
RandomNumberGenerator& rng)
{
- ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
+ const ECDSA_PrivateKey* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
+
if (priv_key == 0)
- {
- throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
- }
- ASN1_Ced ced(system_time());
+ throw Invalid_Argument("link_cvca(): unsupported key type");
+
+ ASN1_Ced ced(std::chrono::system_clock::now());
ASN1_Cex cex(signee.get_cex());
if (*static_cast<EAC_Time*>(&ced) > *static_cast<EAC_Time*>(&cex))
{
@@ -232,7 +231,7 @@ EAC1_1_CVC link_cvca(EAC1_1_CVC const& signer,
AlgorithmIdentifier sig_algo = signer.signature_algorithm();
std::string padding_and_hash = padding_and_hash_from_oid(sig_algo.oid);
PK_Signer pk_signer(*priv_key, padding_and_hash);
- std::auto_ptr<Public_Key> pk(signee.subject_public_key());
+ std::unique_ptr<Public_Key> pk(signee.subject_public_key());
ECDSA_PublicKey* subj_pk = dynamic_cast<ECDSA_PublicKey*>(pk.get());
subj_pk->set_parameter_encoding(EC_DOMPAR_ENC_EXPLICIT);
@@ -262,13 +261,19 @@ EAC1_1_CVC sign_request(EAC1_1_CVC const& signer_cert,
throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
}
std::string chr_str = signee.get_chr().value();
- chr_str += to_string(seqnr, seqnr_len);
+
+ std::string seqnr_string = std::to_string(seqnr);
+
+ while(seqnr_string.size() < seqnr_len)
+ seqnr_string = '0' + seqnr_string;
+
+ chr_str += seqnr_string;
ASN1_Chr chr(chr_str);
std::string padding_and_hash = padding_and_hash_from_oid(signee.signature_algorithm().oid);
PK_Signer pk_signer(*priv_key, padding_and_hash);
- std::auto_ptr<Public_Key> pk(signee.subject_public_key());
+ std::unique_ptr<Public_Key> pk(signee.subject_public_key());
ECDSA_PublicKey* subj_pk = dynamic_cast<ECDSA_PublicKey*>(pk.get());
- std::auto_ptr<Public_Key> signer_pk(signer_cert.subject_public_key());
+ std::unique_ptr<Public_Key> signer_pk(signer_cert.subject_public_key());
// for the case that the domain parameters are not set...
// (we use those from the signer because they must fit)
@@ -277,8 +282,9 @@ EAC1_1_CVC sign_request(EAC1_1_CVC const& signer_cert,
subj_pk->set_parameter_encoding(EC_DOMPAR_ENC_IMPLICITCA);
AlgorithmIdentifier sig_algo(signer_cert.signature_algorithm());
- const u64bit current_time = system_time();
- ASN1_Ced ced(current_time);
+
+ ASN1_Ced ced(std::chrono::system_clock::now());
+
u32bit chat_val;
u32bit chat_low = signer_cert.get_chat_value() & 0x3; // take the chat rights from signer
ASN1_Cex cex(ced);
diff --git a/src/cert/cvc/eac_asn_obj.h b/src/cert/cvc/eac_asn_obj.h
index d0bab6fdd..54a9f1517 100644
--- a/src/cert/cvc/eac_asn_obj.h
+++ b/src/cert/cvc/eac_asn_obj.h
@@ -56,7 +56,6 @@ class BOTAN_DLL EAC_Time : public ASN1_Object
* e.g. "2007 08 01"
*/
void set_to(const std::string& str);
- //void set_to(const std::string&, ASN1_Tag);
/**
* Add the specified number of years to this.
@@ -74,24 +73,28 @@ class BOTAN_DLL EAC_Time : public ASN1_Object
* Get the year value of this objects.
* @return year value
*/
- u32bit get_year() const;
+ u32bit get_year() const { return year; }
/**
* Get the month value of this objects.
* @return month value
*/
- u32bit get_month() const;
+ u32bit get_month() const { return month; }
/**
* Get the day value of this objects.
* @return day value
*/
- u32bit get_day() const;
+ u32bit get_day() const { return day; }
- EAC_Time(u64bit, ASN1_Tag t = ASN1_Tag(0));
- //EAC_Time(const std::string& = "");
- EAC_Time(const std::string&, ASN1_Tag = ASN1_Tag(0));
- EAC_Time(u32bit year, u32bit month, u32bit day, ASN1_Tag = ASN1_Tag(0));
+ EAC_Time(const std::chrono::system_clock::time_point& time,
+ ASN1_Tag tag = ASN1_Tag(0));
+
+ EAC_Time(const std::string& yyyy_mm_dd,
+ ASN1_Tag tag = ASN1_Tag(0));
+
+ EAC_Time(u32bit year, u32bit month, u32bit day,
+ ASN1_Tag tag = ASN1_Tag(0));
virtual ~EAC_Time() {}
private:
@@ -113,25 +116,25 @@ class BOTAN_DLL ASN1_Ced : public EAC_Time
* @param str a string in the format "yyyy mm dd",
* e.g. "2007 08 01"
*/
- ASN1_Ced(std::string const& str = "");
+ ASN1_Ced(const std::string& str = "") :
+ EAC_Time(str, ASN1_Tag(37)) {}
/**
- * Construct a CED from a timer value.
- * @param time the number of seconds elapsed midnight, 1st
- * January 1970 GMT (or 7pm, 31st December 1969 EST) up to the
- * desired date
+ * Construct a CED from a time point
*/
- ASN1_Ced(u64bit time);
+ ASN1_Ced(const std::chrono::system_clock::time_point& time) :
+ EAC_Time(time, ASN1_Tag(37)) {}
/**
* Copy constructor (for general EAC_Time objects).
* @param other the object to copy from
*/
- ASN1_Ced(EAC_Time const& other);
- //ASN1_Ced(ASN1_Cex const& cex);
+ ASN1_Ced(const EAC_Time& other) :
+ EAC_Time(other.get_year(), other.get_month(), other.get_day(),
+ ASN1_Tag(37))
+ {}
};
-
/**
* This class represents CVC CEXs. Only limited sanity checks of
* the inputted date value are performed.
@@ -140,27 +143,20 @@ class BOTAN_DLL ASN1_Cex : public EAC_Time
{
public:
/**
- * Construct a CED from a string value.
+ * Construct a CEX from a string value.
* @param str a string in the format "yyyy mm dd",
* e.g. "2007 08 01"
*/
- ASN1_Cex(std::string const& str="");
+ ASN1_Cex(const std::string& str = "") :
+ EAC_Time(str, ASN1_Tag(36)) {}
- /**
- * Construct a CED from a timer value.
- * @param time the number of seconds elapsed
- * midnight, 1st
- * January 1970 GMT (or 7pm, 31st December 1969 EST)
- * up to the desired date
- */
- ASN1_Cex(u64bit time);
+ ASN1_Cex(const std::chrono::system_clock::time_point& time) :
+ EAC_Time(time, ASN1_Tag(36)) {}
- /**
- * Copy constructor (for general EAC_Time objects).
- * @param other the object to copy from
- */
- ASN1_Cex(EAC_Time const& other);
- //ASN1_Cex(ASN1_Ced const& ced);
+ ASN1_Cex(const EAC_Time& other) :
+ EAC_Time(other.get_year(), other.get_month(), other.get_day(),
+ ASN1_Tag(36))
+ {}
};
/**
diff --git a/src/cert/cvc/info.txt b/src/cert/cvc/info.txt
index 33a872053..3cf759188 100644
--- a/src/cert/cvc/info.txt
+++ b/src/cert/cvc/info.txt
@@ -1,5 +1,4 @@
define CARD_VERIFIABLE_CERTIFICATES
-
load_on request
<header:public>
diff --git a/src/cert/pkcs10/pkcs10.cpp b/src/cert/pkcs10/pkcs10.cpp
index 784318d3d..870a4d3a1 100644
--- a/src/cert/pkcs10/pkcs10.cpp
+++ b/src/cert/pkcs10/pkcs10.cpp
@@ -45,7 +45,7 @@ void PKCS10_Request::force_decode()
cert_req_info.decode(version);
if(version != 0)
throw Decoding_Error("Unknown version code in PKCS #10 request: " +
- to_string(version));
+ std::to_string(version));
X509_DN dn_subject;
cert_req_info.decode(dn_subject);
diff --git a/src/cert/x509ca/x509_ca.cpp b/src/cert/x509ca/x509_ca.cpp
index 40f2e3b3a..37b4f44b4 100644
--- a/src/cert/x509ca/x509_ca.cpp
+++ b/src/cert/x509ca/x509_ca.cpp
@@ -13,10 +13,6 @@
#include <botan/parsing.h>
#include <botan/lookup.h>
#include <botan/oids.h>
-#include <botan/time.h>
-#include <algorithm>
-#include <typeinfo>
-#include <iterator>
#include <memory>
#include <set>
@@ -56,7 +52,7 @@ X509_Certificate X509_CA::sign_request(const PKCS10_Request& req,
constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN);
else
{
- std::auto_ptr<Public_Key> key(req.subject_public_key());
+ std::unique_ptr<Public_Key> key(req.subject_public_key());
constraints = X509::find_constraints(*key, req.constraints());
}
@@ -172,7 +168,8 @@ X509_CRL X509_CA::make_crl(const std::vector<CRL_Entry>& revoked,
next_update = timespec_to_u32bit("7d");
// Totally stupid: ties encoding logic to the return of std::time!!
- const u64bit current_time = system_time();
+ auto current_time = std::chrono::system_clock::now();
+ auto expire_time = current_time + std::chrono::seconds(next_update);
Extensions extensions;
extensions.add(
@@ -185,7 +182,7 @@ X509_CRL X509_CA::make_crl(const std::vector<CRL_Entry>& revoked,
.encode(ca_sig_algo)
.encode(cert.issuer_dn())
.encode(X509_Time(current_time))
- .encode(X509_Time(current_time + next_update))
+ .encode(X509_Time(expire_time))
.encode_if(revoked.size() > 0,
DER_Encoder()
.start_cons(SEQUENCE)
diff --git a/src/cert/x509ca/x509_ca.h b/src/cert/x509ca/x509_ca.h
index 97be6a415..7aca26d03 100644
--- a/src/cert/x509ca/x509_ca.h
+++ b/src/cert/x509ca/x509_ca.h
@@ -99,11 +99,11 @@ class BOTAN_DLL X509_CA
const Private_Key& key,
const std::string& hash_fn);
+ X509_CA(const X509_CA&) = delete;
+ X509_CA& operator=(const X509_CA&) = delete;
+
~X509_CA();
private:
- X509_CA(const X509_CA&) {}
- X509_CA& operator=(const X509_CA&) { return (*this); }
-
X509_CRL make_crl(const std::vector<CRL_Entry>& entries,
u32bit crl_number, u32bit next_update,
RandomNumberGenerator& rng) const;
diff --git a/src/cert/x509cert/x509_obj.cpp b/src/cert/x509cert/x509_obj.cpp
index 13193f09c..eff8e2543 100644
--- a/src/cert/x509cert/x509_obj.cpp
+++ b/src/cert/x509cert/x509_obj.cpp
@@ -168,7 +168,7 @@ std::string X509_Object::hash_used_for_signature() const
*/
bool X509_Object::check_signature(Public_Key* pub_key) const
{
- std::auto_ptr<Public_Key> key(pub_key);
+ std::unique_ptr<Public_Key> key(pub_key);
return check_signature(*key);
}
diff --git a/src/cert/x509cert/x509cert.cpp b/src/cert/x509cert/x509cert.cpp
index 7d9370f2a..4cff28c39 100644
--- a/src/cert/x509cert/x509cert.cpp
+++ b/src/cert/x509cert/x509cert.cpp
@@ -30,12 +30,8 @@ std::vector<std::string> lookup_oids(const std::vector<std::string>& in)
{
std::vector<std::string> out;
- std::vector<std::string>::const_iterator i = in.begin();
- while(i != in.end())
- {
+ for(auto i = in.begin(); i != in.end(); ++i)
out.push_back(OIDS::lookup(OID(*i)));
- ++i;
- }
return out;
}
@@ -87,7 +83,7 @@ void X509_Certificate::force_decode()
.decode(dn_subject);
if(version > 2)
- throw Decoding_Error("Unknown X.509 cert version " + Botan::to_string(version));
+ throw Decoding_Error("Unknown X.509 cert version " + std::to_string(version));
if(sig_algo != sig_algo_inner)
throw Decoding_Error("Algorithm identifier mismatch");
@@ -284,6 +280,50 @@ X509_DN X509_Certificate::subject_dn() const
return create_dn(subject);
}
+namespace {
+
+bool cert_subject_dns_match(const std::string& name,
+ const std::vector<std::string>& cert_names)
+ {
+ for(size_t i = 0; i != cert_names.size(); ++i)
+ {
+ 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;
+ }
+
+}
+
+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;
+
+ if(cert_subject_dns_match(name, subject_info("Name")))
+ return true;
+
+ return false;
+ }
+
/*
* Compare two certificates for equality
*/
@@ -296,6 +336,24 @@ bool X509_Certificate::operator==(const X509_Certificate& other) const
subject == other.subject);
}
+bool X509_Certificate::operator<(const X509_Certificate& other) const
+ {
+ /* If signature values are not equal, sort by lexicographic ordering of that */
+ if(sig != other.sig)
+ {
+ if(sig < other.sig)
+ return true;
+ return false;
+ }
+
+ /*
+ * same signatures, highly unlikely case, revert to compare
+ * of entire contents
+ */
+
+ return to_string() < other.to_string();
+ }
+
/*
* X.509 Certificate Comparison
*/
@@ -413,24 +471,15 @@ std::string X509_Certificate::to_string() const
*/
X509_DN create_dn(const Data_Store& info)
{
- class DN_Matcher : public Data_Store::Matcher
+ auto names = info.search_for(
+ [](const std::string& key, const std::string&)
{
- public:
- bool operator()(const std::string& key, const std::string&) const
- {
- if(key.find("X520.") != std::string::npos)
- return true;
- return false;
- }
- };
-
- std::multimap<std::string, std::string> names =
- info.search_with(DN_Matcher());
+ return (key.find("X520.") != std::string::npos);
+ });
X509_DN dn;
- std::multimap<std::string, std::string>::iterator i;
- for(i = names.begin(); i != names.end(); ++i)
+ for(auto i = names.begin(); i != names.end(); ++i)
dn.add_attribute(i->first, i->second);
return dn;
@@ -441,32 +490,18 @@ X509_DN create_dn(const Data_Store& info)
*/
AlternativeName create_alt_name(const Data_Store& info)
{
- class AltName_Matcher : public Data_Store::Matcher
+ auto names = info.search_for(
+ [](const std::string& key, const std::string&)
{
- public:
- bool operator()(const std::string& key, const std::string&) const
- {
- for(size_t i = 0; i != matches.size(); ++i)
- if(key.compare(matches[i]) == 0)
- return true;
- return false;
- }
-
- AltName_Matcher(const std::string& match_any_of)
- {
- matches = split_on(match_any_of, '/');
- }
- private:
- std::vector<std::string> matches;
- };
-
- std::multimap<std::string, std::string> names =
- info.search_with(AltName_Matcher("RFC822/DNS/URI/IP"));
+ return (key == "RFC822" ||
+ key == "DNS" ||
+ key == "URI" ||
+ key == "IP");
+ });
AlternativeName alt_name;
- std::multimap<std::string, std::string>::iterator i;
- for(i = names.begin(); i != names.end(); ++i)
+ for(auto i = names.begin(); i != names.end(); ++i)
alt_name.add_attribute(i->first, i->second);
return alt_name;
diff --git a/src/cert/x509cert/x509cert.h b/src/cert/x509cert/x509cert.h
index 8798ef1c2..26c57e524 100644
--- a/src/cert/x509cert/x509cert.h
+++ b/src/cert/x509cert/x509cert.h
@@ -146,12 +146,24 @@ class BOTAN_DLL X509_Certificate : public X509_Object
std::string to_string() const;
/**
+ * Check if a certain DNS name matches up with the information in
+ * the cert
+ */
+ bool matches_dns_name(const std::string& name) const;
+
+ /**
* Check to certificates for equality.
* @return true both certificates are (binary) equal
*/
bool operator==(const X509_Certificate& other) const;
/**
+ * Impose an arbitrary (but consistent) ordering
+ * @return true if this is less than other by some unspecified criteria
+ */
+ bool operator<(const X509_Certificate& other) const;
+
+ /**
* Create a certificate from a data source providing the DER or
* PEM encoded certificate.
* @param source the data source
diff --git a/src/cert/x509crl/crl_ent.cpp b/src/cert/x509crl/crl_ent.cpp
index d566637f6..a5663e6bb 100644
--- a/src/cert/x509crl/crl_ent.cpp
+++ b/src/cert/x509crl/crl_ent.cpp
@@ -11,7 +11,6 @@
#include <botan/ber_dec.h>
#include <botan/bigint.h>
#include <botan/oids.h>
-#include <botan/time.h>
namespace Botan {
@@ -31,7 +30,7 @@ CRL_Entry::CRL_Entry(const X509_Certificate& cert, CRL_Code why) :
throw_on_unknown_critical(false)
{
serial = cert.serial_number();
- time = X509_Time(system_time());
+ time = X509_Time(std::chrono::system_clock::now());
reason = why;
}
diff --git a/src/cert/x509crl/x509_crl.cpp b/src/cert/x509crl/x509_crl.cpp
index 01fce4c52..72da81fce 100644
--- a/src/cert/x509crl/x509_crl.cpp
+++ b/src/cert/x509crl/x509_crl.cpp
@@ -44,7 +44,7 @@ void X509_CRL::force_decode()
if(version != 0 && version != 1)
throw X509_CRL_Error("Unknown X.509 CRL version " +
- to_string(version+1));
+ std::to_string(version+1));
AlgorithmIdentifier sig_algo_inner;
tbs_crl.decode(sig_algo_inner);
diff --git a/src/cert/x509self/x509opt.cpp b/src/cert/x509self/x509opt.cpp
index 345df1fe0..8a27fdbde 100644
--- a/src/cert/x509self/x509opt.cpp
+++ b/src/cert/x509self/x509opt.cpp
@@ -8,7 +8,7 @@
#include <botan/x509self.h>
#include <botan/oids.h>
#include <botan/parsing.h>
-#include <botan/time.h>
+#include <chrono>
namespace Botan {
@@ -78,16 +78,16 @@ void X509_Cert_Options::sanity_check() const
* Initialize the certificate options
*/
X509_Cert_Options::X509_Cert_Options(const std::string& initial_opts,
- u32bit expiration_time_in_seconds)
+ u32bit expiration_time)
{
is_CA = false;
path_limit = 0;
constraints = NO_CONSTRAINTS;
- const u64bit now = system_time();
+ auto now = std::chrono::system_clock::now();
start = X509_Time(now);
- end = X509_Time(now + expiration_time_in_seconds);
+ end = X509_Time(now + std::chrono::seconds(expiration_time));
if(initial_opts == "")
return;
diff --git a/src/cert/x509self/x509self.cpp b/src/cert/x509self/x509self.cpp
index a2f89159f..c100ee825 100644
--- a/src/cert/x509self/x509self.cpp
+++ b/src/cert/x509self/x509self.cpp
@@ -54,7 +54,7 @@ X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts,
opts.sanity_check();
MemoryVector<byte> pub_key = X509::BER_encode(key);
- std::auto_ptr<PK_Signer> signer(choose_sig_format(key, hash_fn, sig_algo));
+ std::unique_ptr<PK_Signer> signer(choose_sig_format(key, hash_fn, sig_algo));
load_info(opts, subject_dn, subject_alt);
Key_Constraints constraints;
@@ -100,7 +100,7 @@ PKCS10_Request create_cert_req(const X509_Cert_Options& opts,
opts.sanity_check();
MemoryVector<byte> pub_key = X509::BER_encode(key);
- std::auto_ptr<PK_Signer> signer(choose_sig_format(key, hash_fn, sig_algo));
+ std::unique_ptr<PK_Signer> signer(choose_sig_format(key, hash_fn, sig_algo));
load_info(opts, subject_dn, subject_alt);
const size_t PKCS10_VERSION = 0;
diff --git a/src/cert/x509store/x509stor.cpp b/src/cert/x509store/x509stor.cpp
index 3fe1adf62..a635b3930 100644
--- a/src/cert/x509store/x509stor.cpp
+++ b/src/cert/x509store/x509stor.cpp
@@ -9,8 +9,8 @@
#include <botan/parsing.h>
#include <botan/pubkey.h>
#include <botan/oids.h>
-#include <botan/time.h>
#include <algorithm>
+#include <chrono>
#include <memory>
namespace Botan {
@@ -21,13 +21,14 @@ namespace {
* Do a validity check
*/
s32bit validity_check(const X509_Time& start, const X509_Time& end,
- u64bit current_time, u32bit slack)
+ const std::chrono::system_clock::time_point& now,
+ std::chrono::seconds slack)
{
const s32bit NOT_YET_VALID = -1, VALID_TIME = 0, EXPIRED = 1;
- if(start.cmp(current_time + slack) > 0)
+ if(start.cmp(now + slack) > 0)
return NOT_YET_VALID;
- if(end.cmp(current_time - slack) < 0)
+ if(end.cmp(now - slack) < 0)
return EXPIRED;
return VALID_TIME;
}
@@ -168,7 +169,8 @@ bool X509_Store::CRL_Data::operator<(const X509_Store::CRL_Data& other) const
/*
* X509_Store Constructor
*/
-X509_Store::X509_Store(u32bit slack, u32bit cache_timeout)
+X509_Store::X509_Store(std::chrono::seconds slack,
+ std::chrono::seconds cache_timeout)
{
revoked_info_valid = true;
@@ -211,10 +213,11 @@ X509_Code X509_Store::validate_cert(const X509_Certificate& cert,
if(chaining_result != VERIFIED)
return chaining_result;
- const u64bit current_time = system_time();
+ auto current_time = std::chrono::system_clock::now();
s32bit time_check = validity_check(cert.start_time(), cert.end_time(),
current_time, time_slack);
+
if(time_check < 0) return CERT_NOT_YET_VALID;
else if(time_check > 0) return CERT_HAS_EXPIRED;
@@ -373,7 +376,7 @@ X509_Code X509_Store::check_sig(const Cert_Info& cert_info,
*/
X509_Code X509_Store::check_sig(const X509_Object& object, Public_Key* key)
{
- std::auto_ptr<Public_Key> pub_key(key);
+ std::unique_ptr<Public_Key> pub_key(key);
try {
std::vector<std::string> sig_info =
@@ -528,8 +531,10 @@ void X509_Store::add_trusted_certs(DataSource& source)
*/
X509_Code X509_Store::add_crl(const X509_CRL& crl)
{
+ auto current_time = std::chrono::system_clock::now();
+
s32bit time_check = validity_check(crl.this_update(), crl.next_update(),
- system_time(), time_slack);
+ current_time, time_slack);
if(time_check < 0) return CRL_NOT_YET_VALID;
else if(time_check > 0) return CRL_HAS_EXPIRED;
@@ -568,8 +573,7 @@ X509_Code X509_Store::add_crl(const X509_CRL& crl)
revoked_info.serial = revoked_certs[j].serial_number();
revoked_info.auth_key_id = crl.authority_key_id();
- std::vector<CRL_Data>::iterator p =
- std::find(revoked.begin(), revoked.end(), revoked_info);
+ auto p = std::find(revoked.begin(), revoked.end(), revoked_info);
if(revoked_certs[j].reason_code() == REMOVE_FROM_CRL)
{
@@ -607,8 +611,8 @@ X509_Store::Cert_Info::Cert_Info(const X509_Certificate& c,
bool t) : cert(c), trusted(t)
{
checked = false;
+ last_checked = std::chrono::system_clock::time_point::min();
result = UNKNOWN_X509_ERROR;
- last_checked = 0;
}
/*
@@ -626,9 +630,9 @@ X509_Code X509_Store::Cert_Info::verify_result() const
*/
void X509_Store::Cert_Info::set_result(X509_Code code) const
{
- result = code;
- last_checked = system_time();
checked = true;
+ last_checked = std::chrono::system_clock::now();
+ result = code;
}
/*
@@ -642,16 +646,16 @@ bool X509_Store::Cert_Info::is_trusted() const
/*
* Check if this certificate has been verified
*/
-bool X509_Store::Cert_Info::is_verified(u32bit timeout) const
+bool X509_Store::Cert_Info::is_verified(std::chrono::seconds timeout) const
{
if(!checked)
return false;
if(result != VERIFIED && result != CERT_NOT_YET_VALID)
return true;
- const u64bit current_time = system_time();
+ auto now = std::chrono::system_clock::now();
- if(current_time > last_checked + timeout)
+ if(now > last_checked + timeout)
checked = false;
return checked;
diff --git a/src/cert/x509store/x509stor.h b/src/cert/x509store/x509stor.h
index b4b50022c..532db6190 100644
--- a/src/cert/x509store/x509stor.h
+++ b/src/cert/x509store/x509stor.h
@@ -11,6 +11,7 @@
#include <botan/x509cert.h>
#include <botan/x509_crl.h>
#include <botan/certstor.h>
+#include <functional>
namespace Botan {
@@ -70,14 +71,18 @@ class BOTAN_DLL X509_Store
void add_new_certstore(Certificate_Store*);
- X509_Store(u32bit time_slack = 24*60*60,
- u32bit cache_results = 30*60);
+ X509_Store& operator=(const X509_Store&) = delete;
+
+ /**
+ * @param slack the slack in checking validity times against current clock
+ * @param cache how long to cache validation results before rechecking
+ */
+ X509_Store(std::chrono::seconds slack = std::chrono::seconds(24*60*60),
+ std::chrono::seconds cache = std::chrono::seconds(30*60));
X509_Store(const X509_Store&);
~X509_Store();
private:
- X509_Store& operator=(const X509_Store&) { return (*this); }
-
class BOTAN_DLL CRL_Data
{
public:
@@ -91,7 +96,7 @@ class BOTAN_DLL X509_Store
class BOTAN_DLL Cert_Info
{
public:
- bool is_verified(u32bit timeout) const;
+ bool is_verified(std::chrono::seconds cache_timeout) const;
bool is_trusted() const;
X509_Code verify_result() const;
void set_result(X509_Code) const;
@@ -102,7 +107,7 @@ class BOTAN_DLL X509_Store
private:
mutable bool checked;
mutable X509_Code result;
- mutable u64bit last_checked;
+ mutable std::chrono::system_clock::time_point last_checked;
};
static X509_Code check_sig(const X509_Object&, Public_Key*);
@@ -122,7 +127,8 @@ class BOTAN_DLL X509_Store
std::vector<Cert_Info> certs;
std::vector<CRL_Data> revoked;
std::vector<Certificate_Store*> stores;
- u32bit time_slack, validation_cache_timeout;
+
+ std::chrono::seconds time_slack, validation_cache_timeout;
mutable bool revoked_info_valid;
};
diff --git a/src/cms/cms_dalg.cpp b/src/cms/cms_dalg.cpp
index 2935f3070..9fb5a29f2 100644
--- a/src/cms/cms_dalg.cpp
+++ b/src/cms/cms_dalg.cpp
@@ -28,7 +28,7 @@ SecureVector<byte> hash_of(const SecureVector<byte>& content,
Algorithm_Factory& af = global_state().algorithm_factory();
- std::auto_ptr<HashFunction> hash_fn(af.make_hash_function(hash_name));
+ std::unique_ptr<HashFunction> hash_fn(af.make_hash_function(hash_name));
return hash_fn->process(content);
}
@@ -51,10 +51,11 @@ std::vector<X509_Certificate> get_cert(BER_Decoder& signer_info,
iands.decode(issuer);
iands.decode(serial);
- found = store.get_certs(IandS_Match(issuer, BigInt::encode(serial)));
+ found = store.get_certs(
+ X509_Store_Search::by_issuer_and_serial(issuer, serial));
}
else if(id.type_tag == 0 && id.class_tag == CONSTRUCTED)
- found = store.get_certs(SKID_Match(id.value));
+ found = store.get_certs(X509_Store_Search::by_skid(id.value));
else
throw Decoding_Error("CMS: Unknown tag for cert identifier");
#endif
diff --git a/src/cms/cms_ealg.cpp b/src/cms/cms_ealg.cpp
index 4aee8afd8..2acffa5f7 100644
--- a/src/cms/cms_ealg.cpp
+++ b/src/cms/cms_ealg.cpp
@@ -57,7 +57,7 @@ SecureVector<byte> hash_of(const SecureVector<byte>& content,
const std::string& hash_name)
{
Algorithm_Factory& af = global_state().algorithm_factory();
- std::auto_ptr<HashFunction> hash_fn(af.make_hash_function(hash_name));
+ std::unique_ptr<HashFunction> hash_fn(af.make_hash_function(hash_name));
return hash_fn->process(content);
}
@@ -96,7 +96,7 @@ void CMS_Encoder::encrypt(RandomNumberGenerator& rng,
{
const std::string cipher = choose_algo(user_cipher, "TripleDES");
- std::auto_ptr<Public_Key> key(to.subject_public_key());
+ std::unique_ptr<Public_Key> key(to.subject_public_key());
const std::string algo = key->algo_name();
Key_Constraints constraints = to.constraints();
diff --git a/src/codec/pem/pem.cpp b/src/codec/pem/pem.cpp
index 005ec7310..52a22d8ef 100644
--- a/src/codec/pem/pem.cpp
+++ b/src/codec/pem/pem.cpp
@@ -110,6 +110,19 @@ SecureVector<byte> decode(DataSource& source, std::string& label)
return base64.read_all();
}
+SecureVector<byte> decode_check_label(const std::string& pem,
+ const std::string& label_want)
+ {
+ DataSource_Memory src(pem);
+ return decode_check_label(src, label_want);
+ }
+
+SecureVector<byte> decode(const std::string& pem, std::string& label)
+ {
+ DataSource_Memory src(pem);
+ return decode(src, label);
+ }
+
/*
* Search for a PEM signature
*/
diff --git a/src/codec/pem/pem.h b/src/codec/pem/pem.h
index d15bfe978..10267f029 100644
--- a/src/codec/pem/pem.h
+++ b/src/codec/pem/pem.h
@@ -14,18 +14,56 @@ namespace Botan {
namespace PEM_Code {
-/*
-* PEM Encoding/Decoding
+/**
+* Encode some binary data in PEM format
+*/
+BOTAN_DLL std::string encode(const byte der[],
+ size_t der_len,
+ const std::string& label,
+ size_t line_width = 64);
+
+/**
+* Encode some binary data in PEM format
*/
-BOTAN_DLL std::string encode(const byte[], size_t,
- const std::string&, size_t = 64);
-BOTAN_DLL std::string encode(const MemoryRegion<byte>&,
- const std::string&, size_t = 64);
+BOTAN_DLL std::string encode(const MemoryRegion<byte>& der,
+ const std::string& label,
+ size_t line_width = 64);
-BOTAN_DLL SecureVector<byte> decode(DataSource&, std::string&);
-BOTAN_DLL SecureVector<byte> decode_check_label(DataSource&,
- const std::string&);
-BOTAN_DLL bool matches(DataSource&, const std::string& = "",
+/**
+* Decode PEM data
+* @param label is set to the PEM label found for later inspection
+*/
+BOTAN_DLL SecureVector<byte> decode(DataSource& pem,
+ std::string& label);
+
+/**
+* Decode PEM data
+* @param label is set to the PEM label found for later inspection
+*/
+BOTAN_DLL SecureVector<byte> decode(const std::string& pem,
+ std::string& label);
+
+/**
+* Decode PEM data
+* @param label is what we expect the label to be
+*/
+BOTAN_DLL SecureVector<byte> decode_check_label(
+ DataSource& pem,
+ const std::string& label);
+
+/**
+* Decode PEM data
+* @param label is what we expect the label to be
+*/
+BOTAN_DLL SecureVector<byte> decode_check_label(
+ const std::string& pem,
+ const std::string& label);
+
+/**
+* Heuristic test for PEM data.
+*/
+BOTAN_DLL bool matches(DataSource& source,
+ const std::string& extra = "",
size_t search_range = 4096);
}
diff --git a/src/constructs/rfc3394/rfc3394.cpp b/src/constructs/rfc3394/rfc3394.cpp
index b000873fd..db6420ff3 100644
--- a/src/constructs/rfc3394/rfc3394.cpp
+++ b/src/constructs/rfc3394/rfc3394.cpp
@@ -39,7 +39,7 @@ SecureVector<byte> rfc3394_keywrap(const MemoryRegion<byte>& key,
if(key.size() % 8 != 0)
throw std::invalid_argument("Bad input key size for NIST key wrap");
- std::auto_ptr<BlockCipher> aes(make_aes(kek.length(), af));
+ std::unique_ptr<BlockCipher> aes(make_aes(kek.length(), af));
aes->set_key(kek);
const size_t n = key.size() / 8;
@@ -81,7 +81,7 @@ SecureVector<byte> rfc3394_keyunwrap(const MemoryRegion<byte>& key,
if(key.size() < 16 || key.size() % 8 != 0)
throw std::invalid_argument("Bad input key size for NIST key unwrap");
- std::auto_ptr<BlockCipher> aes(make_aes(kek.length(), af));
+ std::unique_ptr<BlockCipher> aes(make_aes(kek.length(), af));
aes->set_key(kek);
const size_t n = (key.size() - 8) / 8;
diff --git a/src/constructs/srp6/srp6.cpp b/src/constructs/srp6/srp6.cpp
index 0dfe2104b..0eccdc154 100644
--- a/src/constructs/srp6/srp6.cpp
+++ b/src/constructs/srp6/srp6.cpp
@@ -20,7 +20,7 @@ BigInt hash_seq(const std::string& hash_id,
const BigInt& in1,
const BigInt& in2)
{
- std::auto_ptr<HashFunction> hash_fn(
+ std::unique_ptr<HashFunction> hash_fn(
global_state().algorithm_factory().make_hash_function(hash_id));
hash_fn->update(BigInt::encode_1363(in1, pad_to));
@@ -35,7 +35,7 @@ BigInt hash_seq(const std::string& hash_id,
const BigInt& in2,
const BigInt& in3)
{
- std::auto_ptr<HashFunction> hash_fn(
+ std::unique_ptr<HashFunction> hash_fn(
global_state().algorithm_factory().make_hash_function(hash_id));
hash_fn->update(BigInt::encode_1363(in1, pad_to));
@@ -50,7 +50,7 @@ BigInt compute_x(const std::string& hash_id,
const std::string& password,
const MemoryRegion<byte>& salt)
{
- std::auto_ptr<HashFunction> hash_fn(
+ std::unique_ptr<HashFunction> hash_fn(
global_state().algorithm_factory().make_hash_function(hash_id));
hash_fn->update(identifier);
@@ -77,7 +77,7 @@ std::string srp6_group_identifier(const BigInt& N, const BigInt& g)
*/
try
{
- const std::string group_name = "modp/srp/" + to_string(N.bits());
+ const std::string group_name = "modp/srp/" + std::to_string(N.bits());
DL_Group group(group_name);
diff --git a/src/constructs/tss/tss.cpp b/src/constructs/tss/tss.cpp
index d0a18f534..cc34216f3 100644
--- a/src/constructs/tss/tss.cpp
+++ b/src/constructs/tss/tss.cpp
@@ -205,7 +205,7 @@ RTSS_Share::reconstruct(const std::vector<RTSS_Share>& shares)
byte hash_id = shares[0].contents[16];
- std::auto_ptr<HashFunction> hash(get_rtss_hash_by_id(hash_id));
+ std::unique_ptr<HashFunction> hash(get_rtss_hash_by_id(hash_id));
if(shares[0].size() != secret_len + hash->output_length() + RTSS_HEADER_SIZE + 1)
throw Decoding_Error("Bad RTSS length field in header");
diff --git a/src/credentials/credentials_manager.cpp b/src/credentials/credentials_manager.cpp
new file mode 100644
index 000000000..07d2979f9
--- /dev/null
+++ b/src/credentials/credentials_manager.cpp
@@ -0,0 +1,149 @@
+/*
+* Credentials Manager
+* (C) 2011,2012 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/credentials_manager.h>
+#include <botan/x509stor.h>
+
+namespace Botan {
+
+std::string Credentials_Manager::psk_identity_hint(const std::string&,
+ const std::string&)
+ {
+ return "";
+ }
+
+std::string Credentials_Manager::psk_identity(const std::string&,
+ const std::string&,
+ const std::string&)
+ {
+ return "";
+ }
+
+SymmetricKey Credentials_Manager::psk(const std::string&,
+ const std::string&,
+ const std::string& identity)
+ {
+ 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&)
+ {
+ return "";
+ }
+
+std::string Credentials_Manager::srp_password(const std::string&,
+ const std::string&,
+ const std::string&)
+ {
+ return "";
+ }
+
+bool Credentials_Manager::srp_verifier(const std::string&,
+ const std::string&,
+ const std::string&,
+ std::string&,
+ BigInt&,
+ MemoryRegion<byte>&,
+ bool)
+ {
+ return false;
+ }
+
+std::vector<X509_Certificate> Credentials_Manager::cert_chain(
+ const std::vector<std::string>&,
+ const std::string&,
+ const std::string&)
+ {
+ return std::vector<X509_Certificate>();
+ }
+
+std::vector<X509_Certificate> Credentials_Manager::cert_chain_single_type(
+ const std::string& cert_key_type,
+ const std::string& type,
+ const std::string& context)
+ {
+ std::vector<std::string> cert_types;
+ cert_types.push_back(cert_key_type);
+ return cert_chain(cert_types, type, context);
+ }
+
+Private_Key* Credentials_Manager::private_key_for(const X509_Certificate&,
+ const std::string&,
+ const std::string&)
+ {
+ return 0;
+ }
+
+std::vector<X509_Certificate>
+Credentials_Manager::trusted_certificate_authorities(
+ const std::string&,
+ const std::string&)
+ {
+ return std::vector<X509_Certificate>();
+ }
+
+void Credentials_Manager::verify_certificate_chain(
+ const std::string& type,
+ const std::string& purported_hostname,
+ const std::vector<X509_Certificate>& cert_chain)
+ {
+ if(cert_chain.empty())
+ throw std::invalid_argument("Certificate chain was empty");
+
+ 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;
+
+ for(size_t i = 0; i != CAs.size(); ++i)
+ store.add_cert(CAs[i], true);
+ for(size_t i = 0; i != cert_chain.size(); ++i)
+ store.add_cert(cert_chain[i]);
+
+ X509_Code result = store.validate_cert(cert_chain[0], X509_Store::TLS_SERVER);
+
+ 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, code " +
+ std::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
new file mode 100644
index 000000000..67da07eec
--- /dev/null
+++ b/src/credentials/credentials_manager.h
@@ -0,0 +1,153 @@
+/*
+* Credentials Manager
+* (C) 2011,2012 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_CREDENTIALS_MANAGER_H__
+#define BOTAN_CREDENTIALS_MANAGER_H__
+
+#include <botan/x509cert.h>
+#include <botan/symkey.h>
+#include <string>
+
+namespace Botan {
+
+class BigInt;
+
+/**
+* Interface for a credentials manager.
+*
+* A type is a fairly static value that represents the general nature
+* of the transaction occuring. Currently used values are "tls-client"
+* and "tls-server". Context represents a hostname, email address,
+* username, or other identifier.
+*/
+class BOTAN_DLL Credentials_Manager
+ {
+ public:
+ virtual ~Credentials_Manager() {}
+
+ virtual std::string psk_identity_hint(const std::string& type,
+ const std::string& context);
+
+ /**
+ * @param identity_hint was passed by the server (but may be empty)
+ * @return the PSK identity we want to use
+ */
+ virtual std::string psk_identity(const std::string& type,
+ const std::string& context,
+ const std::string& identity_hint);
+
+ /**
+ * @return the PSK used for identity, or throw an exception if no
+ * key exists
+ */
+ virtual SymmetricKey psk(const std::string& type,
+ const std::string& context,
+ 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.
+ */
+ virtual std::string srp_identifier(const std::string& type,
+ const std::string& context);
+
+ /**
+ * @param identifier specifies what identifier we want the
+ * password for. This will be a value previously returned
+ * by srp_identifier.
+ * @return password for client-side SRP auth, if available
+ for this identifier/type/context.
+ */
+ virtual std::string srp_password(const std::string& type,
+ const std::string& context,
+ const std::string& identifier);
+
+ /**
+ * Retrieve SRP verifier parameters
+ */
+ virtual bool srp_verifier(const std::string& type,
+ const std::string& context,
+ const std::string& identifier,
+ 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,
+ * 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_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,
+ const std::string& type,
+ const std::string& context);
+
+ /**
+ * 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 specifies the type of key requested
+ * ("RSA", "DSA", "ECDSA", etc)
+ */
+ std::vector<X509_Certificate> cert_chain_single_type(
+ const std::string& cert_key_type,
+ const std::string& type,
+ const std::string& context);
+
+ /**
+ * Return a list of the certificates of CAs that we trust in this
+ * type/context.
+ */
+ virtual std::vector<X509_Certificate> trusted_certificate_authorities(
+ const std::string& type,
+ const std::string& context);
+
+ /**
+ * Check the certificate chain is valid up to a trusted root, and
+ * optionally (if hostname != "") that the hostname given is
+ * consistent with the leaf certificate.
+ *
+ * This function should throw an exception derived from
+ * std::exception with an informative what() result if the
+ * certificate chain cannot be verified.
+ */
+ virtual void verify_certificate_chain(
+ const std::string& type,
+ const std::string& hostname,
+ const std::vector<X509_Certificate>& cert_chain);
+
+ /**
+ * @return private key associated with this certificate if we should
+ * use it with this context. cert was returned by cert_chain
+ * @note this object should retain ownership of the returned key;
+ * it should not be deleted by the caller.
+ */
+ virtual Private_Key* private_key_for(const X509_Certificate& cert,
+ const std::string& type,
+ const std::string& context);
+ };
+
+}
+
+#endif
diff --git a/src/credentials/info.txt b/src/credentials/info.txt
new file mode 100644
index 000000000..689c4f1ae
--- /dev/null
+++ b/src/credentials/info.txt
@@ -0,0 +1,6 @@
+define CREDENTIALS_MANAGER
+
+<requires>
+x509cert
+x509store
+</requires>
diff --git a/src/engine/dyn_engine/dyn_engine.cpp b/src/engine/dyn_engine/dyn_engine.cpp
index b76544d0f..2d8dbae3b 100644
--- a/src/engine/dyn_engine/dyn_engine.cpp
+++ b/src/engine/dyn_engine/dyn_engine.cpp
@@ -35,7 +35,7 @@ Dynamically_Loaded_Engine::Dynamically_Loaded_Engine(
if(mod_version != 20101003)
throw std::runtime_error("Incompatible version in " +
library_path + " of " +
- to_string(mod_version));
+ std::to_string(mod_version));
creator_func creator =
lib->resolve<creator_func>("create_engine");
diff --git a/src/engine/openssl/ossl_arc4.cpp b/src/engine/openssl/ossl_arc4.cpp
index 0c524003d..6469d263a 100644
--- a/src/engine/openssl/ossl_arc4.cpp
+++ b/src/engine/openssl/ossl_arc4.cpp
@@ -46,7 +46,7 @@ std::string ARC4_OpenSSL::name() const
{
if(SKIP == 0) return "ARC4";
if(SKIP == 256) return "MARK-4";
- else return "RC4_skip(" + to_string(SKIP) + ")";
+ else return "RC4_skip(" + std::to_string(SKIP) + ")";
}
/*
diff --git a/src/entropy/hres_timer/hres_timer.cpp b/src/entropy/hres_timer/hres_timer.cpp
index dd1fc6f7c..c6b31d996 100644
--- a/src/entropy/hres_timer/hres_timer.cpp
+++ b/src/entropy/hres_timer/hres_timer.cpp
@@ -7,9 +7,8 @@
#include <botan/internal/hres_timer.h>
#include <botan/cpuid.h>
-#include <botan/time.h>
-#if defined(BOTAN_TARGET_OS_IS_WINDOWS)
+#if defined(BOTAN_TARGET_OS_HAS_QUERY_PERF_COUNTER)
#include <windows.h>
#endif
@@ -20,8 +19,7 @@ namespace Botan {
*/
void High_Resolution_Timestamp::poll(Entropy_Accumulator& accum)
{
- // If Windows, grab the Performance Counter (usually TSC or PIT)
-#if defined(BOTAN_TARGET_OS_IS_WINDOWS)
+#if defined(BOTAN_TARGET_OS_HAS_QUERY_PERF_COUNTER)
{
LARGE_INTEGER tv;
::QueryPerformanceCounter(&tv);
diff --git a/src/entropy/proc_walk/es_ftw.cpp b/src/entropy/proc_walk/es_ftw.cpp
index 8b4408aee..407034891 100644
--- a/src/entropy/proc_walk/es_ftw.cpp
+++ b/src/entropy/proc_walk/es_ftw.cpp
@@ -71,10 +71,8 @@ std::pair<struct dirent*, std::string> Directory_Walker::get_next_dirent()
{
while(m_cur_dir.first)
{
- struct dirent* dir = ::readdir(m_cur_dir.first);
-
- if(dir)
- return std::make_pair<struct dirent*, std::string>(dir, m_cur_dir.second);
+ if(struct dirent* dir = ::readdir(m_cur_dir.first))
+ return std::make_pair(dir, m_cur_dir.second);
::closedir(m_cur_dir.first);
m_cur_dir = std::make_pair<DIR*, std::string>(0, "");
diff --git a/src/filters/bzip2/bzip2.cpp b/src/filters/bzip2/bzip2.cpp
index a291c1173..18a53558c 100644
--- a/src/filters/bzip2/bzip2.cpp
+++ b/src/filters/bzip2/bzip2.cpp
@@ -48,7 +48,7 @@ void* bzip_malloc(void* info_ptr, int n, int size)
void bzip_free(void* info_ptr, void* ptr)
{
Bzip_Alloc_Info* info = static_cast<Bzip_Alloc_Info*>(info_ptr);
- std::map<void*, size_t>::const_iterator i = info->current_allocs.find(ptr);
+ auto i = info->current_allocs.find(ptr);
if(i == info->current_allocs.end())
throw Invalid_Argument("bzip_free: Got pointer not allocated by us");
info->alloc->deallocate(ptr, i->second);
diff --git a/src/filters/codec_filt/b64_filt.cpp b/src/filters/codec_filt/b64_filt.cpp
index 9341571d4..b804b33c7 100644
--- a/src/filters/codec_filt/b64_filt.cpp
+++ b/src/filters/codec_filt/b64_filt.cpp
@@ -79,7 +79,7 @@ void Base64_Encoder::do_output(const byte input[], size_t length)
*/
void Base64_Encoder::write(const byte input[], size_t length)
{
- in.copy(position, input, length);
+ buffer_insert(in, position, input, length);
if(position + length >= in.size())
{
encode_and_send(&in[0], in.size());
@@ -91,7 +91,7 @@ void Base64_Encoder::write(const byte input[], size_t length)
input += in.size();
length -= in.size();
}
- in.copy(input, length);
+ copy_mem(&in[0], input, length);
position = 0;
}
position += length;
diff --git a/src/filters/codec_filt/hex_filt.cpp b/src/filters/codec_filt/hex_filt.cpp
index 3d56beec4..e85bdb17e 100644
--- a/src/filters/codec_filt/hex_filt.cpp
+++ b/src/filters/codec_filt/hex_filt.cpp
@@ -75,7 +75,7 @@ void Hex_Encoder::encode_and_send(const byte block[], size_t length)
*/
void Hex_Encoder::write(const byte input[], size_t length)
{
- in.copy(position, input, length);
+ buffer_insert(in, position, input, length);
if(position + length >= in.size())
{
encode_and_send(&in[0], in.size());
@@ -87,7 +87,7 @@ void Hex_Encoder::write(const byte input[], size_t length)
input += in.size();
length -= in.size();
}
- in.copy(input, length);
+ copy_mem(&in[0], input, length);
position = 0;
}
position += length;
diff --git a/src/filters/data_snk.h b/src/filters/data_snk.h
index e31cb9d28..6b9da0b4d 100644
--- a/src/filters/data_snk.h
+++ b/src/filters/data_snk.h
@@ -22,9 +22,9 @@ class BOTAN_DLL DataSink : public Filter
bool attachable() { return false; }
DataSink() {}
virtual ~DataSink() {}
- private:
- DataSink& operator=(const DataSink&) { return (*this); }
- DataSink(const DataSink&);
+
+ DataSink& operator=(const DataSink&) = delete;
+ DataSink(const DataSink&) = delete;
};
/**
diff --git a/src/filters/data_src.h b/src/filters/data_src.h
index a274de8e2..d2d51fe23 100644
--- a/src/filters/data_src.h
+++ b/src/filters/data_src.h
@@ -81,9 +81,8 @@ class BOTAN_DLL DataSource
DataSource() {}
virtual ~DataSource() {}
- private:
- DataSource& operator=(const DataSource&) { return (*this); }
- DataSource(const DataSource&);
+ DataSource& operator=(const DataSource&) = delete;
+ DataSource(const DataSource&) = delete;
};
/**
diff --git a/src/filters/filter.h b/src/filters/filter.h
index 962b2816e..b62846075 100644
--- a/src/filters/filter.h
+++ b/src/filters/filter.h
@@ -78,9 +78,6 @@ class BOTAN_DLL Filter
Filter();
private:
- Filter(const Filter&) {}
- Filter& operator=(const Filter&) { return (*this); }
-
/**
* Start a new message in *this and all following filters. Only for
* internal use, not intended for use in client applications.
@@ -96,6 +93,9 @@ class BOTAN_DLL Filter
friend class Pipe;
friend class Fanout_Filter;
+ Filter(const Filter&) = delete;
+ Filter& operator=(const Filter&) = delete;
+
size_t total_ports() const;
size_t current_port() const { return port_num; }
diff --git a/src/filters/modes/cfb/cfb.cpp b/src/filters/modes/cfb/cfb.cpp
index 8f7471c98..9aa6f6159 100644
--- a/src/filters/modes/cfb/cfb.cpp
+++ b/src/filters/modes/cfb/cfb.cpp
@@ -26,7 +26,7 @@ CFB_Encryption::CFB_Encryption(BlockCipher* ciph, size_t fback_bits)
if(feedback == 0 || fback_bits % 8 != 0 || feedback > cipher->block_size())
throw Invalid_Argument("CFB_Encryption: Invalid feedback size " +
- to_string(fback_bits));
+ std::to_string(fback_bits));
}
/*
@@ -46,7 +46,7 @@ CFB_Encryption::CFB_Encryption(BlockCipher* ciph,
if(feedback == 0 || fback_bits % 8 != 0 || feedback > cipher->block_size())
throw Invalid_Argument("CFB_Encryption: Invalid feedback size " +
- to_string(fback_bits));
+ std::to_string(fback_bits));
set_key(key);
set_iv(iv);
@@ -82,7 +82,10 @@ void CFB_Encryption::write(const byte input[], size_t length)
{
for(size_t j = 0; j != cipher->block_size() - feedback; ++j)
state[j] = state[j + feedback];
- state.copy(cipher->block_size() - feedback, buffer, feedback);
+
+ buffer_insert(state, cipher->block_size() - feedback,
+ &buffer[0], feedback);
+
cipher->encrypt(state, buffer);
position = 0;
}
@@ -103,7 +106,7 @@ CFB_Decryption::CFB_Decryption(BlockCipher* ciph, size_t fback_bits)
if(feedback == 0 || fback_bits % 8 != 0 || feedback > cipher->block_size())
throw Invalid_Argument("CFB_Decryption: Invalid feedback size " +
- to_string(fback_bits));
+ std::to_string(fback_bits));
}
/*
@@ -123,7 +126,7 @@ CFB_Decryption::CFB_Decryption(BlockCipher* ciph,
if(feedback == 0 || fback_bits % 8 != 0 || feedback > cipher->block_size())
throw Invalid_Argument("CFB_Decryption: Invalid feedback size " +
- to_string(fback_bits));
+ std::to_string(fback_bits));
set_key(key);
set_iv(iv);
@@ -151,7 +154,7 @@ void CFB_Decryption::write(const byte input[], size_t length)
size_t xored = std::min(feedback - position, length);
xor_buf(&buffer[position], input, xored);
send(&buffer[position], xored);
- buffer.copy(position, input, xored);
+ buffer_insert(buffer, position, input, xored);
input += xored;
length -= xored;
position += xored;
@@ -159,7 +162,10 @@ void CFB_Decryption::write(const byte input[], size_t length)
{
for(size_t j = 0; j != cipher->block_size() - feedback; ++j)
state[j] = state[j + feedback];
- state.copy(cipher->block_size() - feedback, buffer, feedback);
+
+ buffer_insert(state, cipher->block_size() - feedback,
+ &buffer[0], feedback);
+
cipher->encrypt(state, buffer);
position = 0;
}
diff --git a/src/filters/modes/cts/cts.cpp b/src/filters/modes/cts/cts.cpp
index c654c8719..694d7d524 100644
--- a/src/filters/modes/cts/cts.cpp
+++ b/src/filters/modes/cts/cts.cpp
@@ -67,7 +67,7 @@ void CTS_Encryption::encrypt(const byte block[])
void CTS_Encryption::write(const byte input[], size_t length)
{
size_t copied = std::min<size_t>(buffer.size() - position, length);
- buffer.copy(position, input, copied);
+ buffer_insert(buffer, position, input, copied);
length -= copied;
input += copied;
position += copied;
@@ -91,7 +91,7 @@ void CTS_Encryption::write(const byte input[], size_t length)
copy_mem(&buffer[0], &buffer[cipher->block_size()], cipher->block_size());
position = cipher->block_size();
}
- buffer.copy(position, input, length);
+ buffer_insert(buffer, position, input, length);
position += length;
}
@@ -161,7 +161,7 @@ void CTS_Decryption::decrypt(const byte block[])
cipher->decrypt(block, &temp[0]);
xor_buf(temp, state, cipher->block_size());
send(temp, cipher->block_size());
- state.copy(block, cipher->block_size());
+ copy_mem(&state[0], block, cipher->block_size());
}
/*
@@ -170,7 +170,7 @@ void CTS_Decryption::decrypt(const byte block[])
void CTS_Decryption::write(const byte input[], size_t length)
{
size_t copied = std::min<size_t>(buffer.size() - position, length);
- buffer.copy(position, input, copied);
+ buffer_insert(buffer, position, input, copied);
length -= copied;
input += copied;
position += copied;
@@ -194,7 +194,7 @@ void CTS_Decryption::write(const byte input[], size_t length)
copy_mem(&buffer[0], &buffer[cipher->block_size()], cipher->block_size());
position = cipher->block_size();
}
- buffer.copy(position, input, length);
+ buffer_insert(buffer, position, input, length);
position += length;
}
diff --git a/src/filters/modes/eax/eax.cpp b/src/filters/modes/eax/eax.cpp
index 6d6d9ec18..791286cc6 100644
--- a/src/filters/modes/eax/eax.cpp
+++ b/src/filters/modes/eax/eax.cpp
@@ -45,7 +45,7 @@ EAX_Base::EAX_Base(BlockCipher* cipher, size_t tag_size) :
ctr = new CTR_BE(cipher); // takes ownership
if(tag_size % 8 != 0 || TAG_SIZE == 0 || TAG_SIZE > cmac->output_length())
- throw Invalid_Argument(name() + ": Bad tag size " + to_string(tag_size));
+ throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(tag_size));
}
/*
diff --git a/src/filters/modes/eax/eax_dec.cpp b/src/filters/modes/eax/eax_dec.cpp
index 72e2249ac..d14ba5e70 100644
--- a/src/filters/modes/eax/eax_dec.cpp
+++ b/src/filters/modes/eax/eax_dec.cpp
@@ -47,7 +47,7 @@ void EAX_Decryption::write(const byte input[], size_t length)
{
const size_t copied = std::min<size_t>(length, queue.size() - queue_end);
- queue.copy(queue_end, input, copied);
+ buffer_insert(queue, queue_end, input, copied);
input += copied;
length -= copied;
queue_end += copied;
@@ -63,8 +63,8 @@ void EAX_Decryption::write(const byte input[], size_t length)
queue_start >= queue.size() / 2)
{
SecureVector<byte> queue_data(TAG_SIZE);
- queue_data.copy(&queue[queue_start], TAG_SIZE);
- queue.copy(&queue_data[0], TAG_SIZE);
+ copy_mem(&queue_data[0], &queue[queue_start], TAG_SIZE);
+ copy_mem(&queue[0], &queue_data[0], TAG_SIZE);
queue_start = 0;
queue_end = TAG_SIZE;
}
diff --git a/src/filters/modes/xts/xts.cpp b/src/filters/modes/xts/xts.cpp
index 2d2957088..42b1f2bf0 100644
--- a/src/filters/modes/xts/xts.cpp
+++ b/src/filters/modes/xts/xts.cpp
@@ -92,14 +92,14 @@ void XTS_Encryption::set_iv(const InitializationVector& iv)
const size_t blocks_in_tweak = tweak.size() / cipher->block_size();
- tweak.copy(iv.begin(), iv.length());
+ tweak.assign(iv.begin(), iv.end());
cipher2->encrypt(tweak);
for(size_t i = 1; i < blocks_in_tweak; ++i)
{
- tweak.copy(i*cipher->block_size(),
- &tweak[(i-1)*cipher->block_size()],
- cipher->block_size());
+ buffer_insert(tweak, i*cipher->block_size(),
+ &tweak[(i-1)*cipher->block_size()],
+ cipher->block_size());
poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
}
@@ -151,13 +151,15 @@ void XTS_Encryption::buffered_block(const byte input[], size_t length)
send(temp, to_proc_bytes);
- tweak.copy(&tweak[(to_proc-1)*cipher->block_size()],
- cipher->block_size());
+ copy_mem(&tweak[0],
+ &tweak[(to_proc-1)*cipher->block_size()],
+ cipher->block_size());
+
poly_double(&tweak[0], cipher->block_size());
for(size_t i = 1; i < blocks_in_tweak; ++i)
{
- tweak.copy(i*cipher->block_size(),
+ buffer_insert(tweak, i*cipher->block_size(),
&tweak[(i-1)*cipher->block_size()],
cipher->block_size());
@@ -264,12 +266,12 @@ void XTS_Decryption::set_iv(const InitializationVector& iv)
const size_t blocks_in_tweak = tweak.size() / cipher->block_size();
- tweak.copy(iv.begin(), iv.length());
+ tweak.assign(iv.begin(), iv.end());
cipher2->encrypt(tweak);
for(size_t i = 1; i < blocks_in_tweak; ++i)
{
- tweak.copy(i*cipher->block_size(),
+ buffer_insert(tweak, i*cipher->block_size(),
&tweak[(i-1)*cipher->block_size()],
cipher->block_size());
@@ -324,15 +326,17 @@ void XTS_Decryption::buffered_block(const byte input[], size_t input_length)
send(temp, to_proc_bytes);
- tweak.copy(&tweak[(to_proc-1)*cipher->block_size()],
- cipher->block_size());
+ copy_mem(&tweak[0],
+ &tweak[(to_proc-1)*cipher->block_size()],
+ cipher->block_size());
+
poly_double(&tweak[0], cipher->block_size());
for(size_t i = 1; i < blocks_in_tweak; ++i)
{
- tweak.copy(i*cipher->block_size(),
- &tweak[(i-1)*cipher->block_size()],
- cipher->block_size());
+ buffer_insert(tweak, i*cipher->block_size(),
+ &tweak[(i-1)*cipher->block_size()],
+ cipher->block_size());
poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
}
diff --git a/src/filters/pipe.cpp b/src/filters/pipe.cpp
index 85a6cddab..2c5e07589 100644
--- a/src/filters/pipe.cpp
+++ b/src/filters/pipe.cpp
@@ -43,11 +43,12 @@ Pipe::Pipe(Filter* f1, Filter* f2, Filter* f3, Filter* f4)
/*
* Pipe Constructor
*/
-Pipe::Pipe(Filter* filter_array[], size_t count)
+Pipe::Pipe(std::initializer_list<Filter*> args)
{
init();
- for(size_t j = 0; j != count; ++j)
- append(filter_array[j]);
+
+ for(auto i = args.begin(); i != args.end(); ++i)
+ append(*i);
}
/*
diff --git a/src/filters/pipe.h b/src/filters/pipe.h
index e5cb5f445..6df518d3e 100644
--- a/src/filters/pipe.h
+++ b/src/filters/pipe.h
@@ -11,6 +11,7 @@
#include <botan/data_src.h>
#include <botan/filter.h>
#include <botan/exceptn.h>
+#include <initializer_list>
#include <iosfwd>
namespace Botan {
@@ -42,7 +43,7 @@ class BOTAN_DLL Pipe : public DataSource
*/
Invalid_Message_Number(const std::string& where, message_id msg) :
Invalid_Argument("Pipe::" + where + ": Invalid message number " +
- to_string(msg))
+ std::to_string(msg))
{}
};
@@ -264,15 +265,16 @@ class BOTAN_DLL Pipe : public DataSource
Pipe(Filter* = 0, Filter* = 0, Filter* = 0, Filter* = 0);
/**
- * Construct a Pipe from range of filters passed as an array
+ * Construct a Pipe from a list of filters
* @param filters the set of filters to use
- * @param count the number of elements in filters
*/
- Pipe(Filter* filters[], size_t count);
+ Pipe(std::initializer_list<Filter*> filters);
+
+ Pipe(const Pipe&) = delete;
+ Pipe& operator=(const Pipe&) = delete;
+
~Pipe();
private:
- Pipe(const Pipe&) : DataSource() {}
- Pipe& operator=(const Pipe&) { return (*this); }
void init();
void destruct(Filter*);
void find_endpoints(Filter*);
diff --git a/src/filters/secqueue.cpp b/src/filters/secqueue.cpp
index 8dc95ea99..f65aff2a9 100644
--- a/src/filters/secqueue.cpp
+++ b/src/filters/secqueue.cpp
@@ -208,4 +208,9 @@ bool SecureQueue::end_of_data() const
return (size() == 0);
}
+bool SecureQueue::empty() const
+ {
+ return (size() == 0);
+ }
+
}
diff --git a/src/filters/secqueue.h b/src/filters/secqueue.h
index 632ae857d..e773b69bc 100644
--- a/src/filters/secqueue.h
+++ b/src/filters/secqueue.h
@@ -28,6 +28,8 @@ class BOTAN_DLL SecureQueue : public Fanout_Filter, public DataSource
bool end_of_data() const;
+ bool empty() const;
+
/**
* @return number of bytes available in the queue
*/
diff --git a/src/filters/zlib/zlib.cpp b/src/filters/zlib/zlib.cpp
index 0f88b5558..169146826 100644
--- a/src/filters/zlib/zlib.cpp
+++ b/src/filters/zlib/zlib.cpp
@@ -47,7 +47,7 @@ void* zlib_malloc(void* info_ptr, unsigned int n, unsigned int size)
void zlib_free(void* info_ptr, void* ptr)
{
Zlib_Alloc_Info* info = static_cast<Zlib_Alloc_Info*>(info_ptr);
- std::map<void*, size_t>::const_iterator i = info->current_allocs.find(ptr);
+ auto i = info->current_allocs.find(ptr);
if(i == info->current_allocs.end())
throw Invalid_Argument("zlib_free: Got pointer not allocated by us");
info->alloc->deallocate(ptr, i->second);
@@ -91,10 +91,12 @@ class Zlib_Stream
/*
* Zlib_Compression Constructor
*/
-Zlib_Compression::Zlib_Compression(size_t l) :
- level((l >= 9) ? 9 : l), buffer(DEFAULT_BUFFERSIZE)
+Zlib_Compression::Zlib_Compression(size_t l, bool raw_deflate) :
+ level((l >= 9) ? 9 : l),
+ raw_deflate(raw_deflate),
+ buffer(DEFAULT_BUFFERSIZE),
+ zlib(0)
{
- zlib = 0;
}
/*
@@ -104,7 +106,17 @@ void Zlib_Compression::start_msg()
{
clear();
zlib = new Zlib_Stream;
- if(deflateInit(&(zlib->stream), level) != Z_OK)
+
+ int res = deflateInit2(&(zlib->stream),
+ level,
+ Z_DEFLATED,
+ (raw_deflate ? -15 : 15),
+ 8,
+ Z_DEFAULT_STRATEGY);
+
+ if(res == Z_STREAM_ERROR)
+ throw Invalid_Argument("Bad setting in deflateInit2");
+ else if(res != Z_OK)
throw Memory_Exhaustion();
}
@@ -185,10 +197,12 @@ void Zlib_Compression::clear()
/*
* Zlib_Decompression Constructor
*/
-Zlib_Decompression::Zlib_Decompression() : buffer(DEFAULT_BUFFERSIZE)
+Zlib_Decompression::Zlib_Decompression(bool raw_deflate) :
+ raw_deflate(raw_deflate),
+ buffer(DEFAULT_BUFFERSIZE),
+ zlib(0),
+ no_writes(true)
{
- zlib = 0;
- no_writes = true;
}
/*
@@ -198,7 +212,8 @@ void Zlib_Decompression::start_msg()
{
clear();
zlib = new Zlib_Stream;
- if(inflateInit(&(zlib->stream)) != Z_OK)
+
+ if(inflateInit2(&(zlib->stream), (raw_deflate ? -15 : 15)) != Z_OK)
throw Memory_Exhaustion();
}
diff --git a/src/filters/zlib/zlib.h b/src/filters/zlib/zlib.h
index 77ec5eecc..60117f2bc 100644
--- a/src/filters/zlib/zlib.h
+++ b/src/filters/zlib/zlib.h
@@ -31,15 +31,20 @@ class BOTAN_DLL Zlib_Compression : public Filter
void flush();
/**
- @param level how much effort to use on compressing (0 to 9);
- higher levels are slower but tend to give better compression
+ * @param level how much effort to use on compressing (0 to 9);
+ * higher levels are slower but tend to give better
+ * compression
+ * @param raw_deflate if true no zlib header/trailer will be used
*/
- Zlib_Compression(size_t level = 6);
+ Zlib_Compression(size_t level = 6,
+ bool raw_deflate = false);
~Zlib_Compression() { clear(); }
private:
void clear();
const size_t level;
+ const bool raw_deflate;
+
SecureVector<byte> buffer;
class Zlib_Stream* zlib;
};
@@ -56,10 +61,13 @@ class BOTAN_DLL Zlib_Decompression : public Filter
void start_msg();
void end_msg();
- Zlib_Decompression();
+ Zlib_Decompression(bool raw_deflate = false);
~Zlib_Decompression() { clear(); }
private:
void clear();
+
+ const bool raw_deflate;
+
SecureVector<byte> buffer;
class Zlib_Stream* zlib;
bool no_writes;
diff --git a/src/hash/gost_3411/gost_3411.cpp b/src/hash/gost_3411/gost_3411.cpp
index c0f39da47..6e56c2b97 100644
--- a/src/hash/gost_3411/gost_3411.cpp
+++ b/src/hash/gost_3411/gost_3411.cpp
@@ -43,7 +43,7 @@ void GOST_34_11::add_data(const byte input[], size_t length)
if(position)
{
- buffer.copy(position, input, length);
+ buffer_insert(buffer, position, input, length);
if(position + length >= hash_block_size())
{
@@ -60,7 +60,7 @@ void GOST_34_11::add_data(const byte input[], size_t length)
if(full_blocks)
compress_n(input, full_blocks);
- buffer.copy(position, input + full_blocks * hash_block_size(), remaining);
+ buffer_insert(buffer, position, input + full_blocks * hash_block_size(), remaining);
position += remaining;
}
@@ -210,7 +210,7 @@ void GOST_34_11::compress_n(const byte input[], size_t blocks)
S2[30] = S[ 2] ^ S[ 4] ^ S[ 8] ^ S[14] ^ S[16] ^ S[18] ^ S[22] ^ S[24] ^ S[28] ^ S[30];
S2[31] = S[ 3] ^ S[ 5] ^ S[ 9] ^ S[15] ^ S[17] ^ S[19] ^ S[23] ^ S[25] ^ S[29] ^ S[31];
- hash.copy(S2, 32);
+ copy_mem(&hash[0], &S2[0], 32);
}
}
diff --git a/src/hash/keccak/keccak.cpp b/src/hash/keccak/keccak.cpp
index 922167b61..107055509 100644
--- a/src/hash/keccak/keccak.cpp
+++ b/src/hash/keccak/keccak.cpp
@@ -112,12 +112,12 @@ Keccak_1600::Keccak_1600(size_t output_bits) :
if(output_bits != 224 && output_bits != 256 &&
output_bits != 384 && output_bits != 512)
throw Invalid_Argument("Keccak_1600: Invalid output length " +
- to_string(output_bits));
+ std::to_string(output_bits));
}
std::string Keccak_1600::name() const
{
- return "Keccak-1600(" + to_string(output_bits) + ")";
+ return "Keccak-1600(" + std::to_string(output_bits) + ")";
}
HashFunction* Keccak_1600::clone() const
diff --git a/src/hash/md2/md2.cpp b/src/hash/md2/md2.cpp
index 761528dc6..8f6a90208 100644
--- a/src/hash/md2/md2.cpp
+++ b/src/hash/md2/md2.cpp
@@ -39,7 +39,7 @@ void MD2::hash(const byte input[])
0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33,
0x9F, 0x11, 0x83, 0x14 };
- X.copy(16, input, hash_block_size());
+ buffer_insert(X, 16, input, hash_block_size());
xor_buf(&X[32], &X[0], &X[16], hash_block_size());
byte T = 0;
@@ -66,7 +66,7 @@ void MD2::hash(const byte input[])
*/
void MD2::add_data(const byte input[], size_t length)
{
- buffer.copy(position, input, length);
+ buffer_insert(buffer, position, input, length);
if(position + length >= hash_block_size())
{
@@ -79,7 +79,7 @@ void MD2::add_data(const byte input[], size_t length)
input += hash_block_size();
length -= hash_block_size();
}
- buffer.copy(input, length);
+ copy_mem(&buffer[0], input, length);
position = 0;
}
position += length;
diff --git a/src/hash/mdx_hash/mdx_hash.cpp b/src/hash/mdx_hash/mdx_hash.cpp
index 7bfcf6592..81042c1fa 100644
--- a/src/hash/mdx_hash/mdx_hash.cpp
+++ b/src/hash/mdx_hash/mdx_hash.cpp
@@ -44,7 +44,7 @@ void MDx_HashFunction::add_data(const byte input[], size_t length)
if(position)
{
- buffer.copy(position, input, length);
+ buffer_insert(buffer, position, input, length);
if(position + length >= buffer.size())
{
@@ -61,7 +61,7 @@ void MDx_HashFunction::add_data(const byte input[], size_t length)
if(full_blocks)
compress_n(input, full_blocks);
- buffer.copy(position, input + full_blocks * buffer.size(), remaining);
+ buffer_insert(buffer, position, input + full_blocks * buffer.size(), remaining);
position += remaining;
}
diff --git a/src/hash/par_hash/par_hash.cpp b/src/hash/par_hash/par_hash.cpp
index 328be6a11..df47780ef 100644
--- a/src/hash/par_hash/par_hash.cpp
+++ b/src/hash/par_hash/par_hash.cpp
@@ -1,11 +1,12 @@
/*
* Parallel
-* (C) 1999-2007 Jack Lloyd
+* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
#include <botan/par_hash.h>
+#include <botan/parsing.h>
namespace Botan {
@@ -14,20 +15,21 @@ namespace Botan {
*/
void Parallel::add_data(const byte input[], size_t length)
{
- for(size_t i = 0; i != hashes.size(); ++i)
- hashes[i]->update(input, length);
+ for(auto hash : hashes)
+ hash->update(input, length);
}
/*
* Finalize the hash
*/
-void Parallel::final_result(byte hash[])
+void Parallel::final_result(byte out[])
{
- size_t offset = 0;
- for(size_t i = 0; i != hashes.size(); ++i)
+ u32bit offset = 0;
+
+ for(auto hash : hashes)
{
- hashes[i]->final(hash + offset);
- offset += hashes[i]->output_length();
+ hash->final(out + offset);
+ offset += hash->output_length();
}
}
@@ -37,8 +39,9 @@ void Parallel::final_result(byte hash[])
size_t Parallel::output_length() const
{
size_t sum = 0;
- for(size_t i = 0; i != hashes.size(); ++i)
- sum += hashes[i]->output_length();
+
+ for(auto hash : hashes)
+ sum += hash->output_length();
return sum;
}
@@ -47,14 +50,12 @@ size_t Parallel::output_length() const
*/
std::string Parallel::name() const
{
- std::string hash_names;
- for(size_t i = 0; i != hashes.size(); ++i)
- {
- if(i)
- hash_names += ',';
- hash_names += hashes[i]->name();
- }
- return "Parallel(" + hash_names + ")";
+ std::vector<std::string> names;
+
+ for(auto hash : hashes)
+ names.push_back(hash->name());
+
+ return "Parallel(" + string_join(names, ',') + ")";
}
/*
@@ -63,8 +64,10 @@ std::string Parallel::name() const
HashFunction* Parallel::clone() const
{
std::vector<HashFunction*> hash_copies;
- for(size_t i = 0; i != hashes.size(); ++i)
- hash_copies.push_back(hashes[i]->clone());
+
+ for(auto hash : hashes)
+ hash_copies.push_back(hash->clone());
+
return new Parallel(hash_copies);
}
@@ -73,8 +76,8 @@ HashFunction* Parallel::clone() const
*/
void Parallel::clear()
{
- for(size_t i = 0; i != hashes.size(); ++i)
- hashes[i]->clear();
+ for(auto hash : hashes)
+ hash->clear();
}
/*
@@ -90,8 +93,8 @@ Parallel::Parallel(const std::vector<HashFunction*>& hash_in) :
*/
Parallel::~Parallel()
{
- for(size_t i = 0; i != hashes.size(); ++i)
- delete hashes[i];
+ for(auto hash : hashes)
+ delete hash;
}
}
diff --git a/src/hash/skein/skein_512.cpp b/src/hash/skein/skein_512.cpp
index 571bf9c0b..2458bf5f0 100644
--- a/src/hash/skein/skein_512.cpp
+++ b/src/hash/skein/skein_512.cpp
@@ -185,8 +185,9 @@ Skein_512::Skein_512(size_t arg_output_bits,
std::string Skein_512::name() const
{
if(personalization != "")
- return "Skein-512(" + to_string(output_bits) + "," + personalization + ")";
- return "Skein-512(" + to_string(output_bits) + ")";
+ return "Skein-512(" + std::to_string(output_bits) + "," +
+ personalization + ")";
+ return "Skein-512(" + std::to_string(output_bits) + ")";
}
HashFunction* Skein_512::clone() const
@@ -209,7 +210,7 @@ void Skein_512::add_data(const byte input[], size_t length)
if(buf_pos)
{
- buffer.copy(buf_pos, input, length);
+ buffer_insert(buffer, buf_pos, input, length);
if(buf_pos + length > 64)
{
ubi_512(H, T, &buffer[0], buffer.size());
@@ -227,7 +228,7 @@ void Skein_512::add_data(const byte input[], size_t length)
length -= full_blocks * 64;
- buffer.copy(buf_pos, input + full_blocks * 64, length);
+ buffer_insert(buffer, buf_pos, input + full_blocks * 64, length);
buf_pos += length;
}
@@ -250,7 +251,7 @@ void Skein_512::final_result(byte out[])
{
const size_t to_proc = std::min<size_t>(out_bytes, 64);
- H_out.copy(&H[0], 8);
+ copy_mem(&H_out[0], &H[0], 8);
reset_tweak(T, SKEIN_OUTPUT, true);
ubi_512(H_out, T, counter, sizeof(counter));
diff --git a/src/hash/tiger/tiger.cpp b/src/hash/tiger/tiger.cpp
index 6f40f84c8..daa0939b9 100644
--- a/src/hash/tiger/tiger.cpp
+++ b/src/hash/tiger/tiger.cpp
@@ -160,7 +160,8 @@ void Tiger::clear()
*/
std::string Tiger::name() const
{
- return "Tiger(" + to_string(output_length()) + "," + to_string(passes) + ")";
+ return "Tiger(" + std::to_string(output_length()) + "," +
+ std::to_string(passes) + ")";
}
/*
@@ -175,11 +176,11 @@ Tiger::Tiger(size_t hash_len, size_t passes) :
{
if(output_length() != 16 && output_length() != 20 && output_length() != 24)
throw Invalid_Argument("Tiger: Illegal hash output size: " +
- to_string(output_length()));
+ std::to_string(output_length()));
if(passes < 3)
throw Invalid_Argument("Tiger: Invalid number of passes: "
- + to_string(passes));
+ + std::to_string(passes));
clear();
}
diff --git a/src/kdf/prf_tls/info.txt b/src/kdf/prf_tls/info.txt
index 9531a6a83..113c92251 100644
--- a/src/kdf/prf_tls/info.txt
+++ b/src/kdf/prf_tls/info.txt
@@ -1,4 +1,5 @@
define TLS_V10_PRF
+define TLS_V12_PRF
<requires>
hmac
diff --git a/src/kdf/prf_tls/prf_tls.cpp b/src/kdf/prf_tls/prf_tls.cpp
index 2b57cdd25..1236e13c7 100644
--- a/src/kdf/prf_tls/prf_tls.cpp
+++ b/src/kdf/prf_tls/prf_tls.cpp
@@ -23,7 +23,16 @@ void P_hash(MemoryRegion<byte>& output,
const byte secret[], size_t secret_len,
const byte seed[], size_t seed_len)
{
- mac->set_key(secret, secret_len);
+ try
+ {
+ mac->set_key(secret, secret_len);
+ }
+ catch(Invalid_Key_Length)
+ {
+ throw Internal_Error("The premaster secret of " +
+ std::to_string(secret_len) +
+ " bytes is too long for the PRF");
+ }
SecureVector<byte> A(seed, seed_len);
diff --git a/src/libstate/get_enc.cpp b/src/libstate/get_enc.cpp
index 6a87268e8..b7c9a7146 100644
--- a/src/libstate/get_enc.cpp
+++ b/src/libstate/get_enc.cpp
@@ -96,7 +96,11 @@ EMSA* get_emsa(const std::string& algo_spec)
#if defined(BOTAN_HAS_EMSA1)
if(request.algo_name() == "EMSA1" && request.arg_count() == 1)
+ {
+ if(request.arg(0) == "Raw")
+ return new EMSA_Raw;
return new EMSA1(af.make_hash_function(request.arg(0)));
+ }
#endif
#if defined(BOTAN_HAS_EMSA1_BSI)
@@ -195,14 +199,24 @@ KDF* get_kdf(const std::string& algo_spec)
return new X942_PRF(request.arg(0)); // OID
#endif
+#if defined(BOTAN_HAS_SSL_V3_PRF)
+ if(request.algo_name() == "SSL3-PRF" && request.arg_count() == 0)
+ return new SSL3_PRF;
+#endif
+
#if defined(BOTAN_HAS_TLS_V10_PRF)
if(request.algo_name() == "TLS-PRF" && request.arg_count() == 0)
return new TLS_PRF;
#endif
-#if defined(BOTAN_HAS_SSL_V3_PRF)
- if(request.algo_name() == "SSL3-PRF" && request.arg_count() == 0)
- return new SSL3_PRF;
+#if defined(BOTAN_HAS_TLS_V10_PRF)
+ if(request.algo_name() == "TLS-PRF" && request.arg_count() == 0)
+ return new TLS_PRF;
+#endif
+
+#if defined(BOTAN_HAS_TLS_V12_PRF)
+ if(request.algo_name() == "TLS-12-PRF" && request.arg_count() == 1)
+ return new TLS_12_PRF(af.make_mac("HMAC(" + request.arg(0) + ")"));
#endif
throw Algorithm_Not_Found(algo_spec);
diff --git a/src/libstate/global_rng.cpp b/src/libstate/global_rng.cpp
index 7e7976f58..f80146596 100644
--- a/src/libstate/global_rng.cpp
+++ b/src/libstate/global_rng.cpp
@@ -6,7 +6,6 @@
*/
#include <botan/libstate.h>
-#include <botan/internal/mutex.h>
#if defined(BOTAN_HAS_RANDPOOL)
#include <botan/randpool.h>
@@ -115,60 +114,60 @@ class Serialized_PRNG : public RandomNumberGenerator
public:
void randomize(byte out[], size_t len)
{
- Mutex_Holder lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
rng->randomize(out, len);
}
bool is_seeded() const
{
- Mutex_Holder lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
return rng->is_seeded();
}
void clear()
{
- Mutex_Holder lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
rng->clear();
}
std::string name() const
{
- Mutex_Holder lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
return rng->name();
}
void reseed(size_t poll_bits)
{
- Mutex_Holder lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
rng->reseed(poll_bits);
}
void add_entropy_source(EntropySource* es)
{
- Mutex_Holder lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
rng->add_entropy_source(es);
}
void add_entropy(const byte in[], size_t len)
{
- Mutex_Holder lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
rng->add_entropy(in, len);
}
// We do not own the mutex; Library_State does
- Serialized_PRNG(RandomNumberGenerator* r, Mutex* m) :
+ Serialized_PRNG(RandomNumberGenerator* r, std::mutex& m) :
mutex(m), rng(r) {}
~Serialized_PRNG() { delete rng; }
private:
- Mutex* mutex;
+ std::mutex& mutex;
RandomNumberGenerator* rng;
};
}
RandomNumberGenerator* Library_State::make_global_rng(Algorithm_Factory& af,
- Mutex* mutex)
+ std::mutex& mutex)
{
RandomNumberGenerator* rng = 0;
diff --git a/src/libstate/global_state.cpp b/src/libstate/global_state.cpp
index 43c935ca3..34bcd03fc 100644
--- a/src/libstate/global_state.cpp
+++ b/src/libstate/global_state.cpp
@@ -37,7 +37,7 @@ Library_State& global_state()
if(!global_lib_state)
{
global_lib_state = new Library_State;
- global_lib_state->initialize(true);
+ global_lib_state->initialize();
}
return (*global_lib_state);
diff --git a/src/libstate/info.txt b/src/libstate/info.txt
index d48ad70d5..ef0c9a47e 100644
--- a/src/libstate/info.txt
+++ b/src/libstate/info.txt
@@ -38,8 +38,6 @@ hmac_rng
kdf
mac
mode_pad
-mutex
-noop_mutex
pbkdf
pk_pad
pubkey
diff --git a/src/libstate/init.cpp b/src/libstate/init.cpp
index 6d1ca1dbc..6ab303909 100644
--- a/src/libstate/init.cpp
+++ b/src/libstate/init.cpp
@@ -1,12 +1,11 @@
/*
* Default Initialization Function
-* (C) 1999-2007 Jack Lloyd
+* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
#include <botan/init.h>
-#include <botan/parsing.h>
#include <botan/libstate.h>
#include <botan/global_state.h>
@@ -15,36 +14,8 @@ namespace Botan {
/*
* Library Initialization
*/
-void LibraryInitializer::initialize(const std::string& arg_string)
+void LibraryInitializer::initialize(const std::string&)
{
- bool thread_safe = false;
-
- const std::vector<std::string> arg_list = split_on(arg_string, ' ');
- for(size_t i = 0; i != arg_list.size(); ++i)
- {
- if(arg_list[i].size() == 0)
- continue;
-
- std::string name, value;
-
- if(arg_list[i].find('=') == std::string::npos)
- {
- name = arg_list[i];
- value = "true";
- }
- else
- {
- std::vector<std::string> name_and_value = split_on(arg_list[i], '=');
- name = name_and_value[0];
- value = name_and_value[1];
- }
-
- bool is_on =
- (value == "1" || value == "true" || value == "yes" || value == "on");
-
- if(name == "thread_safe")
- thread_safe = is_on;
- }
try
{
@@ -56,7 +27,7 @@ void LibraryInitializer::initialize(const std::string& arg_string)
*/
Global_State_Management::set_global_state(new Library_State);
- global_state().initialize(thread_safe);
+ global_state().initialize();
}
catch(...)
{
diff --git a/src/libstate/libstate.cpp b/src/libstate/libstate.cpp
index 3a5c0a9e7..588c5db1b 100644
--- a/src/libstate/libstate.cpp
+++ b/src/libstate/libstate.cpp
@@ -11,8 +11,6 @@
#include <botan/cpuid.h>
#include <botan/internal/defalloc.h>
#include <botan/internal/core_engine.h>
-#include <botan/internal/mutex.h>
-#include <botan/internal/mux_noop.h>
#include <botan/internal/stl_util.h>
#include <botan/internal/mlock.h>
#include <algorithm>
@@ -21,12 +19,6 @@
#include <botan/selftest.h>
#endif
-#if defined(BOTAN_HAS_MUTEX_PTHREAD)
- #include <botan/internal/mux_pthr.h>
-#elif defined(BOTAN_HAS_MUTEX_WIN32)
- #include <botan/internal/mux_win32.h>
-#endif
-
#if defined(BOTAN_HAS_ALLOC_MMAP)
#include <botan/internal/mmap_mem.h>
#endif
@@ -54,19 +46,11 @@
namespace Botan {
/*
-* Get a new mutex object
-*/
-Mutex* Library_State::get_mutex() const
- {
- return mutex_factory->make();
- }
-
-/*
* Get an allocator by its name
*/
-Allocator* Library_State::get_allocator(const std::string& type) const
+Allocator* Library_State::get_allocator(const std::string& type)
{
- Mutex_Holder lock(allocator_lock);
+ std::lock_guard<std::mutex> lock(allocator_lock);
if(type != "")
return search_map<std::string, Allocator*>(alloc_factory, type, 0);
@@ -86,7 +70,7 @@ Allocator* Library_State::get_allocator(const std::string& type) const
*/
void Library_State::add_allocator(Allocator* allocator)
{
- Mutex_Holder lock(allocator_lock);
+ std::lock_guard<std::mutex> lock(allocator_lock);
allocator->init();
@@ -99,11 +83,11 @@ void Library_State::add_allocator(Allocator* allocator)
*/
void Library_State::set_default_allocator(const std::string& type)
{
- Mutex_Holder lock(allocator_lock);
-
if(type == "")
return;
+ std::lock_guard<std::mutex> lock(allocator_lock);
+
default_allocator_name = type;
cached_default_allocator = 0;
}
@@ -112,9 +96,9 @@ void Library_State::set_default_allocator(const std::string& type)
* Get a configuration value
*/
std::string Library_State::get(const std::string& section,
- const std::string& key) const
+ const std::string& key)
{
- Mutex_Holder lock(config_lock);
+ std::lock_guard<std::mutex> lock(config_lock);
return search_map<std::string, std::string>(config,
section + "/" + key, "");
@@ -124,9 +108,9 @@ std::string Library_State::get(const std::string& section,
* See if a particular option has been set
*/
bool Library_State::is_set(const std::string& section,
- const std::string& key) const
+ const std::string& key)
{
- Mutex_Holder lock(config_lock);
+ std::lock_guard<std::mutex> lock(config_lock);
return config.count(section + "/" + key) != 0;
}
@@ -137,12 +121,11 @@ bool Library_State::is_set(const std::string& section,
void Library_State::set(const std::string& section, const std::string& key,
const std::string& value, bool overwrite)
{
- Mutex_Holder lock(config_lock);
+ std::lock_guard<std::mutex> lock(config_lock);
std::string full_key = section + "/" + key;
- std::map<std::string, std::string>::const_iterator i =
- config.find(full_key);
+ auto i = config.find(full_key);
if(overwrite || i == config.end() || i->second == "")
config[full_key] = value;
@@ -159,7 +142,7 @@ void Library_State::add_alias(const std::string& key, const std::string& value)
/*
* Dereference an alias to a fixed name
*/
-std::string Library_State::deref_alias(const std::string& key) const
+std::string Library_State::deref_alias(const std::string& key)
{
std::string result = key;
while(is_set("alias", result))
@@ -182,7 +165,7 @@ Algorithm_Factory& Library_State::algorithm_factory() const
*/
RandomNumberGenerator& Library_State::global_rng()
{
- Mutex_Holder lock(global_rng_lock);
+ std::lock_guard<std::mutex> lock(global_rng_lock);
if(!global_rng_ptr)
global_rng_ptr = make_global_rng(algorithm_factory(),
@@ -194,44 +177,26 @@ RandomNumberGenerator& Library_State::global_rng()
/*
* Load a set of modules
*/
-void Library_State::initialize(bool thread_safe)
+void Library_State::initialize()
{
CPUID::initialize();
- if(mutex_factory)
+ if(m_algorithm_factory)
throw Invalid_State("Library_State has already been initialized");
- if(!thread_safe)
- {
- mutex_factory = new Noop_Mutex_Factory;
- }
- else
- {
-#if defined(BOTAN_HAS_MUTEX_PTHREAD)
- mutex_factory = new Pthread_Mutex_Factory;
-#elif defined(BOTAN_HAS_MUTEX_WIN32)
- mutex_factory = new Win32_Mutex_Factory;
-#else
- throw Invalid_State("Could not find a thread-safe mutex object to use");
-#endif
- }
-
- allocator_lock = get_mutex();
- config_lock = get_mutex();
- global_rng_lock = get_mutex();
-
+ cached_default_allocator = 0;
default_allocator_name = has_mlock() ? "locking" : "malloc";
add_allocator(new Malloc_Allocator);
- add_allocator(new Locking_Allocator(get_mutex()));
+ add_allocator(new Locking_Allocator);
#if defined(BOTAN_HAS_ALLOC_MMAP)
- add_allocator(new MemoryMapping_Allocator(get_mutex()));
+ add_allocator(new MemoryMapping_Allocator);
#endif
load_default_config();
- m_algorithm_factory = new Algorithm_Factory(*mutex_factory);
+ m_algorithm_factory = new Algorithm_Factory();
#if defined(BOTAN_HAS_ENGINE_GNU_MP)
algorithm_factory().add_engine(new GMP_Engine);
@@ -265,12 +230,9 @@ void Library_State::initialize(bool thread_safe)
*/
Library_State::Library_State()
{
- mutex_factory = 0;
- allocator_lock = config_lock = 0;
cached_default_allocator = 0;
m_algorithm_factory = 0;
- global_rng_lock = 0;
global_rng_ptr = 0;
}
@@ -280,7 +242,11 @@ Library_State::Library_State()
Library_State::~Library_State()
{
delete m_algorithm_factory;
+ m_algorithm_factory = 0;
+
delete global_rng_ptr;
+ global_rng_ptr = 0;
+
cached_default_allocator = 0;
@@ -289,11 +255,6 @@ Library_State::~Library_State()
allocators[i]->destroy();
delete allocators[i];
}
-
- delete global_rng_lock;
- delete allocator_lock;
- delete mutex_factory;
- delete config_lock;
}
}
diff --git a/src/libstate/libstate.h b/src/libstate/libstate.h
index aa957c8c9..49908a1e3 100644
--- a/src/libstate/libstate.h
+++ b/src/libstate/libstate.h
@@ -13,16 +13,15 @@
#include <botan/algo_factory.h>
#include <botan/rng.h>
+#include <mutex>
#include <string>
#include <vector>
#include <map>
namespace Botan {
-class Mutex;
-
-/**
-* Global state container aka the buritto at the center of it all
+/*
+* Global State Container Base
*/
class BOTAN_DLL Library_State
{
@@ -30,10 +29,10 @@ class BOTAN_DLL Library_State
Library_State();
~Library_State();
- /**
- * @param thread_safe should a mutex be used for serialization
- */
- void initialize(bool thread_safe);
+ Library_State(const Library_State&) = delete;
+ Library_State& operator=(const Library_State&) = delete;
+
+ void initialize();
/**
* @return global Algorithm_Factory
@@ -49,7 +48,7 @@ class BOTAN_DLL Library_State
* @param name the name of the allocator
* @return allocator matching this name, or NULL
*/
- Allocator* get_allocator(const std::string& name = "") const;
+ Allocator* get_allocator(const std::string& name = "");
/**
* Add a new allocator to the list of available ones
@@ -70,7 +69,7 @@ class BOTAN_DLL Library_State
* @result the value of the parameter
*/
std::string get(const std::string& section,
- const std::string& key) const;
+ const std::string& key);
/**
* Check whether a certain parameter is set or not.
@@ -80,7 +79,7 @@ class BOTAN_DLL Library_State
* false otherwise
*/
bool is_set(const std::string& section,
- const std::string& key) const;
+ const std::string& key);
/**
* Set a configuration parameter.
@@ -109,30 +108,20 @@ class BOTAN_DLL Library_State
* @param alias the alias to resolve.
* @return what the alias stands for
*/
- std::string deref_alias(const std::string& alias) const;
-
- /**
- * @return newly created Mutex (free with delete)
- */
- Mutex* get_mutex() const;
+ std::string deref_alias(const std::string&);
private:
static RandomNumberGenerator* make_global_rng(Algorithm_Factory& af,
- Mutex* mutex);
+ std::mutex& mutex);
void load_default_config();
- Library_State(const Library_State&) {}
- Library_State& operator=(const Library_State&) { return (*this); }
-
- class Mutex_Factory* mutex_factory;
-
- Mutex* global_rng_lock;
+ std::mutex global_rng_lock;
RandomNumberGenerator* global_rng_ptr;
- Mutex* config_lock;
+ std::mutex config_lock;
std::map<std::string, std::string> config;
- Mutex* allocator_lock;
+ std::mutex allocator_lock;
std::string default_allocator_name;
std::map<std::string, Allocator*> alloc_factory;
mutable Allocator* cached_default_allocator;
diff --git a/src/mac/cmac/cmac.cpp b/src/mac/cmac/cmac.cpp
index baf22f4e8..7cd53f578 100644
--- a/src/mac/cmac/cmac.cpp
+++ b/src/mac/cmac/cmac.cpp
@@ -38,7 +38,7 @@ SecureVector<byte> CMAC::poly_double(const MemoryRegion<byte>& in,
*/
void CMAC::add_data(const byte input[], size_t length)
{
- buffer.copy(position, input, length);
+ buffer_insert(buffer, position, input, length);
if(position + length > output_length())
{
xor_buf(state, buffer, output_length());
@@ -52,7 +52,7 @@ void CMAC::add_data(const byte input[], size_t length)
input += output_length();
length -= output_length();
}
- buffer.copy(input, length);
+ copy_mem(&buffer[0], input, length);
position = 0;
}
position += length;
diff --git a/src/mac/hmac/hmac.h b/src/mac/hmac/hmac.h
index b76a058f4..9de1bc7b5 100644
--- a/src/mac/hmac/hmac.h
+++ b/src/mac/hmac/hmac.h
@@ -27,7 +27,7 @@ class BOTAN_DLL HMAC : public MessageAuthenticationCode
Key_Length_Specification key_spec() const
{
- return Key_Length_Specification(0, 2*hash->hash_block_size());
+ return Key_Length_Specification(0, 512);
}
/**
diff --git a/src/mac/ssl3mac/ssl3_mac.cpp b/src/mac/ssl3mac/ssl3_mac.cpp
index a07622eb3..8799c96a5 100644
--- a/src/mac/ssl3mac/ssl3_mac.cpp
+++ b/src/mac/ssl3mac/ssl3_mac.cpp
@@ -38,8 +38,9 @@ void SSL3_MAC::key_schedule(const byte key[], size_t length)
std::fill(i_key.begin(), i_key.end(), 0x36);
std::fill(o_key.begin(), o_key.end(), 0x5C);
- i_key.copy(key, length);
- o_key.copy(key, length);
+ copy_mem(&i_key[0], key, length);
+ copy_mem(&o_key[0], key, length);
+
hash->update(i_key);
}
diff --git a/src/math/bigint/big_code.cpp b/src/math/bigint/big_code.cpp
index 75a310a7c..28614c9f1 100644
--- a/src/math/bigint/big_code.cpp
+++ b/src/math/bigint/big_code.cpp
@@ -111,7 +111,9 @@ BigInt BigInt::decode(const byte buf[], size_t length, Base base)
if(length % 2)
{
// Handle lack of leading 0
- const char buf0_with_leading_0[2] = { '0', buf[0] };
+ const char buf0_with_leading_0[2] =
+ { '0', static_cast<char>(buf[0]) };
+
binary = hex_decode(buf0_with_leading_0, 2);
binary += hex_decode(reinterpret_cast<const char*>(&buf[1]),
diff --git a/src/math/bigint/bigint.cpp b/src/math/bigint/bigint.cpp
index e2e062f2d..df4414aba 100644
--- a/src/math/bigint/bigint.cpp
+++ b/src/math/bigint/bigint.cpp
@@ -40,23 +40,12 @@ BigInt::BigInt(Sign s, size_t size)
}
/*
-* Construct a BigInt from a "raw" BigInt
+* Copy constructor
*/
BigInt::BigInt(const BigInt& b)
{
- const size_t b_words = b.sig_words();
-
- if(b_words)
- {
- reg.resize(round_up<size_t>(b_words, 8));
- reg.copy(b.data(), b_words);
- set_sign(b.sign());
- }
- else
- {
- reg.resize(2);
- set_sign(Positive);
- }
+ reg = b.get_reg();
+ set_sign(b.sign());
}
/*
@@ -101,15 +90,6 @@ BigInt::BigInt(RandomNumberGenerator& rng, size_t bits)
}
/*
-* Swap this BigInt with another
-*/
-void BigInt::swap(BigInt& other)
- {
- reg.swap(other.reg);
- std::swap(signedness, other.signedness);
- }
-
-/*
* Grow the internal storage
*/
void BigInt::grow_reg(size_t n)
diff --git a/src/math/bigint/bigint.h b/src/math/bigint/bigint.h
index 87c7cb766..57aa84528 100644
--- a/src/math/bigint/bigint.h
+++ b/src/math/bigint/bigint.h
@@ -438,7 +438,11 @@ class BOTAN_DLL BigInt
* Swap this value with another
* @param other BigInt to swap values with
*/
- void swap(BigInt& other);
+ void swap(BigInt& other)
+ {
+ reg.swap(other.reg);
+ std::swap(signedness, other.signedness);
+ }
/**
* Create empty BigInt
@@ -500,6 +504,29 @@ class BOTAN_DLL BigInt
*/
BigInt(NumberType type, size_t n);
+ /**
+ * Move constructor
+ */
+ BigInt(BigInt&& other)
+ {
+ this->swap(other);
+ }
+
+ /**
+ * Move assignment
+ */
+ BigInt& operator=(BigInt&& other)
+ {
+ if(this != &other)
+ this->swap(other);
+
+ return (*this);
+ }
+
+ /**
+ * Copy assignment
+ */
+ BigInt& operator=(const BigInt&) = default;
private:
SecureVector<word> reg;
Sign signedness;
diff --git a/src/math/ec_gfp/point_gfp.h b/src/math/ec_gfp/point_gfp.h
index b2b6fe2f0..546a8dd6f 100644
--- a/src/math/ec_gfp/point_gfp.h
+++ b/src/math/ec_gfp/point_gfp.h
@@ -59,6 +59,34 @@ class BOTAN_DLL PointGFp
PointGFp(const CurveGFp& curve);
/**
+ * Copy constructor
+ */
+ PointGFp(const PointGFp&) = default;
+
+ /**
+ * Move Constructor
+ */
+ PointGFp(PointGFp&& other)
+ {
+ this->swap(other);
+ }
+
+ /**
+ * Standard Assignment
+ */
+ PointGFp& operator=(const PointGFp&) = default;
+
+ /**
+ * Move Assignment
+ */
+ PointGFp& operator=(PointGFp&& other)
+ {
+ if(this != &other)
+ this->swap(other);
+ return (*this);
+ }
+
+ /**
* Construct a point from its affine coordinates
* @param curve the base curve
* @param x affine x coordinate
@@ -66,9 +94,6 @@ class BOTAN_DLL PointGFp
*/
PointGFp(const CurveGFp& curve, const BigInt& x, const BigInt& y);
- //PointGFp(const PointGFp& other) = default;
- //PointGFp& operator=(const PointGFp& other) = default;
-
/**
* += Operator
* @param rhs the PointGFp to add to the local value
diff --git a/src/math/numbertheory/dsa_gen.cpp b/src/math/numbertheory/dsa_gen.cpp
index 670f103da..612370804 100644
--- a/src/math/numbertheory/dsa_gen.cpp
+++ b/src/math/numbertheory/dsa_gen.cpp
@@ -47,15 +47,15 @@ bool generate_dsa_primes(RandomNumberGenerator& rng,
if(!fips186_3_valid_size(pbits, qbits))
throw Invalid_Argument(
"FIPS 186-3 does not allow DSA domain parameters of " +
- to_string(pbits) + "/" + to_string(qbits) + " bits long");
+ std::to_string(pbits) + "/" + std::to_string(qbits) + " bits long");
if(seed_c.size() * 8 < qbits)
throw Invalid_Argument(
- "Generating a DSA parameter set with a " + to_string(qbits) +
+ "Generating a DSA parameter set with a " + std::to_string(qbits) +
"long q requires a seed at least as many bits long");
- std::auto_ptr<HashFunction> hash(
- af.make_hash_function("SHA-" + to_string(qbits)));
+ std::unique_ptr<HashFunction> hash(
+ af.make_hash_function("SHA-" + std::to_string(qbits)));
const size_t HASH_SIZE = hash->output_length();
diff --git a/src/math/numbertheory/make_prm.cpp b/src/math/numbertheory/make_prm.cpp
index 4fb3f908c..1e8d11000 100644
--- a/src/math/numbertheory/make_prm.cpp
+++ b/src/math/numbertheory/make_prm.cpp
@@ -20,7 +20,7 @@ BigInt random_prime(RandomNumberGenerator& rng,
{
if(bits <= 1)
throw Invalid_Argument("random_prime: Can't make a prime of " +
- to_string(bits) + " bits");
+ std::to_string(bits) + " bits");
else if(bits == 2)
return ((rng.next_byte() % 2) ? 2 : 3);
else if(bits == 3)
@@ -88,7 +88,7 @@ BigInt random_safe_prime(RandomNumberGenerator& rng, size_t bits)
{
if(bits <= 64)
throw Invalid_Argument("random_safe_prime: Can't make a prime of " +
- to_string(bits) + " bits");
+ std::to_string(bits) + " bits");
BigInt p;
do
diff --git a/src/math/numbertheory/numthry.cpp b/src/math/numbertheory/numthry.cpp
index c7896c17a..18f6ce429 100644
--- a/src/math/numbertheory/numthry.cpp
+++ b/src/math/numbertheory/numthry.cpp
@@ -83,7 +83,7 @@ size_t miller_rabin_test_iterations(size_t bits, size_t level)
{
struct mapping { size_t bits; size_t verify_iter; size_t check_iter; };
- static const mapping tests[] = {
+ const mapping tests[] = {
{ 50, 55, 25 },
{ 100, 38, 22 },
{ 160, 32, 18 },
diff --git a/src/mutex/info.txt b/src/mutex/info.txt
deleted file mode 100644
index af4cf9bb3..000000000
--- a/src/mutex/info.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-define MUTEX_WRAPPERS
-
-<header:internal>
-mutex.h
-</header:internal>
diff --git a/src/mutex/mutex.h b/src/mutex/mutex.h
deleted file mode 100644
index f209466d5..000000000
--- a/src/mutex/mutex.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
-* Mutex
-* (C) 1999-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_MUTEX_H__
-#define BOTAN_MUTEX_H__
-
-#include <botan/exceptn.h>
-
-namespace Botan {
-
-/**
-* Mutex Base Class
-*/
-class Mutex
- {
- public:
- /**
- * Lock the mutex
- */
- virtual void lock() = 0;
-
- /**
- * Unlock the mutex
- */
- virtual void unlock() = 0;
- virtual ~Mutex() {}
- };
-
-/**
-* Mutex Factory
-*/
-class Mutex_Factory
- {
- public:
- /**
- * @return newly allocated mutex
- */
- virtual Mutex* make() = 0;
-
- virtual ~Mutex_Factory() {}
- };
-
-/**
-* Mutex Holding Class for RAII
-*/
-class Mutex_Holder
- {
- public:
- /**
- * Hold onto a mutex until we leave scope
- * @param m the mutex to lock
- */
- Mutex_Holder(Mutex* m) : mux(m)
- {
- if(!mux)
- throw Invalid_Argument("Mutex_Holder: Argument was NULL");
- mux->lock();
- }
-
- ~Mutex_Holder() { mux->unlock(); }
- private:
- Mutex* mux;
- };
-
-}
-
-#endif
diff --git a/src/mutex/noop_mutex/info.txt b/src/mutex/noop_mutex/info.txt
deleted file mode 100644
index 16670b1dd..000000000
--- a/src/mutex/noop_mutex/info.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-define MUTEX_NOOP
-
-<source>
-mux_noop.cpp
-</source>
-
-<header:internal>
-mux_noop.h
-</header:internal>
diff --git a/src/mutex/noop_mutex/mux_noop.cpp b/src/mutex/noop_mutex/mux_noop.cpp
deleted file mode 100644
index 18151274a..000000000
--- a/src/mutex/noop_mutex/mux_noop.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-* No-Op Mutex Factory
-* (C) 1999-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#include <botan/internal/mux_noop.h>
-
-namespace Botan {
-
-/*
-* No-Op Mutex Factory
-*/
-Mutex* Noop_Mutex_Factory::make()
- {
- class Noop_Mutex : public Mutex
- {
- public:
- class Mutex_State_Error : public Internal_Error
- {
- public:
- Mutex_State_Error(const std::string& where) :
- Internal_Error("Noop_Mutex::" + where + ": " +
- "Mutex is already " + where + "ed") {}
- };
-
- void lock()
- {
- if(locked)
- throw Mutex_State_Error("lock");
- locked = true;
- }
-
- void unlock()
- {
- if(!locked)
- throw Mutex_State_Error("unlock");
- locked = false;
- }
-
- Noop_Mutex() { locked = false; }
- private:
- bool locked;
- };
-
- return new Noop_Mutex;
- }
-
-}
diff --git a/src/mutex/noop_mutex/mux_noop.h b/src/mutex/noop_mutex/mux_noop.h
deleted file mode 100644
index 20989a635..000000000
--- a/src/mutex/noop_mutex/mux_noop.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
-* No-Op Mutex Factory
-* (C) 1999-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_NOOP_MUTEX_FACTORY_H__
-#define BOTAN_NOOP_MUTEX_FACTORY_H__
-
-#include <botan/internal/mutex.h>
-
-namespace Botan {
-
-/**
-* No-Op Mutex Factory
-*/
-class Noop_Mutex_Factory : public Mutex_Factory
- {
- public:
- Mutex* make();
- };
-
-}
-
-#endif
diff --git a/src/mutex/pthreads/info.txt b/src/mutex/pthreads/info.txt
deleted file mode 100644
index 1d826b61c..000000000
--- a/src/mutex/pthreads/info.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-define MUTEX_PTHREAD
-
-<source>
-mux_pthr.cpp
-</source>
-
-<header:internal>
-mux_pthr.h
-</header:internal>
-
-<libs>
-all!qnx,freebsd,dragonfly,openbsd,netbsd -> pthread
-</libs>
-
-<os>
-aix
-cygwin
-darwin
-freebsd
-dragonfly
-hpux
-irix
-linux
-netbsd
-openbsd
-qnx
-solaris
-tru64
-</os>
diff --git a/src/mutex/pthreads/mux_pthr.cpp b/src/mutex/pthreads/mux_pthr.cpp
deleted file mode 100644
index 165132239..000000000
--- a/src/mutex/pthreads/mux_pthr.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-* Pthread Mutex
-* (C) 1999-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#include <botan/internal/mux_pthr.h>
-#include <botan/exceptn.h>
-
-#ifndef _POSIX_C_SOURCE
- #define _POSIX_C_SOURCE 199506
-#endif
-
-#include <pthread.h>
-
-namespace Botan {
-
-/*
-* Pthread Mutex Factory
-*/
-Mutex* Pthread_Mutex_Factory::make()
- {
-
- class Pthread_Mutex : public Mutex
- {
- public:
- void lock()
- {
- if(pthread_mutex_lock(&mutex) != 0)
- throw Invalid_State("Pthread_Mutex::lock: Error occured");
- }
-
- void unlock()
- {
- if(pthread_mutex_unlock(&mutex) != 0)
- throw Invalid_State("Pthread_Mutex::unlock: Error occured");
- }
-
- Pthread_Mutex()
- {
- if(pthread_mutex_init(&mutex, 0) != 0)
- throw Invalid_State("Pthread_Mutex: initialization failed");
- }
-
- ~Pthread_Mutex()
- {
- if(pthread_mutex_destroy(&mutex) != 0)
- throw Invalid_State("~Pthread_Mutex: mutex is still locked");
- }
- private:
- pthread_mutex_t mutex;
- };
-
- return new Pthread_Mutex();
- }
-
-}
diff --git a/src/mutex/pthreads/mux_pthr.h b/src/mutex/pthreads/mux_pthr.h
deleted file mode 100644
index 5cecd09ad..000000000
--- a/src/mutex/pthreads/mux_pthr.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
-* Pthread Mutex
-* (C) 1999-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_MUTEX_PTHREAD_H__
-#define BOTAN_MUTEX_PTHREAD_H__
-
-#include <botan/internal/mutex.h>
-
-namespace Botan {
-
-/**
-* Pthread Mutex Factory
-*/
-class Pthread_Mutex_Factory : public Mutex_Factory
- {
- public:
- Mutex* make();
- };
-
-}
-
-#endif
diff --git a/src/mutex/win32_crit_section/info.txt b/src/mutex/win32_crit_section/info.txt
deleted file mode 100644
index d90b8b64b..000000000
--- a/src/mutex/win32_crit_section/info.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-define MUTEX_WIN32
-
-<source>
-mux_win32.cpp
-</source>
-
-<header:internal>
-mux_win32.h
-</header:internal>
-
-<os>
-cygwin
-windows
-mingw
-</os>
diff --git a/src/mutex/win32_crit_section/mux_win32.cpp b/src/mutex/win32_crit_section/mux_win32.cpp
deleted file mode 100644
index fa6051798..000000000
--- a/src/mutex/win32_crit_section/mux_win32.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-* Win32 Mutex
-* (C) 2006 Luca Piccarreta
-* 2006-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#include <botan/internal/mux_win32.h>
-#include <windows.h>
-
-namespace Botan {
-
-/*
-* Win32 Mutex Factory
-*/
-Mutex* Win32_Mutex_Factory::make()
- {
- class Win32_Mutex : public Mutex
- {
- public:
- void lock() { EnterCriticalSection(&mutex); }
- void unlock() { LeaveCriticalSection(&mutex); }
-
- Win32_Mutex() { InitializeCriticalSection(&mutex); }
- ~Win32_Mutex() { DeleteCriticalSection(&mutex); }
- private:
- CRITICAL_SECTION mutex;
- };
-
- return new Win32_Mutex();
- }
-
-}
diff --git a/src/mutex/win32_crit_section/mux_win32.h b/src/mutex/win32_crit_section/mux_win32.h
deleted file mode 100644
index 2aa51e18b..000000000
--- a/src/mutex/win32_crit_section/mux_win32.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
-* Win32 Mutex
-* (C) 2006 Luca Piccarreta
-* 2006-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_MUTEX_WIN32_H__
-#define BOTAN_MUTEX_WIN32_H__
-
-#include <botan/internal/mutex.h>
-
-namespace Botan {
-
-/**
-* Win32 Mutex Factory
-*/
-class Win32_Mutex_Factory : public Mutex_Factory
- {
- public:
- Mutex* make();
- };
-}
-
-#endif
diff --git a/src/passhash/bcrypt/bcrypt.cpp b/src/passhash/bcrypt/bcrypt.cpp
index bb2e9095a..b0d654717 100644
--- a/src/passhash/bcrypt/bcrypt.cpp
+++ b/src/passhash/bcrypt/bcrypt.cpp
@@ -112,8 +112,13 @@ std::string make_bcrypt(const std::string& pass,
std::string salt_b64 = bcrypt_base64_encode(&salt[0], salt.size());
- return "$2a$" + to_string(work_factor, 2) + "$" + salt_b64.substr(0, 22) +
- bcrypt_base64_encode(&ctext[0], ctext.size() - 1);
+ std::string work_factor_str = std::to_string(work_factor);
+ if(work_factor_str.length() == 1)
+ work_factor_str = "0" + work_factor_str;
+
+ return "$2a$" + work_factor_str +
+ "$" + salt_b64.substr(0, 22) +
+ bcrypt_base64_encode(&ctext[0], ctext.size() - 1);
}
}
diff --git a/src/passhash/passhash9/passhash9.cpp b/src/passhash/passhash9/passhash9.cpp
index e1e37da1e..43bfdd36e 100644
--- a/src/passhash/passhash9/passhash9.cpp
+++ b/src/passhash/passhash9/passhash9.cpp
@@ -53,7 +53,8 @@ std::string generate_passhash9(const std::string& pass,
MessageAuthenticationCode* prf = get_pbkdf_prf(alg_id);
if(!prf)
- throw Invalid_Argument("Passhash9: Algorithm id " + to_string(alg_id) +
+ throw Invalid_Argument("Passhash9: Algorithm id " +
+ std::to_string(alg_id) +
" is not defined");
PKCS5_PBKDF2 kdf(prf); // takes ownership of pointer
diff --git a/src/pbkdf/pbkdf2/pbkdf2.cpp b/src/pbkdf/pbkdf2/pbkdf2.cpp
index 7e4d1cd8a..39d53d417 100644
--- a/src/pbkdf/pbkdf2/pbkdf2.cpp
+++ b/src/pbkdf/pbkdf2/pbkdf2.cpp
@@ -30,7 +30,7 @@ OctetString PKCS5_PBKDF2::derive_key(size_t key_len,
catch(Invalid_Key_Length)
{
throw Exception(name() + " cannot accept passphrases of length " +
- to_string(passphrase.length()));
+ std::to_string(passphrase.length()));
}
SecureVector<byte> key(key_len);
diff --git a/src/pbkdf/pgps2k/pgp_s2k.cpp b/src/pbkdf/pgps2k/pgp_s2k.cpp
index 9cec7304c..4ee4c6bd9 100644
--- a/src/pbkdf/pgps2k/pgp_s2k.cpp
+++ b/src/pbkdf/pgps2k/pgp_s2k.cpp
@@ -46,7 +46,7 @@ OctetString OpenPGP_S2K::derive_key(size_t key_len,
}
hash_buf = hash->final();
- key.copy(generated, &hash_buf[0], hash->output_length());
+ buffer_insert(key, generated, &hash_buf[0], hash->output_length());
generated += hash->output_length();
++pass;
}
diff --git a/src/pk_pad/eme1/eme1.cpp b/src/pk_pad/eme1/eme1.cpp
index 1cc0c332d..69251605f 100644
--- a/src/pk_pad/eme1/eme1.cpp
+++ b/src/pk_pad/eme1/eme1.cpp
@@ -28,9 +28,9 @@ SecureVector<byte> EME1::pad(const byte in[], size_t in_length,
rng.randomize(&out[0], Phash.size());
- out.copy(Phash.size(), &Phash[0], Phash.size());
+ buffer_insert(out, Phash.size(), &Phash[0], Phash.size());
out[out.size() - in_length - 1] = 0x01;
- out.copy(out.size() - in_length, in, in_length);
+ buffer_insert(out, out.size() - in_length, in, in_length);
mgf->mask(&out[0], Phash.size(),
&out[Phash.size()], out.size() - Phash.size());
@@ -66,7 +66,7 @@ SecureVector<byte> EME1::unpad(const byte in[], size_t in_length,
in_length = 0;
SecureVector<byte> input(key_length);
- input.copy(key_length - in_length, in, in_length);
+ buffer_insert(input, key_length - in_length, in, in_length);
mgf->mask(&input[Phash.size()], input.size() - Phash.size(),
&input[0], Phash.size());
diff --git a/src/pk_pad/eme_pkcs/eme_pkcs.cpp b/src/pk_pad/eme_pkcs/eme_pkcs.cpp
index c4d6838b1..a217d6d03 100644
--- a/src/pk_pad/eme_pkcs/eme_pkcs.cpp
+++ b/src/pk_pad/eme_pkcs/eme_pkcs.cpp
@@ -29,7 +29,7 @@ SecureVector<byte> EME_PKCS1v15::pad(const byte in[], size_t inlen,
for(size_t j = 1; j != olen - inlen - 1; ++j)
while(out[j] == 0)
out[j] = rng.next_byte();
- out.copy(olen - inlen, in, inlen);
+ buffer_insert(out, olen - inlen, in, inlen);
return out;
}
diff --git a/src/pk_pad/emsa2/emsa2.cpp b/src/pk_pad/emsa2/emsa2.cpp
index 96ac8e908..50ea7dbe3 100644
--- a/src/pk_pad/emsa2/emsa2.cpp
+++ b/src/pk_pad/emsa2/emsa2.cpp
@@ -39,7 +39,7 @@ SecureVector<byte> emsa2_encoding(const MemoryRegion<byte>& msg,
output[0] = (empty ? 0x4B : 0x6B);
output[output_length - 3 - HASH_SIZE] = 0xBA;
set_mem(&output[1], output_length - 4 - HASH_SIZE, 0xBB);
- output.copy(output_length - (HASH_SIZE + 2), &msg[0], msg.size());
+ buffer_insert(output, output_length - (HASH_SIZE + 2), &msg[0], msg.size());
output[output_length-2] = hash_id;
output[output_length-1] = 0xCC;
diff --git a/src/pk_pad/emsa3/emsa3.cpp b/src/pk_pad/emsa3/emsa3.cpp
index a381a82f6..6532bafd4 100644
--- a/src/pk_pad/emsa3/emsa3.cpp
+++ b/src/pk_pad/emsa3/emsa3.cpp
@@ -30,8 +30,8 @@ SecureVector<byte> emsa3_encoding(const MemoryRegion<byte>& msg,
T[0] = 0x01;
set_mem(&T[1], P_LENGTH, 0xFF);
T[P_LENGTH+1] = 0x00;
- T.copy(P_LENGTH+2, hash_id, hash_id_length);
- T.copy(output_length-msg.size(), &msg[0], msg.size());
+ buffer_insert(T, P_LENGTH+2, hash_id, hash_id_length);
+ buffer_insert(T, output_length-msg.size(), &msg[0], msg.size());
return T;
}
diff --git a/src/pk_pad/emsa4/emsa4.cpp b/src/pk_pad/emsa4/emsa4.cpp
index 194d934c1..d05e4a5b5 100644
--- a/src/pk_pad/emsa4/emsa4.cpp
+++ b/src/pk_pad/emsa4/emsa4.cpp
@@ -54,10 +54,10 @@ SecureVector<byte> EMSA4::encoding_of(const MemoryRegion<byte>& msg,
SecureVector<byte> EM(output_length);
EM[output_length - HASH_SIZE - SALT_SIZE - 2] = 0x01;
- EM.copy(output_length - 1 - HASH_SIZE - SALT_SIZE, salt, SALT_SIZE);
+ buffer_insert(EM, output_length - 1 - HASH_SIZE - SALT_SIZE, salt);
mgf->mask(H, HASH_SIZE, EM, output_length - HASH_SIZE - 1);
EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits);
- EM.copy(output_length - 1 - HASH_SIZE, H, HASH_SIZE);
+ buffer_insert(EM, output_length - 1 - HASH_SIZE, H);
EM[output_length-1] = 0xBC;
return EM;
@@ -88,7 +88,7 @@ bool EMSA4::verify(const MemoryRegion<byte>& const_coded,
if(coded.size() < KEY_BYTES)
{
SecureVector<byte> temp(KEY_BYTES);
- temp.copy(KEY_BYTES - coded.size(), coded, coded.size());
+ buffer_insert(temp, KEY_BYTES - coded.size(), coded);
coded = temp;
}
diff --git a/src/pubkey/dl_group/dl_group.cpp b/src/pubkey/dl_group/dl_group.cpp
index 7f0160b6b..3904841ba 100644
--- a/src/pubkey/dl_group/dl_group.cpp
+++ b/src/pubkey/dl_group/dl_group.cpp
@@ -47,7 +47,7 @@ DL_Group::DL_Group(RandomNumberGenerator& rng,
PrimeType type, size_t pbits, size_t qbits)
{
if(pbits < 512)
- throw Invalid_Argument("DL_Group: prime size " + to_string(pbits) +
+ throw Invalid_Argument("DL_Group: prime size " + std::to_string(pbits) +
" is too small");
if(type == Strong)
@@ -239,7 +239,7 @@ SecureVector<byte> DL_Group::DER_encode(Format format) const
.get_contents();
}
- throw Invalid_Argument("Unknown DL_Group encoding " + to_string(format));
+ throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format));
}
/*
@@ -255,7 +255,7 @@ std::string DL_Group::PEM_encode(Format format) const
else if(format == ANSI_X9_42)
return PEM_Code::encode(encoding, "X942 DH PARAMETERS");
else
- throw Invalid_Argument("Unknown DL_Group encoding " + to_string(format));
+ throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format));
}
/*
@@ -289,7 +289,7 @@ void DL_Group::BER_decode(DataSource& source, Format format)
.discard_remaining();
}
else
- throw Invalid_Argument("Unknown DL_Group encoding " + to_string(format));
+ throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format));
initialize(new_p, new_q, new_g);
}
diff --git a/src/pubkey/dlies/dlies.cpp b/src/pubkey/dlies/dlies.cpp
index 2b3f65d06..80dde048b 100644
--- a/src/pubkey/dlies/dlies.cpp
+++ b/src/pubkey/dlies/dlies.cpp
@@ -43,8 +43,8 @@ SecureVector<byte> DLIES_Encryptor::enc(const byte in[], size_t length,
throw Invalid_State("DLIES: The other key was never set");
SecureVector<byte> out(my_key.size() + length + mac->output_length());
- out.copy(&my_key[0], my_key.size());
- out.copy(my_key.size(), in, length);
+ buffer_insert(out, 0, my_key);
+ buffer_insert(out, my_key.size(), in, length);
SecureVector<byte> vz = my_key;
vz += ka.derive_key(0, other_key).bits_of();
diff --git a/src/pubkey/dsa/dsa.cpp b/src/pubkey/dsa/dsa.cpp
index 5e511840f..c3b4f260b 100644
--- a/src/pubkey/dsa/dsa.cpp
+++ b/src/pubkey/dsa/dsa.cpp
@@ -8,7 +8,7 @@
#include <botan/dsa.h>
#include <botan/numthry.h>
#include <botan/keypair.h>
-
+#include <future>
namespace Botan {
/*
@@ -89,8 +89,12 @@ DSA_Signature_Operation::sign(const byte msg[], size_t msg_len,
k.randomize(rng, q.bits());
while(k >= q);
- r = mod_q.reduce(powermod_g_p(k));
- s = mod_q.multiply(inverse_mod(k, q), mul_add(x, r, i));
+ auto future_r = std::async(std::launch::async,
+ [&]() { return mod_q.reduce(powermod_g_p(k)); });
+
+ s = inverse_mod(k, q);
+ r = future_r.get();
+ s = mod_q.multiply(s, mul_add(x, r, i));
}
SecureVector<byte> output(2*q.bytes());
@@ -124,8 +128,14 @@ bool DSA_Verification_Operation::verify(const byte msg[], size_t msg_len,
return false;
s = inverse_mod(s, q);
- s = mod_p.multiply(powermod_g_p(mod_q.multiply(s, i)),
- powermod_y_p(mod_q.multiply(s, r)));
+
+ auto future_s_i = std::async(std::launch::async,
+ [&]() { return powermod_g_p(mod_q.multiply(s, i)); });
+
+ BigInt s_r = powermod_y_p(mod_q.multiply(s, r));
+ BigInt s_i = future_s_i.get();
+
+ s = mod_p.multiply(s_i, s_r);
return (mod_q.reduce(s) == r);
}
diff --git a/src/pubkey/ec_group/ec_group.h b/src/pubkey/ec_group/ec_group.h
index 59a1918c0..dadc9fba3 100644
--- a/src/pubkey/ec_group/ec_group.h
+++ b/src/pubkey/ec_group/ec_group.h
@@ -63,8 +63,8 @@ class BOTAN_DLL EC_Group
EC_Group(const OID& oid);
/**
- * Create an EC domain from PEM encoding (as from PEM_encode),
- * or from an OID name (eg "secp160r1", or "1.3.132.0.8")
+ * Create an EC domain from PEM encoding (as from PEM_encode), or
+ * from an OID name (eg "secp256r1", or "1.2.840.10045.3.1.7")
* @param pem_or_oid PEM-encoded data, or an OID
*/
EC_Group(const std::string& pem_or_oid = "");
diff --git a/src/pubkey/nr/nr.cpp b/src/pubkey/nr/nr.cpp
index 03885e140..7490e1b64 100644
--- a/src/pubkey/nr/nr.cpp
+++ b/src/pubkey/nr/nr.cpp
@@ -8,6 +8,7 @@
#include <botan/nr.h>
#include <botan/numthry.h>
#include <botan/keypair.h>
+#include <future>
namespace Botan {
@@ -132,7 +133,10 @@ NR_Verification_Operation::verify_mr(const byte msg[], size_t msg_len)
if(c.is_zero() || c >= q || d >= q)
throw Invalid_Argument("NR verification: Invalid signature");
- BigInt i = mod_p.multiply(powermod_g_p(d), powermod_y_p(c));
+ auto future_y_c = std::async(std::launch::async, powermod_y_p, c);
+ BigInt g_d = powermod_g_p(d);
+
+ BigInt i = mod_p.multiply(g_d, future_y_c.get());
return BigInt::encode(mod_q.reduce(c - i));
}
diff --git a/src/pubkey/pkcs8.cpp b/src/pubkey/pkcs8.cpp
index 16440b648..57bb5c1e2 100644
--- a/src/pubkey/pkcs8.cpp
+++ b/src/pubkey/pkcs8.cpp
@@ -41,8 +41,10 @@ SecureVector<byte> PKCS8_extract(DataSource& source,
/*
* PEM decode and/or decrypt a private key
*/
-SecureVector<byte> PKCS8_decode(DataSource& source, const User_Interface& ui,
- AlgorithmIdentifier& pk_alg_id)
+SecureVector<byte> PKCS8_decode(
+ DataSource& source,
+ std::function<std::pair<bool,std::string> ()> get_passphrase,
+ AlgorithmIdentifier& pk_alg_id)
{
AlgorithmIdentifier pbe_alg_id;
SecureVector<byte> key_data, key;
@@ -89,16 +91,14 @@ SecureVector<byte> PKCS8_decode(DataSource& source, const User_Interface& ui,
if(is_encrypted)
{
DataSource_Memory params(pbe_alg_id.parameters);
- std::auto_ptr<PBE> pbe(get_pbe(pbe_alg_id.oid, params));
+ std::unique_ptr<PBE> pbe(get_pbe(pbe_alg_id.oid, params));
- User_Interface::UI_Result result = User_Interface::OK;
- const std::string passphrase =
- ui.get_passphrase("PKCS #8 private key", source.id(), result);
+ std::pair<bool, std::string> pass = get_passphrase();
- if(result == User_Interface::CANCEL_ACTION)
+ if(pass.first == false)
break;
- pbe->set_key(passphrase);
+ pbe->set_key(pass.second);
Pipe decryptor(pbe.release());
decryptor.process_msg(key_data);
@@ -162,7 +162,7 @@ SecureVector<byte> BER_encode(const Private_Key& key,
{
const std::string DEFAULT_PBE = "PBE-PKCS5v20(SHA-1,AES-256/CBC)";
- std::auto_ptr<PBE> pbe(get_pbe(((pbe_algo != "") ? pbe_algo : DEFAULT_PBE)));
+ std::unique_ptr<PBE> pbe(get_pbe(((pbe_algo != "") ? pbe_algo : DEFAULT_PBE)));
pbe->new_params(rng);
pbe->set_key(pass);
@@ -200,10 +200,10 @@ std::string PEM_encode(const Private_Key& key,
*/
Private_Key* load_key(DataSource& source,
RandomNumberGenerator& rng,
- const User_Interface& ui)
+ std::function<std::pair<bool, std::string> ()> get_pass)
{
AlgorithmIdentifier alg_id;
- SecureVector<byte> pkcs8_key = PKCS8_decode(source, ui, alg_id);
+ SecureVector<byte> pkcs8_key = PKCS8_decode(source, get_pass, alg_id);
const std::string alg_name = OIDS::lookup(alg_id.oid);
if(alg_name == "" || alg_name == alg_id.oid.as_string())
@@ -218,12 +218,38 @@ Private_Key* load_key(DataSource& source,
*/
Private_Key* load_key(const std::string& fsname,
RandomNumberGenerator& rng,
- const User_Interface& ui)
+ std::function<std::pair<bool, std::string> ()> get_pass)
{
DataSource_Stream source(fsname, true);
- return PKCS8::load_key(source, rng, ui);
+ return PKCS8::load_key(source, rng, get_pass);
}
+namespace {
+
+class Single_Shot_Passphrase
+ {
+ public:
+ Single_Shot_Passphrase(const std::string& pass) :
+ passphrase(pass), first(true) {}
+
+ std::pair<bool, std::string> operator()()
+ {
+ if(first)
+ {
+ first = false;
+ return std::make_pair(true, passphrase);
+ }
+ else
+ return std::make_pair(false, "");
+ }
+
+ private:
+ std::string passphrase;
+ bool first;
+ };
+
+}
+
/*
* Extract a private key and return it
*/
@@ -231,7 +257,7 @@ Private_Key* load_key(DataSource& source,
RandomNumberGenerator& rng,
const std::string& pass)
{
- return PKCS8::load_key(source, rng, User_Interface(pass));
+ return PKCS8::load_key(source, rng, Single_Shot_Passphrase(pass));
}
/*
@@ -241,7 +267,7 @@ Private_Key* load_key(const std::string& fsname,
RandomNumberGenerator& rng,
const std::string& pass)
{
- return PKCS8::load_key(fsname, rng, User_Interface(pass));
+ return PKCS8::load_key(fsname, rng, Single_Shot_Passphrase(pass));
}
/*
diff --git a/src/pubkey/pkcs8.h b/src/pubkey/pkcs8.h
index 00607b329..d573fb460 100644
--- a/src/pubkey/pkcs8.h
+++ b/src/pubkey/pkcs8.h
@@ -9,7 +9,7 @@
#define BOTAN_PKCS8_H__
#include <botan/x509_key.h>
-#include <botan/ui.h>
+#include <functional>
namespace Botan {
@@ -123,18 +123,19 @@ inline void encrypt_key(const Private_Key& key,
* Load a key from a data source.
* @param source the data source providing the encoded key
* @param rng the rng to use
-* @param ui the user interface to be used for passphrase dialog
+* @param get_passphrase a function that returns passphrases
* @return loaded private key object
*/
-BOTAN_DLL Private_Key* load_key(DataSource& source,
- RandomNumberGenerator& rng,
- const User_Interface& ui);
+BOTAN_DLL Private_Key* load_key(
+ DataSource& source,
+ RandomNumberGenerator& rng,
+ std::function<std::pair<bool, std::string> ()> get_passphrase);
/** Load a key from a data source.
* @param source the data source providing the encoded key
* @param rng the rng to use
* @param pass the passphrase to decrypt the key. Provide an empty
-* string if the key is not encoded.
+* string if the key is not encrypted
* @return loaded private key object
*/
BOTAN_DLL Private_Key* load_key(DataSource& source,
@@ -145,18 +146,19 @@ BOTAN_DLL Private_Key* load_key(DataSource& source,
* Load a key from a file.
* @param filename the path to the file containing the encoded key
* @param rng the rng to use
-* @param ui the user interface to be used for passphrase dialog
+* @param get_passphrase a function that returns passphrases
* @return loaded private key object
*/
-BOTAN_DLL Private_Key* load_key(const std::string& filename,
- RandomNumberGenerator& rng,
- const User_Interface& ui);
+BOTAN_DLL Private_Key* load_key(
+ const std::string& filename,
+ RandomNumberGenerator& rng,
+ std::function<std::pair<bool, std::string> ()> get_passphrase);
/** Load a key from a file.
* @param filename the path to the file containing the encoded key
* @param rng the rng to use
* @param pass the passphrase to decrypt the key. Provide an empty
-* string if the key is not encoded.
+* string if the key is not encrypted
* @return loaded private key object
*/
BOTAN_DLL Private_Key* load_key(const std::string& filename,
diff --git a/src/pubkey/pubkey.cpp b/src/pubkey/pubkey.cpp
index 6e63f9fc9..d0b74071c 100644
--- a/src/pubkey/pubkey.cpp
+++ b/src/pubkey/pubkey.cpp
@@ -238,7 +238,7 @@ SecureVector<byte> PK_Signer::signature(RandomNumberGenerator& rng)
}
else
throw Encoding_Error("PK_Signer: Unknown signature format " +
- to_string(sig_format));
+ std::to_string(sig_format));
}
/*
@@ -324,7 +324,7 @@ bool PK_Verifier::check_signature(const byte sig[], size_t length)
}
else
throw Decoding_Error("PK_Verifier: Unknown signature format " +
- to_string(sig_format));
+ std::to_string(sig_format));
}
catch(Invalid_Argument) { return false; }
}
diff --git a/src/pubkey/rsa/rsa.cpp b/src/pubkey/rsa/rsa.cpp
index 40c3968af..2da366699 100644
--- a/src/pubkey/rsa/rsa.cpp
+++ b/src/pubkey/rsa/rsa.cpp
@@ -11,6 +11,7 @@
#include <botan/numthry.h>
#include <botan/keypair.h>
#include <botan/internal/assert.h>
+#include <future>
namespace Botan {
@@ -22,7 +23,7 @@ RSA_PrivateKey::RSA_PrivateKey(RandomNumberGenerator& rng,
{
if(bits < 512)
throw Invalid_Argument(algo_name() + ": Can't make a key that is only " +
- to_string(bits) + " bits long");
+ std::to_string(bits) + " bits long");
if(exp < 3 || exp % 2 == 0)
throw Invalid_Argument(algo_name() + ": Invalid encryption exponent");
@@ -78,8 +79,9 @@ BigInt RSA_Private_Operation::private_op(const BigInt& m) const
if(m >= n)
throw Invalid_Argument("RSA private op - input is too large");
- BigInt j1 = powermod_d1_p(m);
+ auto future_j1 = std::async(std::launch::async, powermod_d1_p, m);
BigInt j2 = powermod_d2_q(m);
+ BigInt j1 = future_j1.get();
j1 = mod_p.reduce(sub_mul(j1, j2, c));
diff --git a/src/pubkey/rw/rw.cpp b/src/pubkey/rw/rw.cpp
index 5f58d8e88..dab84b59f 100644
--- a/src/pubkey/rw/rw.cpp
+++ b/src/pubkey/rw/rw.cpp
@@ -21,7 +21,7 @@ RW_PrivateKey::RW_PrivateKey(RandomNumberGenerator& rng,
{
if(bits < 512)
throw Invalid_Argument(algo_name() + ": Can't make a key that is only " +
- to_string(bits) + " bits long");
+ std::to_string(bits) + " bits long");
if(exp < 2 || exp % 2 == 1)
throw Invalid_Argument(algo_name() + ": Invalid encryption exponent");
diff --git a/src/rng/hmac_rng/hmac_rng.cpp b/src/rng/hmac_rng/hmac_rng.cpp
index 174651e18..311942c19 100644
--- a/src/rng/hmac_rng/hmac_rng.cpp
+++ b/src/rng/hmac_rng/hmac_rng.cpp
@@ -8,7 +8,6 @@
#include <botan/hmac_rng.h>
#include <botan/get_byte.h>
#include <botan/internal/xor_buf.h>
-#include <botan/internal/stl_util.h>
#include <algorithm>
namespace Botan {
@@ -224,8 +223,8 @@ HMAC_RNG::~HMAC_RNG()
delete extractor;
delete prf;
- std::for_each(entropy_sources.begin(), entropy_sources.end(),
- del_fun<EntropySource>());
+ for(auto src : entropy_sources)
+ delete src;
counter = 0;
}
diff --git a/src/rng/randpool/randpool.cpp b/src/rng/randpool/randpool.cpp
index 92f225a9c..51354db12 100644
--- a/src/rng/randpool/randpool.cpp
+++ b/src/rng/randpool/randpool.cpp
@@ -8,8 +8,8 @@
#include <botan/randpool.h>
#include <botan/get_byte.h>
#include <botan/internal/xor_buf.h>
-#include <botan/internal/stl_util.h>
#include <algorithm>
+#include <chrono>
namespace Botan {
@@ -202,8 +202,8 @@ Randpool::~Randpool()
delete cipher;
delete mac;
- std::for_each(entropy_sources.begin(), entropy_sources.end(),
- del_fun<EntropySource>());
+ for(auto i = entropy_sources.begin(); i != entropy_sources.end(); ++i)
+ delete *i;
}
}
diff --git a/src/selftest/selftest.cpp b/src/selftest/selftest.cpp
index 0dac31cef..8f4dc70d8 100644
--- a/src/selftest/selftest.cpp
+++ b/src/selftest/selftest.cpp
@@ -125,8 +125,7 @@ namespace {
void verify_results(const std::string& algo,
const std::map<std::string, bool>& results)
{
- for(std::map<std::string, bool>::const_iterator i = results.begin();
- i != results.end(); ++i)
+ for(auto i = results.begin(); i != results.end(); ++i)
{
if(!i->second)
throw Self_Test_Failure(algo + " self-test failed, provider "+
diff --git a/src/ssl/c_kex.cpp b/src/ssl/c_kex.cpp
deleted file mode 100644
index 0f20b819c..000000000
--- a/src/ssl/c_kex.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
-* Client Key Exchange Message
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/internal/tls_messages.h>
-#include <botan/internal/tls_reader.h>
-#include <botan/pubkey.h>
-#include <botan/dh.h>
-#include <botan/rsa.h>
-#include <botan/rng.h>
-#include <botan/loadstor.h>
-#include <memory>
-
-namespace Botan {
-
-/**
-* Create a new Client Key Exchange message
-*/
-Client_Key_Exchange::Client_Key_Exchange(RandomNumberGenerator& rng,
- Record_Writer& writer,
- HandshakeHash& hash,
- const Public_Key* pub_key,
- Version_Code using_version,
- Version_Code pref_version)
- {
- include_length = true;
-
- if(const DH_PublicKey* dh_pub = dynamic_cast<const DH_PublicKey*>(pub_key))
- {
- DH_PrivateKey priv_key(rng, dh_pub->get_domain());
-
- PK_Key_Agreement ka(priv_key, "Raw");
-
- pre_master = ka.derive_key(0, dh_pub->public_value()).bits_of();
-
- key_material = priv_key.public_value();
- }
- else if(const RSA_PublicKey* rsa_pub = dynamic_cast<const RSA_PublicKey*>(pub_key))
- {
- pre_master = rng.random_vec(48);
- pre_master[0] = (pref_version >> 8) & 0xFF;
- pre_master[1] = (pref_version ) & 0xFF;
-
- PK_Encryptor_EME encryptor(*rsa_pub, "PKCS1v15");
-
- key_material = encryptor.encrypt(pre_master, rng);
-
- if(using_version == SSL_V3)
- include_length = false;
- }
- else
- throw Invalid_Argument("Client_Key_Exchange: Key not RSA or DH");
-
- send(writer, hash);
- }
-
-/**
-* Read a Client Key Exchange message
-*/
-Client_Key_Exchange::Client_Key_Exchange(const MemoryRegion<byte>& contents,
- const CipherSuite& suite,
- Version_Code using_version)
- {
- include_length = true;
-
- if(using_version == SSL_V3 && (suite.kex_type() == TLS_ALGO_KEYEXCH_RSA))
- include_length = false;
-
- deserialize(contents);
- }
-
-/**
-* Serialize a Client Key Exchange message
-*/
-SecureVector<byte> Client_Key_Exchange::serialize() const
- {
- if(include_length)
- {
- SecureVector<byte> buf;
- append_tls_length_value(buf, key_material, 2);
- return buf;
- }
- else
- return key_material;
- }
-
-/**
-* Deserialize a Client Key Exchange message
-*/
-void Client_Key_Exchange::deserialize(const MemoryRegion<byte>& buf)
- {
- if(include_length)
- {
- TLS_Data_Reader reader(buf);
- key_material = reader.get_range<byte>(2, 0, 65535);
- }
- else
- key_material = buf;
- }
-
-/**
-* Return the pre_master_secret
-*/
-SecureVector<byte>
-Client_Key_Exchange::pre_master_secret(RandomNumberGenerator& rng,
- const Private_Key* priv_key,
- Version_Code version)
- {
-
- if(const DH_PrivateKey* dh_priv = dynamic_cast<const DH_PrivateKey*>(priv_key))
- {
- try {
- PK_Key_Agreement ka(*dh_priv, "Raw");
-
- pre_master = ka.derive_key(0, key_material).bits_of();
- }
- catch(...)
- {
- /*
- * Something failed in the DH computation. To avoid possible
- * timing attacks, randomize the pre-master output and carry
- * on, allowing the protocol to fail later in the finished
- * checks.
- */
- pre_master = rng.random_vec(dh_priv->public_value().size());
- }
-
- return pre_master;
- }
- else if(const RSA_PrivateKey* rsa_priv = dynamic_cast<const RSA_PrivateKey*>(priv_key))
- {
- PK_Decryptor_EME decryptor(*rsa_priv, "PKCS1v15");
-
- try {
- pre_master = decryptor.decrypt(key_material);
-
- if(pre_master.size() != 48 ||
- make_u16bit(pre_master[0], pre_master[1]) != version)
- throw Decoding_Error("Client_Key_Exchange: Secret corrupted");
- }
- catch(...)
- {
- pre_master = rng.random_vec(48);
- pre_master[0] = (version >> 8) & 0xFF;
- pre_master[1] = (version ) & 0xFF;
- }
-
- return pre_master;
- }
- else
- throw Invalid_Argument("Client_Key_Exchange: Bad key for decrypt");
- }
-
-/**
-* Return the pre_master_secret
-*/
-SecureVector<byte> Client_Key_Exchange::pre_master_secret() const
- {
- return pre_master;
- }
-
-}
diff --git a/src/ssl/cert_req.cpp b/src/ssl/cert_req.cpp
deleted file mode 100644
index b8b2624bf..000000000
--- a/src/ssl/cert_req.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
-* Certificate Request Message
-* (C) 2004-2006 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/internal/tls_messages.h>
-#include <botan/internal/tls_reader.h>
-#include <botan/der_enc.h>
-#include <botan/ber_dec.h>
-#include <botan/loadstor.h>
-#include <botan/secqueue.h>
-
-namespace Botan {
-
-/**
-* Create a new Certificate Request message
-*/
-Certificate_Req::Certificate_Req(Record_Writer& writer,
- HandshakeHash& hash,
- const std::vector<X509_Certificate>& certs)
- {
- for(size_t i = 0; i != certs.size(); ++i)
- names.push_back(certs[i].subject_dn());
-
- // FIXME: should be able to choose what to ask for
- types.push_back(RSA_CERT);
- types.push_back(DSS_CERT);
-
- send(writer, hash);
- }
-
-/**
-* Serialize a Certificate Request message
-*/
-SecureVector<byte> Certificate_Req::serialize() const
- {
- SecureVector<byte> buf;
-
- append_tls_length_value(buf, types, 1);
-
- DER_Encoder encoder;
- for(size_t i = 0; i != names.size(); ++i)
- encoder.encode(names[i]);
-
- append_tls_length_value(buf, encoder.get_contents(), 2);
-
- return buf;
- }
-
-/**
-* Deserialize a Certificate Request message
-*/
-void Certificate_Req::deserialize(const MemoryRegion<byte>& buf)
- {
- if(buf.size() < 4)
- throw Decoding_Error("Certificate_Req: Bad certificate request");
-
- size_t types_size = buf[0];
-
- if(buf.size() < types_size + 3)
- throw Decoding_Error("Certificate_Req: Bad certificate request");
-
- for(size_t i = 0; i != types_size; ++i)
- types.push_back(static_cast<Certificate_Type>(buf[i+1]));
-
- size_t names_size = make_u16bit(buf[types_size+2], buf[types_size+3]);
-
- if(buf.size() != names_size + types_size + 3)
- throw Decoding_Error("Certificate_Req: Bad certificate request");
-
- BER_Decoder decoder(&buf[types_size + 3], names_size);
-
- while(decoder.more_items())
- {
- X509_DN name;
- decoder.decode(name);
- names.push_back(name);
- }
- }
-
-/**
-* Create a new Certificate message
-*/
-Certificate::Certificate(Record_Writer& writer,
- const std::vector<X509_Certificate>& cert_list,
- HandshakeHash& hash)
- {
- certs = cert_list;
- send(writer, hash);
- }
-
-/**
-* Serialize a Certificate message
-*/
-SecureVector<byte> Certificate::serialize() const
- {
- SecureVector<byte> buf(3);
-
- for(size_t i = 0; i != certs.size(); ++i)
- {
- SecureVector<byte> raw_cert = certs[i].BER_encode();
- const size_t cert_size = raw_cert.size();
- for(size_t i = 0; i != 3; ++i)
- buf.push_back(get_byte<u32bit>(i+1, cert_size));
- buf += raw_cert;
- }
-
- const size_t buf_size = buf.size() - 3;
- for(size_t i = 0; i != 3; ++i)
- buf[i] = get_byte<u32bit>(i+1, buf_size);
-
- return buf;
- }
-
-/**
-* Deserialize a Certificate message
-*/
-void Certificate::deserialize(const MemoryRegion<byte>& buf)
- {
- if(buf.size() < 3)
- throw Decoding_Error("Certificate: Message malformed");
-
- const size_t total_size = make_u32bit(0, buf[0], buf[1], buf[2]);
-
- SecureQueue queue;
- queue.write(&buf[3], buf.size() - 3);
-
- if(queue.size() != total_size)
- throw Decoding_Error("Certificate: Message malformed");
-
- while(queue.size())
- {
- if(queue.size() < 3)
- throw Decoding_Error("Certificate: Message malformed");
-
- byte len[3];
- queue.read(len, 3);
-
- const size_t cert_size = make_u32bit(0, len[0], len[1], len[2]);
- const size_t original_size = queue.size();
-
- X509_Certificate cert(queue);
- if(queue.size() + cert_size != original_size)
- throw Decoding_Error("Certificate: Message malformed");
- certs.push_back(cert);
- }
- }
-
-}
diff --git a/src/ssl/cert_ver.cpp b/src/ssl/cert_ver.cpp
deleted file mode 100644
index b634a662d..000000000
--- a/src/ssl/cert_ver.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
-* Certificate Verify Message
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/internal/tls_messages.h>
-#include <botan/internal/tls_reader.h>
-#include <botan/pubkey.h>
-#include <botan/rsa.h>
-#include <botan/dsa.h>
-#include <botan/loadstor.h>
-#include <memory>
-
-namespace Botan {
-
-/**
-* Create a new Certificate Verify message
-*/
-Certificate_Verify::Certificate_Verify(RandomNumberGenerator& rng,
- Record_Writer& writer,
- HandshakeHash& hash,
- const Private_Key* priv_key)
- {
- std::string padding = "";
- Signature_Format format = IEEE_1363;
-
- if(priv_key->algo_name() == "RSA")
- padding = "EMSA3(TLS.Digest.0)";
- else if(priv_key->algo_name() == "DSA")
- {
- padding = "EMSA1(SHA-1)";
- format = DER_SEQUENCE;
- }
- else
- throw Invalid_Argument(priv_key->algo_name() +
- " is invalid/unknown for TLS signatures");
-
- PK_Signer signer(*priv_key, padding, format);
-
- signature = signer.sign_message(hash.final(), rng);
- send(writer, hash);
- }
-
-/**
-* Serialize a Certificate Verify message
-*/
-SecureVector<byte> Certificate_Verify::serialize() const
- {
- SecureVector<byte> buf;
-
- const u16bit sig_len = signature.size();
- buf.push_back(get_byte(0, sig_len));
- buf.push_back(get_byte(1, sig_len));
- buf += signature;
-
- return buf;
- }
-
-/**
-* Deserialize a Certificate Verify message
-*/
-void Certificate_Verify::deserialize(const MemoryRegion<byte>& buf)
- {
- TLS_Data_Reader reader(buf);
- signature = reader.get_range<byte>(2, 0, 65535);
- }
-
-/**
-* Verify a Certificate Verify message
-*/
-bool Certificate_Verify::verify(const X509_Certificate& cert,
- HandshakeHash& hash)
- {
- // FIXME: duplicate of Server_Key_Exchange::verify
-
- std::auto_ptr<Public_Key> key(cert.subject_public_key());
-
- std::string padding = "";
- Signature_Format format = IEEE_1363;
-
- if(key->algo_name() == "RSA")
- padding = "EMSA3(TLS.Digest.0)";
- else if(key->algo_name() == "DSA")
- {
- padding = "EMSA1(SHA-1)";
- format = DER_SEQUENCE;
- }
- else
- throw Invalid_Argument(key->algo_name() +
- " is invalid/unknown for TLS signatures");
-
- PK_Verifier verifier(*key, padding, format);
- return verifier.verify_message(hash.final(), signature);
- }
-
-}
diff --git a/src/ssl/finished.cpp b/src/ssl/finished.cpp
deleted file mode 100644
index d76fbd884..000000000
--- a/src/ssl/finished.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
-* Finished Message
-* (C) 2004-2006 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/internal/tls_messages.h>
-#include <botan/prf_tls.h>
-
-namespace Botan {
-
-/**
-* Create a new Finished message
-*/
-Finished::Finished(Record_Writer& writer,
- Version_Code version, Connection_Side side,
- const MemoryRegion<byte>& master_secret,
- HandshakeHash& hash)
- {
- verification_data = compute_verify(master_secret, hash, side, version);
- send(writer, hash);
- }
-
-/**
-* Serialize a Finished message
-*/
-SecureVector<byte> Finished::serialize() const
- {
- return verification_data;
- }
-
-/**
-* Deserialize a Finished message
-*/
-void Finished::deserialize(const MemoryRegion<byte>& buf)
- {
- verification_data = buf;
- }
-
-/**
-* Verify a Finished message
-*/
-bool Finished::verify(const MemoryRegion<byte>& secret, Version_Code version,
- const HandshakeHash& hash, Connection_Side side)
- {
- SecureVector<byte> computed = compute_verify(secret, hash, side, version);
- if(computed == verification_data)
- return true;
- return false;
- }
-
-/**
-* Compute the verify_data
-*/
-SecureVector<byte> Finished::compute_verify(const MemoryRegion<byte>& secret,
- HandshakeHash hash,
- Connection_Side side,
- Version_Code version)
- {
- if(version == SSL_V3)
- {
- const byte SSL_CLIENT_LABEL[] = { 0x43, 0x4C, 0x4E, 0x54 };
- const byte SSL_SERVER_LABEL[] = { 0x53, 0x52, 0x56, 0x52 };
-
- SecureVector<byte> ssl3_finished;
-
- if(side == CLIENT)
- hash.update(SSL_CLIENT_LABEL, sizeof(SSL_CLIENT_LABEL));
- else
- hash.update(SSL_SERVER_LABEL, sizeof(SSL_SERVER_LABEL));
-
- return hash.final_ssl3(secret);
- }
- else if(version == TLS_V10 || version == TLS_V11)
- {
- const byte TLS_CLIENT_LABEL[] = {
- 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x66, 0x69, 0x6E, 0x69,
- 0x73, 0x68, 0x65, 0x64 };
-
- const byte TLS_SERVER_LABEL[] = {
- 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x66, 0x69, 0x6E, 0x69,
- 0x73, 0x68, 0x65, 0x64 };
-
- TLS_PRF prf;
-
- SecureVector<byte> input;
- if(side == CLIENT)
- input += std::make_pair(TLS_CLIENT_LABEL, sizeof(TLS_CLIENT_LABEL));
- else
- input += std::make_pair(TLS_SERVER_LABEL, sizeof(TLS_SERVER_LABEL));
- input += hash.final();
-
- return prf.derive_key(12, secret, input);
- }
- else
- throw Invalid_Argument("Finished message: Unknown protocol version");
- }
-
-}
diff --git a/src/ssl/hello.cpp b/src/ssl/hello.cpp
deleted file mode 100644
index ae0d9607b..000000000
--- a/src/ssl/hello.cpp
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
-* TLS Hello Messages
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/internal/tls_messages.h>
-#include <botan/internal/tls_reader.h>
-
-namespace Botan {
-
-/*
-* Encode and send a Handshake message
-*/
-void HandshakeMessage::send(Record_Writer& writer, HandshakeHash& hash) const
- {
- SecureVector<byte> buf = serialize();
- SecureVector<byte> send_buf(4);
-
- const size_t buf_size = buf.size();
-
- send_buf[0] = type();
-
- for(size_t i = 1; i != 4; ++i)
- send_buf[i] = get_byte<u32bit>(i, buf_size);
-
- send_buf += buf;
-
- hash.update(send_buf);
-
- writer.send(HANDSHAKE, &send_buf[0], send_buf.size());
- writer.flush();
- }
-
-/*
-* Create a new Hello Request message
-*/
-Hello_Request::Hello_Request(Record_Writer& writer)
- {
- HandshakeHash dummy; // FIXME: *UGLY*
- send(writer, dummy);
- }
-
-/*
-* Serialize a Hello Request message
-*/
-SecureVector<byte> Hello_Request::serialize() const
- {
- return SecureVector<byte>();
- }
-
-/*
-* Deserialize a Hello Request message
-*/
-void Hello_Request::deserialize(const MemoryRegion<byte>& buf)
- {
- if(buf.size())
- throw Decoding_Error("Hello_Request: Must be empty, and is not");
- }
-
-/*
-* Create a new Client Hello message
-*/
-Client_Hello::Client_Hello(RandomNumberGenerator& rng,
- Record_Writer& writer,
- const TLS_Policy& policy,
- HandshakeHash& hash)
- {
- c_random = rng.random_vec(32);
-
- suites = policy.ciphersuites();
- comp_algos = policy.compression();
- c_version = policy.pref_version();
-
- send(writer, hash);
- }
-
-/*
-* Serialize a Client Hello message
-*/
-SecureVector<byte> Client_Hello::serialize() const
- {
- SecureVector<byte> buf;
-
- buf.push_back(static_cast<byte>(c_version >> 8));
- buf.push_back(static_cast<byte>(c_version ));
- buf += c_random;
-
- append_tls_length_value(buf, sess_id, 1);
- append_tls_length_value(buf, suites, 2);
- append_tls_length_value(buf, comp_algos, 1);
-
- return buf;
- }
-
-void Client_Hello::deserialize_sslv2(const MemoryRegion<byte>& buf)
- {
- if(buf.size() < 12 || buf[0] != 1)
- throw Decoding_Error("Client_Hello: SSLv2 hello corrupted");
-
- const size_t cipher_spec_len = make_u16bit(buf[3], buf[4]);
- const size_t sess_id_len = make_u16bit(buf[5], buf[6]);
- const size_t challenge_len = make_u16bit(buf[7], buf[8]);
-
- const size_t expected_size =
- (9 + sess_id_len + cipher_spec_len + challenge_len);
-
- if(buf.size() != expected_size)
- throw Decoding_Error("Client_Hello: SSLv2 hello corrupted");
-
- if(sess_id_len != 0 || cipher_spec_len % 3 != 0 ||
- (challenge_len < 16 || challenge_len > 32))
- {
- throw Decoding_Error("Client_Hello: SSLv2 hello corrupted");
- }
-
- for(size_t i = 9; i != 9 + cipher_spec_len; i += 3)
- {
- if(buf[i] != 0) // a SSLv2 cipherspec; ignore it
- continue;
-
- suites.push_back(make_u16bit(buf[i+1], buf[i+2]));
- }
-
- c_version = static_cast<Version_Code>(make_u16bit(buf[1], buf[2]));
-
- c_random.resize(challenge_len);
- copy_mem(&c_random[0], &buf[9+cipher_spec_len+sess_id_len], challenge_len);
- }
-
-/*
-* Deserialize a Client Hello message
-*/
-void Client_Hello::deserialize(const MemoryRegion<byte>& buf)
- {
- if(buf.size() == 0)
- throw Decoding_Error("Client_Hello: Packet corrupted");
-
- if(buf.size() < 41)
- throw Decoding_Error("Client_Hello: Packet corrupted");
-
- TLS_Data_Reader reader(buf);
-
- c_version = static_cast<Version_Code>(reader.get_u16bit());
- c_random = reader.get_fixed<byte>(32);
-
- sess_id = reader.get_range<byte>(1, 0, 32);
-
- suites = reader.get_range_vector<u16bit>(2, 1, 32767);
-
- comp_algos = reader.get_range_vector<byte>(1, 1, 255);
-
- if(reader.has_remaining())
- {
- const u16bit all_extn_size = reader.get_u16bit();
-
- if(reader.remaining_bytes() != all_extn_size)
- throw Decoding_Error("Client_Hello: Bad extension size");
-
- while(reader.has_remaining())
- {
- const u16bit extension_code = reader.get_u16bit();
- const u16bit extension_size = reader.get_u16bit();
-
- if(extension_code == TLSEXT_SERVER_NAME_INDICATION)
- {
- u16bit name_bytes = reader.get_u16bit();
-
- while(name_bytes)
- {
- byte name_type = reader.get_byte();
- name_bytes--;
-
- if(name_type == 0) // DNS
- {
- std::vector<byte> name =
- reader.get_range_vector<byte>(2, 1, 65535);
-
- requested_hostname.assign(
- reinterpret_cast<const char*>(&name[0]),
- name.size());
-
- name_bytes -= (2 + name.size());
- }
- else
- {
- reader.discard_next(name_bytes);
- name_bytes = 0;
- }
- }
- }
- else if(extension_code == TLSEXT_SRP_IDENTIFIER)
- {
- std::vector<byte> name = reader.get_range_vector<byte>(1, 1, 255);
-
- requested_srp_id.assign(
- reinterpret_cast<char*>(&name[0]),
- name.size());
- }
- else
- {
- reader.discard_next(extension_size);
- }
- }
- }
- }
-
-/*
-* Check if we offered this ciphersuite
-*/
-bool Client_Hello::offered_suite(u16bit ciphersuite) const
- {
- for(size_t i = 0; i != suites.size(); ++i)
- if(suites[i] == ciphersuite)
- return true;
- return false;
- }
-
-/*
-* Create a new Server Hello message
-*/
-Server_Hello::Server_Hello(RandomNumberGenerator& rng,
- Record_Writer& writer,
- const TLS_Policy& policy,
- const std::vector<X509_Certificate>& certs,
- const Client_Hello& c_hello,
- Version_Code ver,
- HandshakeHash& hash)
- {
- bool have_rsa = false, have_dsa = false;
-
- for(size_t i = 0; i != certs.size(); ++i)
- {
- Public_Key* key = certs[i].subject_public_key();
- if(key->algo_name() == "RSA")
- have_rsa = true;
-
- if(key->algo_name() == "DSA")
- have_dsa = true;
- }
-
- suite = policy.choose_suite(c_hello.ciphersuites(), have_rsa, have_dsa);
-
- if(suite == 0)
- throw TLS_Exception(PROTOCOL_VERSION,
- "Can't agree on a ciphersuite with client");
-
- comp_algo = policy.choose_compression(c_hello.compression_algos());
-
- s_version = ver;
- s_random = rng.random_vec(32);
-
- send(writer, hash);
- }
-
-/*
-* Serialize a Server Hello message
-*/
-SecureVector<byte> Server_Hello::serialize() const
- {
- SecureVector<byte> buf;
-
- buf.push_back(static_cast<byte>(s_version >> 8));
- buf.push_back(static_cast<byte>(s_version ));
- buf += s_random;
-
- append_tls_length_value(buf, sess_id, 1);
-
- buf.push_back(get_byte(0, suite));
- buf.push_back(get_byte(1, suite));
-
- buf.push_back(comp_algo);
-
- return buf;
- }
-
-/*
-* Deserialize a Server Hello message
-*/
-void Server_Hello::deserialize(const MemoryRegion<byte>& buf)
- {
- if(buf.size() < 38)
- throw Decoding_Error("Server_Hello: Packet corrupted");
-
- TLS_Data_Reader reader(buf);
-
- s_version = static_cast<Version_Code>(reader.get_u16bit());
-
- if(s_version != SSL_V3 && s_version != TLS_V10 && s_version != TLS_V11)
- {
- throw TLS_Exception(PROTOCOL_VERSION,
- "Server_Hello: Unsupported server version");
- }
-
- s_random = reader.get_fixed<byte>(32);
-
- sess_id = reader.get_range<byte>(1, 0, 32);
-
- suite = reader.get_u16bit();
-
- comp_algo = reader.get_byte();
- }
-
-/*
-* Create a new Server Hello Done message
-*/
-Server_Hello_Done::Server_Hello_Done(Record_Writer& writer,
- HandshakeHash& hash)
- {
- send(writer, hash);
- }
-
-/*
-* Serialize a Server Hello Done message
-*/
-SecureVector<byte> Server_Hello_Done::serialize() const
- {
- return SecureVector<byte>();
- }
-
-/*
-* Deserialize a Server Hello Done message
-*/
-void Server_Hello_Done::deserialize(const MemoryRegion<byte>& buf)
- {
- if(buf.size())
- throw Decoding_Error("Server_Hello_Done: Must be empty, and is not");
- }
-
-}
diff --git a/src/ssl/info.txt b/src/ssl/info.txt
deleted file mode 100644
index 169b76115..000000000
--- a/src/ssl/info.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-define SSL_TLS
-
-load_on request
-
-<comment>
-A new TLS API is being developed. This version has numerous
-performance and usability issues and will not be supported in the
-future. Only use it if you need it for compatability with code written
-against previous versions.
-</comment>
-
-uses_tr1 yes
-
-<header:public>
-tls_client.h
-tls_connection.h
-tls_exceptn.h
-tls_magic.h
-tls_policy.h
-tls_record.h
-tls_server.h
-tls_session_key.h
-tls_suites.h
-</header:public>
-
-<header:internal>
-tls_alerts.h
-tls_handshake_hash.h
-tls_messages.h
-tls_reader.h
-tls_state.h
-</header:internal>
-
-<source>
-c_kex.cpp
-cert_req.cpp
-cert_ver.cpp
-finished.cpp
-tls_handshake_hash.cpp
-hello.cpp
-rec_read.cpp
-rec_wri.cpp
-s_kex.cpp
-tls_client.cpp
-tls_policy.cpp
-tls_server.cpp
-tls_session_key.cpp
-tls_state.cpp
-tls_suites.cpp
-</source>
-
-<requires>
-aes
-arc4
-asn1
-des
-dh
-dsa
-eme_pkcs
-emsa3
-filters
-hmac
-md5
-prf_ssl3
-prf_tls
-rng
-rsa
-sha1
-ssl3mac
-x509cert
-</requires>
diff --git a/src/ssl/rec_read.cpp b/src/ssl/rec_read.cpp
deleted file mode 100644
index 7e295f8a4..000000000
--- a/src/ssl/rec_read.cpp
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
-* TLS Record Reading
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/tls_record.h>
-#include <botan/lookup.h>
-#include <botan/loadstor.h>
-
-namespace Botan {
-
-/*
-* Reset the state
-*/
-void Record_Reader::reset()
- {
- cipher.reset();
-
- delete mac;
- mac = 0;
-
- mac_size = 0;
- block_size = 0;
- iv_size = 0;
- major = minor = 0;
- seq_no = 0;
- }
-
-/*
-* Set the version to use
-*/
-void Record_Reader::set_version(Version_Code version)
- {
- if(version != SSL_V3 && version != TLS_V10 && version != TLS_V11)
- throw Invalid_Argument("Record_Reader: Invalid protocol version");
-
- major = (version >> 8) & 0xFF;
- minor = (version & 0xFF);
- }
-
-/*
-* Set the keys for reading
-*/
-void Record_Reader::set_keys(const CipherSuite& suite, const SessionKeys& keys,
- Connection_Side side)
- {
- cipher.reset();
- delete mac;
- mac = 0;
-
- SymmetricKey mac_key, cipher_key;
- InitializationVector iv;
-
- if(side == CLIENT)
- {
- cipher_key = keys.server_cipher_key();
- iv = keys.server_iv();
- mac_key = keys.server_mac_key();
- }
- else
- {
- cipher_key = keys.client_cipher_key();
- iv = keys.client_iv();
- mac_key = keys.client_mac_key();
- }
-
- const std::string cipher_algo = suite.cipher_algo();
- const std::string mac_algo = suite.mac_algo();
-
- if(have_block_cipher(cipher_algo))
- {
- cipher.append(get_cipher(
- cipher_algo + "/CBC/NoPadding",
- cipher_key, iv, DECRYPTION)
- );
- block_size = block_size_of(cipher_algo);
-
- if(major > 3 || (major == 3 && minor >= 2))
- iv_size = block_size;
- else
- iv_size = 0;
- }
- else if(have_stream_cipher(cipher_algo))
- {
- cipher.append(get_cipher(cipher_algo, cipher_key, DECRYPTION));
- block_size = 0;
- iv_size = 0;
- }
- else
- throw Invalid_Argument("Record_Reader: Unknown cipher " + cipher_algo);
-
- if(have_hash(mac_algo))
- {
- Algorithm_Factory& af = global_state().algorithm_factory();
-
- if(major == 3 && minor == 0)
- mac = af.make_mac("SSL3-MAC(" + mac_algo + ")");
- else
- mac = af.make_mac("HMAC(" + mac_algo + ")");
-
- mac->set_key(mac_key);
- mac_size = mac->output_length();
- }
- else
- throw Invalid_Argument("Record_Reader: Unknown hash " + mac_algo);
- }
-
-void Record_Reader::add_input(const byte input[], size_t input_size)
- {
- input_queue.write(input, input_size);
- }
-
-/*
-* Retrieve the next record
-*/
-size_t Record_Reader::get_record(byte& msg_type,
- MemoryRegion<byte>& output)
- {
- byte header[5] = { 0 };
-
- const size_t have_in_queue = input_queue.size();
-
- if(have_in_queue < sizeof(header))
- return (sizeof(header) - have_in_queue);
-
- /*
- * We peek first to make sure we have the full record
- */
- input_queue.peek(header, sizeof(header));
-
- // SSLv2-format client hello?
- if(header[0] & 0x80 && header[2] == 1 && header[3] == 3)
- {
- size_t record_len = make_u16bit(header[0], header[1]) & 0x7FFF;
-
- if(have_in_queue < record_len + 2)
- return (record_len + 2 - have_in_queue);
-
- msg_type = HANDSHAKE;
- output.resize(record_len + 4);
-
- input_queue.read(&output[2], record_len + 2);
- output[0] = CLIENT_HELLO_SSLV2;
- output[1] = 0;
- output[2] = header[0] & 0x7F;
- output[3] = header[1];
-
- return 0;
- }
-
- if(header[0] != CHANGE_CIPHER_SPEC &&
- header[0] != ALERT &&
- header[0] != HANDSHAKE &&
- header[0] != APPLICATION_DATA)
- {
- throw TLS_Exception(UNEXPECTED_MESSAGE,
- "Record_Reader: Unknown record type");
- }
-
- const u16bit version = make_u16bit(header[1], header[2]);
- const u16bit record_len = make_u16bit(header[3], header[4]);
-
- if(major && (header[1] != major || header[2] != minor))
- throw TLS_Exception(PROTOCOL_VERSION,
- "Record_Reader: Got unexpected version");
-
- // If insufficient data, return without doing anything
- if(have_in_queue < (sizeof(header) + record_len))
- return (sizeof(header) + record_len - have_in_queue);
-
- SecureVector<byte> buffer(record_len);
-
- input_queue.read(header, sizeof(header)); // pull off the header
- input_queue.read(&buffer[0], buffer.size());
-
- /*
- * We are handshaking, no crypto to do so return as-is
- * TODO: Check msg_type to confirm a handshake?
- */
- if(mac_size == 0)
- {
- msg_type = header[0];
- output = buffer;
- return 0; // got a full record
- }
-
- // Otherwise, decrypt, check MAC, return plaintext
-
- cipher.process_msg(buffer);
- SecureVector<byte> plaintext = cipher.read_all(Pipe::LAST_MESSAGE);
-
- size_t pad_size = 0;
-
- if(block_size)
- {
- byte pad_value = plaintext[plaintext.size()-1];
- pad_size = pad_value + 1;
-
- /*
- * Check the padding; if it is wrong, then say we have 0 bytes of
- * padding, which should ensure that the MAC check below does not
- * suceed. This hides a timing channel.
- *
- * This particular countermeasure is recommended in the TLS 1.2
- * spec (RFC 5246) in section 6.2.3.2
- */
- if(version == SSL_V3)
- {
- if(pad_value > block_size)
- pad_size = 0;
- }
- else
- {
- bool padding_good = true;
-
- for(size_t i = 0; i != pad_size; ++i)
- if(plaintext[plaintext.size()-i-1] != pad_value)
- padding_good = false;
-
- if(!padding_good)
- pad_size = 0;
- }
- }
-
- if(plaintext.size() < mac_size + pad_size + iv_size)
- throw Decoding_Error("Record_Reader: Record truncated");
-
- const size_t mac_offset = plaintext.size() - (mac_size + pad_size);
- SecureVector<byte> received_mac(&plaintext[mac_offset],
- mac_size);
-
- const u16bit plain_length = plaintext.size() - (mac_size + pad_size + iv_size);
-
- mac->update_be(seq_no);
- mac->update(header[0]); // msg_type
-
- if(version != SSL_V3)
- for(size_t i = 0; i != 2; ++i)
- mac->update(get_byte(i, version));
-
- mac->update_be(plain_length);
- mac->update(&plaintext[iv_size], plain_length);
-
- ++seq_no;
-
- SecureVector<byte> computed_mac = mac->final();
-
- if(received_mac != computed_mac)
- throw TLS_Exception(BAD_RECORD_MAC, "Record_Reader: MAC failure");
-
- msg_type = header[0];
-
- output.resize(plain_length);
- copy_mem(&output[0], &plaintext[iv_size], plain_length);
- return 0;
- }
-
-}
diff --git a/src/ssl/rec_wri.cpp b/src/ssl/rec_wri.cpp
deleted file mode 100644
index 59dead3cd..000000000
--- a/src/ssl/rec_wri.cpp
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
-* TLS Record Writing
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/tls_record.h>
-#include <botan/internal/tls_handshake_hash.h>
-#include <botan/lookup.h>
-#include <botan/loadstor.h>
-#include <botan/libstate.h>
-
-namespace Botan {
-
-/**
-* Record_Writer Constructor
-*/
-Record_Writer::Record_Writer(std::tr1::function<void (const byte[], size_t)> out) :
- output_fn(out),
- buffer(DEFAULT_BUFFERSIZE)
- {
- mac = 0;
- reset();
- }
-
-/**
-* Reset the state
-*/
-void Record_Writer::reset()
- {
- cipher.reset();
-
- delete mac;
- mac = 0;
-
- zeroise(buffer);
- buf_pos = 0;
-
- major = minor = buf_type = 0;
- block_size = 0;
- mac_size = 0;
- iv_size = 0;
-
- seq_no = 0;
- }
-
-/**
-* Set the version to use
-*/
-void Record_Writer::set_version(Version_Code version)
- {
- if(version != SSL_V3 && version != TLS_V10 && version != TLS_V11)
- throw Invalid_Argument("Record_Writer: Invalid protocol version");
-
- major = (version >> 8) & 0xFF;
- minor = (version & 0xFF);
- }
-
-/**
-* Set the keys for writing
-*/
-void Record_Writer::set_keys(const CipherSuite& suite, const SessionKeys& keys,
- Connection_Side side)
- {
- cipher.reset();
- delete mac;
- mac = 0;
-
- SymmetricKey mac_key, cipher_key;
- InitializationVector iv;
-
- if(side == CLIENT)
- {
- cipher_key = keys.client_cipher_key();
- iv = keys.client_iv();
- mac_key = keys.client_mac_key();
- }
- else
- {
- cipher_key = keys.server_cipher_key();
- iv = keys.server_iv();
- mac_key = keys.server_mac_key();
- }
-
- const std::string cipher_algo = suite.cipher_algo();
- const std::string mac_algo = suite.mac_algo();
-
- if(have_block_cipher(cipher_algo))
- {
- cipher.append(get_cipher(
- cipher_algo + "/CBC/NoPadding",
- cipher_key, iv, ENCRYPTION)
- );
- block_size = block_size_of(cipher_algo);
-
- if(major > 3 || (major == 3 && minor >= 2))
- iv_size = block_size;
- else
- iv_size = 0;
- }
- else if(have_stream_cipher(cipher_algo))
- {
- cipher.append(get_cipher(cipher_algo, cipher_key, ENCRYPTION));
- block_size = 0;
- iv_size = 0;
- }
- else
- throw Invalid_Argument("Record_Writer: Unknown cipher " + cipher_algo);
-
- if(have_hash(mac_algo))
- {
- Algorithm_Factory& af = global_state().algorithm_factory();
-
- if(major == 3 && minor == 0)
- mac = af.make_mac("SSL3-MAC(" + mac_algo + ")");
- else
- mac = af.make_mac("HMAC(" + mac_algo + ")");
-
- mac->set_key(mac_key);
- mac_size = mac->output_length();
- }
- else
- throw Invalid_Argument("Record_Writer: Unknown hash " + mac_algo);
- }
-
-/**
-* Send one or more records to the other side
-*/
-void Record_Writer::send(byte type, const byte input[], size_t length)
- {
- if(type != buf_type)
- flush();
-
- const size_t BUFFER_SIZE = buffer.size();
- buf_type = type;
-
- // FIXME: compression right here
-
- buffer.copy(buf_pos, input, length);
- if(buf_pos + length >= BUFFER_SIZE)
- {
- send_record(buf_type, &buffer[0], length);
- input += (BUFFER_SIZE - buf_pos);
- length -= (BUFFER_SIZE - buf_pos);
- while(length >= BUFFER_SIZE)
- {
- send_record(buf_type, input, BUFFER_SIZE);
- input += BUFFER_SIZE;
- length -= BUFFER_SIZE;
- }
- buffer.copy(input, length);
- buf_pos = 0;
- }
- buf_pos += length;
- }
-
-/**
-* Split buffer into records, and send them all
-*/
-void Record_Writer::flush()
- {
- const byte* buf_ptr = &buffer[0];
- size_t offset = 0;
-
- while(offset != buf_pos)
- {
- size_t record_size = buf_pos - offset;
- if(record_size > MAX_PLAINTEXT_SIZE)
- record_size = MAX_PLAINTEXT_SIZE;
-
- send_record(buf_type, buf_ptr + offset, record_size);
- offset += record_size;
- }
- buf_type = 0;
- buf_pos = 0;
- }
-
-/**
-* Encrypt and send the record
-*/
-void Record_Writer::send_record(byte type, const byte buf[], size_t length)
- {
- if(length >= MAX_COMPRESSED_SIZE)
- throw TLS_Exception(INTERNAL_ERROR,
- "Record_Writer: Compressed packet is too big");
-
- if(mac_size == 0)
- send_record(type, major, minor, buf, length);
- else
- {
- mac->update_be(seq_no);
- mac->update(type);
-
- if(major > 3 || (major == 3 && minor != 0))
- {
- mac->update(major);
- mac->update(minor);
- }
-
- mac->update(get_byte<u16bit>(0, length));
- mac->update(get_byte<u16bit>(1, length));
- mac->update(buf, length);
-
- SecureVector<byte> buf_mac = mac->final();
-
- // TODO: This could all use a single buffer
- cipher.start_msg();
-
- if(iv_size)
- {
- RandomNumberGenerator& rng = global_state().global_rng();
-
- SecureVector<byte> random_iv(iv_size);
-
- rng.randomize(&random_iv[0], random_iv.size());
-
- cipher.write(random_iv);
- }
-
- cipher.write(buf, length);
- cipher.write(buf_mac);
-
- if(block_size)
- {
- size_t pad_val =
- (block_size - (1 + length + buf_mac.size())) % block_size;
-
- for(size_t i = 0; i != pad_val + 1; ++i)
- cipher.write(pad_val);
- }
- cipher.end_msg();
-
- SecureVector<byte> output = cipher.read_all(Pipe::LAST_MESSAGE);
-
- send_record(type, major, minor, &output[0], output.size());
-
- seq_no++;
- }
- }
-
-/**
-* Send a final record packet
-*/
-void Record_Writer::send_record(byte type, byte major, byte minor,
- const byte out[], size_t length)
- {
- if(length >= MAX_CIPHERTEXT_SIZE)
- throw TLS_Exception(INTERNAL_ERROR,
- "Record_Writer: Record is too big");
-
- byte header[5] = { type, major, minor, 0 };
- for(size_t i = 0; i != 2; ++i)
- header[i+3] = get_byte<u16bit>(i, length);
-
- output_fn(header, 5);
- output_fn(out, length);
- }
-
-/**
-* Send an alert
-*/
-void Record_Writer::alert(Alert_Level level, Alert_Type type)
- {
- byte alert[2] = { level, type };
- send(ALERT, alert, sizeof(alert));
- flush();
- }
-
-}
diff --git a/src/ssl/s_kex.cpp b/src/ssl/s_kex.cpp
deleted file mode 100644
index 879ee660a..000000000
--- a/src/ssl/s_kex.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
-* Server Key Exchange Message
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/internal/tls_messages.h>
-#include <botan/internal/tls_reader.h>
-#include <botan/pubkey.h>
-#include <botan/dh.h>
-#include <botan/rsa.h>
-#include <botan/dsa.h>
-#include <botan/loadstor.h>
-#include <memory>
-
-namespace Botan {
-
-/**
-* Create a new Server Key Exchange message
-*/
-Server_Key_Exchange::Server_Key_Exchange(RandomNumberGenerator& rng,
- Record_Writer& writer,
- const Public_Key* kex_key,
- const Private_Key* priv_key,
- const MemoryRegion<byte>& c_random,
- const MemoryRegion<byte>& s_random,
- HandshakeHash& hash)
- {
- const DH_PublicKey* dh_pub = dynamic_cast<const DH_PublicKey*>(kex_key);
- const RSA_PublicKey* rsa_pub = dynamic_cast<const RSA_PublicKey*>(kex_key);
-
- if(dh_pub)
- {
- params.push_back(dh_pub->get_domain().get_p());
- params.push_back(dh_pub->get_domain().get_g());
- params.push_back(BigInt::decode(dh_pub->public_value()));
- }
- else if(rsa_pub)
- {
- params.push_back(rsa_pub->get_n());
- params.push_back(rsa_pub->get_e());
- }
- else
- throw Invalid_Argument("Bad key for TLS key exchange: not DH or RSA");
-
-
- std::string padding = "";
- Signature_Format format = IEEE_1363;
-
- if(priv_key->algo_name() == "RSA")
- padding = "EMSA3(TLS.Digest.0)";
- else if(priv_key->algo_name() == "DSA")
- {
- padding = "EMSA1(SHA-1)";
- format = DER_SEQUENCE;
- }
- else
- throw Invalid_Argument(priv_key->algo_name() +
- " is invalid/unknown for TLS signatures");
-
- PK_Signer signer(*priv_key, padding, format);
-
- signer.update(c_random);
- signer.update(s_random);
- signer.update(serialize_params());
- signature = signer.signature(rng);
-
- send(writer, hash);
- }
-
-/**
-* Serialize a Server Key Exchange message
-*/
-SecureVector<byte> Server_Key_Exchange::serialize() const
- {
- SecureVector<byte> buf = serialize_params();
- append_tls_length_value(buf, signature, 2);
- return buf;
- }
-
-/**
-* Serialize the ServerParams structure
-*/
-SecureVector<byte> Server_Key_Exchange::serialize_params() const
- {
- SecureVector<byte> buf;
-
- for(size_t i = 0; i != params.size(); ++i)
- append_tls_length_value(buf, BigInt::encode(params[i]), 2);
-
- return buf;
- }
-
-/**
-* Deserialize a Server Key Exchange message
-*/
-void Server_Key_Exchange::deserialize(const MemoryRegion<byte>& buf)
- {
- if(buf.size() < 6)
- throw Decoding_Error("Server_Key_Exchange: Packet corrupted");
-
- SecureVector<byte> values[4];
- size_t so_far = 0;
-
- for(size_t i = 0; i != 4; ++i)
- {
- const u16bit len = make_u16bit(buf[so_far], buf[so_far+1]);
- so_far += 2;
-
- if(len + so_far > buf.size())
- throw Decoding_Error("Server_Key_Exchange: Packet corrupted");
-
- values[i].resize(len);
- copy_mem(&values[i][0], &buf[so_far], len);
- so_far += len;
-
- if(i == 2 && so_far == buf.size())
- break;
- }
-
- params.push_back(BigInt::decode(values[0]));
- params.push_back(BigInt::decode(values[1]));
- if(values[3].size())
- {
- params.push_back(BigInt::decode(values[2]));
- signature = values[3];
- }
- else
- signature = values[2];
- }
-
-/**
-* Return the public key
-*/
-Public_Key* Server_Key_Exchange::key() const
- {
- if(params.size() == 2)
- return new RSA_PublicKey(params[0], params[1]);
- else if(params.size() == 3)
- return new DH_PublicKey(DL_Group(params[0], params[1]), params[2]);
- else
- throw Internal_Error("Server_Key_Exchange::key: No key set");
- }
-
-/**
-* Verify a Server Key Exchange message
-*/
-bool Server_Key_Exchange::verify(const X509_Certificate& cert,
- const MemoryRegion<byte>& c_random,
- const MemoryRegion<byte>& s_random) const
- {
-
- std::auto_ptr<Public_Key> key(cert.subject_public_key());
-
- std::string padding = "";
- Signature_Format format = IEEE_1363;
-
- if(key->algo_name() == "RSA")
- padding = "EMSA3(TLS.Digest.0)";
- else if(key->algo_name() == "DSA")
- {
- padding = "EMSA1(SHA-1)";
- format = DER_SEQUENCE;
- }
- else
- throw Invalid_Argument(key->algo_name() +
- " is invalid/unknown for TLS signatures");
-
- PK_Verifier verifier(*key, padding, format);
-
- SecureVector<byte> params_got = serialize_params();
- verifier.update(c_random);
- verifier.update(s_random);
- verifier.update(params_got);
-
- return verifier.check_signature(signature);
- }
-
-}
diff --git a/src/ssl/tls_alerts.h b/src/ssl/tls_alerts.h
deleted file mode 100644
index 241599aa8..000000000
--- a/src/ssl/tls_alerts.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
-* Alert Message
-* (C) 2004-2006 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#ifndef BOTAN_TLS_ALERT_H__
-#define BOTAN_TLS_ALERT_H__
-
-#include <botan/tls_exceptn.h>
-
-namespace Botan {
-
-/**
-* SSL/TLS Alert Message
-*/
-class Alert
- {
- public:
- /**
- * @return if this alert is a fatal one or not
- */
- bool is_fatal() const { return fatal; }
-
- /**
- * @return type of alert
- */
- Alert_Type type() const { return type_code; }
-
- /**
- * Deserialize an Alert message
- * @param buf the serialized alert
- */
- Alert(const MemoryRegion<byte>& buf)
- {
- if(buf.size() != 2)
- throw Decoding_Error("Alert: Bad size for alert message");
-
- if(buf[0] == 1) fatal = false;
- else if(buf[0] == 2) fatal = true;
- else
- throw Decoding_Error("Alert: Bad type code for alert level");
-
- type_code = static_cast<Alert_Type>(buf[1]);
- }
- private:
- bool fatal;
- Alert_Type type_code;
- };
-
-}
-
-#endif
diff --git a/src/ssl/tls_client.cpp b/src/ssl/tls_client.cpp
deleted file mode 100644
index a136752fd..000000000
--- a/src/ssl/tls_client.cpp
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
-* TLS Client
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/tls_client.h>
-#include <botan/internal/tls_alerts.h>
-#include <botan/internal/tls_state.h>
-#include <botan/loadstor.h>
-#include <botan/rsa.h>
-#include <botan/dsa.h>
-#include <botan/dh.h>
-
-namespace Botan {
-
-namespace {
-
-/**
-* Verify the state transition is allowed
-* FIXME: checks are wrong for session reuse (add a flag for that)
-*/
-void client_check_state(Handshake_Type new_msg, Handshake_State* state)
- {
- class State_Transition_Error : public Unexpected_Message
- {
- public:
- State_Transition_Error(const std::string& err) :
- Unexpected_Message("State transition error from " + err) {}
- };
-
- if(new_msg == HELLO_REQUEST)
- {
- if(state->client_hello)
- throw State_Transition_Error("HelloRequest");
- }
- else if(new_msg == SERVER_HELLO)
- {
- if(!state->client_hello || state->server_hello)
- throw State_Transition_Error("ServerHello");
- }
- else if(new_msg == CERTIFICATE)
- {
- if(!state->server_hello || state->server_kex ||
- state->cert_req || state->server_hello_done)
- throw State_Transition_Error("ServerCertificate");
- }
- else if(new_msg == SERVER_KEX)
- {
- if(!state->server_hello || state->server_kex ||
- state->cert_req || state->server_hello_done)
- throw State_Transition_Error("ServerKeyExchange");
- }
- else if(new_msg == CERTIFICATE_REQUEST)
- {
- if(!state->server_certs || state->cert_req || state->server_hello_done)
- throw State_Transition_Error("CertificateRequest");
- }
- else if(new_msg == SERVER_HELLO_DONE)
- {
- if(!state->server_hello || state->server_hello_done)
- throw State_Transition_Error("ServerHelloDone");
- }
- else if(new_msg == HANDSHAKE_CCS)
- {
- if(!state->client_finished || state->server_finished)
- throw State_Transition_Error("ServerChangeCipherSpec");
- }
- else if(new_msg == FINISHED)
- {
- if(!state->got_server_ccs)
- throw State_Transition_Error("ServerFinished");
- }
- else
- throw Unexpected_Message("Unexpected message in handshake");
- }
-
-}
-
-/**
-* TLS Client Constructor
-*/
-TLS_Client::TLS_Client(std::tr1::function<size_t (byte[], size_t)> input_fn,
- std::tr1::function<void (const byte[], size_t)> output_fn,
- const TLS_Policy& policy,
- RandomNumberGenerator& rng) :
- input_fn(input_fn),
- policy(policy),
- rng(rng),
- writer(output_fn)
- {
- initialize();
- }
-
-void TLS_Client::add_client_cert(const X509_Certificate& cert,
- Private_Key* cert_key)
- {
- certs.push_back(std::make_pair(cert, cert_key));
- }
-
-/**
-* TLS Client Destructor
-*/
-TLS_Client::~TLS_Client()
- {
- close();
- for(size_t i = 0; i != certs.size(); i++)
- delete certs[i].second;
- delete state;
- }
-
-/**
-* Initialize a TLS client connection
-*/
-void TLS_Client::initialize()
- {
- std::string error_str;
- Alert_Type error_type = NO_ALERT_TYPE;
-
- try {
- state = 0;
- active = false;
- writer.set_version(policy.pref_version());
- do_handshake();
- }
- catch(TLS_Exception& e)
- {
- error_str = e.what();
- error_type = e.type();
- }
- catch(std::exception& e)
- {
- error_str = e.what();
- error_type = HANDSHAKE_FAILURE;
- }
-
- if(error_type != NO_ALERT_TYPE)
- {
- if(active)
- {
- active = false;
- reader.reset();
-
- writer.alert(FATAL, error_type);
- writer.reset();
- }
-
- if(state)
- {
- delete state;
- state = 0;
- }
-
- throw Stream_IO_Error("TLS_Client: Handshake failed: " + error_str);
- }
- }
-
-/**
-* Return the peer's certificate chain
-*/
-std::vector<X509_Certificate> TLS_Client::peer_cert_chain() const
- {
- return peer_certs;
- }
-
-/**
-* Write to a TLS connection
-*/
-void TLS_Client::write(const byte buf[], size_t length)
- {
- if(!active)
- throw TLS_Exception(INTERNAL_ERROR,
- "TLS_Client::write called while closed");
-
- writer.send(APPLICATION_DATA, buf, length);
- }
-
-/**
-* Read from a TLS connection
-*/
-size_t TLS_Client::read(byte out[], size_t length)
- {
- if(!active)
- return 0;
-
- writer.flush();
-
- while(read_buf.size() == 0)
- {
- state_machine();
- if(active == false)
- break;
- }
-
- size_t got = std::min<size_t>(read_buf.size(), length);
- read_buf.read(out, got);
- return got;
- }
-
-/**
-* Close a TLS connection
-*/
-void TLS_Client::close()
- {
- close(WARNING, CLOSE_NOTIFY);
- }
-
-/**
-* Check connection status
-*/
-bool TLS_Client::is_closed() const
- {
- if(!active)
- return true;
- return false;
- }
-
-/**
-* Close a TLS connection
-*/
-void TLS_Client::close(Alert_Level level, Alert_Type alert_code)
- {
- if(active)
- {
- try {
- writer.alert(level, alert_code);
- writer.flush();
- }
- catch(...) {}
-
- active = false;
- }
- }
-
-/**
-* Iterate the TLS state machine
-*/
-void TLS_Client::state_machine()
- {
- byte rec_type = CONNECTION_CLOSED;
- SecureVector<byte> record(1024);
-
- size_t bytes_needed = reader.get_record(rec_type, record);
-
- while(bytes_needed)
- {
- size_t to_get = std::min<size_t>(record.size(), bytes_needed);
- size_t got = input_fn(&record[0], to_get);
-
- if(got == 0)
- {
- rec_type = CONNECTION_CLOSED;
- break;
- }
-
- reader.add_input(&record[0], got);
-
- bytes_needed = reader.get_record(rec_type, record);
- }
-
- if(rec_type == CONNECTION_CLOSED)
- {
- active = false;
- reader.reset();
- writer.reset();
- }
- else if(rec_type == APPLICATION_DATA)
- {
- if(active)
- read_buf.write(&record[0], record.size());
- else
- 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(record);
-
- if(alert.is_fatal() || alert.type() == CLOSE_NOTIFY)
- {
- if(alert.type() == CLOSE_NOTIFY)
- writer.alert(WARNING, CLOSE_NOTIFY);
-
- reader.reset();
- writer.reset();
- active = false;
- if(state)
- {
- delete state;
- state = 0;
- }
- }
- }
- else
- throw Unexpected_Message("Unknown message type received");
- }
-
-/**
-* Split up and process handshake messages
-*/
-void TLS_Client::read_handshake(byte rec_type,
- const MemoryRegion<byte>& rec_buf)
- {
- if(rec_type == HANDSHAKE)
- state->queue.write(&rec_buf[0], rec_buf.size());
-
- while(true)
- {
- Handshake_Type type = HANDSHAKE_NONE;
- SecureVector<byte> contents;
-
- if(rec_type == HANDSHAKE)
- {
- if(state->queue.size() >= 4)
- {
- byte head[4] = { 0 };
- state->queue.peek(head, 4);
-
- const size_t length = make_u32bit(0, head[1], head[2], head[3]);
-
- if(state->queue.size() >= length + 4)
- {
- type = static_cast<Handshake_Type>(head[0]);
- contents.resize(length);
- state->queue.read(head, 4);
- state->queue.read(&contents[0], contents.size());
- }
- }
- }
- else if(rec_type == CHANGE_CIPHER_SPEC)
- {
- if(state->queue.size() == 0 && rec_buf.size() == 1 && rec_buf[0] == 1)
- type = HANDSHAKE_CCS;
- else
- throw Decoding_Error("Malformed ChangeCipherSpec message");
- }
- else
- throw Decoding_Error("Unknown message type in handshake processing");
-
- if(type == HANDSHAKE_NONE)
- break;
-
- process_handshake_msg(type, contents);
-
- if(type == HANDSHAKE_CCS || !state)
- break;
- }
- }
-
-/**
-* Process a handshake message
-*/
-void TLS_Client::process_handshake_msg(Handshake_Type type,
- const MemoryRegion<byte>& contents)
- {
- rng.add_entropy(&contents[0], contents.size());
-
- if(type == HELLO_REQUEST)
- {
- if(state == 0)
- state = new Handshake_State();
- else
- return;
- }
-
- if(state == 0)
- throw Unexpected_Message("Unexpected handshake message");
-
- if(type != HANDSHAKE_CCS && type != HELLO_REQUEST && type != FINISHED)
- {
- state->hash.update(static_cast<byte>(type));
- const size_t record_length = contents.size();
- for(size_t i = 0; i != 3; i++)
- state->hash.update(get_byte<u32bit>(i+1, record_length));
- state->hash.update(contents);
- }
-
- if(type == HELLO_REQUEST)
- {
- client_check_state(type, state);
-
- Hello_Request hello_request(contents);
- state->client_hello = new Client_Hello(rng, writer, policy, state->hash);
- }
- else if(type == SERVER_HELLO)
- {
- client_check_state(type, state);
-
- state->server_hello = new Server_Hello(contents);
-
- if(!state->client_hello->offered_suite(
- state->server_hello->ciphersuite()
- )
- )
- throw TLS_Exception(HANDSHAKE_FAILURE,
- "TLS_Client: Server replied with bad ciphersuite");
-
- state->version = state->server_hello->version();
-
- if(state->version > state->client_hello->version())
- throw TLS_Exception(HANDSHAKE_FAILURE,
- "TLS_Client: Server replied with bad version");
-
- if(state->version < policy.min_version())
- throw TLS_Exception(PROTOCOL_VERSION,
- "TLS_Client: Server is too old for specified policy");
-
- writer.set_version(state->version);
- reader.set_version(state->version);
-
- state->suite = CipherSuite(state->server_hello->ciphersuite());
- }
- else if(type == CERTIFICATE)
- {
- client_check_state(type, state);
-
- if(state->suite.sig_type() == TLS_ALGO_SIGNER_ANON)
- throw Unexpected_Message("Recived certificate from anonymous server");
-
- state->server_certs = new Certificate(contents);
-
- peer_certs = state->server_certs->cert_chain();
- if(peer_certs.size() == 0)
- throw TLS_Exception(HANDSHAKE_FAILURE,
- "TLS_Client: No certificates sent by server");
-
- if(!policy.check_cert(peer_certs))
- throw TLS_Exception(BAD_CERTIFICATE,
- "TLS_Client: Server certificate is not valid");
-
- state->kex_pub = peer_certs[0].subject_public_key();
-
- bool is_dsa = false, is_rsa = false;
-
- if(dynamic_cast<DSA_PublicKey*>(state->kex_pub))
- is_dsa = true;
- else if(dynamic_cast<RSA_PublicKey*>(state->kex_pub))
- is_rsa = true;
- else
- throw TLS_Exception(UNSUPPORTED_CERTIFICATE,
- "Unknown key type received in server kex");
-
- if((is_dsa && state->suite.sig_type() != TLS_ALGO_SIGNER_DSA) ||
- (is_rsa && state->suite.sig_type() != TLS_ALGO_SIGNER_RSA))
- throw TLS_Exception(ILLEGAL_PARAMETER,
- "Certificate key type did not match ciphersuite");
- }
- else if(type == SERVER_KEX)
- {
- client_check_state(type, state);
-
- if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_NOKEX)
- throw Unexpected_Message("Unexpected key exchange from server");
-
- state->server_kex = new Server_Key_Exchange(contents);
-
- if(state->kex_pub)
- delete state->kex_pub;
-
- state->kex_pub = state->server_kex->key();
-
- bool is_dh = false, is_rsa = false;
-
- if(dynamic_cast<DH_PublicKey*>(state->kex_pub))
- is_dh = true;
- else if(dynamic_cast<RSA_PublicKey*>(state->kex_pub))
- is_rsa = true;
- else
- throw TLS_Exception(HANDSHAKE_FAILURE,
- "Unknown key type received in server kex");
-
- if((is_dh && state->suite.kex_type() != TLS_ALGO_KEYEXCH_DH) ||
- (is_rsa && state->suite.kex_type() != TLS_ALGO_KEYEXCH_RSA))
- throw TLS_Exception(ILLEGAL_PARAMETER,
- "Certificate key type did not match ciphersuite");
-
- if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON)
- {
- if(!state->server_kex->verify(peer_certs[0],
- state->client_hello->random(),
- state->server_hello->random()))
- throw TLS_Exception(DECRYPT_ERROR,
- "Bad signature on server key exchange");
- }
- }
- else if(type == CERTIFICATE_REQUEST)
- {
- client_check_state(type, state);
-
- state->cert_req = new Certificate_Req(contents);
- state->do_client_auth = true;
- }
- else if(type == SERVER_HELLO_DONE)
- {
- client_check_state(type, state);
-
- state->server_hello_done = new Server_Hello_Done(contents);
-
- if(state->do_client_auth)
- {
- std::vector<X509_Certificate> send_certs;
-
- std::vector<Certificate_Type> types =
- state->cert_req->acceptable_types();
-
- // FIXME: Fill in useful certs here, if any
- state->client_certs = new Certificate(writer, send_certs,
- state->hash);
- }
-
- state->client_kex =
- new Client_Key_Exchange(rng, writer, state->hash,
- state->kex_pub, state->version,
- state->client_hello->version());
-
- if(state->do_client_auth)
- {
- Private_Key* key_matching_cert = 0; // FIXME
- state->client_verify = new Certificate_Verify(rng,
- writer, state->hash,
- key_matching_cert);
- }
-
- state->keys = SessionKeys(state->suite, state->version,
- state->client_kex->pre_master_secret(),
- state->client_hello->random(),
- state->server_hello->random());
-
- writer.send(CHANGE_CIPHER_SPEC, 1);
- writer.flush();
-
- writer.set_keys(state->suite, state->keys, CLIENT);
-
- state->client_finished = new Finished(writer, state->version, CLIENT,
- state->keys.master_secret(),
- state->hash);
- }
- else if(type == HANDSHAKE_CCS)
- {
- client_check_state(type, state);
-
- reader.set_keys(state->suite, state->keys, CLIENT);
- state->got_server_ccs = true;
- }
- else if(type == FINISHED)
- {
- client_check_state(type, state);
-
- state->server_finished = new Finished(contents);
-
- if(!state->server_finished->verify(state->keys.master_secret(),
- state->version, state->hash, SERVER))
- throw TLS_Exception(DECRYPT_ERROR,
- "Finished message didn't verify");
-
- delete state;
- state = 0;
- active = true;
- }
- else
- throw Unexpected_Message("Unknown handshake message received");
- }
-
-/**
-* Perform a client-side TLS handshake
-*/
-void TLS_Client::do_handshake()
- {
- state = new Handshake_State;
-
- state->client_hello = new Client_Hello(rng, writer, policy, state->hash);
-
- while(true)
- {
- if(active && !state)
- break;
- if(!active && !state)
- throw TLS_Exception(HANDSHAKE_FAILURE, "TLS_Client: Handshake failed (do_handshake)");
-
- state_machine();
- }
- }
-
-}
diff --git a/src/ssl/tls_client.h b/src/ssl/tls_client.h
deleted file mode 100644
index 7d2ce9cda..000000000
--- a/src/ssl/tls_client.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
-* TLS Client
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#ifndef BOTAN_TLS_CLIENT_H__
-#define BOTAN_TLS_CLIENT_H__
-
-#include <botan/tls_connection.h>
-#include <botan/tls_policy.h>
-#include <botan/tls_record.h>
-#include <vector>
-#include <string>
-
-namespace Botan {
-
-/**
-* SSL/TLS Client
-*/
-class BOTAN_DLL TLS_Client : public TLS_Connection
- {
- public:
- size_t read(byte buf[], size_t buf_len);
- void write(const byte buf[], size_t buf_len);
-
- void close();
- bool is_closed() const;
-
- std::vector<X509_Certificate> peer_cert_chain() const;
-
- void add_client_cert(const X509_Certificate& cert,
- Private_Key* cert_key);
-
- TLS_Client(std::tr1::function<size_t (byte[], size_t)> input_fn,
- std::tr1::function<void (const byte[], size_t)> output_fn,
- const TLS_Policy& policy,
- RandomNumberGenerator& rng);
-
- ~TLS_Client();
- private:
- void close(Alert_Level, Alert_Type);
-
- size_t get_pending_socket_input(byte output[], size_t length);
-
- void initialize();
- void do_handshake();
-
- void state_machine();
- void read_handshake(byte, const MemoryRegion<byte>&);
- void process_handshake_msg(Handshake_Type, const MemoryRegion<byte>&);
-
- std::tr1::function<size_t (byte[], size_t)> input_fn;
-
- const TLS_Policy& policy;
- RandomNumberGenerator& rng;
-
- Record_Writer writer;
- Record_Reader reader;
-
- std::vector<X509_Certificate> peer_certs;
- std::vector<std::pair<X509_Certificate, Private_Key*> > certs;
-
- class Handshake_State* state;
- SecureVector<byte> session_id;
- SecureQueue read_buf;
- bool active;
- };
-
-}
-
-#endif
diff --git a/src/ssl/tls_connection.h b/src/ssl/tls_connection.h
deleted file mode 100644
index bbefa2114..000000000
--- a/src/ssl/tls_connection.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-* TLS Connection
-* (C) 2004-2006 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#ifndef BOTAN_TLS_CONNECTION_H__
-#define BOTAN_TLS_CONNECTION_H__
-
-#include <botan/x509cert.h>
-#include <vector>
-
-namespace Botan {
-
-/**
-* TLS Connection
-*/
-class BOTAN_DLL TLS_Connection
- {
- public:
- virtual size_t read(byte[], size_t) = 0;
- virtual void write(const byte[], size_t) = 0;
- size_t read(byte& in) { return read(&in, 1); }
- void write(byte out) { write(&out, 1); }
-
- virtual std::vector<X509_Certificate> peer_cert_chain() const = 0;
-
- virtual void close() = 0;
-
- virtual ~TLS_Connection() {}
- };
-
-}
-
-#endif
diff --git a/src/ssl/tls_handshake_hash.cpp b/src/ssl/tls_handshake_hash.cpp
deleted file mode 100644
index 7c1e2e385..000000000
--- a/src/ssl/tls_handshake_hash.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
-* TLS Handshake Hash
-* (C) 2004-2006 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/internal/tls_handshake_hash.h>
-#include <botan/md5.h>
-#include <botan/sha160.h>
-#include <memory>
-
-namespace Botan {
-
-/**
-* Return a TLS Handshake Hash
-*/
-SecureVector<byte> HandshakeHash::final()
- {
- MD5 md5;
- SHA_160 sha1;
-
- md5.update(data);
- sha1.update(data);
-
- SecureVector<byte> output;
- output += md5.final();
- output += sha1.final();
- return output;
- }
-
-/**
-* Return a SSLv3 Handshake Hash
-*/
-SecureVector<byte> HandshakeHash::final_ssl3(const MemoryRegion<byte>& secret)
- {
- const byte PAD_INNER = 0x36, PAD_OUTER = 0x5C;
-
- MD5 md5;
- SHA_160 sha1;
-
- md5.update(data);
- sha1.update(data);
-
- md5.update(secret);
- sha1.update(secret);
-
- for(size_t i = 0; i != 48; ++i)
- md5.update(PAD_INNER);
- for(size_t i = 0; i != 40; ++i)
- sha1.update(PAD_INNER);
-
- SecureVector<byte> inner_md5 = md5.final(), inner_sha1 = sha1.final();
-
- md5.update(secret);
- sha1.update(secret);
- for(size_t i = 0; i != 48; ++i)
- md5.update(PAD_OUTER);
- for(size_t i = 0; i != 40; ++i)
- sha1.update(PAD_OUTER);
- md5.update(inner_md5);
- sha1.update(inner_sha1);
-
- SecureVector<byte> output;
- output += md5.final();
- output += sha1.final();
- return output;
- }
-
-}
diff --git a/src/ssl/tls_magic.h b/src/ssl/tls_magic.h
deleted file mode 100644
index 00898738e..000000000
--- a/src/ssl/tls_magic.h
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
-* SSL/TLS Protocol Constants
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#ifndef BOTAN_TLS_PROTOCOL_MAGIC_H__
-#define BOTAN_TLS_PROTOCOL_MAGIC_H__
-
-namespace Botan {
-
-/**
-* Protocol Constants for SSL/TLS
-*/
-enum Size_Limits {
- MAX_PLAINTEXT_SIZE = 16*1024,
- MAX_COMPRESSED_SIZE = MAX_PLAINTEXT_SIZE + 1024,
- MAX_CIPHERTEXT_SIZE = MAX_COMPRESSED_SIZE + 1024
-};
-
-enum Version_Code {
- NO_VERSION_SET = 0x0000,
- SSL_V3 = 0x0300,
- TLS_V10 = 0x0301,
- TLS_V11 = 0x0302
-};
-
-enum Connection_Side { CLIENT, SERVER };
-
-enum Record_Type {
- CONNECTION_CLOSED = 0,
-
- CHANGE_CIPHER_SPEC = 20,
- ALERT = 21,
- HANDSHAKE = 22,
- APPLICATION_DATA = 23
-};
-
-enum Handshake_Type {
- HELLO_REQUEST = 0,
- CLIENT_HELLO = 1,
- CLIENT_HELLO_SSLV2 = 255, // not a wire value
- SERVER_HELLO = 2,
- CERTIFICATE = 11,
- SERVER_KEX = 12,
- CERTIFICATE_REQUEST = 13,
- SERVER_HELLO_DONE = 14,
- CERTIFICATE_VERIFY = 15,
- CLIENT_KEX = 16,
- FINISHED = 20,
-
- HANDSHAKE_CCS = 100,
- HANDSHAKE_NONE = 101
-};
-
-enum Alert_Level {
- WARNING = 1,
- FATAL = 2
-};
-
-enum Alert_Type {
- CLOSE_NOTIFY = 0,
- UNEXPECTED_MESSAGE = 10,
- BAD_RECORD_MAC = 20,
- DECRYPTION_FAILED = 21,
- RECORD_OVERFLOW = 22,
- DECOMPRESSION_FAILURE = 30,
- HANDSHAKE_FAILURE = 40,
- 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,
-
- UNKNOWN_PSK_IDENTITY = 115,
-
- NO_ALERT_TYPE = 0xFFFF
-};
-
-enum Certificate_Type {
- RSA_CERT = 1,
- DSS_CERT = 2,
- DH_RSA_CERT = 3,
- DH_DSS_CERT = 4
-};
-
-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_SEED_CBC_SHA = 0x0096,
-
- TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013,
- TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032,
- TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038,
- TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040,
- TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x006A,
- TLS_DHE_DSS_WITH_SEED_CBC_SHA = 0x0099,
-
- TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016,
- TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033,
- TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039,
- TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067,
- TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B,
- TLS_DHE_RSA_WITH_SEED_CBC_SHA = 0x009A,
-
- TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007,
- TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008,
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009,
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A,
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023,
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024,
-
- TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011,
- TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012,
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013,
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014,
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027,
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028
-};
-
-/*
-* Form of the ciphersuites broken down by field instead of
-* being randomly assigned codepoints.
-*/
-enum TLS_Ciphersuite_Algos {
- TLS_ALGO_SIGNER_MASK = 0xFF000000,
- TLS_ALGO_SIGNER_ANON = 0x01000000,
- TLS_ALGO_SIGNER_RSA = 0x02000000,
- TLS_ALGO_SIGNER_DSA = 0x03000000,
- TLS_ALGO_SIGNER_ECDSA = 0x04000000,
-
- TLS_ALGO_KEYEXCH_MASK = 0x00FF0000,
- TLS_ALGO_KEYEXCH_NOKEX = 0x00010000,
- TLS_ALGO_KEYEXCH_RSA = 0x00020000,
- TLS_ALGO_KEYEXCH_DH = 0x00030000,
- TLS_ALGO_KEYEXCH_ECDH = 0x00040000,
-
- TLS_ALGO_MAC_MASK = 0x0000FF00,
- TLS_ALGO_MAC_MD5 = 0x00000100,
- TLS_ALGO_MAC_SHA1 = 0x00000200,
- TLS_ALGO_MAC_SHA256 = 0x00000300,
- TLS_ALGO_MAC_SHA384 = 0x00000400,
-
- TLS_ALGO_CIPHER_MASK = 0x000000FF,
- TLS_ALGO_CIPHER_RC4_128 = 0x00000001,
- TLS_ALGO_CIPHER_3DES_CBC = 0x00000002,
- TLS_ALGO_CIPHER_AES128_CBC = 0x00000003,
- TLS_ALGO_CIPHER_AES256_CBC = 0x00000004,
- TLS_ALGO_CIPHER_SEED_CBC = 0x00000005
-};
-
-enum Compression_Algo {
- NO_COMPRESSION = 0x00
-};
-
-enum TLS_Handshake_Extension_Type {
- TLSEXT_SERVER_NAME_INDICATION = 0,
- TLSEXT_MAX_FRAGMENT_LENGTH = 1,
- TLSEXT_CLIENT_CERT_URL = 2,
- TLSEXT_TRUSTED_CA_KEYS = 3,
- TLSEXT_TRUNCATED_HMAC = 4,
-
- TLSEXT_USABLE_ELLIPTIC_CURVES = 10,
- TLSEXT_EC_POINT_FORMATS = 11,
-
- TLSEXT_SRP_IDENTIFIER = 12,
-
- TLSEXT_CERTIFICATE_TYPES = 9,
- TLSEXT_SESSION_TICKET = 35
-};
-
-}
-
-#endif
diff --git a/src/ssl/tls_messages.h b/src/ssl/tls_messages.h
deleted file mode 100644
index e7eaa56e1..000000000
--- a/src/ssl/tls_messages.h
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
-* TLS Messages
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#ifndef BOTAN_TLS_MESSAGES_H__
-#define BOTAN_TLS_MESSAGES_H__
-
-#include <botan/tls_record.h>
-#include <botan/internal/tls_handshake_hash.h>
-#include <botan/tls_policy.h>
-#include <botan/bigint.h>
-#include <botan/pkcs8.h>
-#include <botan/x509cert.h>
-#include <vector>
-
-namespace Botan {
-
-/**
-* TLS Handshake Message Base Class
-*/
-class HandshakeMessage
- {
- public:
- void send(Record_Writer&, HandshakeHash&) const;
-
- virtual Handshake_Type type() const = 0;
-
- virtual ~HandshakeMessage() {}
- private:
- HandshakeMessage& operator=(const HandshakeMessage&) { return (*this); }
- virtual SecureVector<byte> serialize() const = 0;
- virtual void deserialize(const MemoryRegion<byte>&) = 0;
- };
-
-/**
-* Client Hello Message
-*/
-class Client_Hello : public HandshakeMessage
- {
- public:
- Handshake_Type type() const { return CLIENT_HELLO; }
- Version_Code version() const { return c_version; }
- const SecureVector<byte>& session_id() const { return sess_id; }
- std::vector<u16bit> ciphersuites() const { return suites; }
- std::vector<byte> compression_algos() const { return comp_algos; }
-
- const SecureVector<byte>& random() const { return c_random; }
-
- std::string hostname() const { return requested_hostname; }
-
- std::string srp_identifier() const { return requested_srp_id; }
-
- bool offered_suite(u16bit) const;
-
- Client_Hello(RandomNumberGenerator& rng,
- Record_Writer&, const TLS_Policy&, HandshakeHash&);
-
- Client_Hello(const MemoryRegion<byte>& buf,
- Handshake_Type type)
- {
- if(type == CLIENT_HELLO)
- deserialize(buf);
- else
- deserialize_sslv2(buf);
- }
-
- private:
- SecureVector<byte> serialize() const;
- void deserialize(const MemoryRegion<byte>&);
- void deserialize_sslv2(const MemoryRegion<byte>&);
-
- Version_Code c_version;
- SecureVector<byte> sess_id, c_random;
- std::vector<u16bit> suites;
- std::vector<byte> comp_algos;
- std::string requested_hostname;
- std::string requested_srp_id;
- };
-
-/**
-* Client Key Exchange Message
-*/
-class Client_Key_Exchange : public HandshakeMessage
- {
- public:
- Handshake_Type type() const { return CLIENT_KEX; }
-
- SecureVector<byte> pre_master_secret() const;
-
- SecureVector<byte> pre_master_secret(RandomNumberGenerator& rng,
- const Private_Key* key,
- Version_Code version);
-
- Client_Key_Exchange(RandomNumberGenerator& rng,
- Record_Writer& output,
- HandshakeHash& hash,
- const Public_Key* my_key,
- Version_Code using_version,
- Version_Code pref_version);
-
- Client_Key_Exchange(const MemoryRegion<byte>& buf,
- const CipherSuite& suite,
- Version_Code using_version);
- private:
- SecureVector<byte> serialize() const;
- void deserialize(const MemoryRegion<byte>&);
-
- SecureVector<byte> key_material, pre_master;
- bool include_length;
- };
-
-/**
-* Certificate Message
-*/
-class Certificate : public HandshakeMessage
- {
- public:
- Handshake_Type type() const { return CERTIFICATE; }
- std::vector<X509_Certificate> cert_chain() const { return certs; }
-
- Certificate(Record_Writer&, const std::vector<X509_Certificate>&,
- HandshakeHash&);
- Certificate(const MemoryRegion<byte>& buf) { deserialize(buf); }
- private:
- SecureVector<byte> serialize() const;
- void deserialize(const MemoryRegion<byte>&);
- std::vector<X509_Certificate> certs;
- };
-
-/**
-* Certificate Request Message
-*/
-class Certificate_Req : public HandshakeMessage
- {
- public:
- Handshake_Type type() const { return CERTIFICATE_REQUEST; }
-
- std::vector<Certificate_Type> acceptable_types() const { return types; }
- std::vector<X509_DN> acceptable_CAs() const { return names; }
-
- /* TODO
- Certificate_Req(Record_Writer&, HandshakeHash&,
- const X509_Certificate&);
- */
- Certificate_Req(Record_Writer&, HandshakeHash&,
- const std::vector<X509_Certificate>&);
-
- Certificate_Req(const MemoryRegion<byte>& buf) { deserialize(buf); }
- private:
- SecureVector<byte> serialize() const;
- void deserialize(const MemoryRegion<byte>&);
-
- std::vector<X509_DN> names;
- std::vector<Certificate_Type> types;
- };
-
-/**
-* Certificate Verify Message
-*/
-class Certificate_Verify : public HandshakeMessage
- {
- public:
- Handshake_Type type() const { return CERTIFICATE_VERIFY; }
-
- bool verify(const X509_Certificate&, HandshakeHash&);
-
- Certificate_Verify(RandomNumberGenerator& rng,
- Record_Writer&, HandshakeHash&,
- const Private_Key*);
-
- Certificate_Verify(const MemoryRegion<byte>& buf) { deserialize(buf); }
- private:
- SecureVector<byte> serialize() const;
- void deserialize(const MemoryRegion<byte>&);
-
- SecureVector<byte> signature;
- };
-
-/**
-* Finished Message
-*/
-class Finished : public HandshakeMessage
- {
- public:
- Handshake_Type type() const { return FINISHED; }
-
- bool verify(const MemoryRegion<byte>&, Version_Code,
- const HandshakeHash&, Connection_Side);
-
- Finished(Record_Writer&, Version_Code, Connection_Side,
- const MemoryRegion<byte>&, HandshakeHash&);
- Finished(const MemoryRegion<byte>& buf) { deserialize(buf); }
- private:
- SecureVector<byte> serialize() const;
- void deserialize(const MemoryRegion<byte>&);
-
- SecureVector<byte> compute_verify(const MemoryRegion<byte>&,
- HandshakeHash, Connection_Side,
- Version_Code);
-
- Connection_Side side;
- SecureVector<byte> verification_data;
- };
-
-/**
-* Hello Request Message
-*/
-class Hello_Request : public HandshakeMessage
- {
- public:
- Handshake_Type type() const { return HELLO_REQUEST; }
-
- Hello_Request(Record_Writer&);
- Hello_Request(const MemoryRegion<byte>& buf) { deserialize(buf); }
- private:
- SecureVector<byte> serialize() const;
- void deserialize(const MemoryRegion<byte>&);
- };
-
-/**
-* Server Hello Message
-*/
-class Server_Hello : public HandshakeMessage
- {
- public:
- Handshake_Type type() const { return SERVER_HELLO; }
- Version_Code version() { return s_version; }
- const SecureVector<byte>& session_id() const { return sess_id; }
- u16bit ciphersuite() const { return suite; }
- byte compression_algo() const { return comp_algo; }
-
- const SecureVector<byte>& random() const { return s_random; }
-
- Server_Hello(RandomNumberGenerator& rng,
- Record_Writer&, const TLS_Policy&,
- const std::vector<X509_Certificate>&,
- const Client_Hello&, Version_Code, HandshakeHash&);
-
- Server_Hello(const MemoryRegion<byte>& buf) { deserialize(buf); }
- private:
- SecureVector<byte> serialize() const;
- void deserialize(const MemoryRegion<byte>&);
-
- Version_Code s_version;
- SecureVector<byte> sess_id, s_random;
- u16bit suite;
- byte comp_algo;
- };
-
-/**
-* Server Key Exchange Message
-*/
-class Server_Key_Exchange : public HandshakeMessage
- {
- public:
- Handshake_Type type() const { return SERVER_KEX; }
- Public_Key* key() const;
-
- bool verify(const X509_Certificate&, const MemoryRegion<byte>&,
- const MemoryRegion<byte>&) const;
-
- Server_Key_Exchange(RandomNumberGenerator& rng,
- Record_Writer&, const Public_Key*,
- const Private_Key*, const MemoryRegion<byte>&,
- const MemoryRegion<byte>&, HandshakeHash&);
-
- Server_Key_Exchange(const MemoryRegion<byte>& buf) { deserialize(buf); }
- private:
- SecureVector<byte> serialize() const;
- SecureVector<byte> serialize_params() const;
- void deserialize(const MemoryRegion<byte>&);
-
- std::vector<BigInt> params;
- SecureVector<byte> signature;
- };
-
-/**
-* Server Hello Done Message
-*/
-class Server_Hello_Done : public HandshakeMessage
- {
- public:
- Handshake_Type type() const { return SERVER_HELLO_DONE; }
-
- Server_Hello_Done(Record_Writer&, HandshakeHash&);
- Server_Hello_Done(const MemoryRegion<byte>& buf) { deserialize(buf); }
- private:
- SecureVector<byte> serialize() const;
- void deserialize(const MemoryRegion<byte>&);
- };
-
-}
-
-#endif
diff --git a/src/ssl/tls_policy.cpp b/src/ssl/tls_policy.cpp
deleted file mode 100644
index b73ff7850..000000000
--- a/src/ssl/tls_policy.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
-* Policies for TLS
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/tls_policy.h>
-#include <botan/tls_exceptn.h>
-
-namespace Botan {
-
-/*
-* Return allowed ciphersuites
-*/
-std::vector<u16bit> TLS_Policy::ciphersuites() const
- {
- return suite_list(allow_static_rsa(), allow_edh_rsa(), allow_edh_dsa());
- }
-
-/*
-* Return allowed ciphersuites
-*/
-std::vector<u16bit> TLS_Policy::suite_list(bool use_rsa,
- bool use_edh_rsa,
- bool use_edh_dsa) const
- {
- std::vector<u16bit> suites;
-
- if(use_edh_dsa)
- {
- suites.push_back(TLS_DHE_DSS_WITH_AES_256_CBC_SHA);
- suites.push_back(TLS_DHE_DSS_WITH_AES_128_CBC_SHA);
- suites.push_back(TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA);
- suites.push_back(TLS_DHE_DSS_WITH_SEED_CBC_SHA);
- }
-
- if(use_edh_rsa)
- {
- suites.push_back(TLS_DHE_RSA_WITH_AES_256_CBC_SHA);
- suites.push_back(TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
- suites.push_back(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA);
- suites.push_back(TLS_DHE_RSA_WITH_SEED_CBC_SHA);
- }
-
- if(use_rsa)
- {
- suites.push_back(TLS_RSA_WITH_AES_256_CBC_SHA);
- suites.push_back(TLS_RSA_WITH_AES_128_CBC_SHA);
- suites.push_back(TLS_RSA_WITH_3DES_EDE_CBC_SHA);
- suites.push_back(TLS_RSA_WITH_SEED_CBC_SHA);
- suites.push_back(TLS_RSA_WITH_RC4_128_SHA);
- suites.push_back(TLS_RSA_WITH_RC4_128_MD5);
- }
-
- if(suites.size() == 0)
- throw TLS_Exception(INTERNAL_ERROR,
- "TLS_Policy error: All ciphersuites disabled");
-
- return suites;
- }
-
-/*
-* Return allowed compression algorithms
-*/
-std::vector<byte> TLS_Policy::compression() const
- {
- std::vector<byte> algs;
- algs.push_back(NO_COMPRESSION);
- return algs;
- }
-
-/*
-* Choose which ciphersuite to use
-*/
-u16bit TLS_Policy::choose_suite(const std::vector<u16bit>& c_suites,
- bool have_rsa,
- bool have_dsa) const
- {
- bool use_static_rsa = allow_static_rsa() && have_rsa;
- bool use_edh_rsa = allow_edh_rsa() && have_rsa;
- bool use_edh_dsa = allow_edh_dsa() && have_dsa;
-
- std::vector<u16bit> s_suites = suite_list(use_static_rsa, use_edh_rsa,
- use_edh_dsa);
-
- for(size_t i = 0; i != s_suites.size(); ++i)
- for(size_t j = 0; j != c_suites.size(); ++j)
- if(s_suites[i] == c_suites[j])
- return s_suites[i];
-
- return 0;
- }
-
-/*
-* Choose which compression algorithm to use
-*/
-byte TLS_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;
- }
-
-/*
-* Return the group to use for empheral DH
-*/
-DL_Group TLS_Policy::dh_group() const
- {
- return DL_Group("modp/ietf/1024");
- }
-
-}
diff --git a/src/ssl/tls_policy.h b/src/ssl/tls_policy.h
deleted file mode 100644
index 461164d2f..000000000
--- a/src/ssl/tls_policy.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
-* Policies
-* (C) 2004-2006 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#ifndef BOTAN_TLS_POLICY_H__
-#define BOTAN_TLS_POLICY_H__
-
-#include <botan/tls_magic.h>
-#include <botan/x509cert.h>
-#include <botan/dl_group.h>
-#include <vector>
-
-namespace Botan {
-
-/**
-* TLS Policy Base Class
-* Inherit and overload as desired to suite local policy concerns
-*/
-class BOTAN_DLL TLS_Policy
- {
- public:
- std::vector<u16bit> ciphersuites() const;
- virtual std::vector<byte> compression() const;
-
- virtual u16bit choose_suite(const std::vector<u16bit>& client_suites,
- bool rsa_ok,
- bool dsa_ok) const;
-
- virtual byte choose_compression(const std::vector<byte>& client) const;
-
- virtual bool allow_static_rsa() const { return true; }
- virtual bool allow_edh_rsa() const { return true; }
- virtual bool allow_edh_dsa() const { return true; }
- virtual bool require_client_auth() const { return false; }
-
- virtual DL_Group dh_group() const;
- virtual size_t rsa_export_keysize() const { return 512; }
-
- /*
- * @return the minimum version that we will negotiate
- */
- virtual Version_Code min_version() const { return SSL_V3; }
-
- /*
- * @return the version we would prefer to negotiate
- */
- virtual Version_Code pref_version() const { return TLS_V11; }
-
- virtual bool check_cert(const std::vector<X509_Certificate>& cert_chain) const = 0;
-
- virtual ~TLS_Policy() {}
- private:
- virtual std::vector<u16bit> suite_list(bool use_rsa,
- bool use_edh_rsa,
- bool use_edh_dsa) const;
- };
-
-}
-
-#endif
diff --git a/src/ssl/tls_record.h b/src/ssl/tls_record.h
deleted file mode 100644
index 09fd921c6..000000000
--- a/src/ssl/tls_record.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
-* TLS Record Handling
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#ifndef BOTAN_TLS_RECORDS_H__
-#define BOTAN_TLS_RECORDS_H__
-
-#include <botan/tls_session_key.h>
-#include <botan/tls_suites.h>
-#include <botan/pipe.h>
-#include <botan/mac.h>
-#include <botan/secqueue.h>
-#include <vector>
-
-#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 {
-
-using namespace std::tr1::placeholders;
-
-/**
-* TLS Record Writer
-*/
-class BOTAN_DLL Record_Writer
- {
- public:
- void send(byte type, const byte input[], size_t length);
- void send(byte type, byte val) { send(type, &val, 1); }
-
- void flush();
-
- void alert(Alert_Level, Alert_Type);
-
- void set_keys(const CipherSuite&, const SessionKeys&, Connection_Side);
-
- void set_version(Version_Code);
-
- void reset();
-
- Record_Writer(std::tr1::function<void (const byte[], size_t)> output_fn);
-
- ~Record_Writer() { delete mac; }
- private:
- void send_record(byte type, const byte input[], size_t length);
- void send_record(byte type, byte major, byte minor,
- const byte input[], size_t length);
-
- std::tr1::function<void (const byte[], size_t)> output_fn;
- Pipe cipher;
- MessageAuthenticationCode* mac;
-
- SecureVector<byte> buffer;
- size_t buf_pos;
-
- size_t block_size, mac_size, iv_size;
-
- u64bit seq_no;
- byte major, minor, buf_type;
- };
-
-/**
-* TLS Record Reader
-*/
-class BOTAN_DLL Record_Reader
- {
- public:
- void add_input(const byte input[], size_t input_size);
-
- /**
- * @param msg_type (output variable)
- * @param buffer (output variable)
- * @return Number of bytes still needed (minimum), or 0 if success
- */
- size_t get_record(byte& msg_type,
- MemoryRegion<byte>& buffer);
-
- SecureVector<byte> get_record(byte& msg_type);
-
- void set_keys(const CipherSuite& suite,
- const SessionKeys& keys,
- Connection_Side side);
-
- void set_version(Version_Code version);
-
- void reset();
-
- Record_Reader() { mac = 0; reset(); }
-
- ~Record_Reader() { delete mac; }
- private:
- SecureQueue input_queue;
-
- Pipe cipher;
- MessageAuthenticationCode* mac;
- size_t block_size, mac_size, iv_size;
- u64bit seq_no;
- byte major, minor;
- };
-
-}
-
-#endif
diff --git a/src/ssl/tls_server.cpp b/src/ssl/tls_server.cpp
deleted file mode 100644
index 8964be3d7..000000000
--- a/src/ssl/tls_server.cpp
+++ /dev/null
@@ -1,494 +0,0 @@
-/*
-* TLS Server
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/tls_server.h>
-#include <botan/internal/tls_alerts.h>
-#include <botan/internal/tls_state.h>
-#include <botan/loadstor.h>
-#include <botan/rsa.h>
-#include <botan/dh.h>
-
-namespace Botan {
-
-namespace {
-
-/*
-* Choose what version to respond with
-*/
-Version_Code choose_version(Version_Code client, Version_Code minimum)
- {
- if(client < minimum)
- throw TLS_Exception(PROTOCOL_VERSION,
- "Client version is unacceptable by policy");
-
- if(client == SSL_V3 || client == TLS_V10 || client == TLS_V11)
- return client;
- return TLS_V11;
- }
-
-// FIXME: checks are wrong for session reuse (add a flag for that)
-/*
-* Verify the state transition is allowed
-*/
-void server_check_state(Handshake_Type new_msg, Handshake_State* state)
- {
- class State_Transition_Error : public Unexpected_Message
- {
- public:
- State_Transition_Error(const std::string& err) :
- Unexpected_Message("State transition error from " + err) {}
- };
-
- if(new_msg == CLIENT_HELLO || new_msg == CLIENT_HELLO_SSLV2)
- {
- if(state->server_hello)
- throw State_Transition_Error("ClientHello");
- }
- else if(new_msg == CERTIFICATE)
- {
- if(!state->do_client_auth || !state->cert_req ||
- !state->server_hello_done || state->client_kex)
- throw State_Transition_Error("ClientCertificate");
- }
- else if(new_msg == CLIENT_KEX)
- {
- if(!state->server_hello_done || state->client_verify ||
- state->got_client_ccs)
- throw State_Transition_Error("ClientKeyExchange");
- }
- else if(new_msg == CERTIFICATE_VERIFY)
- {
- if(!state->cert_req || !state->client_certs || !state->client_kex ||
- state->got_client_ccs)
- throw State_Transition_Error("CertificateVerify");
- }
- else if(new_msg == HANDSHAKE_CCS)
- {
- if(!state->client_kex || state->client_finished)
- throw State_Transition_Error("ClientChangeCipherSpec");
- }
- else if(new_msg == FINISHED)
- {
- if(!state->got_client_ccs)
- throw State_Transition_Error("ClientFinished");
- }
- else
- throw Unexpected_Message("Unexpected message in handshake");
- }
-
-}
-
-/*
-* TLS Server Constructor
-*/
-TLS_Server::TLS_Server(std::tr1::function<size_t (byte[], size_t)> input_fn,
- std::tr1::function<void (const byte[], size_t)> output_fn,
- const TLS_Policy& policy,
- RandomNumberGenerator& rng,
- const X509_Certificate& cert,
- const Private_Key& cert_key) :
- input_fn(input_fn),
- policy(policy),
- rng(rng),
- writer(output_fn)
- {
- state = 0;
-
- cert_chain.push_back(cert);
- private_key = PKCS8::copy_key(cert_key, rng);
-
- try {
- active = false;
- writer.set_version(TLS_V10);
- do_handshake();
- active = true;
- }
- catch(std::exception& e)
- {
- if(state)
- {
- delete state;
- state = 0;
- }
-
- writer.alert(FATAL, HANDSHAKE_FAILURE);
- throw Stream_IO_Error(std::string("TLS_Server: Handshake failed: ") +
- e.what());
- }
- }
-
-/*
-* TLS Server Destructor
-*/
-TLS_Server::~TLS_Server()
- {
- close();
- delete private_key;
- delete state;
- }
-
-/*
-* Return the peer's certificate chain
-*/
-std::vector<X509_Certificate> TLS_Server::peer_cert_chain() const
- {
- return peer_certs;
- }
-
-/*
-* Write to a TLS connection
-*/
-void TLS_Server::write(const byte buf[], size_t length)
- {
- if(!active)
- throw Internal_Error("TLS_Server::write called while closed");
-
- writer.send(APPLICATION_DATA, buf, length);
- }
-
-/*
-* Read from a TLS connection
-*/
-size_t TLS_Server::read(byte out[], size_t length)
- {
- if(!active)
- throw Internal_Error("TLS_Server::read called while closed");
-
- writer.flush();
-
- while(read_buf.size() == 0)
- {
- state_machine();
- if(active == false)
- break;
- }
-
- size_t got = std::min<size_t>(read_buf.size(), length);
- read_buf.read(out, got);
- return got;
- }
-
-/*
-* Check connection status
-*/
-bool TLS_Server::is_closed() const
- {
- if(!active)
- return true;
- return false;
- }
-
-/*
-* Close a TLS connection
-*/
-void TLS_Server::close()
- {
- close(WARNING, CLOSE_NOTIFY);
- }
-
-/*
-* Close a TLS connection
-*/
-void TLS_Server::close(Alert_Level level, Alert_Type alert_code)
- {
- if(active)
- {
- try {
- active = false;
- writer.alert(level, alert_code);
- writer.flush();
- }
- catch(...) {}
- }
- }
-
-/*
-* Iterate the TLS state machine
-*/
-void TLS_Server::state_machine()
- {
- byte rec_type = CONNECTION_CLOSED;
- SecureVector<byte> record(1024);
-
- size_t bytes_needed = reader.get_record(rec_type, record);
-
- while(bytes_needed)
- {
- size_t to_get = std::min<size_t>(record.size(), bytes_needed);
- size_t got = input_fn(&record[0], to_get);
-
- if(got == 0)
- {
- rec_type = CONNECTION_CLOSED;
- break;
- }
-
- reader.add_input(&record[0], got);
-
- bytes_needed = reader.get_record(rec_type, record);
- }
-
- if(rec_type == CONNECTION_CLOSED)
- {
- active = false;
- reader.reset();
- writer.reset();
- }
- else if(rec_type == APPLICATION_DATA)
- {
- if(active)
- read_buf.write(&record[0], record.size());
- else
- 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(record);
-
- if(alert.is_fatal() || alert.type() == CLOSE_NOTIFY)
- {
- if(alert.type() == CLOSE_NOTIFY)
- writer.alert(WARNING, CLOSE_NOTIFY);
-
- reader.reset();
- writer.reset();
- active = false;
- }
- }
- else
- throw Unexpected_Message("Unknown message type received");
- }
-
-/*
-* Split up and process handshake messages
-*/
-void TLS_Server::read_handshake(byte rec_type,
- const MemoryRegion<byte>& rec_buf)
- {
- if(rec_type == HANDSHAKE)
- {
- if(!state)
- state = new Handshake_State;
- state->queue.write(&rec_buf[0], rec_buf.size());
- }
-
- while(true)
- {
- Handshake_Type type = HANDSHAKE_NONE;
- SecureVector<byte> contents;
-
- if(rec_type == HANDSHAKE)
- {
- if(state->queue.size() >= 4)
- {
- byte head[4] = { 0 };
- state->queue.peek(head, 4);
-
- const size_t length = make_u32bit(0, head[1], head[2], head[3]);
-
- if(state->queue.size() >= length + 4)
- {
- type = static_cast<Handshake_Type>(head[0]);
- contents.resize(length);
- state->queue.read(head, 4);
- state->queue.read(&contents[0], contents.size());
- }
- }
- }
- else if(rec_type == CHANGE_CIPHER_SPEC)
- {
- if(state->queue.size() == 0 && rec_buf.size() == 1 && rec_buf[0] == 1)
- type = HANDSHAKE_CCS;
- else
- throw Decoding_Error("Malformed ChangeCipherSpec message");
- }
- else
- throw Decoding_Error("Unknown message type in handshake processing");
-
- if(type == HANDSHAKE_NONE)
- break;
-
- process_handshake_msg(type, contents);
-
- if(type == HANDSHAKE_CCS || !state)
- break;
- }
- }
-
-/*
-* Process a handshake message
-*/
-void TLS_Server::process_handshake_msg(Handshake_Type type,
- const MemoryRegion<byte>& contents)
- {
- rng.add_entropy(&contents[0], contents.size());
-
- if(state == 0)
- throw Unexpected_Message("Unexpected handshake message");
-
- if(type != HANDSHAKE_CCS && type != FINISHED)
- {
- if(type != CLIENT_HELLO_SSLV2)
- {
- state->hash.update(static_cast<byte>(type));
-
- const size_t record_length = contents.size();
- for(size_t i = 0; i != 3; i++)
- state->hash.update(get_byte<u32bit>(i+1, record_length));
- }
-
- state->hash.update(contents);
- }
-
- if(type == CLIENT_HELLO || type == CLIENT_HELLO_SSLV2)
- {
- server_check_state(type, state);
-
- state->client_hello = new Client_Hello(contents, type);
-
- client_requested_hostname = state->client_hello->hostname();
-
- state->version = choose_version(state->client_hello->version(),
- policy.min_version());
-
- writer.set_version(state->version);
- reader.set_version(state->version);
-
- state->server_hello = new Server_Hello(rng, writer,
- policy, cert_chain,
- *(state->client_hello),
- state->version, state->hash);
-
- state->suite = CipherSuite(state->server_hello->ciphersuite());
-
- if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON)
- {
- // FIXME: should choose certs based on sig type
- state->server_certs = new Certificate(writer, cert_chain,
- state->hash);
- }
-
- state->kex_priv = PKCS8::copy_key(*private_key, rng);
- if(state->suite.kex_type() != TLS_ALGO_KEYEXCH_NOKEX)
- {
- if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_RSA)
- {
- state->kex_priv = new RSA_PrivateKey(rng,
- policy.rsa_export_keysize());
- }
- else if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_DH)
- {
- state->kex_priv = new DH_PrivateKey(rng, policy.dh_group());
- }
- else
- throw Internal_Error("TLS_Server: Unknown ciphersuite kex type");
-
- state->server_kex =
- new Server_Key_Exchange(rng, writer,
- state->kex_priv, private_key,
- state->client_hello->random(),
- state->server_hello->random(),
- state->hash);
- }
-
- if(policy.require_client_auth())
- {
- state->do_client_auth = true;
- throw Internal_Error("Client auth not implemented");
- // FIXME: send client auth request here
- }
-
- state->server_hello_done = new Server_Hello_Done(writer, state->hash);
- }
- else if(type == CERTIFICATE)
- {
- server_check_state(type, state);
- // FIXME: process this
- }
- else if(type == CLIENT_KEX)
- {
- server_check_state(type, state);
-
- state->client_kex = new Client_Key_Exchange(contents, state->suite,
- state->version);
-
- SecureVector<byte> pre_master =
- state->client_kex->pre_master_secret(rng, state->kex_priv,
- state->server_hello->version());
-
- state->keys = SessionKeys(state->suite, state->version, pre_master,
- state->client_hello->random(),
- state->server_hello->random());
- }
- else if(type == CERTIFICATE_VERIFY)
- {
- server_check_state(type, state);
- // FIXME: process this
- }
- else if(type == HANDSHAKE_CCS)
- {
- server_check_state(type, state);
-
- reader.set_keys(state->suite, state->keys, SERVER);
- state->got_client_ccs = true;
- }
- else if(type == FINISHED)
- {
- server_check_state(type, state);
-
- state->client_finished = new Finished(contents);
-
- if(!state->client_finished->verify(state->keys.master_secret(),
- state->version, state->hash, CLIENT))
- throw TLS_Exception(DECRYPT_ERROR,
- "Finished message didn't verify");
-
- state->hash.update(static_cast<byte>(type));
-
- const size_t record_length = contents.size();
- for(size_t i = 0; i != 3; i++)
- state->hash.update(get_byte<u32bit>(i+1, record_length));
-
- state->hash.update(contents);
-
- writer.send(CHANGE_CIPHER_SPEC, 1);
- writer.flush();
-
- writer.set_keys(state->suite, state->keys, SERVER);
-
- state->server_finished = new Finished(writer, state->version, SERVER,
- state->keys.master_secret(),
- state->hash);
-
- delete state;
- state = 0;
- active = true;
- }
- else
- throw Unexpected_Message("Unknown handshake message received");
- }
-
-/*
-* Perform a server-side TLS handshake
-*/
-void TLS_Server::do_handshake()
- {
- while(true)
- {
- if(active && !state)
- break;
-
- state_machine();
-
- if(!active && !state)
- throw TLS_Exception(HANDSHAKE_FAILURE, "TLS_Server: Handshake failed");
- }
- }
-
-}
diff --git a/src/ssl/tls_server.h b/src/ssl/tls_server.h
deleted file mode 100644
index a6b0f9cb4..000000000
--- a/src/ssl/tls_server.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-* TLS Server
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#ifndef BOTAN_TLS_SERVER_H__
-#define BOTAN_TLS_SERVER_H__
-
-#include <botan/tls_connection.h>
-#include <botan/tls_record.h>
-#include <botan/tls_policy.h>
-#include <vector>
-
-namespace Botan {
-
-/**
-* TLS Server
-*/
-class BOTAN_DLL TLS_Server : public TLS_Connection
- {
- public:
- size_t read(byte buf[], size_t buf_len);
- void write(const byte buf[], size_t buf_len);
-
- std::vector<X509_Certificate> peer_cert_chain() const;
-
- std::string requested_hostname() const
- { return client_requested_hostname; }
-
- void close();
- bool is_closed() const;
-
- /*
- * FIXME: support cert chains (!)
- * FIXME: support anonymous servers
- */
- TLS_Server(std::tr1::function<size_t (byte[], size_t)> input_fn,
- std::tr1::function<void (const byte[], size_t)> output_fn,
- const TLS_Policy& policy,
- RandomNumberGenerator& rng,
- const X509_Certificate& cert,
- const Private_Key& cert_key);
-
- ~TLS_Server();
- private:
- void close(Alert_Level, Alert_Type);
-
- void do_handshake();
- void state_machine();
- void read_handshake(byte, const MemoryRegion<byte>&);
-
- void process_handshake_msg(Handshake_Type, const MemoryRegion<byte>&);
-
- std::tr1::function<size_t (byte[], size_t)> input_fn;
-
- const TLS_Policy& policy;
- RandomNumberGenerator& rng;
-
- Record_Writer writer;
- Record_Reader reader;
-
- // FIXME: rename to match TLS_Client
- std::vector<X509_Certificate> cert_chain, peer_certs;
- Private_Key* private_key;
-
- class Handshake_State* state;
- SecureVector<byte> session_id;
- SecureQueue read_buf;
- std::string client_requested_hostname;
- bool active;
- };
-
-}
-
-#endif
diff --git a/src/ssl/tls_session_key.cpp b/src/ssl/tls_session_key.cpp
deleted file mode 100644
index 7c75d1758..000000000
--- a/src/ssl/tls_session_key.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
-* TLS Session Key
-* (C) 2004-2006 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/tls_session_key.h>
-#include <botan/prf_ssl3.h>
-#include <botan/prf_tls.h>
-#include <botan/lookup.h>
-
-namespace Botan {
-
-/**
-* Return the client cipher key
-*/
-SymmetricKey SessionKeys::client_cipher_key() const
- {
- return c_cipher;
- }
-
-/**
-* Return the server cipher key
-*/
-SymmetricKey SessionKeys::server_cipher_key() const
- {
- return s_cipher;
- }
-
-/**
-* Return the client MAC key
-*/
-SymmetricKey SessionKeys::client_mac_key() const
- {
- return c_mac;
- }
-
-/**
-* Return the server MAC key
-*/
-SymmetricKey SessionKeys::server_mac_key() const
- {
- return s_mac;
- }
-
-/**
-* Return the client cipher IV
-*/
-InitializationVector SessionKeys::client_iv() const
- {
- return c_iv;
- }
-
-/**
-* Return the server cipher IV
-*/
-InitializationVector SessionKeys::server_iv() const
- {
- return s_iv;
- }
-
-/**
-* Return the TLS master secret
-*/
-SecureVector<byte> SessionKeys::master_secret() const
- {
- return master_sec;
- }
-
-/**
-* Generate SSLv3 session keys
-*/
-SymmetricKey SessionKeys::ssl3_keygen(size_t prf_gen,
- const MemoryRegion<byte>& pre_master,
- const MemoryRegion<byte>& client_random,
- const MemoryRegion<byte>& server_random)
- {
- SSL3_PRF prf;
-
- SecureVector<byte> salt;
- salt += client_random;
- salt += server_random;
-
- master_sec = prf.derive_key(48, pre_master, salt);
-
- salt.clear();
- salt += server_random;
- salt += client_random;
-
- return prf.derive_key(prf_gen, master_sec, salt);
- }
-
-/**
-* Generate TLS 1.0 session keys
-*/
-SymmetricKey SessionKeys::tls1_keygen(size_t prf_gen,
- const MemoryRegion<byte>& pre_master,
- const MemoryRegion<byte>& client_random,
- const MemoryRegion<byte>& server_random)
- {
- const byte MASTER_SECRET_MAGIC[] = {
- 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65,
- 0x74 };
- const byte KEY_GEN_MAGIC[] = {
- 0x6B, 0x65, 0x79, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6E, 0x73, 0x69, 0x6F,
- 0x6E };
-
- TLS_PRF prf;
-
- SecureVector<byte> salt;
- salt += std::make_pair(MASTER_SECRET_MAGIC, sizeof(MASTER_SECRET_MAGIC));
- salt += client_random;
- salt += server_random;
-
- master_sec = prf.derive_key(48, pre_master, salt);
-
- salt.clear();
- salt += std::make_pair(KEY_GEN_MAGIC, sizeof(KEY_GEN_MAGIC));
- salt += server_random;
- salt += client_random;
-
- return prf.derive_key(prf_gen, master_sec, salt);
- }
-
-/**
-* SessionKeys Constructor
-*/
-SessionKeys::SessionKeys(const CipherSuite& suite, Version_Code version,
- const MemoryRegion<byte>& pre_master_secret,
- const MemoryRegion<byte>& c_random,
- const MemoryRegion<byte>& s_random)
- {
- if(version != SSL_V3 && version != TLS_V10 && version != TLS_V11)
- throw Invalid_Argument("SessionKeys: Unknown version code");
-
- const size_t mac_keylen = output_length_of(suite.mac_algo());
- const size_t cipher_keylen = suite.cipher_keylen();
-
- size_t cipher_ivlen = 0;
- if(have_block_cipher(suite.cipher_algo()))
- cipher_ivlen = block_size_of(suite.cipher_algo());
-
- const size_t prf_gen = 2 * (mac_keylen + cipher_keylen + cipher_ivlen);
-
- SymmetricKey keyblock = (version == SSL_V3) ?
- ssl3_keygen(prf_gen, pre_master_secret, c_random, s_random) :
- tls1_keygen(prf_gen, pre_master_secret, c_random, s_random);
-
- const byte* key_data = keyblock.begin();
-
- c_mac = SymmetricKey(key_data, mac_keylen);
- key_data += mac_keylen;
-
- s_mac = SymmetricKey(key_data, mac_keylen);
- key_data += mac_keylen;
-
- c_cipher = SymmetricKey(key_data, cipher_keylen);
- key_data += cipher_keylen;
-
- s_cipher = SymmetricKey(key_data, cipher_keylen);
- key_data += cipher_keylen;
-
- c_iv = InitializationVector(key_data, cipher_ivlen);
- key_data += cipher_ivlen;
-
- s_iv = InitializationVector(key_data, cipher_ivlen);
- }
-
-}
diff --git a/src/ssl/tls_session_key.h b/src/ssl/tls_session_key.h
deleted file mode 100644
index 51397984b..000000000
--- a/src/ssl/tls_session_key.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
-* TLS Session Key
-* (C) 2004-2006 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#ifndef BOTAN_TLS_SESSION_KEYS_H__
-#define BOTAN_TLS_SESSION_KEYS_H__
-
-#include <botan/tls_suites.h>
-#include <botan/tls_exceptn.h>
-#include <botan/symkey.h>
-
-namespace Botan {
-
-/**
-* TLS Session Keys
-*/
-class BOTAN_DLL SessionKeys
- {
- public:
- SymmetricKey client_cipher_key() const;
- SymmetricKey server_cipher_key() const;
-
- SymmetricKey client_mac_key() const;
- SymmetricKey server_mac_key() const;
-
- InitializationVector client_iv() const;
- InitializationVector server_iv() const;
-
- SecureVector<byte> master_secret() const;
-
- SessionKeys() {}
- SessionKeys(const CipherSuite&, Version_Code, const MemoryRegion<byte>&,
- const MemoryRegion<byte>&, const MemoryRegion<byte>&);
- private:
- SymmetricKey ssl3_keygen(size_t, const MemoryRegion<byte>&,
- const MemoryRegion<byte>&,
- const MemoryRegion<byte>&);
- SymmetricKey tls1_keygen(size_t, const MemoryRegion<byte>&,
- const MemoryRegion<byte>&,
- const MemoryRegion<byte>&);
-
- SecureVector<byte> master_sec;
- SymmetricKey c_cipher, s_cipher, c_mac, s_mac;
- InitializationVector c_iv, s_iv;
- };
-
-}
-
-#endif
diff --git a/src/ssl/tls_state.cpp b/src/ssl/tls_state.cpp
deleted file mode 100644
index 6aaf5e201..000000000
--- a/src/ssl/tls_state.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-* TLS Handshaking
-* (C) 2004-2006 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/internal/tls_state.h>
-
-namespace Botan {
-
-/**
-* Initialize the SSL/TLS Handshake State
-*/
-Handshake_State::Handshake_State()
- {
- client_hello = 0;
- server_hello = 0;
- server_certs = 0;
- server_kex = 0;
- cert_req = 0;
- server_hello_done = 0;
-
- client_certs = 0;
- client_kex = 0;
- client_verify = 0;
- client_finished = 0;
- server_finished = 0;
-
- kex_pub = 0;
- kex_priv = 0;
-
- do_client_auth = got_client_ccs = got_server_ccs = false;
- version = SSL_V3;
- }
-
-/**
-* Destroy the SSL/TLS Handshake State
-*/
-Handshake_State::~Handshake_State()
- {
- delete client_hello;
- delete server_hello;
- delete server_certs;
- delete server_kex;
- delete cert_req;
- delete server_hello_done;
-
- delete client_certs;
- delete client_kex;
- delete client_verify;
- delete client_finished;
- delete server_finished;
-
- delete kex_pub;
- delete kex_priv;
- }
-
-}
diff --git a/src/ssl/tls_state.h b/src/ssl/tls_state.h
deleted file mode 100644
index e2728198f..000000000
--- a/src/ssl/tls_state.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-* TLS Handshake State
-* (C) 2004-2006 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#ifndef BOTAN_TLS_HANDSHAKE_H__
-#define BOTAN_TLS_HANDSHAKE_H__
-
-#include <botan/internal/tls_messages.h>
-#include <botan/secqueue.h>
-
-namespace Botan {
-
-/**
-* SSL/TLS Handshake State
-*/
-class Handshake_State
- {
- public:
- Client_Hello* client_hello;
- Server_Hello* server_hello;
- Certificate* server_certs;
- Server_Key_Exchange* server_kex;
- Certificate_Req* cert_req;
- Server_Hello_Done* server_hello_done;
-
- Certificate* client_certs;
- Client_Key_Exchange* client_kex;
- Certificate_Verify* client_verify;
- Finished* client_finished;
- Finished* server_finished;
-
- Public_Key* kex_pub;
- Private_Key* kex_priv;
-
- CipherSuite suite;
- SessionKeys keys;
- HandshakeHash hash;
-
- SecureQueue queue;
-
- Version_Code version;
- bool got_client_ccs, got_server_ccs, do_client_auth;
-
- Handshake_State();
- ~Handshake_State();
- };
-
-}
-
-#endif
diff --git a/src/ssl/tls_suites.cpp b/src/ssl/tls_suites.cpp
deleted file mode 100644
index 07cbec608..000000000
--- a/src/ssl/tls_suites.cpp
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
-* TLS Cipher Suites
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#include <botan/tls_suites.h>
-#include <botan/tls_exceptn.h>
-
-namespace Botan {
-
-/**
-* Convert an SSL/TLS ciphersuite to algorithm fields
-*/
-TLS_Ciphersuite_Algos CipherSuite::lookup_ciphersuite(u16bit suite)
- {
- if(suite == TLS_RSA_WITH_RC4_128_MD5)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_NOKEX |
- TLS_ALGO_MAC_MD5 |
- TLS_ALGO_CIPHER_RC4_128);
-
- if(suite == TLS_RSA_WITH_RC4_128_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_NOKEX |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_RC4_128);
-
- if(suite == TLS_RSA_WITH_3DES_EDE_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_NOKEX |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_3DES_CBC);
-
- if(suite == TLS_RSA_WITH_AES_128_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_NOKEX |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_AES128_CBC);
-
- if(suite == TLS_RSA_WITH_AES_256_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_NOKEX |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_AES256_CBC);
-
- if(suite == TLS_RSA_WITH_SEED_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_NOKEX |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_SEED_CBC);
-
- if(suite == TLS_RSA_WITH_AES_128_CBC_SHA256)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_NOKEX |
- TLS_ALGO_MAC_SHA256 |
- TLS_ALGO_CIPHER_AES128_CBC);
-
- if(suite == TLS_RSA_WITH_AES_256_CBC_SHA256)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_NOKEX |
- TLS_ALGO_MAC_SHA256 |
- TLS_ALGO_CIPHER_AES256_CBC);
-
- if(suite == TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA |
- TLS_ALGO_KEYEXCH_DH |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_3DES_CBC);
-
- if(suite == TLS_DHE_DSS_WITH_AES_128_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA |
- TLS_ALGO_KEYEXCH_DH |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_AES128_CBC);
-
- if(suite == TLS_DHE_DSS_WITH_SEED_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA |
- TLS_ALGO_KEYEXCH_DH |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_SEED_CBC);
-
- if(suite == TLS_DHE_DSS_WITH_AES_256_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA |
- TLS_ALGO_KEYEXCH_DH |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_AES256_CBC);
-
- if(suite == TLS_DHE_DSS_WITH_AES_128_CBC_SHA256)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA |
- TLS_ALGO_KEYEXCH_DH |
- TLS_ALGO_MAC_SHA256 |
- TLS_ALGO_CIPHER_AES128_CBC);
-
- if(suite == TLS_DHE_DSS_WITH_AES_256_CBC_SHA256)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA |
- TLS_ALGO_KEYEXCH_DH |
- TLS_ALGO_MAC_SHA256 |
- TLS_ALGO_CIPHER_AES256_CBC);
-
- if(suite == TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_DH |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_3DES_CBC);
-
- if(suite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_DH |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_AES128_CBC);
-
- if(suite == TLS_DHE_DSS_WITH_SEED_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_DH |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_SEED_CBC);
-
- if(suite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_DH |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_AES256_CBC);
-
- if(suite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA256)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_DH |
- TLS_ALGO_MAC_SHA256 |
- TLS_ALGO_CIPHER_AES128_CBC);
-
- if(suite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA256)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_DH |
- TLS_ALGO_MAC_SHA256 |
- TLS_ALGO_CIPHER_AES256_CBC);
-
- if(suite == TLS_ECDHE_ECDSA_WITH_RC4_128_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
- TLS_ALGO_KEYEXCH_ECDH |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_RC4_128);
-
- if(suite == TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
- TLS_ALGO_KEYEXCH_ECDH |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_3DES_CBC);
-
- if(suite == TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
- TLS_ALGO_KEYEXCH_ECDH |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_AES128_CBC);
-
- if(suite == TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
- TLS_ALGO_KEYEXCH_ECDH |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_AES256_CBC);
-
- if(suite == TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
- TLS_ALGO_KEYEXCH_ECDH |
- TLS_ALGO_MAC_SHA256 |
- TLS_ALGO_CIPHER_AES128_CBC);
-
- if(suite == TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
- TLS_ALGO_KEYEXCH_ECDH |
- TLS_ALGO_MAC_SHA384 |
- TLS_ALGO_CIPHER_AES256_CBC);
-
- if(suite == TLS_ECDHE_RSA_WITH_RC4_128_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_ECDH |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_RC4_128);
-
- if(suite == TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_ECDH |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_3DES_CBC);
-
- if(suite == TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_ECDH |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_AES128_CBC);
-
- if(suite == TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA |
- TLS_ALGO_KEYEXCH_ECDH |
- TLS_ALGO_MAC_SHA1 |
- TLS_ALGO_CIPHER_AES256_CBC);
-
- if(suite == TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
- TLS_ALGO_KEYEXCH_ECDH |
- TLS_ALGO_MAC_SHA256 |
- TLS_ALGO_CIPHER_AES128_CBC);
-
- if(suite == TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384)
- return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA |
- TLS_ALGO_KEYEXCH_ECDH |
- TLS_ALGO_MAC_SHA384 |
- TLS_ALGO_CIPHER_AES256_CBC);
-
- return TLS_Ciphersuite_Algos(0);
- }
-
-namespace {
-
-std::pair<std::string, size_t> cipher_code_to_name(TLS_Ciphersuite_Algos algo)
- {
- if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_RC4_128)
- return std::make_pair("ARC4", 16);
-
- if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_3DES_CBC)
- return std::make_pair("3DES", 24);
-
- if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_AES128_CBC)
- return std::make_pair("AES-128", 16);
-
- if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_AES256_CBC)
- return std::make_pair("AES-256", 32);
-
- if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_SEED_CBC)
- return std::make_pair("SEED", 16);
-
- throw TLS_Exception(INTERNAL_ERROR,
- "CipherSuite: Unknown cipher type " + to_string(algo));
- }
-
-std::string mac_code_to_name(TLS_Ciphersuite_Algos algo)
- {
- if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_MD5)
- return "MD5";
-
- if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_SHA1)
- return "SHA-1";
-
- if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_SHA256)
- return "SHA-256";
-
- if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_SHA384)
- return "SHA-384";
-
- throw TLS_Exception(INTERNAL_ERROR,
- "CipherSuite: Unknown MAC type " + to_string(algo));
- }
-
-}
-
-/**
-* CipherSuite Constructor
-*/
-CipherSuite::CipherSuite(u16bit suite_code)
- {
- if(suite_code == 0)
- return;
-
- TLS_Ciphersuite_Algos algos = lookup_ciphersuite(suite_code);
-
- if(algos == 0)
- throw Invalid_Argument("Unknown ciphersuite: " + to_string(suite_code));
-
- sig_algo = TLS_Ciphersuite_Algos(algos & TLS_ALGO_SIGNER_MASK);
-
- kex_algo = TLS_Ciphersuite_Algos(algos & TLS_ALGO_KEYEXCH_MASK);
-
- std::pair<std::string, size_t> cipher_info = cipher_code_to_name(algos);
-
- cipher = cipher_info.first;
- cipher_key_length = cipher_info.second;
-
- mac = mac_code_to_name(algos);
- }
-
-}
diff --git a/src/ssl/tls_suites.h b/src/ssl/tls_suites.h
deleted file mode 100644
index 8d6db0e8b..000000000
--- a/src/ssl/tls_suites.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
-* Cipher Suites
-* (C) 2004-2010 Jack Lloyd
-*
-* Released under the terms of the Botan license
-*/
-
-#ifndef BOTAN_TLS_CIPHERSUITES_H__
-#define BOTAN_TLS_CIPHERSUITES_H__
-
-#include <botan/types.h>
-#include <botan/tls_magic.h>
-#include <string>
-
-namespace Botan {
-
-/**
-* Ciphersuite Information
-*/
-class BOTAN_DLL CipherSuite
- {
- public:
- static TLS_Ciphersuite_Algos lookup_ciphersuite(u16bit suite);
-
- std::string cipher_algo() const { return cipher; }
- std::string mac_algo() const { return mac; }
-
- size_t cipher_keylen() const { return cipher_key_length; }
-
- TLS_Ciphersuite_Algos kex_type() const { return kex_algo; }
- TLS_Ciphersuite_Algos sig_type() const { return sig_algo; }
-
- CipherSuite(u16bit = 0);
- private:
- TLS_Ciphersuite_Algos kex_algo, sig_algo;
- std::string cipher, mac;
- size_t cipher_key_length;
- };
-
-}
-
-#endif
diff --git a/src/stream/arc4/arc4.cpp b/src/stream/arc4/arc4.cpp
index 6eea7bb45..a25b68185 100644
--- a/src/stream/arc4/arc4.cpp
+++ b/src/stream/arc4/arc4.cpp
@@ -85,7 +85,7 @@ std::string ARC4::name() const
{
if(SKIP == 0) return "ARC4";
if(SKIP == 256) return "MARK-4";
- else return "RC4_skip(" + to_string(SKIP) + ")";
+ else return "RC4_skip(" + std::to_string(SKIP) + ")";
}
/*
diff --git a/src/stream/ctr/ctr.cpp b/src/stream/ctr/ctr.cpp
index 3a370eca3..8ceac858a 100644
--- a/src/stream/ctr/ctr.cpp
+++ b/src/stream/ctr/ctr.cpp
@@ -89,14 +89,14 @@ void CTR_BE::set_iv(const byte iv[], size_t iv_len)
zeroise(counter);
- counter.copy(0, iv, iv_len);
+ buffer_insert(counter, 0, iv, iv_len);
/*
* Set counter blocks to IV, IV + 1, ... IV + 255
*/
for(size_t i = 1; i != 256; ++i)
{
- counter.copy(i*bs, &counter[(i-1)*bs], bs);
+ buffer_insert(counter, i*bs, &counter[(i-1)*bs], bs);
for(size_t j = 0; j != bs; ++j)
if(++counter[i*bs + (bs - 1 - j)])
diff --git a/src/stream/ofb/ofb.cpp b/src/stream/ofb/ofb.cpp
index 382a2b4dd..02521581b 100644
--- a/src/stream/ofb/ofb.cpp
+++ b/src/stream/ofb/ofb.cpp
@@ -84,7 +84,7 @@ void OFB::set_iv(const byte iv[], size_t iv_len)
throw Invalid_IV_Length(name(), iv_len);
zeroise(buffer);
- buffer.copy(0, iv, iv_len);
+ buffer_insert(buffer, 0, iv, iv_len);
permutation->encrypt(buffer);
position = 0;
diff --git a/src/tls/c_hello.cpp b/src/tls/c_hello.cpp
new file mode 100644
index 000000000..df3957a4b
--- /dev/null
+++ b/src/tls/c_hello.cpp
@@ -0,0 +1,394 @@
+/*
+* TLS Hello Request and Client Hello Messages
+* (C) 2004-2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/internal/tls_messages.h>
+#include <botan/internal/tls_reader.h>
+#include <botan/internal/tls_session_key.h>
+#include <botan/internal/tls_extensions.h>
+#include <botan/tls_record.h>
+#include <botan/internal/stl_util.h>
+#include <chrono>
+
+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()));
+
+ store_be(time32, buf);
+ rng.randomize(&buf[4], buf.size() - 4);
+ return buf;
+ }
+
+/*
+* Create a new Hello Request message
+*/
+Hello_Request::Hello_Request(Record_Writer& writer)
+ {
+ writer.send(*this);
+ }
+
+/*
+* Deserialize a Hello Request message
+*/
+Hello_Request::Hello_Request(const MemoryRegion<byte>& buf)
+ {
+ if(buf.size())
+ throw Decoding_Error("Bad Hello_Request, has non-zero size");
+ }
+
+/*
+* Serialize a Hello Request message
+*/
+MemoryVector<byte> Hello_Request::serialize() const
+ {
+ return MemoryVector<byte>();
+ }
+
+/*
+* Create a new Client Hello message
+*/
+Client_Hello::Client_Hello(Record_Writer& writer,
+ Handshake_Hash& hash,
+ const Policy& policy,
+ RandomNumberGenerator& rng,
+ const MemoryRegion<byte>& reneg_info,
+ bool next_protocol,
+ const std::string& hostname,
+ const std::string& srp_identifier) :
+ m_version(policy.pref_version()),
+ m_random(make_hello_random(rng)),
+ m_suites(ciphersuite_list(policy, (srp_identifier != ""))),
+ m_comp_methods(policy.compression()),
+ m_hostname(hostname),
+ m_srp_identifier(srp_identifier),
+ m_next_protocol(next_protocol),
+ m_fragment_size(0),
+ m_secure_renegotiation(true),
+ m_renegotiation_info(reneg_info),
+ m_supported_curves(policy.allowed_ecc_curves()),
+ 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();
+
+ for(size_t i = 0; i != hashes.size(); ++i)
+ for(size_t j = 0; j != sigs.size(); ++j)
+ m_supported_algos.push_back(std::make_pair(hashes[i], sigs[j]));
+
+ hash.update(writer.send(*this));
+ }
+
+/*
+* Create a new Client Hello message (session resumption case)
+*/
+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(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_supports_heartbeats(true),
+ m_peer_can_send_heartbeats(true)
+ {
+ if(!value_exists(m_suites, session.ciphersuite_code()))
+ m_suites.push_back(session.ciphersuite_code());
+
+ if(!value_exists(m_comp_methods, session.compression_method()))
+ m_comp_methods.push_back(session.compression_method());
+
+ std::vector<std::string> hashes = policy.allowed_hashes();
+ std::vector<std::string> sigs = policy.allowed_signature_methods();
+
+ for(size_t i = 0; i != hashes.size(); ++i)
+ for(size_t j = 0; j != sigs.size(); ++j)
+ m_supported_algos.push_back(std::make_pair(hashes[i], sigs[j]));
+
+ hash.update(writer.send(*this));
+ }
+
+/*
+* Read a counterparty client hello
+*/
+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)
+ deserialize(buf);
+ else
+ deserialize_sslv2(buf);
+ }
+
+/*
+* Serialize a Client Hello message
+*/
+MemoryVector<byte> Client_Hello::serialize() const
+ {
+ MemoryVector<byte> buf;
+
+ 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);
+ append_tls_length_value(buf, m_suites, 2);
+ append_tls_length_value(buf, m_comp_methods, 1);
+
+ /*
+ * May not want to send extensions at all in some cases.
+ * If so, should include SCSV value (if reneg info is empty, if
+ * not we are renegotiating with a modern server and should only
+ * send that extension.
+ */
+
+ Extensions extensions;
+
+ if(m_secure_renegotiation)
+ extensions.add(new Renegotation_Extension(m_renegotiation_info));
+
+ extensions.add(new Session_Ticket(m_session_ticket));
+
+ 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 Heartbeat_Support_Indicator(true));
+
+ if(m_renegotiation_info.empty() && m_next_protocol)
+ extensions.add(new Next_Protocol_Notification());
+
+ buf += extensions.serialize();
+
+ return buf;
+ }
+
+void Client_Hello::deserialize_sslv2(const MemoryRegion<byte>& buf)
+ {
+ if(buf.size() < 12 || buf[0] != 1)
+ throw Decoding_Error("Client_Hello: SSLv2 hello corrupted");
+
+ const size_t cipher_spec_len = make_u16bit(buf[3], buf[4]);
+ const size_t m_session_id_len = make_u16bit(buf[5], buf[6]);
+ const size_t challenge_len = make_u16bit(buf[7], buf[8]);
+
+ const size_t expected_size =
+ (9 + m_session_id_len + cipher_spec_len + challenge_len);
+
+ if(buf.size() != expected_size)
+ throw Decoding_Error("Client_Hello: SSLv2 hello corrupted");
+
+ if(m_session_id_len != 0 || cipher_spec_len % 3 != 0 ||
+ (challenge_len < 16 || challenge_len > 32))
+ {
+ throw Decoding_Error("Client_Hello: SSLv2 hello corrupted");
+ }
+
+ for(size_t i = 9; i != 9 + cipher_spec_len; i += 3)
+ {
+ if(buf[i] != 0) // a SSLv2 cipherspec; ignore it
+ continue;
+
+ m_suites.push_back(make_u16bit(buf[i+1], buf[i+2]));
+ }
+
+ m_version = Protocol_Version(buf[1], buf[2]);
+
+ m_random.resize(challenge_len);
+ copy_mem(&m_random[0], &buf[9+cipher_spec_len+m_session_id_len], challenge_len);
+
+ m_secure_renegotiation =
+ value_exists(m_suites, static_cast<u16bit>(TLS_EMPTY_RENEGOTIATION_INFO_SCSV));
+ }
+
+/*
+* Deserialize a Client Hello message
+*/
+void Client_Hello::deserialize(const MemoryRegion<byte>& buf)
+ {
+ if(buf.size() == 0)
+ throw Decoding_Error("Client_Hello: Packet corrupted");
+
+ if(buf.size() < 41)
+ throw Decoding_Error("Client_Hello: Packet corrupted");
+
+ TLS_Data_Reader reader(buf);
+
+ const byte major_version = reader.get_byte();
+ const byte minor_version = reader.get_byte();
+
+ m_version = Protocol_Version(major_version, minor_version);
+
+ m_random = reader.get_fixed<byte>(32);
+
+ m_session_id = reader.get_range<byte>(1, 0, 32);
+
+ m_suites = reader.get_range_vector<u16bit>(2, 1, 32767);
+
+ m_comp_methods = reader.get_range_vector<byte>(1, 1, 255);
+
+ Extensions extensions(reader);
+
+ if(Server_Name_Indicator* sni = extensions.get<Server_Name_Indicator>())
+ {
+ m_hostname = sni->host_name();
+ }
+
+ if(SRP_Identifier* srp = extensions.get<SRP_Identifier>())
+ {
+ m_srp_identifier = srp->identifier();
+ }
+
+ if(Next_Protocol_Notification* npn = extensions.get<Next_Protocol_Notification>())
+ {
+ if(!npn->protocols().empty())
+ throw Decoding_Error("Client sent non-empty NPN extension");
+
+ m_next_protocol = true;
+ }
+
+ if(Maximum_Fragment_Length* frag = extensions.get<Maximum_Fragment_Length>())
+ {
+ m_fragment_size = frag->fragment_size();
+ }
+
+ if(Renegotation_Extension* reneg = extensions.get<Renegotation_Extension>())
+ {
+ // checked by Client / Server as they know the handshake state
+ m_secure_renegotiation = true;
+ m_renegotiation_info = reneg->renegotiation_info();
+ }
+
+ if(Supported_Elliptic_Curves* ecc = extensions.get<Supported_Elliptic_Curves>())
+ m_supported_curves = ecc->curves();
+
+ if(Signature_Algorithms* sigs = extensions.get<Signature_Algorithms>())
+ {
+ m_supported_algos = sigs->supported_signature_algorthms();
+ }
+ else
+ {
+ if(m_version >= Protocol_Version::TLS_V12)
+ {
+ /*
+ The rule for when a TLS 1.2 client not sending the extension
+ is strange; in theory, the server is supposed to act as if
+ the client had sent only SHA-1 using whatever signature
+ algorithm we end up negotiating. Right here, we don't know
+ what we'll end up negotiating (depends on policy), but we do
+ know that we'll only negotiate something the client sent, so
+ we can safely say it supports everything here and know that
+ we'll filter it out later.
+ */
+ m_supported_algos.push_back(std::make_pair("SHA-1", "RSA"));
+ m_supported_algos.push_back(std::make_pair("SHA-1", "DSA"));
+ m_supported_algos.push_back(std::make_pair("SHA-1", "ECDSA"));
+ }
+ else
+ {
+ // For versions before TLS 1.2, insert fake values for the old defaults
+
+ m_supported_algos.push_back(std::make_pair("TLS.Digest.0", "RSA"));
+ m_supported_algos.push_back(std::make_pair("SHA-1", "DSA"));
+ m_supported_algos.push_back(std::make_pair("SHA-1", "ECDSA"));
+ }
+ }
+
+ if(Maximum_Fragment_Length* frag = extensions.get<Maximum_Fragment_Length>())
+ {
+ m_fragment_size = frag->fragment_size();
+ }
+
+ if(Session_Ticket* ticket = extensions.get<Session_Ticket>())
+ {
+ m_supports_session_ticket = true;
+ 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
+ m_secure_renegotiation = true;
+ m_renegotiation_info = reneg->renegotiation_info();
+ }
+
+ if(value_exists(m_suites, static_cast<u16bit>(TLS_EMPTY_RENEGOTIATION_INFO_SCSV)))
+ {
+ /*
+ * Clients are allowed to send both the extension and the SCSV
+ * though it is not recommended. If it did, require that the
+ * extension value be empty.
+ */
+ if(m_secure_renegotiation)
+ {
+ if(!m_renegotiation_info.empty())
+ {
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Client send SCSV and non-empty extension");
+ }
+ }
+
+ m_secure_renegotiation = true;
+ m_renegotiation_info.clear();
+ }
+ }
+
+/*
+* Check if we offered this ciphersuite
+*/
+bool Client_Hello::offered_suite(u16bit ciphersuite) const
+ {
+ for(size_t i = 0; i != m_suites.size(); ++i)
+ if(m_suites[i] == ciphersuite)
+ return true;
+ return false;
+ }
+
+}
+
+}
diff --git a/src/tls/c_kex.cpp b/src/tls/c_kex.cpp
new file mode 100644
index 000000000..f97081383
--- /dev/null
+++ b/src/tls/c_kex.cpp
@@ -0,0 +1,393 @@
+/*
+* Client Key Exchange Message
+* (C) 2004-2010 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/internal/tls_messages.h>
+#include <botan/internal/tls_reader.h>
+#include <botan/internal/tls_extensions.h>
+#include <botan/tls_record.h>
+#include <botan/internal/assert.h>
+#include <botan/credentials_manager.h>
+#include <botan/pubkey.h>
+#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>
+
+namespace Botan {
+
+namespace TLS {
+
+namespace {
+
+SecureVector<byte> strip_leading_zeros(const MemoryRegion<byte>& input)
+ {
+ size_t leading_zeros = 0;
+
+ for(size_t i = 0; i != input.size(); ++i)
+ {
+ if(input[i] != 0)
+ break;
+ ++leading_zeros;
+ }
+
+ SecureVector<byte> output(&input[leading_zeros],
+ input.size() - leading_zeros);
+ return output;
+ }
+
+}
+
+/*
+* Create a new Client Key Exchange message
+*/
+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();
+
+ if(kex_algo == "PSK")
+ {
+ std::string identity_hint = "";
+
+ if(state->server_kex)
+ {
+ TLS_Data_Reader reader(state->server_kex->params());
+ identity_hint = reader.get_string(2, 0, 65535);
+ }
+
+ const std::string hostname = state->client_hello->sni_hostname();
+
+ const std::string psk_identity = creds.psk_identity("tls-client",
+ hostname,
+ identity_hint);
+
+ append_tls_length_value(key_material, psk_identity, 2);
+
+ SymmetricKey psk = creds.psk("tls-client", hostname, psk_identity);
+
+ MemoryVector<byte> zeros(psk.length());
+
+ append_tls_length_value(pre_master, zeros, 2);
+ append_tls_length_value(pre_master, psk.bits_of(), 2);
+ }
+ else if(state->server_kex)
+ {
+ TLS_Data_Reader reader(state->server_kex->params());
+
+ SymmetricKey psk;
+
+ if(kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK")
+ {
+ std::string identity_hint = reader.get_string(2, 0, 65535);
+
+ const std::string hostname = state->client_hello->sni_hostname();
+
+ const std::string psk_identity = creds.psk_identity("tls-client",
+ hostname,
+ identity_hint);
+
+ append_tls_length_value(key_material, psk_identity, 2);
+
+ psk = creds.psk("tls-client", hostname, psk_identity);
+ }
+
+ if(kex_algo == "DH" || kex_algo == "DHE_PSK")
+ {
+ BigInt p = BigInt::decode(reader.get_range<byte>(2, 1, 65535));
+ BigInt g = BigInt::decode(reader.get_range<byte>(2, 1, 65535));
+ BigInt Y = BigInt::decode(reader.get_range<byte>(2, 1, 65535));
+
+ if(reader.remaining_bytes())
+ throw Decoding_Error("Bad params size for DH key exchange");
+
+ DL_Group group(p, g);
+
+ if(!group.verify_group(rng, true))
+ throw Internal_Error("DH group failed validation, possible attack");
+
+ DH_PublicKey counterparty_key(group, Y);
+
+ // FIXME Check that public key is residue?
+
+ DH_PrivateKey priv_key(rng, group);
+
+ PK_Key_Agreement ka(priv_key, "Raw");
+
+ SecureVector<byte> dh_secret = strip_leading_zeros(
+ ka.derive_key(0, counterparty_key.public_value()).bits_of());
+
+ if(kex_algo == "DH")
+ pre_master = dh_secret;
+ else
+ {
+ append_tls_length_value(pre_master, dh_secret, 2);
+ append_tls_length_value(pre_master, psk.bits_of(), 2);
+ }
+
+ append_tls_length_value(key_material, priv_key.public_value(), 2);
+ }
+ else if(kex_algo == "ECDH" || kex_algo == "ECDHE_PSK")
+ {
+ const byte curve_type = reader.get_byte();
+
+ if(curve_type != 3)
+ throw Decoding_Error("Server sent non-named ECC curve");
+
+ const u16bit curve_id = reader.get_u16bit();
+
+ 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));
+
+ EC_Group group(name);
+
+ MemoryVector<byte> ecdh_key = reader.get_range<byte>(1, 1, 255);
+
+ ECDH_PublicKey counterparty_key(group, OS2ECP(ecdh_key, group.get_curve()));
+
+ ECDH_PrivateKey priv_key(rng, group);
+
+ PK_Key_Agreement ka(priv_key, "Raw");
+
+ SecureVector<byte> ecdh_secret = ka.derive_key(0, counterparty_key.public_value()).bits_of();
+
+ if(kex_algo == "ECDH")
+ pre_master = ecdh_secret;
+ else
+ {
+ append_tls_length_value(pre_master, ecdh_secret, 2);
+ append_tls_length_value(pre_master, psk.bits_of(), 2);
+ }
+
+ 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 " +
+ kex_algo);
+ }
+ }
+ else
+ {
+ // No server key exchange msg better mean RSA kex + RSA key in cert
+
+ if(kex_algo != "RSA")
+ throw Unexpected_Message("No server kex but negotiated kex " + kex_algo);
+
+ 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());
+
+ if(const RSA_PublicKey* rsa_pub = dynamic_cast<const RSA_PublicKey*>(pub_key.get()))
+ {
+ const Protocol_Version pref_version = state->client_hello->version();
+
+ pre_master = rng.random_vec(48);
+ pre_master[0] = pref_version.major_version();
+ pre_master[1] = pref_version.minor_version();
+
+ PK_Encryptor_EME encryptor(*rsa_pub, "PKCS1v15");
+
+ MemoryVector<byte> encrypted_key = encryptor.encrypt(pre_master, rng);
+
+ if(state->version() == Protocol_Version::SSL_V3)
+ key_material = encrypted_key; // no length field
+ else
+ append_tls_length_value(key_material, encrypted_key, 2);
+ }
+ else
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Expected a RSA key in server cert but got " +
+ pub_key->algo_name());
+ }
+
+ state->hash.update(writer.send(*this));
+ }
+
+/*
+* Read a Client Key Exchange message
+*/
+Client_Key_Exchange::Client_Key_Exchange(const MemoryRegion<byte>& contents,
+ const Handshake_State* state,
+ Credentials_Manager& creds,
+ const Policy& policy,
+ RandomNumberGenerator& rng)
+ {
+ const std::string kex_algo = state->suite.kex_algo();
+
+ if(kex_algo == "RSA")
+ {
+ BOTAN_ASSERT(state->server_certs && !state->server_certs->cert_chain().empty(),
+ "No server certificate to use for RSA");
+
+ const Private_Key* private_key = state->server_rsa_kex_key;
+
+ if(!private_key)
+ throw Internal_Error("Expected RSA kex but no server kex key set");
+
+ if(!dynamic_cast<const RSA_PrivateKey*>(private_key))
+ throw Internal_Error("Expected RSA key but got " + private_key->algo_name());
+
+ PK_Decryptor_EME decryptor(*private_key, "PKCS1v15");
+
+ Protocol_Version client_version = state->client_hello->version();
+
+ try
+ {
+ if(state->version() == Protocol_Version::SSL_V3)
+ {
+ pre_master = decryptor.decrypt(contents);
+ }
+ else
+ {
+ TLS_Data_Reader reader(contents);
+ pre_master = decryptor.decrypt(reader.get_range<byte>(2, 0, 65535));
+ }
+
+ if(pre_master.size() != 48 ||
+ client_version.major_version() != pre_master[0] ||
+ client_version.minor_version() != pre_master[1])
+ {
+ throw Decoding_Error("Client_Key_Exchange: Secret corrupted");
+ }
+ }
+ catch(...)
+ {
+ // Randomize the hide timing channel
+ pre_master = rng.random_vec(48);
+ pre_master[0] = client_version.major_version();
+ pre_master[1] = client_version.minor_version();
+ }
+ }
+ else
+ {
+ TLS_Data_Reader reader(contents);
+
+ SymmetricKey psk;
+
+ if(kex_algo == "PSK" || kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK")
+ {
+ const std::string psk_identity = reader.get_string(2, 0, 65535);
+
+ psk = creds.psk("tls-server",
+ state->client_hello->sni_hostname(),
+ psk_identity);
+
+ if(psk.length() == 0)
+ {
+ if(policy.hide_unknown_users())
+ psk = SymmetricKey(rng, 16);
+ else
+ throw TLS_Exception(Alert::UNKNOWN_PSK_IDENTITY,
+ "No PSK for identifier " + psk_identity);
+ }
+
+ }
+
+ if(kex_algo == "PSK")
+ {
+ MemoryVector<byte> zeros(psk.length());
+ 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")
+ {
+ const Private_Key& private_key = state->server_kex->server_kex_key();
+
+ const PK_Key_Agreement_Key* ka_key =
+ dynamic_cast<const PK_Key_Agreement_Key*>(&private_key);
+
+ if(!ka_key)
+ throw Internal_Error("Expected key agreement key type but got " +
+ private_key.algo_name());
+
+ try
+ {
+ PK_Key_Agreement ka(*ka_key, "Raw");
+
+ MemoryVector<byte> client_pubkey;
+
+ if(ka_key->algo_name() == "DH")
+ client_pubkey = reader.get_range<byte>(2, 0, 65535);
+ else
+ client_pubkey = reader.get_range<byte>(1, 0, 255);
+
+ SecureVector<byte> shared_secret = ka.derive_key(0, client_pubkey).bits_of();
+
+ if(ka_key->algo_name() == "DH")
+ shared_secret = strip_leading_zeros(shared_secret);
+
+ if(kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK")
+ {
+ append_tls_length_value(pre_master, shared_secret, 2);
+ append_tls_length_value(pre_master, psk.bits_of(), 2);
+ }
+ else
+ pre_master = shared_secret;
+ }
+ catch(std::exception &e)
+ {
+ /*
+ * Something failed in the DH computation. To avoid possible
+ * timing attacks, randomize the pre-master output and carry
+ * on, allowing the protocol to fail later in the finished
+ * checks.
+ */
+ pre_master = rng.random_vec(ka_key->public_value().size());
+ }
+ }
+ else
+ throw Internal_Error("Client_Key_Exchange: Unknown kex type " + kex_algo);
+ }
+ }
+
+}
+
+}
diff --git a/src/tls/cert_req.cpp b/src/tls/cert_req.cpp
new file mode 100644
index 000000000..1b686c1c4
--- /dev/null
+++ b/src/tls/cert_req.cpp
@@ -0,0 +1,241 @@
+/*
+* Certificate Request Message
+* (C) 2004-2006,2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/internal/tls_messages.h>
+#include <botan/internal/tls_reader.h>
+#include <botan/internal/tls_extensions.h>
+#include <botan/tls_record.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/loadstor.h>
+
+namespace Botan {
+
+namespace TLS {
+
+namespace {
+
+std::string cert_type_code_to_name(byte code)
+ {
+ switch(code)
+ {
+ case 1:
+ return "RSA";
+ case 2:
+ return "DSA";
+ case 64:
+ return "ECDSA";
+ default:
+ return ""; // DH or something else
+ }
+ }
+
+byte cert_type_name_to_code(const std::string& name)
+ {
+ if(name == "RSA")
+ return 1;
+ if(name == "DSA")
+ return 2;
+ if(name == "ECDSA")
+ return 64;
+
+ throw Invalid_Argument("Unknown cert type " + name);
+ }
+
+}
+
+/**
+* Create a new Certificate Request message
+*/
+Certificate_Req::Certificate_Req(Record_Writer& writer,
+ Handshake_Hash& hash,
+ const Policy& policy,
+ const std::vector<X509_Certificate>& ca_certs,
+ Protocol_Version version)
+ {
+ for(size_t i = 0; i != ca_certs.size(); ++i)
+ names.push_back(ca_certs[i].subject_dn());
+
+ cert_key_types.push_back("RSA");
+ cert_key_types.push_back("DSA");
+ cert_key_types.push_back("ECDSA");
+
+ if(version >= Protocol_Version::TLS_V12)
+ {
+ std::vector<std::string> hashes = policy.allowed_hashes();
+ std::vector<std::string> sigs = policy.allowed_signature_methods();
+
+ for(size_t i = 0; i != hashes.size(); ++i)
+ for(size_t j = 0; j != sigs.size(); ++j)
+ m_supported_algos.push_back(std::make_pair(hashes[i], sigs[j]));
+ }
+
+ hash.update(writer.send(*this));
+ }
+
+/**
+* Deserialize a Certificate Request message
+*/
+Certificate_Req::Certificate_Req(const MemoryRegion<byte>& buf,
+ Protocol_Version version)
+ {
+ if(buf.size() < 4)
+ throw Decoding_Error("Certificate_Req: Bad certificate request");
+
+ TLS_Data_Reader reader(buf);
+
+ std::vector<byte> cert_type_codes = reader.get_range_vector<byte>(1, 1, 255);
+
+ for(size_t i = 0; i != cert_type_codes.size(); ++i)
+ {
+ const std::string cert_type_name = cert_type_code_to_name(cert_type_codes[i]);
+
+ if(cert_type_name == "") // something we don't know
+ continue;
+
+ cert_key_types.push_back(cert_type_name);
+ }
+
+ if(version >= Protocol_Version::TLS_V12)
+ {
+ std::vector<byte> sig_hash_algs = reader.get_range_vector<byte>(2, 2, 65534);
+
+ if(sig_hash_algs.size() % 2 != 0)
+ throw Decoding_Error("Bad length for signature IDs in certificate request");
+
+ for(size_t i = 0; i != sig_hash_algs.size(); i += 2)
+ {
+ std::string hash = Signature_Algorithms::hash_algo_name(sig_hash_algs[i]);
+ std::string sig = Signature_Algorithms::sig_algo_name(sig_hash_algs[i+1]);
+ m_supported_algos.push_back(std::make_pair(hash, sig));
+ }
+ }
+ else
+ {
+ // The hardcoded settings from previous protocol versions
+ m_supported_algos.push_back(std::make_pair("TLS.Digest.0", "RSA"));
+ m_supported_algos.push_back(std::make_pair("SHA-1", "DSA"));
+ m_supported_algos.push_back(std::make_pair("SHA-1", "ECDSA"));
+ }
+
+ const u16bit purported_size = reader.get_u16bit();
+
+ if(reader.remaining_bytes() != purported_size)
+ throw Decoding_Error("Inconsistent length in certificate request");
+
+ while(reader.has_remaining())
+ {
+ std::vector<byte> name_bits = reader.get_range_vector<byte>(2, 0, 65535);
+
+ BER_Decoder decoder(&name_bits[0], name_bits.size());
+ X509_DN name;
+ decoder.decode(name);
+ names.push_back(name);
+ }
+ }
+
+/**
+* Serialize a Certificate Request message
+*/
+MemoryVector<byte> Certificate_Req::serialize() const
+ {
+ MemoryVector<byte> buf;
+
+ std::vector<byte> cert_types;
+
+ for(size_t i = 0; i != cert_key_types.size(); ++i)
+ cert_types.push_back(cert_type_name_to_code(cert_key_types[i]));
+
+ 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(encoded_names, encoder.get_contents(), 2);
+ }
+
+ append_tls_length_value(buf, encoded_names, 2);
+
+ return buf;
+ }
+
+/**
+* Create a new Certificate message
+*/
+Certificate::Certificate(Record_Writer& writer,
+ Handshake_Hash& hash,
+ const std::vector<X509_Certificate>& cert_list) :
+ m_certs(cert_list)
+ {
+ hash.update(writer.send(*this));
+ }
+
+/**
+* Deserialize a Certificate message
+*/
+Certificate::Certificate(const MemoryRegion<byte>& buf)
+ {
+ if(buf.size() < 3)
+ throw Decoding_Error("Certificate: Message malformed");
+
+ const size_t total_size = make_u32bit(0, buf[0], buf[1], buf[2]);
+
+ if(total_size != buf.size() - 3)
+ throw Decoding_Error("Certificate: Message malformed");
+
+ const byte* certs = &buf[3];
+
+ while(certs != buf.end())
+ {
+ if(buf.end() - certs < 3)
+ throw Decoding_Error("Certificate: Message malformed");
+
+ const size_t cert_size = make_u32bit(0, certs[0], certs[1], certs[2]);
+
+ if(buf.end() - certs < (3 + cert_size))
+ throw Decoding_Error("Certificate: Message malformed");
+
+ DataSource_Memory cert_buf(&certs[3], cert_size);
+ m_certs.push_back(X509_Certificate(cert_buf));
+
+ certs += cert_size + 3;
+ }
+ }
+
+/**
+* Serialize a Certificate message
+*/
+MemoryVector<byte> Certificate::serialize() const
+ {
+ MemoryVector<byte> buf(3);
+
+ for(size_t i = 0; i != m_certs.size(); ++i)
+ {
+ MemoryVector<byte> raw_cert = m_certs[i].BER_encode();
+ const size_t cert_size = raw_cert.size();
+ for(size_t i = 0; i != 3; ++i)
+ buf.push_back(get_byte<u32bit>(i+1, cert_size));
+ buf += raw_cert;
+ }
+
+ const size_t buf_size = buf.size() - 3;
+ for(size_t i = 0; i != 3; ++i)
+ buf[i] = get_byte<u32bit>(i+1, buf_size);
+
+ return buf;
+ }
+
+}
+
+}
diff --git a/src/tls/cert_ver.cpp b/src/tls/cert_ver.cpp
new file mode 100644
index 000000000..0a377b35f
--- /dev/null
+++ b/src/tls/cert_ver.cpp
@@ -0,0 +1,117 @@
+/*
+* Certificate Verify Message
+* (C) 2004,2006,2011,2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/internal/tls_messages.h>
+#include <botan/internal/tls_reader.h>
+#include <botan/internal/tls_extensions.h>
+#include <botan/tls_record.h>
+#include <botan/internal/assert.h>
+#include <memory>
+
+namespace Botan {
+
+namespace TLS {
+
+/*
+* Create a new Certificate Verify message
+*/
+Certificate_Verify::Certificate_Verify(Record_Writer& writer,
+ Handshake_State* state,
+ RandomNumberGenerator& rng,
+ const Private_Key* priv_key)
+ {
+ BOTAN_ASSERT_NONNULL(priv_key);
+
+ std::pair<std::string, Signature_Format> format =
+ state->choose_sig_format(priv_key, hash_algo, sig_algo, true);
+
+ PK_Signer signer(*priv_key, format.first, format.second);
+
+ if(state->version() == Protocol_Version::SSL_V3)
+ {
+ SecureVector<byte> md5_sha = state->hash.final_ssl3(
+ state->keys.master_secret());
+
+ if(priv_key->algo_name() == "DSA")
+ signature = signer.sign_message(&md5_sha[16], md5_sha.size()-16, rng);
+ else
+ signature = signer.sign_message(md5_sha, rng);
+ }
+ else
+ {
+ signature = signer.sign_message(state->hash.get_contents(), rng);
+ }
+
+ state->hash.update(writer.send(*this));
+ }
+
+/*
+* Deserialize a Certificate Verify message
+*/
+Certificate_Verify::Certificate_Verify(const MemoryRegion<byte>& buf,
+ Protocol_Version version)
+ {
+ TLS_Data_Reader reader(buf);
+
+ if(version >= Protocol_Version::TLS_V12)
+ {
+ hash_algo = Signature_Algorithms::hash_algo_name(reader.get_byte());
+ sig_algo = Signature_Algorithms::sig_algo_name(reader.get_byte());
+ }
+
+ signature = reader.get_range<byte>(2, 0, 65535);
+ }
+
+/*
+* Serialize a Certificate Verify message
+*/
+MemoryVector<byte> Certificate_Verify::serialize() const
+ {
+ MemoryVector<byte> buf;
+
+ if(hash_algo != "" && sig_algo != "")
+ {
+ buf.push_back(Signature_Algorithms::hash_algo_code(hash_algo));
+ buf.push_back(Signature_Algorithms::sig_algo_code(sig_algo));
+ }
+
+ const u16bit sig_len = signature.size();
+ buf.push_back(get_byte(0, sig_len));
+ buf.push_back(get_byte(1, sig_len));
+ buf += signature;
+
+ return buf;
+ }
+
+/*
+* Verify a Certificate Verify message
+*/
+bool Certificate_Verify::verify(const X509_Certificate& cert,
+ Handshake_State* state)
+ {
+ std::unique_ptr<Public_Key> key(cert.subject_public_key());
+
+ std::pair<std::string, Signature_Format> format =
+ state->understand_sig_format(key.get(), hash_algo, sig_algo, true);
+
+ PK_Verifier verifier(*key, format.first, format.second);
+
+ if(state->version() == Protocol_Version::SSL_V3)
+ {
+ SecureVector<byte> md5_sha = state->hash.final_ssl3(
+ state->keys.master_secret());
+
+ return verifier.verify_message(&md5_sha[16], md5_sha.size()-16,
+ &signature[0], signature.size());
+ }
+
+ return verifier.verify_message(state->hash.get_contents(), signature);
+ }
+
+}
+
+}
diff --git a/src/tls/finished.cpp b/src/tls/finished.cpp
new file mode 100644
index 000000000..bb6e8d20e
--- /dev/null
+++ b/src/tls/finished.cpp
@@ -0,0 +1,104 @@
+/*
+* Finished Message
+* (C) 2004-2006,2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/internal/tls_messages.h>
+#include <botan/tls_record.h>
+#include <memory>
+
+namespace Botan {
+
+namespace TLS {
+
+namespace {
+
+/*
+* Compute the verify_data
+*/
+MemoryVector<byte> finished_compute_verify(Handshake_State* state,
+ Connection_Side side)
+ {
+ if(state->version() == Protocol_Version::SSL_V3)
+ {
+ const byte SSL_CLIENT_LABEL[] = { 0x43, 0x4C, 0x4E, 0x54 };
+ const byte SSL_SERVER_LABEL[] = { 0x53, 0x52, 0x56, 0x52 };
+
+ Handshake_Hash hash = state->hash; // don't modify state
+
+ MemoryVector<byte> ssl3_finished;
+
+ if(side == CLIENT)
+ hash.update(SSL_CLIENT_LABEL, sizeof(SSL_CLIENT_LABEL));
+ else
+ hash.update(SSL_SERVER_LABEL, sizeof(SSL_SERVER_LABEL));
+
+ return hash.final_ssl3(state->keys.master_secret());
+ }
+ else
+ {
+ const byte TLS_CLIENT_LABEL[] = {
+ 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x66, 0x69, 0x6E, 0x69,
+ 0x73, 0x68, 0x65, 0x64 };
+
+ const byte TLS_SERVER_LABEL[] = {
+ 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x66, 0x69, 0x6E, 0x69,
+ 0x73, 0x68, 0x65, 0x64 };
+
+ std::unique_ptr<KDF> prf(state->protocol_specific_prf());
+
+ MemoryVector<byte> input;
+ if(side == CLIENT)
+ input += std::make_pair(TLS_CLIENT_LABEL, sizeof(TLS_CLIENT_LABEL));
+ else
+ input += std::make_pair(TLS_SERVER_LABEL, sizeof(TLS_SERVER_LABEL));
+
+ input += state->hash.final(state->version(), state->suite.mac_algo());
+
+ return prf->derive_key(12, state->keys.master_secret(), input);
+ }
+ }
+
+}
+
+/*
+* Create a new Finished message
+*/
+Finished::Finished(Record_Writer& writer,
+ Handshake_State* state,
+ Connection_Side side)
+ {
+ verification_data = finished_compute_verify(state, side);
+ state->hash.update(writer.send(*this));
+ }
+
+/*
+* Serialize a Finished message
+*/
+MemoryVector<byte> Finished::serialize() const
+ {
+ return verification_data;
+ }
+
+/*
+* Deserialize a Finished message
+*/
+Finished::Finished(const MemoryRegion<byte>& buf)
+ {
+ verification_data = buf;
+ }
+
+/*
+* Verify a Finished message
+*/
+bool Finished::verify(Handshake_State* state,
+ Connection_Side side)
+ {
+ return (verification_data == finished_compute_verify(state, side));
+ }
+
+}
+
+}
diff --git a/src/tls/hello_verify.cpp b/src/tls/hello_verify.cpp
new file mode 100644
index 000000000..e844d7f72
--- /dev/null
+++ b/src/tls/hello_verify.cpp
@@ -0,0 +1,61 @@
+/*
+* DTLS Hello Verify Request
+* (C) 2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/internal/tls_messages.h>
+#include <botan/lookup.h>
+#include <memory>
+
+namespace Botan {
+
+namespace TLS {
+
+Hello_Verify_Request::Hello_Verify_Request(const MemoryRegion<byte>& buf)
+ {
+ if(buf.size() < 3)
+ throw Decoding_Error("Hello verify request too small");
+
+ if(buf[0] != 254 || (buf[1] != 255 && buf[1] != 253))
+ throw Decoding_Error("Unknown version from server in hello verify request");
+
+ m_cookie.resize(buf.size() - 2);
+ copy_mem(&m_cookie[0], &buf[2], buf.size() - 2);
+ }
+
+Hello_Verify_Request::Hello_Verify_Request(const MemoryVector<byte>& client_hello_bits,
+ const std::string& client_identity,
+ const SymmetricKey& secret_key)
+ {
+ std::unique_ptr<MessageAuthenticationCode> hmac(get_mac("HMAC(SHA-256)"));
+ hmac->set_key(secret_key);
+
+ hmac->update_be(client_hello_bits.size());
+ hmac->update(client_hello_bits);
+ hmac->update_be(client_identity.size());
+ hmac->update(client_identity);
+
+ m_cookie = hmac->final();
+ }
+
+MemoryVector<byte> Hello_Verify_Request::serialize() const
+ {
+ /* DTLS 1.2 server implementations SHOULD use DTLS version 1.0
+ regardless of the version of TLS that is expected to be
+ negotiated (RFC 6347, section 4.2.1)
+ */
+
+ Protocol_Version format_version(Protocol_Version::TLS_V11);
+
+ MemoryVector<byte> bits;
+ bits.push_back(format_version.major_version());
+ bits.push_back(format_version.minor_version());
+ bits += m_cookie;
+ return bits;
+ }
+
+}
+
+}
diff --git a/src/tls/info.txt b/src/tls/info.txt
new file mode 100644
index 000000000..3407aba32
--- /dev/null
+++ b/src/tls/info.txt
@@ -0,0 +1,95 @@
+define TLS
+
+load_on auto
+
+<comment>
+The TLS code is complex, new, and not yet reviewed, there may be
+serious bugs or security issues.
+</comment>
+
+<header:public>
+tls_alert.h
+tls_channel.h
+tls_ciphersuite.h
+tls_client.h
+tls_exceptn.h
+tls_magic.h
+tls_policy.h
+tls_record.h
+tls_server.h
+tls_session.h
+tls_session_manager.h
+tls_version.h
+</header:public>
+
+<header:internal>
+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>
+c_hello.cpp
+c_kex.cpp
+cert_req.cpp
+cert_ver.cpp
+finished.cpp
+hello_verify.cpp
+next_protocol.cpp
+rec_read.cpp
+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_suite_info.cpp
+tls_version.cpp
+</source>
+
+<requires>
+aes
+arc4
+asn1
+camellia
+cbc
+credentials
+des
+dh
+dsa
+ecdh
+ecdsa
+eme_pkcs
+emsa3
+filters
+hmac
+kdf2
+md5
+prf_ssl3
+prf_tls
+rng
+rsa
+seed
+srp6
+sha1
+sha2_32
+ssl3mac
+x509cert
+</requires>
diff --git a/src/tls/next_protocol.cpp b/src/tls/next_protocol.cpp
new file mode 100644
index 000000000..17b77fb6e
--- /dev/null
+++ b/src/tls/next_protocol.cpp
@@ -0,0 +1,55 @@
+/*
+* Next Protocol Negotation
+* (C) 2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/internal/tls_messages.h>
+#include <botan/internal/tls_extensions.h>
+#include <botan/internal/tls_reader.h>
+#include <botan/tls_record.h>
+
+namespace Botan {
+
+namespace TLS {
+
+Next_Protocol::Next_Protocol(Record_Writer& writer,
+ Handshake_Hash& hash,
+ const std::string& protocol) :
+ m_protocol(protocol)
+ {
+ hash.update(writer.send(*this));
+ }
+
+Next_Protocol::Next_Protocol(const MemoryRegion<byte>& buf)
+ {
+ TLS_Data_Reader reader(buf);
+
+ m_protocol = reader.get_string(1, 0, 255);
+
+ reader.get_range_vector<byte>(1, 0, 255); // padding, ignored
+ }
+
+MemoryVector<byte> Next_Protocol::serialize() const
+ {
+ MemoryVector<byte> buf;
+
+ append_tls_length_value(buf,
+ reinterpret_cast<const byte*>(m_protocol.data()),
+ m_protocol.size(),
+ 1);
+
+ const byte padding_len = 32 - ((m_protocol.size() + 2) % 32);
+
+ buf.push_back(padding_len);
+
+ for(size_t i = 0; i != padding_len; ++i)
+ buf.push_back(0);
+
+ return buf;
+ }
+
+}
+
+}
diff --git a/src/tls/rec_read.cpp b/src/tls/rec_read.cpp
new file mode 100644
index 000000000..b240f4703
--- /dev/null
+++ b/src/tls/rec_read.cpp
@@ -0,0 +1,353 @@
+/*
+* TLS Record Reading
+* (C) 2004-2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_record.h>
+#include <botan/lookup.h>
+#include <botan/loadstor.h>
+#include <botan/internal/tls_session_key.h>
+#include <botan/internal/rounding.h>
+#include <botan/internal/assert.h>
+
+namespace Botan {
+
+namespace TLS {
+
+Record_Reader::Record_Reader() :
+ m_readbuf(TLS_HEADER_SIZE + MAX_CIPHERTEXT_SIZE),
+ m_mac(0)
+ {
+ reset();
+ set_maximum_fragment_size(0);
+ }
+
+/*
+* Reset the state
+*/
+void Record_Reader::reset()
+ {
+ m_macbuf.clear();
+
+ zeroise(m_readbuf);
+ m_readbuf_pos = 0;
+
+ m_cipher.reset();
+
+ delete m_mac;
+ m_mac = 0;
+
+ m_block_size = 0;
+ m_iv_size = 0;
+ m_version = Protocol_Version();
+ m_seq_no = 0;
+ set_maximum_fragment_size(0);
+ }
+
+void Record_Reader::set_maximum_fragment_size(size_t max_fragment)
+ {
+ if(max_fragment == 0)
+ m_max_fragment = MAX_PLAINTEXT_SIZE;
+ else
+ m_max_fragment = clamp(max_fragment, 128, MAX_PLAINTEXT_SIZE);
+ }
+
+/*
+* Set the version to use
+*/
+void Record_Reader::set_version(Protocol_Version version)
+ {
+ m_version = version;
+ }
+
+/*
+* Set the keys for reading
+*/
+void Record_Reader::activate(Connection_Side side,
+ const Ciphersuite& suite,
+ const Session_Keys& keys,
+ byte compression_method)
+ {
+ m_cipher.reset();
+ delete m_mac;
+ m_mac = 0;
+ m_seq_no = 0;
+
+ if(compression_method != NO_COMPRESSION)
+ throw Internal_Error("Negotiated unknown compression algorithm");
+
+ SymmetricKey mac_key, cipher_key;
+ InitializationVector iv;
+
+ if(side == CLIENT)
+ {
+ cipher_key = keys.server_cipher_key();
+ iv = keys.server_iv();
+ mac_key = keys.server_mac_key();
+ }
+ else
+ {
+ cipher_key = keys.client_cipher_key();
+ iv = keys.client_iv();
+ mac_key = keys.client_mac_key();
+ }
+
+ const std::string cipher_algo = suite.cipher_algo();
+ const std::string mac_algo = suite.mac_algo();
+
+ if(have_block_cipher(cipher_algo))
+ {
+ m_cipher.append(get_cipher(
+ cipher_algo + "/CBC/NoPadding",
+ cipher_key, iv, DECRYPTION)
+ );
+ m_block_size = block_size_of(cipher_algo);
+
+ if(m_version >= Protocol_Version::TLS_V11)
+ m_iv_size = m_block_size;
+ else
+ m_iv_size = 0;
+ }
+ else if(have_stream_cipher(cipher_algo))
+ {
+ m_cipher.append(get_cipher(cipher_algo, cipher_key, DECRYPTION));
+ m_block_size = 0;
+ m_iv_size = 0;
+ }
+ else
+ throw Invalid_Argument("Record_Reader: Unknown cipher " + cipher_algo);
+
+ if(have_hash(mac_algo))
+ {
+ Algorithm_Factory& af = global_state().algorithm_factory();
+
+ if(m_version == Protocol_Version::SSL_V3)
+ m_mac = af.make_mac("SSL3-MAC(" + mac_algo + ")");
+ else
+ m_mac = af.make_mac("HMAC(" + mac_algo + ")");
+
+ m_mac->set_key(mac_key);
+ m_macbuf.resize(m_mac->output_length());
+ }
+ else
+ throw Invalid_Argument("Record_Reader: Unknown hash " + mac_algo);
+ }
+
+size_t Record_Reader::fill_buffer_to(const byte*& input,
+ size_t& input_size,
+ size_t& input_consumed,
+ size_t desired)
+ {
+ if(desired <= m_readbuf_pos)
+ return 0; // already have it
+
+ const size_t space_available = (m_readbuf.size() - m_readbuf_pos);
+ const size_t taken = std::min(input_size, desired - m_readbuf_pos);
+
+ if(taken > space_available)
+ throw TLS_Exception(Alert::RECORD_OVERFLOW,
+ "Record is larger than allowed maximum size");
+
+ copy_mem(&m_readbuf[m_readbuf_pos], input, taken);
+ m_readbuf_pos += taken;
+ input_consumed += taken;
+ input_size -= taken;
+ input += taken;
+
+ return (desired - m_readbuf_pos); // how many bytes do we still need?
+ }
+
+/*
+* Retrieve the next record
+*/
+size_t Record_Reader::add_input(const byte input_array[], size_t input_sz,
+ size_t& consumed,
+ byte& msg_type,
+ MemoryVector<byte>& msg)
+ {
+ const byte* input = &input_array[0];
+
+ consumed = 0;
+
+ if(m_readbuf_pos < TLS_HEADER_SIZE) // header incomplete?
+ {
+ if(size_t needed = fill_buffer_to(input, input_sz, consumed, TLS_HEADER_SIZE))
+ return needed;
+
+ BOTAN_ASSERT_EQUAL(m_readbuf_pos, TLS_HEADER_SIZE,
+ "Have an entire header");
+ }
+
+ // Possible SSLv2 format client hello
+ if((!m_mac) && (m_readbuf[0] & 0x80) && (m_readbuf[2] == 1))
+ {
+ if(m_readbuf[3] == 0 && m_readbuf[4] == 2)
+ throw TLS_Exception(Alert::PROTOCOL_VERSION,
+ "Client claims to only support SSLv2, rejecting");
+
+ if(m_readbuf[3] >= 3) // SSLv2 mapped TLS hello, then?
+ {
+ size_t record_len = make_u16bit(m_readbuf[0], m_readbuf[1]) & 0x7FFF;
+
+ if(size_t needed = fill_buffer_to(input, input_sz, consumed, record_len + 2))
+ return needed;
+
+ BOTAN_ASSERT_EQUAL(m_readbuf_pos, (record_len + 2),
+ "Have the entire SSLv2 hello");
+
+ msg_type = HANDSHAKE;
+
+ msg.resize(record_len + 4);
+
+ // Fake v3-style handshake message wrapper
+ msg[0] = CLIENT_HELLO_SSLV2;
+ msg[1] = 0;
+ msg[2] = m_readbuf[0] & 0x7F;
+ msg[3] = m_readbuf[1];
+
+ copy_mem(&msg[4], &m_readbuf[2], m_readbuf_pos - 2);
+ m_readbuf_pos = 0;
+ return 0;
+ }
+ }
+
+ if(m_readbuf[0] != CHANGE_CIPHER_SPEC &&
+ m_readbuf[0] != ALERT &&
+ m_readbuf[0] != HANDSHAKE &&
+ m_readbuf[0] != APPLICATION_DATA &&
+ m_readbuf[0] != HEARTBEAT)
+ {
+ throw Unexpected_Message(
+ "Unknown record type " + std::to_string(m_readbuf[0]) +
+ " from counterparty");
+ }
+
+ const size_t record_len = make_u16bit(m_readbuf[3], m_readbuf[4]);
+
+ if(m_version.major_version())
+ {
+ if(m_readbuf[1] != m_version.major_version() ||
+ m_readbuf[2] != m_version.minor_version())
+ {
+ throw TLS_Exception(Alert::PROTOCOL_VERSION,
+ "Got unexpected version from counterparty");
+ }
+ }
+
+ if(record_len > MAX_CIPHERTEXT_SIZE)
+ throw TLS_Exception(Alert::RECORD_OVERFLOW,
+ "Got message that exceeds maximum size");
+
+ if(size_t needed = fill_buffer_to(input, input_sz, consumed,
+ TLS_HEADER_SIZE + record_len))
+ return needed;
+
+ BOTAN_ASSERT_EQUAL(static_cast<size_t>(TLS_HEADER_SIZE) + record_len,
+ m_readbuf_pos,
+ "Have the full record");
+
+ // Null mac means no encryption either, only valid during handshake
+ if(!m_mac)
+ {
+ if(m_readbuf[0] != CHANGE_CIPHER_SPEC &&
+ m_readbuf[0] != ALERT &&
+ m_readbuf[0] != HANDSHAKE)
+ {
+ throw Decoding_Error("Invalid msg type received during handshake");
+ }
+
+ msg_type = m_readbuf[0];
+ msg.resize(record_len);
+ copy_mem(&msg[0], &m_readbuf[TLS_HEADER_SIZE], record_len);
+
+ m_readbuf_pos = 0;
+ return 0; // got a full record
+ }
+
+ // Otherwise, decrypt, check MAC, return plaintext
+
+ // FIXME: avoid memory allocation by processing in place
+ m_cipher.process_msg(&m_readbuf[TLS_HEADER_SIZE], record_len);
+ size_t got_back = m_cipher.read(&m_readbuf[TLS_HEADER_SIZE], record_len, Pipe::LAST_MESSAGE);
+ BOTAN_ASSERT_EQUAL(got_back, record_len, "Cipher encrypted full amount");
+
+ BOTAN_ASSERT_EQUAL(m_cipher.remaining(Pipe::LAST_MESSAGE), 0,
+ "Cipher had no remaining inputs");
+
+ size_t pad_size = 0;
+
+ if(m_block_size)
+ {
+ byte pad_value = m_readbuf[TLS_HEADER_SIZE + (record_len-1)];
+ pad_size = pad_value + 1;
+
+ /*
+ * Check the padding; if it is wrong, then say we have 0 bytes of
+ * padding, which should ensure that the MAC check below does not
+ * succeed. This hides a timing channel.
+ *
+ * This particular countermeasure is recommended in the TLS 1.2
+ * spec (RFC 5246) in section 6.2.3.2
+ */
+ if(m_version == Protocol_Version::SSL_V3)
+ {
+ if(pad_value > m_block_size)
+ pad_size = 0;
+ }
+ else
+ {
+ bool padding_good = true;
+
+ for(size_t i = 0; i != pad_size; ++i)
+ if(m_readbuf[TLS_HEADER_SIZE + (record_len-i-1)] != pad_value)
+ padding_good = false;
+
+ if(!padding_good)
+ pad_size = 0;
+ }
+ }
+
+ const size_t mac_pad_iv_size = m_macbuf.size() + pad_size + m_iv_size;
+
+ if(record_len < mac_pad_iv_size)
+ throw Decoding_Error("Record sent with invalid length");
+
+ const u16bit plain_length = record_len - mac_pad_iv_size;
+
+ if(plain_length > m_max_fragment)
+ throw TLS_Exception(Alert::RECORD_OVERFLOW, "Plaintext record is too large");
+
+ m_mac->update_be(m_seq_no);
+ m_mac->update(m_readbuf[0]); // msg_type
+
+ if(m_version != Protocol_Version::SSL_V3)
+ {
+ m_mac->update(m_version.major_version());
+ m_mac->update(m_version.minor_version());
+ }
+
+ m_mac->update_be(plain_length);
+ m_mac->update(&m_readbuf[TLS_HEADER_SIZE + m_iv_size], plain_length);
+
+ ++m_seq_no;
+
+ m_mac->final(m_macbuf);
+
+ const size_t mac_offset = record_len - (m_macbuf.size() + pad_size);
+
+ if(!same_mem(&m_readbuf[TLS_HEADER_SIZE + mac_offset], &m_macbuf[0], m_macbuf.size()))
+ throw TLS_Exception(Alert::BAD_RECORD_MAC, "Message authentication failure");
+
+ msg_type = m_readbuf[0];
+
+ msg.resize(plain_length);
+ copy_mem(&msg[0], &m_readbuf[TLS_HEADER_SIZE + m_iv_size], plain_length);
+ m_readbuf_pos = 0;
+ return 0;
+ }
+
+}
+
+}
diff --git a/src/tls/rec_wri.cpp b/src/tls/rec_wri.cpp
new file mode 100644
index 000000000..3a54d7931
--- /dev/null
+++ b/src/tls/rec_wri.cpp
@@ -0,0 +1,317 @@
+/*
+* TLS Record Writing
+* (C) 2004-2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_record.h>
+#include <botan/internal/tls_messages.h>
+#include <botan/internal/tls_session_key.h>
+#include <botan/internal/tls_handshake_hash.h>
+#include <botan/lookup.h>
+#include <botan/internal/rounding.h>
+#include <botan/internal/assert.h>
+#include <botan/loadstor.h>
+#include <botan/libstate.h>
+
+namespace Botan {
+
+namespace TLS {
+
+/*
+* Record_Writer Constructor
+*/
+Record_Writer::Record_Writer(std::function<void (const byte[], size_t)> out) :
+ m_output_fn(out),
+ m_writebuf(TLS_HEADER_SIZE + MAX_CIPHERTEXT_SIZE),
+ m_mac(0)
+ {
+ reset();
+ set_maximum_fragment_size(0);
+ }
+
+void Record_Writer::set_maximum_fragment_size(size_t max_fragment)
+ {
+ if(max_fragment == 0)
+ m_max_fragment = MAX_PLAINTEXT_SIZE;
+ else
+ m_max_fragment = clamp(max_fragment, 128, MAX_PLAINTEXT_SIZE);
+ }
+
+/*
+* Reset the state
+*/
+void Record_Writer::reset()
+ {
+ set_maximum_fragment_size(0);
+ m_cipher.reset();
+
+ delete m_mac;
+ m_mac = 0;
+
+ m_version = Protocol_Version();
+ m_block_size = 0;
+ m_mac_size = 0;
+ m_iv_size = 0;
+
+ m_seq_no = 0;
+ }
+
+/*
+* Set the version to use
+*/
+void Record_Writer::set_version(Protocol_Version version)
+ {
+ m_version = version;
+ }
+
+/*
+* Set the keys for writing
+*/
+void Record_Writer::activate(Connection_Side side,
+ const Ciphersuite& suite,
+ const Session_Keys& keys,
+ byte compression_method)
+ {
+ m_cipher.reset();
+ delete m_mac;
+ m_mac = 0;
+
+ if(compression_method != NO_COMPRESSION)
+ throw Internal_Error("Negotiated unknown compression algorithm");
+
+ /*
+ RFC 4346:
+ A sequence number is incremented after each record: specifically,
+ the first record transmitted under a particular connection state
+ MUST use sequence number 0
+ */
+ m_seq_no = 0;
+
+ SymmetricKey mac_key, cipher_key;
+ InitializationVector iv;
+
+ if(side == CLIENT)
+ {
+ cipher_key = keys.client_cipher_key();
+ iv = keys.client_iv();
+ mac_key = keys.client_mac_key();
+ }
+ else
+ {
+ cipher_key = keys.server_cipher_key();
+ iv = keys.server_iv();
+ mac_key = keys.server_mac_key();
+ }
+
+ const std::string cipher_algo = suite.cipher_algo();
+ const std::string mac_algo = suite.mac_algo();
+
+ if(have_block_cipher(cipher_algo))
+ {
+ m_cipher.append(get_cipher(
+ cipher_algo + "/CBC/NoPadding",
+ cipher_key, iv, ENCRYPTION)
+ );
+ m_block_size = block_size_of(cipher_algo);
+
+ if(m_version >= Protocol_Version::TLS_V11)
+ m_iv_size = m_block_size;
+ else
+ m_iv_size = 0;
+ }
+ else if(have_stream_cipher(cipher_algo))
+ {
+ m_cipher.append(get_cipher(cipher_algo, cipher_key, ENCRYPTION));
+ m_block_size = 0;
+ m_iv_size = 0;
+ }
+ else
+ throw Invalid_Argument("Record_Writer: Unknown cipher " + cipher_algo);
+
+ if(have_hash(mac_algo))
+ {
+ Algorithm_Factory& af = global_state().algorithm_factory();
+
+ if(m_version == Protocol_Version::SSL_V3)
+ m_mac = af.make_mac("SSL3-MAC(" + mac_algo + ")");
+ else
+ m_mac = af.make_mac("HMAC(" + mac_algo + ")");
+
+ m_mac->set_key(mac_key);
+ m_mac_size = m_mac->output_length();
+ }
+ else
+ throw Invalid_Argument("Record_Writer: Unknown hash " + mac_algo);
+ }
+
+MemoryVector<byte> Record_Writer::send(Handshake_Message& msg)
+ {
+ const MemoryVector<byte> buf = msg.serialize();
+ MemoryVector<byte> send_buf(4);
+
+ const size_t buf_size = buf.size();
+
+ send_buf[0] = msg.type();
+
+ for(size_t i = 1; i != 4; ++i)
+ send_buf[i] = get_byte<u32bit>(i, buf_size);
+
+ send_buf += buf;
+
+ send(HANDSHAKE, &send_buf[0], send_buf.size());
+
+ return send_buf;
+ }
+
+/*
+* Send one or more records to the other side
+*/
+void Record_Writer::send(byte type, const byte input[], size_t length)
+ {
+ if(length == 0)
+ return;
+
+ /*
+ * If using CBC mode in SSLv3/TLS v1.0, send a single byte of
+ * plaintext to randomize the (implicit) IV of the following main
+ * block. If using a stream cipher, or TLS v1.1, this isn't
+ * necessary.
+ *
+ * An empty record also works but apparently some implementations do
+ * not like this (https://bugzilla.mozilla.org/show_bug.cgi?id=665814)
+ *
+ * See http://www.openssl.org/~bodo/tls-cbc.txt for background.
+ */
+ if((type == APPLICATION) && (m_block_size > 0) && (m_iv_size == 0))
+ {
+ send_record(type, &input[0], 1);
+ input += 1;
+ length -= 1;
+ }
+
+ while(length)
+ {
+ const size_t sending = std::min(length, m_max_fragment);
+ send_record(type, &input[0], sending);
+
+ input += sending;
+ length -= sending;
+ }
+ }
+
+/*
+* Encrypt and send the record
+*/
+void Record_Writer::send_record(byte type, const byte input[], size_t length)
+ {
+ if(length >= MAX_PLAINTEXT_SIZE)
+ throw Internal_Error("Record_Writer: Compressed packet is too big");
+
+ if(m_mac_size == 0) // initial unencrypted handshake records
+ {
+ m_writebuf[0] = type;
+ m_writebuf[1] = m_version.major_version();
+ m_writebuf[2] = m_version.minor_version();
+ m_writebuf[3] = get_byte<u16bit>(0, length);
+ m_writebuf[4] = get_byte<u16bit>(1, length);
+
+ copy_mem(&m_writebuf[TLS_HEADER_SIZE], input, length);
+
+ m_output_fn(&m_writebuf[0], TLS_HEADER_SIZE + length);
+ return;
+ }
+
+ m_mac->update_be(m_seq_no);
+ m_mac->update(type);
+
+ if(m_version != Protocol_Version::SSL_V3)
+ {
+ m_mac->update(m_version.major_version());
+ m_mac->update(m_version.minor_version());
+ }
+
+ m_mac->update(get_byte<u16bit>(0, length));
+ m_mac->update(get_byte<u16bit>(1, length));
+ m_mac->update(input, length);
+
+ const size_t buf_size = round_up(m_iv_size + length +
+ m_mac->output_length() +
+ (m_block_size ? 1 : 0),
+ m_block_size);
+
+ if(buf_size >= MAX_CIPHERTEXT_SIZE)
+ throw Internal_Error("Record_Writer: Record is too big");
+
+ BOTAN_ASSERT(m_writebuf.size() >= TLS_HEADER_SIZE + MAX_CIPHERTEXT_SIZE,
+ "Write buffer is big enough");
+
+ // TLS record header
+ m_writebuf[0] = type;
+ m_writebuf[1] = m_version.major_version();
+ m_writebuf[2] = m_version.minor_version();
+ m_writebuf[3] = get_byte<u16bit>(0, buf_size);
+ m_writebuf[4] = get_byte<u16bit>(1, buf_size);
+
+ byte* buf_write_ptr = &m_writebuf[TLS_HEADER_SIZE];
+
+ if(m_iv_size)
+ {
+ RandomNumberGenerator& rng = global_state().global_rng();
+ rng.randomize(buf_write_ptr, m_iv_size);
+ buf_write_ptr += m_iv_size;
+ }
+
+ copy_mem(buf_write_ptr, input, length);
+ buf_write_ptr += length;
+
+ m_mac->final(buf_write_ptr);
+ buf_write_ptr += m_mac->output_length();
+
+ if(m_block_size)
+ {
+ const size_t pad_val =
+ buf_size - (m_iv_size + length + m_mac->output_length() + 1);
+
+ for(size_t i = 0; i != pad_val + 1; ++i)
+ {
+ *buf_write_ptr = pad_val;
+ buf_write_ptr += 1;
+ }
+ }
+
+ // FIXME: this could be done in-place without copying
+ m_cipher.process_msg(&m_writebuf[TLS_HEADER_SIZE], buf_size);
+
+ const size_t ctext_size = m_cipher.remaining(Pipe::LAST_MESSAGE);
+
+ BOTAN_ASSERT_EQUAL(ctext_size, buf_size, "Cipher encrypted full amount");
+
+ if(ctext_size > MAX_CIPHERTEXT_SIZE)
+ throw Internal_Error("Produced ciphertext larger than protocol allows");
+
+ m_cipher.read(&m_writebuf[TLS_HEADER_SIZE], ctext_size, Pipe::LAST_MESSAGE);
+
+ BOTAN_ASSERT_EQUAL(m_cipher.remaining(Pipe::LAST_MESSAGE), 0,
+ "No data remains in pipe");
+
+ m_output_fn(&m_writebuf[0], TLS_HEADER_SIZE + buf_size);
+
+ m_seq_no++;
+ }
+
+/*
+* Send an alert
+*/
+void Record_Writer::send_alert(const Alert& alert)
+ {
+ const byte alert_bits[2] = { static_cast<byte>(alert.is_fatal() ? 2 : 1),
+ static_cast<byte>(alert.type()) };
+
+ send(ALERT, alert_bits, sizeof(alert_bits));
+ }
+
+}
+
+}
diff --git a/src/tls/s_hello.cpp b/src/tls/s_hello.cpp
new file mode 100644
index 000000000..1244dd2d8
--- /dev/null
+++ b/src/tls/s_hello.cpp
@@ -0,0 +1,186 @@
+;/*
+* TLS Server Hello and Server Hello Done
+* (C) 2004-2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/internal/tls_messages.h>
+#include <botan/internal/tls_reader.h>
+#include <botan/internal/tls_session_key.h>
+#include <botan/internal/tls_extensions.h>
+#include <botan/tls_record.h>
+#include <botan/internal/stl_util.h>
+
+namespace Botan {
+
+namespace TLS {
+
+/*
+* 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,
+ byte compression,
+ size_t max_fragment_size,
+ bool client_has_secure_renegotiation,
+ const MemoryRegion<byte>& reneg_info,
+ bool offer_session_ticket,
+ bool client_has_npn,
+ const std::vector<std::string>& next_protocols,
+ bool client_has_heartbeat,
+ RandomNumberGenerator& rng) :
+ m_version(ver),
+ m_session_id(session_id),
+ 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(offer_session_ticket),
+ m_supports_heartbeats(client_has_heartbeat),
+ m_peer_can_send_heartbeats(true)
+ {
+ hash.update(writer.send(*this));
+ }
+
+/*
+* Deserialize a Server Hello message
+*/
+Server_Hello::Server_Hello(const MemoryRegion<byte>& buf)
+ {
+ m_secure_renegotiation = false;
+ m_supports_session_ticket = false;
+ m_next_protocol = false;
+
+ if(buf.size() < 38)
+ throw Decoding_Error("Server_Hello: Packet corrupted");
+
+ TLS_Data_Reader reader(buf);
+
+ const byte major_version = reader.get_byte();
+ const byte minor_version = reader.get_byte();
+
+ m_version = Protocol_Version(major_version, minor_version);
+
+ 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");
+ }
+
+ m_random = reader.get_fixed<byte>(32);
+
+ m_session_id = reader.get_range<byte>(1, 0, 32);
+
+ m_ciphersuite = reader.get_u16bit();
+
+ m_comp_method = reader.get_byte();
+
+ Extensions extensions(reader);
+
+ if(Renegotation_Extension* reneg = extensions.get<Renegotation_Extension>())
+ {
+ // checked by Client / Server as they know the handshake state
+ m_secure_renegotiation = true;
+ m_renegotiation_info = reneg->renegotiation_info();
+ }
+
+ if(Next_Protocol_Notification* npn = extensions.get<Next_Protocol_Notification>())
+ {
+ m_next_protocols = npn->protocols();
+ m_next_protocol = true;
+ }
+
+ if(Session_Ticket* ticket = extensions.get<Session_Ticket>())
+ {
+ if(!ticket->contents().empty())
+ 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();
+ }
+ }
+
+/*
+* Serialize a Server Hello message
+*/
+MemoryVector<byte> Server_Hello::serialize() const
+ {
+ MemoryVector<byte> buf;
+
+ 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, m_ciphersuite));
+ buf.push_back(get_byte(1, m_ciphersuite));
+
+ 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));
+
+ if(m_fragment_size != 0)
+ extensions.add(new Maximum_Fragment_Length(m_fragment_size));
+
+ if(m_next_protocol)
+ extensions.add(new Next_Protocol_Notification(m_next_protocols));
+
+ if(m_supports_session_ticket)
+ extensions.add(new Session_Ticket());
+
+ buf += extensions.serialize();
+
+ return buf;
+ }
+
+/*
+* Create a new Server Hello Done message
+*/
+Server_Hello_Done::Server_Hello_Done(Record_Writer& writer,
+ Handshake_Hash& hash)
+ {
+ hash.update(writer.send(*this));
+ }
+
+/*
+* Deserialize a Server Hello Done message
+*/
+Server_Hello_Done::Server_Hello_Done(const MemoryRegion<byte>& buf)
+ {
+ if(buf.size())
+ throw Decoding_Error("Server_Hello_Done: Must be empty, and is not");
+ }
+
+/*
+* Serialize a Server Hello Done message
+*/
+MemoryVector<byte> Server_Hello_Done::serialize() const
+ {
+ return MemoryVector<byte>();
+ }
+
+}
+
+}
diff --git a/src/tls/s_kex.cpp b/src/tls/s_kex.cpp
new file mode 100644
index 000000000..34cd872ac
--- /dev/null
+++ b/src/tls/s_kex.cpp
@@ -0,0 +1,292 @@
+/*
+* Server Key Exchange Message
+* (C) 2004-2010,2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/internal/tls_messages.h>
+#include <botan/internal/tls_reader.h>
+#include <botan/internal/tls_extensions.h>
+#include <botan/tls_record.h>
+#include <botan/internal/assert.h>
+#include <botan/credentials_manager.h>
+#include <botan/loadstor.h>
+#include <botan/pubkey.h>
+#include <botan/dh.h>
+#include <botan/ecdh.h>
+#include <botan/rsa.h>
+#include <botan/srp6.h>
+#include <botan/oids.h>
+#include <memory>
+
+namespace Botan {
+
+namespace TLS {
+
+/**
+* Create a new Server Key Exchange message
+*/
+Server_Key_Exchange::Server_Key_Exchange(Record_Writer& writer,
+ Handshake_State* state,
+ const Policy& policy,
+ Credentials_Manager& creds,
+ RandomNumberGenerator& rng,
+ const Private_Key* signing_key) :
+ 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", 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()));
+
+ 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);
+ append_tls_length_value(m_params, dh->public_value(), 2);
+ m_kex_key = dh.release();
+ }
+ else if(kex_algo == "ECDH" || kex_algo == "ECDHE_PSK")
+ {
+ const std::vector<std::string>& curves =
+ state->client_hello->supported_ecc_curves();
+
+ if(curves.empty())
+ throw Internal_Error("Client sent no ECC extension but we negotiated ECDH");
+
+ const std::string curve_name = policy.choose_curve(curves);
+
+ if(curve_name == "")
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Could not agree on an ECC curve with the client");
+
+ EC_Group ec_group(curve_name);
+
+ std::unique_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));
+
+ if(domain == "")
+ throw Internal_Error("Could not find name of ECDH domain " + ecdh_domain_oid);
+
+ const u16bit named_curve_id = Supported_Elliptic_Curves::name_to_curve_id(domain);
+
+ m_params.push_back(3); // named curve
+ m_params.push_back(get_byte(0, named_curve_id));
+ m_params.push_back(get_byte(1, named_curve_id));
+
+ append_tls_length_value(m_params, ecdh->public_value(), 1);
+
+ 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);
+
+ if(state->suite.sig_algo() != "")
+ {
+ BOTAN_ASSERT(signing_key, "No signing key set");
+
+ std::pair<std::string, Signature_Format> format =
+ state->choose_sig_format(signing_key, m_hash_algo, m_sig_algo, false);
+
+ PK_Signer signer(*signing_key, format.first, format.second);
+
+ signer.update(state->client_hello->random());
+ signer.update(state->server_hello->random());
+ signer.update(params());
+ m_signature = signer.signature(rng);
+ }
+
+ state->hash.update(writer.send(*this));
+ }
+
+/**
+* Deserialize a Server Key Exchange message
+*/
+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_srp_params(0)
+ {
+ if(buf.size() < 6)
+ throw Decoding_Error("Server_Key_Exchange: Packet corrupted");
+
+ TLS_Data_Reader reader(buf);
+
+ /*
+ * We really are just serializing things back to what they were
+ * before, but unfortunately to know where the signature is we need
+ * to be able to parse the whole thing anyway.
+ */
+
+ if(kex_algo == "PSK" || kex_algo == "DHE_PSK" || kex_algo == "ECDHE_PSK")
+ {
+ const std::string identity_hint = reader.get_string(2, 0, 65535);
+ append_tls_length_value(m_params, identity_hint, 2);
+ }
+
+ if(kex_algo == "DH" || kex_algo == "DHE_PSK")
+ {
+ // 3 bigints, DH p, g, Y
+
+ for(size_t i = 0; i != 3; ++i)
+ {
+ BigInt v = BigInt::decode(reader.get_range<byte>(2, 1, 65535));
+ append_tls_length_value(m_params, BigInt::encode(v), 2);
+ }
+ }
+ else if(kex_algo == "ECDH" || kex_algo == "ECDHE_PSK")
+ {
+ const byte curve_type = reader.get_byte();
+
+ if(curve_type != 3)
+ throw Decoding_Error("Server_Key_Exchange: Server sent non-named ECC curve");
+
+ const u16bit curve_id = reader.get_u16bit();
+
+ const std::string name = Supported_Elliptic_Curves::curve_id_to_name(curve_id);
+
+ MemoryVector<byte> ecdh_key = reader.get_range<byte>(1, 1, 255);
+
+ if(name == "")
+ throw Decoding_Error("Server_Key_Exchange: Server sent unknown named curve " +
+ std::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);
+
+ if(sig_algo != "")
+ {
+ if(version >= Protocol_Version::TLS_V12)
+ {
+ m_hash_algo = Signature_Algorithms::hash_algo_name(reader.get_byte());
+ m_sig_algo = Signature_Algorithms::sig_algo_name(reader.get_byte());
+ }
+
+ m_signature = reader.get_range<byte>(2, 0, 65535);
+ }
+ }
+
+Server_Key_Exchange::~Server_Key_Exchange()
+ {
+ delete m_kex_key;
+ delete m_srp_params;
+ }
+
+
+/**
+* Serialize a Server Key Exchange message
+*/
+MemoryVector<byte> Server_Key_Exchange::serialize() const
+ {
+ MemoryVector<byte> buf = params();
+
+ if(m_signature.size())
+ {
+ // This should be an explicit version check
+ if(m_hash_algo != "" && m_sig_algo != "")
+ {
+ buf.push_back(Signature_Algorithms::hash_algo_code(m_hash_algo));
+ buf.push_back(Signature_Algorithms::sig_algo_code(m_sig_algo));
+ }
+
+ append_tls_length_value(buf, m_signature, 2);
+ }
+
+ return buf;
+ }
+
+/**
+* Verify a Server Key Exchange message
+*/
+bool Server_Key_Exchange::verify(const X509_Certificate& cert,
+ Handshake_State* state) const
+ {
+ std::unique_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);
+
+ PK_Verifier verifier(*key, format.first, format.second);
+
+ verifier.update(state->client_hello->random());
+ verifier.update(state->server_hello->random());
+ verifier.update(params());
+
+ return verifier.check_signature(m_signature);
+ }
+
+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/session_ticket.cpp b/src/tls/session_ticket.cpp
new file mode 100644
index 000000000..273996a16
--- /dev/null
+++ b/src/tls/session_ticket.cpp
@@ -0,0 +1,57 @@
+/*
+* Session Tickets
+* (C) 2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/internal/tls_messages.h>
+#include <botan/internal/tls_extensions.h>
+#include <botan/internal/tls_reader.h>
+#include <botan/tls_record.h>
+#include <botan/loadstor.h>
+
+namespace Botan {
+
+namespace TLS {
+
+New_Session_Ticket::New_Session_Ticket(Record_Writer& writer,
+ Handshake_Hash& hash,
+ const MemoryRegion<byte>& ticket,
+ u32bit lifetime) :
+ m_ticket_lifetime_hint(lifetime),
+ m_ticket(ticket)
+ {
+ hash.update(writer.send(*this));
+ }
+
+New_Session_Ticket::New_Session_Ticket(Record_Writer& writer,
+ Handshake_Hash& hash) :
+ m_ticket_lifetime_hint(0)
+ {
+ hash.update(writer.send(*this));
+ }
+
+New_Session_Ticket::New_Session_Ticket(const MemoryRegion<byte>& buf) :
+ m_ticket_lifetime_hint(0)
+ {
+ if(buf.size() < 6)
+ throw Decoding_Error("Session ticket message too short to be valid");
+
+ TLS_Data_Reader reader(buf);
+
+ m_ticket_lifetime_hint = reader.get_u32bit();
+ m_ticket = reader.get_range<byte>(2, 0, 65535);
+ }
+
+MemoryVector<byte> New_Session_Ticket::serialize() const
+ {
+ MemoryVector<byte> buf(4);
+ store_be(m_ticket_lifetime_hint, &buf[0]);
+ append_tls_length_value(buf, m_ticket, 2);
+ return buf;
+ }
+
+}
+
+}
diff --git a/src/tls/sessions_sqlite/info.txt b/src/tls/sessions_sqlite/info.txt
new file mode 100644
index 000000000..c5fc35952
--- /dev/null
+++ b/src/tls/sessions_sqlite/info.txt
@@ -0,0 +1,11 @@
+define TLS_SQLITE_SESSION_MANAGER
+
+load_on request
+
+<libs>
+all -> sqlite3
+</libs>
+
+<requires>
+pbkdf2
+</requires>
diff --git a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp
new file mode 100644
index 000000000..f4d0e1034
--- /dev/null
+++ b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.cpp
@@ -0,0 +1,350 @@
+/*
+* SQLite TLS Session Manager
+* (C) 2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_sqlite_sess_mgr.h>
+#include <botan/internal/assert.h>
+#include <botan/lookup.h>
+#include <botan/hex.h>
+#include <botan/loadstor.h>
+#include <memory>
+#include <chrono>
+
+#include <sqlite3.h>
+
+namespace Botan {
+
+namespace TLS {
+
+namespace {
+
+class sqlite3_statement
+ {
+ public:
+ sqlite3_statement(sqlite3* db, const std::string& base_sql)
+ {
+ int rc = sqlite3_prepare_v2(db, base_sql.c_str(), -1, &m_stmt, 0);
+
+ if(rc != SQLITE_OK)
+ throw std::runtime_error("sqlite3_prepare failed " + base_sql +
+ ", code " + std::to_string(rc));
+ }
+
+ void bind(int column, const std::string& val)
+ {
+ int rc = sqlite3_bind_text(m_stmt, column, val.c_str(), -1, SQLITE_TRANSIENT);
+ if(rc != SQLITE_OK)
+ throw std::runtime_error("sqlite3_bind_text failed, code " + std::to_string(rc));
+ }
+
+ void bind(int column, int val)
+ {
+ int rc = sqlite3_bind_int(m_stmt, column, val);
+ if(rc != SQLITE_OK)
+ throw std::runtime_error("sqlite3_bind_int failed, code " + std::to_string(rc));
+ }
+
+ void bind(int column, std::chrono::system_clock::time_point time)
+ {
+ const int timeval = std::chrono::duration_cast<std::chrono::seconds>(time.time_since_epoch()).count();
+ bind(column, timeval);
+ }
+
+ void bind(int column, const MemoryRegion<byte>& val)
+ {
+ int rc = sqlite3_bind_blob(m_stmt, column, &val[0], val.size(), SQLITE_TRANSIENT);
+ if(rc != SQLITE_OK)
+ throw std::runtime_error("sqlite3_bind_text failed, code " + std::to_string(rc));
+ }
+
+ 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);
+ }
+
+ sqlite3_stmt* stmt() { return m_stmt; }
+
+ ~sqlite3_statement() { sqlite3_finalize(m_stmt); }
+ private:
+ sqlite3_stmt* m_stmt;
+ };
+
+size_t row_count(sqlite3* db, const std::string& table_name)
+ {
+ sqlite3_statement stmt(db, "select count(*) from " + table_name);
+
+ if(stmt.step() == SQLITE_ROW)
+ return stmt.get_size_t(0);
+ else
+ throw std::runtime_error("Querying size of table " + table_name + " failed");
+ }
+
+void create_table(sqlite3* db, const char* table_schema)
+ {
+ char* errmsg = 0;
+ int rc = sqlite3_exec(db, table_schema, 0, 0, &errmsg);
+
+ if(rc != SQLITE_OK)
+ {
+ const std::string err_msg = errmsg;
+ sqlite3_free(errmsg);
+ sqlite3_close(db);
+ throw std::runtime_error("sqlite3_exec for table failed - " + err_msg);
+ }
+ }
+
+
+SymmetricKey derive_key(const std::string& passphrase,
+ const byte salt[],
+ size_t salt_len,
+ size_t iterations,
+ size_t& check_val)
+ {
+ std::unique_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(SHA-512)"));
+
+ SecureVector<byte> x = pbkdf->derive_key(32 + 3,
+ passphrase,
+ salt, salt_len,
+ iterations).bits_of();
+
+ check_val = make_u32bit(0, x[0], x[1], x[2]);
+ return SymmetricKey(&x[3], x.size() - 3);
+ }
+
+}
+
+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) :
+ m_rng(rng),
+ m_max_sessions(max_sessions),
+ m_session_lifetime(session_lifetime)
+ {
+ int rc = sqlite3_open(db_filename.c_str(), &m_db);
+
+ if(rc)
+ {
+ const std::string err_msg = sqlite3_errmsg(m_db);
+ sqlite3_close(m_db);
+ throw std::runtime_error("sqlite3_open failed - " + err_msg);
+ }
+
+ create_table(m_db,
+ "create table if not exists tls_sessions "
+ "("
+ "session_id TEXT PRIMARY KEY, "
+ "session_start INTEGER, "
+ "hostname TEXT, "
+ "hostport INTEGER, "
+ "session BLOB"
+ ")");
+
+ create_table(m_db,
+ "create table if not exists tls_sessions_metadata "
+ "("
+ "passphrase_salt BLOB, "
+ "passphrase_iterations INTEGER, "
+ "passphrase_check INTEGER "
+ ")");
+
+ const size_t salts = row_count(m_db, "tls_sessions_metadata");
+
+ if(salts == 1)
+ {
+ // existing db
+ sqlite3_statement stmt(m_db, "select * from tls_sessions_metadata");
+
+ int rc = stmt.step();
+ if(rc == SQLITE_ROW)
+ {
+ std::pair<const byte*, size_t> salt = stmt.get_blob(0);
+ const size_t iterations = stmt.get_size_t(1);
+ const size_t check_val_db = stmt.get_size_t(2);
+
+ size_t check_val_created;
+ m_session_key = derive_key(passphrase,
+ salt.first,
+ salt.second,
+ iterations,
+ check_val_created);
+
+ if(check_val_created != check_val_db)
+ throw std::runtime_error("Session database password not valid");
+ }
+ }
+ else
+ {
+ // maybe just zap the salts + sessions tables in this case?
+ if(salts != 0)
+ throw std::runtime_error("Seemingly corrupted database, multiple salts found");
+
+ // new database case
+
+ MemoryVector<byte> salt = rng.random_vec(16);
+ const size_t iterations = 64 * 1024;
+ size_t check_val = 0;
+
+ m_session_key = derive_key(passphrase, &salt[0], salt.size(),
+ iterations, check_val);
+
+ sqlite3_statement stmt(m_db, "insert into tls_sessions_metadata"
+ " values(?1, ?2, ?3)");
+
+ stmt.bind(1, salt);
+ stmt.bind(2, iterations);
+ stmt.bind(3, check_val);
+
+ stmt.spin();
+ }
+ }
+
+Session_Manager_SQLite::~Session_Manager_SQLite()
+ {
+ sqlite3_close(m_db);
+ }
+
+bool Session_Manager_SQLite::load_from_session_id(const MemoryRegion<byte>& session_id,
+ Session& session)
+ {
+ sqlite3_statement stmt(m_db, "select session from tls_sessions where session_id = ?1");
+
+ stmt.bind(1, hex_encode(session_id));
+
+ int rc = stmt.step();
+
+ while(rc == SQLITE_ROW)
+ {
+ std::pair<const byte*, size_t> blob = stmt.get_blob(0);
+
+ try
+ {
+ session = Session::decrypt(blob.first, blob.second, m_session_key);
+ return true;
+ }
+ catch(...)
+ {
+ }
+
+ rc = stmt.step();
+ }
+
+ return false;
+ }
+
+bool Session_Manager_SQLite::load_from_host_info(const std::string& hostname,
+ u16bit port,
+ Session& session)
+ {
+ sqlite3_statement stmt(m_db, "select session from tls_sessions"
+ " where hostname = ?1 and hostport = ?2"
+ " order by session_start desc");
+
+ stmt.bind(1, hostname);
+ stmt.bind(2, port);
+
+ int rc = stmt.step();
+
+ while(rc == SQLITE_ROW)
+ {
+ std::pair<const byte*, size_t> blob = stmt.get_blob(0);
+
+ try
+ {
+ session = Session::decrypt(blob.first, blob.second, m_session_key);
+ return true;
+ }
+ catch(...)
+ {
+ }
+
+ rc = stmt.step();
+ }
+
+ return false;
+ }
+
+void Session_Manager_SQLite::remove_entry(const MemoryRegion<byte>& session_id)
+ {
+ sqlite3_statement stmt(m_db, "delete from tls_sessions where session_id = ?1");
+
+ stmt.bind(1, hex_encode(session_id));
+
+ stmt.spin();
+ }
+
+void Session_Manager_SQLite::save(const Session& session)
+ {
+ sqlite3_statement stmt(m_db, "insert or replace into tls_sessions"
+ " values(?1, ?2, ?3, ?4, ?5)");
+
+ stmt.bind(1, hex_encode(session.session_id()));
+ 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));
+
+ stmt.spin();
+
+ prune_session_cache();
+ }
+
+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::now() - m_session_lifetime);
+
+ remove_expired.spin();
+
+ const size_t sessions = row_count(m_db, "tls_sessions");
+
+ if(sessions > m_max_sessions)
+ {
+ sqlite3_statement remove_some(m_db, "delete from tls_sessions where session_id in "
+ "(select session_id from tls_sessions limit ?1)");
+
+ remove_some.bind(1, sessions - m_max_sessions);
+ remove_some.spin();
+ }
+ }
+
+}
+
+}
diff --git a/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h
new file mode 100644
index 000000000..cac7affd0
--- /dev/null
+++ b/src/tls/sessions_sqlite/tls_sqlite_sess_mgr.h
@@ -0,0 +1,71 @@
+/*
+* SQLite TLS Session Manager
+* (C) 2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_SQLITE_SESSION_MANAGER_H__
+#define BOTAN_TLS_SQLITE_SESSION_MANAGER_H__
+
+#include <botan/tls_session_manager.h>
+#include <botan/rng.h>
+
+class sqlite3;
+
+namespace Botan {
+
+namespace TLS {
+
+/**
+*/
+class BOTAN_DLL Session_Manager_SQLite : public Session_Manager
+ {
+ public:
+ /**
+ * @param passphrase used to encrypt the session data
+ * @param db_filename filename of the SQLite database file.
+ The table names tls_sessions and tls_sessions_metadata
+ will be used
+ * @param max_sessions a hint on the maximum number of sessions
+ * to keep in memory at any one time. (If zero, don't cap)
+ * @param session_lifetime sessions are expired after this many
+ * seconds have elapsed from initial handshake.
+ */
+ Session_Manager_SQLite(const std::string& passphrase,
+ RandomNumberGenerator& rng,
+ const std::string& db_filename,
+ size_t max_sessions = 1000,
+ std::chrono::seconds session_lifetime = std::chrono::seconds(7200));
+
+ ~Session_Manager_SQLite();
+
+ bool load_from_session_id(const MemoryRegion<byte>& session_id,
+ Session& session);
+
+ bool load_from_host_info(const std::string& hostname, u16bit port,
+ Session& session);
+
+ void remove_entry(const MemoryRegion<byte>& session_id);
+
+ void save(const Session& session_data);
+
+ std::chrono::seconds session_lifetime() const { return m_session_lifetime; }
+ private:
+ Session_Manager_SQLite(const Session_Manager_SQLite&);
+ Session_Manager_SQLite& operator=(const Session_Manager_SQLite&);
+
+ void prune_session_cache();
+
+ SymmetricKey m_session_key;
+ RandomNumberGenerator& m_rng;
+ size_t m_max_sessions;
+ std::chrono::seconds m_session_lifetime;
+ class sqlite3* m_db;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/tls/tls_alert.cpp b/src/tls/tls_alert.cpp
new file mode 100644
index 000000000..dee082bac
--- /dev/null
+++ b/src/tls/tls_alert.cpp
@@ -0,0 +1,122 @@
+/*
+* Alert Message
+* (C) 2004-2006,2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_alert.h>
+#include <botan/exceptn.h>
+
+namespace Botan {
+
+namespace TLS {
+
+Alert::Alert(const MemoryRegion<byte>& buf)
+ {
+ if(buf.size() != 2)
+ throw Decoding_Error("Alert: Bad size " + std::to_string(buf.size()) +
+ " for alert message");
+
+ if(buf[0] == 1) fatal = false;
+ else if(buf[0] == 2) fatal = true;
+ else
+ throw Decoding_Error("Alert: Bad code for alert level");
+
+ const byte dc = buf[1];
+
+ /*
+ * This is allowed by the specification but is not allocated and we're
+ * using it internally as a special 'no alert' type.
+ */
+ if(dc == 255)
+ throw Internal_Error("Alert: description code 255, rejecting");
+
+ type_code = static_cast<Type>(dc);
+ }
+
+std::string Alert::type_string() const
+ {
+ switch(type())
+ {
+ case CLOSE_NOTIFY:
+ return "close_notify";
+ case UNEXPECTED_MESSAGE:
+ return "unexpected_message";
+ case BAD_RECORD_MAC:
+ return "bad_record_mac";
+ case DECRYPTION_FAILED:
+ return "decryption_failed";
+ case RECORD_OVERFLOW:
+ return "record_overflow";
+ case DECOMPRESSION_FAILURE:
+ return "decompression_failure";
+ case HANDSHAKE_FAILURE:
+ return "handshake_failure";
+ case NO_CERTIFICATE:
+ return "no_certificate";
+ case BAD_CERTIFICATE:
+ return "bad_certificate";
+ case UNSUPPORTED_CERTIFICATE:
+ return "unsupported_certificate";
+ case CERTIFICATE_REVOKED:
+ return "certificate_revoked";
+ case CERTIFICATE_EXPIRED:
+ return "certificate_expired";
+ case CERTIFICATE_UNKNOWN:
+ return "certificate_unknown";
+ case ILLEGAL_PARAMETER:
+ return "illegal_parameter";
+ case UNKNOWN_CA:
+ return "unknown_ca";
+ case ACCESS_DENIED:
+ return "access_denied";
+ case DECODE_ERROR:
+ return "decode_error";
+ case DECRYPT_ERROR:
+ return "decrypt_error";
+ case EXPORT_RESTRICTION:
+ return "export_restriction";
+ case PROTOCOL_VERSION:
+ return "protocol_version";
+ case INSUFFICIENT_SECURITY:
+ return "insufficient_security";
+ case INTERNAL_ERROR:
+ return "internal_error";
+ case USER_CANCELED:
+ return "user_canceled";
+ case NO_RENEGOTIATION:
+ return "no_renegotiation";
+
+ 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 "none";
+
+ case HEARTBEAT_PAYLOAD:
+ return "heartbeat_payload";
+ }
+
+ /*
+ * This is effectively the default case for the switch above, but we
+ * leave it out so that when an alert type is added to the enum the
+ * compiler can warn us that it is not included in the switch
+ * statement.
+ */
+ return "unrecognized_alert_" + std::to_string(type());
+ }
+
+}
+
+}
diff --git a/src/tls/tls_alert.h b/src/tls/tls_alert.h
new file mode 100644
index 000000000..3dfff3d29
--- /dev/null
+++ b/src/tls/tls_alert.h
@@ -0,0 +1,100 @@
+/*
+* Alert Message
+* (C) 2004-2006,2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_ALERT_H__
+#define BOTAN_TLS_ALERT_H__
+
+#include <botan/secmem.h>
+#include <string>
+
+namespace Botan {
+
+namespace TLS {
+
+/**
+* SSL/TLS Alert Message
+*/
+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,
+ 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
+ };
+
+ /**
+ * @return true iff this alert is non-empty
+ */
+ bool is_valid() const { return (type_code != NULL_ALERT); }
+
+ /**
+ * @return if this alert is a fatal one or not
+ */
+ bool is_fatal() const { return fatal; }
+
+ /**
+ * @return type of alert
+ */
+ Type type() const { return type_code; }
+
+ /**
+ * @return type of alert
+ */
+ std::string type_string() const;
+
+ /**
+ * Deserialize an Alert message
+ * @param buf the serialized alert
+ */
+ Alert(const MemoryRegion<byte>& buf);
+
+ Alert(Type alert_type, bool is_fatal = false) :
+ fatal(is_fatal), type_code(alert_type) {}
+
+ Alert() : fatal(false), type_code(NULL_ALERT) {}
+ private:
+ bool fatal;
+ Type type_code;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/tls/tls_channel.cpp b/src/tls/tls_channel.cpp
new file mode 100644
index 000000000..7a66eb946
--- /dev/null
+++ b/src/tls/tls_channel.cpp
@@ -0,0 +1,326 @@
+/*
+* TLS Channels
+* (C) 2011-2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#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>
+
+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) :
+ proc_fn(proc_fn),
+ handshake_fn(handshake_complete),
+ writer(socket_output_fn),
+ state(0),
+ handshake_completed(false),
+ connection_closed(false),
+ m_peer_supports_heartbeats(false),
+ m_heartbeat_sending_allowed(false)
+ {
+ }
+
+Channel::~Channel()
+ {
+ delete state;
+ state = 0;
+ }
+
+size_t Channel::received_data(const byte buf[], size_t buf_size)
+ {
+ try
+ {
+ while(buf_size)
+ {
+ byte rec_type = CONNECTION_CLOSED;
+ MemoryVector<byte> record;
+ size_t consumed = 0;
+
+ const size_t needed = reader.add_input(buf, buf_size,
+ consumed,
+ rec_type, record);
+
+ buf += consumed;
+ buf_size -= consumed;
+
+ BOTAN_ASSERT(buf_size == 0 || needed == 0,
+ "Got a full record or consumed all input");
+
+ if(buf_size == 0 && needed != 0)
+ return needed; // need more data to complete record
+
+ 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)
+ {
+ /*
+ * OpenSSL among others sends empty records in versions
+ * before TLS v1.1 in order to randomize the IV of the
+ * following record. Avoid spurious callbacks.
+ */
+ if(record.size() > 0)
+ proc_fn(&record[0], record.size(), Alert());
+ }
+ else
+ {
+ throw Unexpected_Message("Application data before handshake done");
+ }
+ }
+ else if(rec_type == ALERT)
+ {
+ Alert alert_msg(record);
+
+ alert_notify(alert_msg);
+
+ proc_fn(0, 0, alert_msg);
+
+ if(alert_msg.type() == Alert::CLOSE_NOTIFY)
+ {
+ if(connection_closed)
+ reader.reset();
+ else
+ send_alert(Alert(Alert::CLOSE_NOTIFY)); // reply in kind
+ }
+ else if(alert_msg.is_fatal())
+ {
+ // delete state immediately
+ connection_closed = true;
+
+ delete state;
+ state = 0;
+
+ writer.reset();
+ reader.reset();
+ }
+ }
+ else
+ throw Unexpected_Message("Unknown TLS message type " +
+ std::to_string(rec_type) + " received");
+ }
+
+ return 0; // on a record boundary
+ }
+ catch(TLS_Exception& e)
+ {
+ send_alert(Alert(e.type(), true));
+ throw;
+ }
+ catch(Decoding_Error& e)
+ {
+ send_alert(Alert(Alert::DECODE_ERROR, true));
+ throw;
+ }
+ catch(Internal_Error& e)
+ {
+ send_alert(Alert(Alert::INTERNAL_ERROR, true));
+ throw;
+ }
+ catch(std::exception& e)
+ {
+ send_alert(Alert(Alert::INTERNAL_ERROR, true));
+ throw;
+ }
+ }
+
+/*
+* Split up and process handshake messages
+*/
+void Channel::read_handshake(byte rec_type,
+ const MemoryRegion<byte>& rec_buf)
+ {
+ if(rec_type == HANDSHAKE)
+ {
+ if(!state)
+ state = new Handshake_State(new Stream_Handshake_Reader);
+ state->handshake_reader()->add_input(&rec_buf[0], rec_buf.size());
+ }
+
+ BOTAN_ASSERT(state, "Handshake message recieved without state in place");
+
+ while(true)
+ {
+ Handshake_Type type = HANDSHAKE_NONE;
+
+ if(rec_type == HANDSHAKE)
+ {
+ if(state->handshake_reader()->have_full_record())
+ {
+ std::pair<Handshake_Type, MemoryVector<byte> > msg =
+ state->handshake_reader()->get_next_record();
+ process_handshake_msg(msg.first, msg.second);
+ }
+ else
+ break;
+ }
+ else if(rec_type == CHANGE_CIPHER_SPEC)
+ {
+ if(state->handshake_reader()->empty() && rec_buf.size() == 1 && rec_buf[0] == 1)
+ process_handshake_msg(HANDSHAKE_CCS, MemoryVector<byte>());
+ else
+ throw Decoding_Error("Malformed ChangeCipherSpec message");
+ }
+ else
+ throw Decoding_Error("Unknown message type in handshake processing");
+
+ if(type == HANDSHAKE_CCS || !state || !state->handshake_reader()->have_full_record())
+ break;
+ }
+ }
+
+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())
+ throw std::runtime_error("Data cannot be sent on inactive TLS connection");
+
+ writer.send(APPLICATION_DATA, buf, buf_size);
+ }
+
+void Channel::send_alert(const Alert& alert)
+ {
+ if(alert.is_valid() && !connection_closed)
+ {
+ try
+ {
+ writer.send_alert(alert);
+ }
+ catch(...) { /* swallow it */ }
+ }
+
+ if(!connection_closed && (alert.type() == Alert::CLOSE_NOTIFY || alert.is_fatal()))
+ {
+ connection_closed = true;
+
+ delete state;
+ state = 0;
+
+ writer.reset();
+ }
+ }
+
+void Channel::Secure_Renegotiation_State::update(Client_Hello* client_hello)
+ {
+ if(initial_handshake)
+ {
+ secure_renegotiation = client_hello->secure_renegotiation();
+ }
+ else
+ {
+ if(secure_renegotiation != client_hello->secure_renegotiation())
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Client changed its mind about secure renegotiation");
+ }
+
+ if(client_hello->secure_renegotiation())
+ {
+ const MemoryVector<byte>& data = client_hello->renegotiation_info();
+
+ if(initial_handshake)
+ {
+ if(!data.empty())
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Client sent renegotiation data on initial handshake");
+ }
+ else
+ {
+ if(data != for_client_hello())
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Client sent bad renegotiation data");
+ }
+ }
+ }
+
+void Channel::Secure_Renegotiation_State::update(Server_Hello* server_hello)
+ {
+ if(initial_handshake)
+ {
+ /* If the client offered but server rejected, then this toggles
+ * secure_renegotiation to off
+ */
+ secure_renegotiation = server_hello->secure_renegotiation();
+ }
+ else
+ {
+ if(secure_renegotiation != server_hello->secure_renegotiation())
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Server changed its mind about secure renegotiation");
+ }
+
+ if(secure_renegotiation)
+ {
+ const MemoryVector<byte>& data = server_hello->renegotiation_info();
+
+ if(initial_handshake)
+ {
+ if(!data.empty())
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Server sent renegotiation data on initial handshake");
+ }
+ else
+ {
+ if(data != for_server_hello())
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Server sent bad renegotiation data");
+ }
+ }
+
+ initial_handshake = false;
+ }
+
+void Channel::Secure_Renegotiation_State::update(Finished* client_finished,
+ Finished* server_finished)
+ {
+ client_verify = client_finished->verify_data();
+ server_verify = server_finished->verify_data();
+ }
+
+}
+
+}
+
diff --git a/src/tls/tls_channel.h b/src/tls/tls_channel.h
new file mode 100644
index 000000000..d1131460b
--- /dev/null
+++ b/src/tls/tls_channel.h
@@ -0,0 +1,155 @@
+/*
+* TLS Channel
+* (C) 2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_CHANNEL_H__
+#define BOTAN_TLS_CHANNEL_H__
+
+#include <botan/tls_policy.h>
+#include <botan/tls_record.h>
+#include <botan/tls_session.h>
+#include <botan/tls_alert.h>
+#include <botan/x509cert.h>
+#include <vector>
+
+namespace Botan {
+
+namespace TLS {
+
+/**
+* Generic interface for TLS endpoint
+*/
+class BOTAN_DLL Channel
+ {
+ public:
+ /**
+ * Inject TLS traffic received from counterparty
+ * @return a hint as the how many more bytes we need to process the
+ * current record (this may be 0 if on a record boundary)
+ */
+ virtual size_t received_data(const byte buf[], size_t buf_size);
+
+ /**
+ * Inject plaintext intended for counterparty
+ */
+ virtual void send(const byte buf[], size_t buf_size);
+
+ /**
+ * Send a close notification alert
+ */
+ void close() { send_alert(Alert(Alert::CLOSE_NOTIFY)); }
+
+ /**
+ * @return true iff the connection is active for sending application data
+ */
+ bool is_active() const { return handshake_completed && !is_closed(); }
+
+ /**
+ * @return true iff the connection has been definitely closed
+ */
+ bool is_closed() const { return connection_closed; }
+
+ /**
+ * Attempt to renegotiate the session
+ * @param force_full_renegotiation if true, require a full renegotiation,
+ * otherwise allow session resumption
+ */
+ 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);
+
+ virtual ~Channel();
+ protected:
+
+ /**
+ * Send a TLS alert message. If the alert is fatal, the
+ * internal state (keys, etc) will be reset
+ * @param level is warning or fatal
+ * @param type is the type of alert
+ */
+ void send_alert(const Alert& alert);
+
+ virtual void read_handshake(byte rec_type,
+ const MemoryRegion<byte>& rec_buf);
+
+ virtual void process_handshake_msg(Handshake_Type type,
+ const MemoryRegion<byte>& contents) = 0;
+
+ 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;
+
+ Record_Writer writer;
+ Record_Reader reader;
+
+ std::vector<X509_Certificate> peer_certs;
+
+ class Handshake_State* state;
+
+ class Secure_Renegotiation_State
+ {
+ public:
+ Secure_Renegotiation_State() : initial_handshake(true),
+ secure_renegotiation(false)
+ {}
+
+ void update(class Client_Hello* client_hello);
+ void update(class Server_Hello* server_hello);
+
+ void update(class Finished* client_finished,
+ class Finished* server_finished);
+
+ const MemoryVector<byte>& for_client_hello() const
+ { return client_verify; }
+
+ MemoryVector<byte> for_server_hello() const
+ {
+ MemoryVector<byte> buf = client_verify;
+ buf += server_verify;
+ return buf;
+ }
+
+ bool supported() const { return secure_renegotiation; }
+ bool renegotiation() const { return !initial_handshake; }
+ private:
+ bool initial_handshake;
+ bool secure_renegotiation;
+ MemoryVector<byte> client_verify, server_verify;
+ };
+
+ Secure_Renegotiation_State secure_renegotiation;
+
+ bool handshake_completed;
+ bool connection_closed;
+ bool m_peer_supports_heartbeats;
+ bool m_heartbeat_sending_allowed;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/tls/tls_ciphersuite.cpp b/src/tls/tls_ciphersuite.cpp
new file mode 100644
index 000000000..e3bda06e4
--- /dev/null
+++ b/src/tls/tls_ciphersuite.cpp
@@ -0,0 +1,104 @@
+/*
+* TLS Cipher Suite
+* (C) 2004-2010,2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_ciphersuite.h>
+#include <botan/parsing.h>
+#include <sstream>
+#include <stdexcept>
+
+namespace Botan {
+
+namespace TLS {
+
+Ciphersuite Ciphersuite::by_name(const std::string& name)
+ {
+ for(size_t i = 0; i != 65536; ++i)
+ {
+ Ciphersuite suite = Ciphersuite::by_id(i);
+
+ if(!suite.valid())
+ continue; // not a ciphersuite we know, skip
+
+ if(suite.to_string() == name)
+ return suite;
+ }
+
+ 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)
+ throw std::runtime_error("Ciphersuite::to_string - no value set");
+
+ std::ostringstream out;
+
+ out << "TLS_";
+
+ if(kex_algo() != "RSA")
+ {
+ if(kex_algo() == "DH")
+ out << "DHE";
+ else if(kex_algo() == "ECDH")
+ out << "ECDHE";
+ else
+ out << kex_algo();
+
+ out << '_';
+ }
+
+ if(sig_algo() == "DSA")
+ out << "DSS_";
+ else if(sig_algo() != "")
+ out << sig_algo() << '_';
+
+ out << "WITH_";
+
+ if(cipher_algo() == "ARC4")
+ {
+ out << "RC4_128_";
+ }
+ else
+ {
+ if(cipher_algo() == "3DES")
+ out << "3DES_EDE";
+ else if(cipher_algo() == "Camellia")
+ out << "CAMELLIA_" << std::to_string(8*cipher_keylen());
+ else
+ out << replace_char(cipher_algo(), '-', '_');
+
+ out << "_CBC_";
+ }
+
+ if(mac_algo() == "SHA-1")
+ out << "SHA";
+ else if(mac_algo() == "SHA-256")
+ out << "SHA256";
+ else if(mac_algo() == "SHA-384")
+ out << "SHA384";
+ else
+ out << mac_algo();
+
+ return out.str();
+ }
+
+}
+
+}
+
diff --git a/src/tls/tls_ciphersuite.h b/src/tls/tls_ciphersuite.h
new file mode 100644
index 000000000..dcb4b6a6f
--- /dev/null
+++ b/src/tls/tls_ciphersuite.h
@@ -0,0 +1,73 @@
+/*
+* TLS Cipher Suites
+* (C) 2004-2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_CIPHER_SUITES_H__
+#define BOTAN_TLS_CIPHER_SUITES_H__
+
+#include <botan/types.h>
+#include <string>
+
+namespace Botan {
+
+namespace TLS {
+
+/**
+* Ciphersuite Information
+*/
+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);
+
+ /**
+ * Formats the ciphersuite back to an RFC-style ciphersuite string
+ */
+ 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; }
+
+ std::string cipher_algo() const { return m_cipher_algo; }
+ std::string mac_algo() const { return m_mac_algo; }
+
+ size_t cipher_keylen() const { return m_cipher_keylen; }
+
+ bool valid() const { return (m_cipher_keylen > 0); }
+
+ Ciphersuite() : m_cipher_keylen(0) {}
+
+ 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)
+ {
+ }
+
+ private:
+ std::string m_sig_algo, m_kex_algo, m_mac_algo, m_cipher_algo;
+ size_t m_cipher_keylen;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp
new file mode 100644
index 000000000..dd17db2cf
--- /dev/null
+++ b/src/tls/tls_client.cpp
@@ -0,0 +1,486 @@
+/*
+* TLS Client
+* (C) 2004-2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_client.h>
+#include <botan/internal/tls_handshake_state.h>
+#include <botan/internal/tls_messages.h>
+#include <botan/internal/stl_util.h>
+#include <memory>
+
+namespace Botan {
+
+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,
+ 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) :
+ Channel(output_fn, proc_fn, handshake_fn),
+ policy(policy),
+ rng(rng),
+ session_manager(session_manager),
+ creds(creds),
+ m_hostname(hostname)
+ {
+ writer.set_version(Protocol_Version::SSL_V3);
+
+ state = new Handshake_State(new Stream_Handshake_Reader);
+ state->set_expected_next(SERVER_HELLO);
+
+ state->client_npn_cb = next_protocol;
+
+ const std::string srp_identifier = creds.srp_identifier("tls-client", hostname);
+
+ const bool send_npn_request = static_cast<bool>(next_protocol);
+
+ if(hostname != "")
+ {
+ Session session_info;
+ if(session_manager.load_from_host_info(hostname, 0, session_info))
+ {
+ if(session_info.srp_identifier() == srp_identifier)
+ {
+ state->client_hello = new Client_Hello(
+ writer,
+ state->hash,
+ policy,
+ rng,
+ secure_renegotiation.for_client_hello(),
+ session_info,
+ send_npn_request);
+
+ state->resume_master_secret = session_info.master_secret();
+ }
+ }
+ }
+
+ if(!state->client_hello) // not resuming
+ {
+ state->client_hello = new Client_Hello(
+ writer,
+ state->hash,
+ policy,
+ rng,
+ secure_renegotiation.for_client_hello(),
+ send_npn_request,
+ hostname,
+ srp_identifier);
+ }
+
+ secure_renegotiation.update(state->client_hello);
+ }
+
+/*
+* Send a new client hello to renegotiate
+*/
+void Client::renegotiate(bool force_full_renegotiation)
+ {
+ 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);
+
+ 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);
+ }
+
+void Client::alert_notify(const Alert& alert)
+ {
+ if(alert.type() == Alert::NO_RENEGOTIATION)
+ {
+ if(handshake_completed && state)
+ {
+ delete state;
+ state = 0;
+ }
+ }
+ }
+
+/*
+* Process a handshake message
+*/
+void Client::process_handshake_msg(Handshake_Type type,
+ const MemoryRegion<byte>& contents)
+ {
+ if(state == 0)
+ throw Unexpected_Message("Unexpected handshake message from server");
+
+ if(type == HELLO_REQUEST)
+ {
+ Hello_Request hello_request(contents);
+
+ // Ignore request entirely if we are currently negotiating a handshake
+ if(state->client_hello)
+ return;
+
+ if(!secure_renegotiation.supported() && policy.require_secure_renegotiation())
+ {
+ delete state;
+ state = 0;
+
+ // RFC 5746 section 4.2
+ send_alert(Alert(Alert::NO_RENEGOTIATION));
+ return;
+ }
+
+ renegotiate(false);
+
+ return;
+ }
+
+ state->confirm_transition_to(type);
+
+ if(type != HANDSHAKE_CCS && type != FINISHED)
+ state->hash.update(type, contents);
+
+ if(type == SERVER_HELLO)
+ {
+ state->server_hello = new Server_Hello(contents);
+
+ if(!state->client_hello->offered_suite(state->server_hello->ciphersuite()))
+ {
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Server replied with ciphersuite we didn't send");
+ }
+
+ if(!value_exists(state->client_hello->compression_methods(),
+ state->server_hello->compression_method()))
+ {
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Server replied with compression method we didn't send");
+ }
+
+ if(!state->client_hello->next_protocol_notification() &&
+ state->server_hello->next_protocol_notification())
+ {
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Server sent next protocol but we didn't request it");
+ }
+
+ if(state->server_hello->supports_session_ticket())
+ {
+ if(!state->client_hello->supports_session_ticket())
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Server sent session ticket extension but we did not");
+ }
+
+ state->set_version(state->server_hello->version());
+
+ writer.set_version(state->version());
+ reader.set_version(state->version());
+
+ 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 =
+ !state->server_hello->session_id().empty() &&
+ (state->server_hello->session_id() == state->client_hello->session_id());
+
+ if(server_returned_same_session_id)
+ {
+ // successful resumption
+
+ /*
+ * In this case, we offered the version used in the original
+ * session, and the server must resume with the same version.
+ */
+ if(state->server_hello->version() != state->client_hello->version())
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Server resumed session but with wrong version");
+
+ state->keys = Session_Keys(state,
+ state->resume_master_secret,
+ true);
+
+ if(state->server_hello->supports_session_ticket())
+ state->set_expected_next(NEW_SESSION_TICKET);
+ else
+ state->set_expected_next(HANDSHAKE_CCS);
+ }
+ else
+ {
+ // new session
+
+ if(state->version() > state->client_hello->version())
+ {
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Client: Server replied with bad version");
+ }
+
+ if(state->version() < policy.min_version())
+ {
+ throw TLS_Exception(Alert::PROTOCOL_VERSION,
+ "Client: Server is too old for specified policy");
+ }
+
+ if(state->suite.sig_algo() != "")
+ {
+ state->set_expected_next(CERTIFICATE);
+ }
+ else if(state->suite.kex_algo() == "PSK")
+ {
+ /* PSK is anonymous so no certificate/cert req message is
+ ever sent. The server may or may not send a server kex,
+ depending on if it has an identity hint for us.
+
+ (EC)DHE_PSK always sends a server key exchange for the
+ DH exchange portion.
+ */
+
+ state->set_expected_next(SERVER_KEX);
+ state->set_expected_next(SERVER_HELLO_DONE);
+ }
+ else if(state->suite.kex_algo() != "RSA")
+ {
+ state->set_expected_next(SERVER_KEX);
+ }
+ else
+ {
+ state->set_expected_next(CERTIFICATE_REQUEST); // optional
+ state->set_expected_next(SERVER_HELLO_DONE);
+ }
+ }
+ }
+ else if(type == CERTIFICATE)
+ {
+ if(state->suite.kex_algo() != "RSA")
+ {
+ state->set_expected_next(SERVER_KEX);
+ }
+ else
+ {
+ state->set_expected_next(CERTIFICATE_REQUEST); // optional
+ state->set_expected_next(SERVER_HELLO_DONE);
+ }
+
+ state->server_certs = new Certificate(contents);
+
+ peer_certs = state->server_certs->cert_chain();
+ if(peer_certs.size() == 0)
+ throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
+ "Client: No certificates sent by server");
+
+ try
+ {
+ 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());
+
+ if(peer_key->algo_name() != state->suite.sig_algo())
+ throw TLS_Exception(Alert::ILLEGAL_PARAMETER,
+ "Certificate key type did not match ciphersuite");
+ }
+ else if(type == SERVER_KEX)
+ {
+ state->set_expected_next(CERTIFICATE_REQUEST); // optional
+ state->set_expected_next(SERVER_HELLO_DONE);
+
+ state->server_kex = new Server_Key_Exchange(contents,
+ state->suite.kex_algo(),
+ state->suite.sig_algo(),
+ state->version());
+
+ if(state->suite.sig_algo() != "")
+ {
+ if(!state->server_kex->verify(peer_certs[0], state))
+ {
+ throw TLS_Exception(Alert::DECRYPT_ERROR,
+ "Bad signature on server key exchange");
+ }
+ }
+ }
+ else if(type == CERTIFICATE_REQUEST)
+ {
+ state->set_expected_next(SERVER_HELLO_DONE);
+ state->cert_req = new Certificate_Req(contents, state->version());
+ }
+ else if(type == SERVER_HELLO_DONE)
+ {
+ state->server_hello_done = new Server_Hello_Done(contents);
+
+ if(state->received_handshake_msg(CERTIFICATE_REQUEST))
+ {
+ const std::vector<std::string>& types =
+ state->cert_req->acceptable_cert_types();
+
+ std::vector<X509_Certificate> client_certs =
+ creds.cert_chain(types,
+ "tls-client",
+ m_hostname);
+
+ state->client_certs = new Certificate(writer,
+ state->hash,
+ client_certs);
+ }
+
+ state->client_kex =
+ new Client_Key_Exchange(writer,
+ state,
+ creds,
+ peer_certs,
+ m_hostname,
+ rng);
+
+ state->keys = Session_Keys(state,
+ state->client_kex->pre_master_secret(),
+ false);
+
+ if(state->received_handshake_msg(CERTIFICATE_REQUEST) &&
+ !state->client_certs->empty())
+ {
+ Private_Key* private_key =
+ creds.private_key_for(state->client_certs->cert_chain()[0],
+ "tls-client",
+ m_hostname);
+
+ state->client_verify = new Certificate_Verify(writer,
+ state,
+ rng,
+ private_key);
+ }
+
+ writer.send(CHANGE_CIPHER_SPEC, 1);
+
+ writer.activate(CLIENT, state->suite, state->keys,
+ state->server_hello->compression_method());
+
+ if(state->server_hello->next_protocol_notification())
+ {
+ const std::string protocol =
+ state->client_npn_cb(state->server_hello->next_protocols());
+
+ state->next_protocol = new Next_Protocol(writer, state->hash, protocol);
+ }
+
+ state->client_finished = new Finished(writer, state, CLIENT);
+
+ if(state->server_hello->supports_session_ticket())
+ state->set_expected_next(NEW_SESSION_TICKET);
+ else
+ state->set_expected_next(HANDSHAKE_CCS);
+ }
+ else if(type == NEW_SESSION_TICKET)
+ {
+ state->new_session_ticket = new New_Session_Ticket(contents);
+
+ state->set_expected_next(HANDSHAKE_CCS);
+ }
+ else if(type == HANDSHAKE_CCS)
+ {
+ state->set_expected_next(FINISHED);
+
+ reader.activate(CLIENT, state->suite, state->keys,
+ state->server_hello->compression_method());
+ }
+ else if(type == FINISHED)
+ {
+ state->set_expected_next(HELLO_REQUEST);
+
+ state->server_finished = new Finished(contents);
+
+ if(!state->server_finished->verify(state, SERVER))
+ throw TLS_Exception(Alert::DECRYPT_ERROR,
+ "Finished message didn't verify");
+
+ state->hash.update(type, contents);
+
+ if(!state->client_finished) // session resume case
+ {
+ writer.send(CHANGE_CIPHER_SPEC, 1);
+
+ writer.activate(CLIENT, state->suite, state->keys,
+ state->server_hello->compression_method());
+
+ state->client_finished = new Finished(writer, state, CLIENT);
+ }
+
+ secure_renegotiation.update(state->client_finished, state->server_finished);
+
+ MemoryVector<byte> session_id = state->server_hello->session_id();
+
+ const MemoryRegion<byte>& session_ticket = state->session_ticket();
+
+ if(session_id.empty() && !session_ticket.empty())
+ session_id = make_hello_random(rng);
+
+ Session session_info(
+ session_id,
+ state->keys.master_secret(),
+ state->server_hello->version(),
+ state->server_hello->ciphersuite(),
+ state->server_hello->compression_method(),
+ CLIENT,
+ secure_renegotiation.supported(),
+ state->server_hello->fragment_size(),
+ peer_certs,
+ session_ticket,
+ m_hostname,
+ ""
+ );
+
+ if(handshake_fn(session_info))
+ session_manager.save(session_info);
+ else
+ session_manager.remove_entry(session_info.session_id());
+
+ delete state;
+ state = 0;
+ handshake_completed = true;
+ }
+ else
+ throw Unexpected_Message("Unknown handshake message received");
+ }
+
+}
+
+}
diff --git a/src/tls/tls_client.h b/src/tls/tls_client.h
new file mode 100644
index 000000000..297c5f611
--- /dev/null
+++ b/src/tls/tls_client.h
@@ -0,0 +1,74 @@
+/*
+* TLS Client
+* (C) 2004-2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_CLIENT_H__
+#define BOTAN_TLS_CLIENT_H__
+
+#include <botan/tls_channel.h>
+#include <botan/tls_session_manager.h>
+#include <botan/credentials_manager.h>
+#include <vector>
+
+namespace Botan {
+
+namespace TLS {
+
+/**
+* SSL/TLS Client
+*/
+class BOTAN_DLL Client : public Channel
+ {
+ public:
+ /**
+ * Set up a new TLS client session
+ * @param socket_output_fn is called with data for the outbound socket
+ * @param proc_fn is called when new data (application or alerts) is received
+ * @param handshake_complete is called when a handshake is completed
+ * @param session_manager manages session state
+ * @param creds manages application/user credentials
+ * @param policy specifies other connection policy information
+ * @param rng a random number generator
+ * @param servername the server's DNS name, if known
+ * @param next_protocol allows the client to specify what the next
+ * protocol will be. For more information read
+ * http://technotes.googlecode.com/git/nextprotoneg.html.
+ *
+ * If the function is not empty, NPN will be negotiated
+ * and if the server supports NPN the function will be
+ * 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,
+ 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>)>());
+
+ void renegotiate(bool force_full_renegotiation);
+ private:
+ void process_handshake_msg(Handshake_Type type,
+ const MemoryRegion<byte>& contents);
+
+ void alert_notify(const Alert& alert);
+
+ const Policy& policy;
+ RandomNumberGenerator& rng;
+ Session_Manager& session_manager;
+ Credentials_Manager& creds;
+ const std::string m_hostname;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/ssl/tls_exceptn.h b/src/tls/tls_exceptn.h
index 37b9c0d27..ad19c6c9d 100644
--- a/src/ssl/tls_exceptn.h
+++ b/src/tls/tls_exceptn.h
@@ -9,24 +9,26 @@
#define BOTAN_TLS_EXCEPTION_H__
#include <botan/exceptn.h>
-#include <botan/tls_magic.h>
+#include <botan/tls_alert.h>
namespace Botan {
+namespace TLS {
+
/**
* Exception Base Class
*/
class BOTAN_DLL TLS_Exception : public Exception
{
public:
- Alert_Type type() const throw() { return alert_type; }
+ Alert::Type type() const throw() { return alert_type; }
- TLS_Exception(Alert_Type type,
+ TLS_Exception(Alert::Type type,
const std::string& err_msg = "Unknown error") :
Exception(err_msg), alert_type(type) {}
private:
- Alert_Type alert_type;
+ Alert::Type alert_type;
};
/**
@@ -35,9 +37,11 @@ class BOTAN_DLL TLS_Exception : public Exception
struct BOTAN_DLL Unexpected_Message : public TLS_Exception
{
Unexpected_Message(const std::string& err) :
- TLS_Exception(UNEXPECTED_MESSAGE, err) {}
+ TLS_Exception(Alert::UNEXPECTED_MESSAGE, err) {}
};
}
+}
+
#endif
diff --git a/src/tls/tls_extensions.cpp b/src/tls/tls_extensions.cpp
new file mode 100644
index 000000000..6d69bfb9b
--- /dev/null
+++ b/src/tls/tls_extensions.cpp
@@ -0,0 +1,524 @@
+/*
+* TLS Extensions
+* (C) 2011,2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/internal/tls_extensions.h>
+#include <botan/internal/tls_reader.h>
+#include <botan/tls_exceptn.h>
+
+namespace Botan {
+
+namespace TLS {
+
+namespace {
+
+Extension* make_extension(TLS_Data_Reader& reader,
+ u16bit code,
+ u16bit size)
+ {
+ switch(code)
+ {
+ case TLSEXT_SERVER_NAME_INDICATION:
+ return new Server_Name_Indicator(reader, size);
+
+ case TLSEXT_MAX_FRAGMENT_LENGTH:
+ return new Maximum_Fragment_Length(reader, size);
+
+ case TLSEXT_SRP_IDENTIFIER:
+ return new SRP_Identifier(reader, size);
+
+ case TLSEXT_USABLE_ELLIPTIC_CURVES:
+ return new Supported_Elliptic_Curves(reader, size);
+
+ case TLSEXT_SAFE_RENEGOTIATION:
+ return new Renegotation_Extension(reader, size);
+
+ case TLSEXT_SIGNATURE_ALGORITHMS:
+ return new Signature_Algorithms(reader, size);
+
+ 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);
+
+ default:
+ return 0; // not known
+ }
+ }
+
+}
+
+Extensions::Extensions(TLS_Data_Reader& reader)
+ {
+ if(reader.has_remaining())
+ {
+ const u16bit all_extn_size = reader.get_u16bit();
+
+ if(reader.remaining_bytes() != all_extn_size)
+ throw Decoding_Error("Bad extension size");
+
+ while(reader.has_remaining())
+ {
+ const u16bit extension_code = reader.get_u16bit();
+ const u16bit extension_size = reader.get_u16bit();
+
+ Extension* extn = make_extension(reader,
+ extension_code,
+ extension_size);
+
+ if(extn)
+ this->add(extn);
+ else // unknown/unhandled extension
+ reader.discard_next(extension_size);
+ }
+ }
+ }
+
+MemoryVector<byte> Extensions::serialize() const
+ {
+ MemoryVector<byte> buf(2); // 2 bytes for length field
+
+ for(std::map<Handshake_Extension_Type, Extension*>::const_iterator i = extensions.begin();
+ i != extensions.end(); ++i)
+ {
+ if(i->second->empty())
+ continue;
+
+ const u16bit extn_code = i->second->type();
+
+ MemoryVector<byte> extn_val = i->second->serialize();
+
+ buf.push_back(get_byte(0, extn_code));
+ buf.push_back(get_byte(1, extn_code));
+
+ buf.push_back(get_byte<u16bit>(0, extn_val.size()));
+ buf.push_back(get_byte<u16bit>(1, extn_val.size()));
+
+ buf += extn_val;
+ }
+
+ const u16bit extn_size = buf.size() - 2;
+
+ buf[0] = get_byte(0, extn_size);
+ buf[1] = get_byte(1, extn_size);
+
+ // avoid sending a completely empty extensions block
+ if(buf.size() == 2)
+ return MemoryVector<byte>();
+
+ return buf;
+ }
+
+Extensions::~Extensions()
+ {
+ for(std::map<Handshake_Extension_Type, Extension*>::const_iterator i = extensions.begin();
+ i != extensions.end(); ++i)
+ {
+ delete i->second;
+ }
+
+ extensions.clear();
+ }
+
+Server_Name_Indicator::Server_Name_Indicator(TLS_Data_Reader& reader,
+ u16bit extension_size)
+ {
+ /*
+ * This is used by the server to confirm that it knew the name
+ */
+ if(extension_size == 0)
+ return;
+
+ u16bit name_bytes = reader.get_u16bit();
+
+ if(name_bytes + 2 != extension_size)
+ throw Decoding_Error("Bad encoding of SNI extension");
+
+ while(name_bytes)
+ {
+ byte name_type = reader.get_byte();
+ name_bytes--;
+
+ if(name_type == 0) // DNS
+ {
+ sni_host_name = reader.get_string(2, 1, 65535);
+ name_bytes -= (2 + sni_host_name.size());
+ }
+ else // some other unknown name type
+ {
+ reader.discard_next(name_bytes);
+ name_bytes = 0;
+ }
+ }
+ }
+
+MemoryVector<byte> Server_Name_Indicator::serialize() const
+ {
+ MemoryVector<byte> buf;
+
+ size_t name_len = sni_host_name.size();
+
+ buf.push_back(get_byte<u16bit>(0, name_len+3));
+ buf.push_back(get_byte<u16bit>(1, name_len+3));
+ buf.push_back(0); // DNS
+
+ buf.push_back(get_byte<u16bit>(0, name_len));
+ buf.push_back(get_byte<u16bit>(1, name_len));
+
+ buf += std::make_pair(
+ reinterpret_cast<const byte*>(sni_host_name.data()),
+ sni_host_name.size());
+
+ return buf;
+ }
+
+SRP_Identifier::SRP_Identifier(TLS_Data_Reader& reader,
+ u16bit extension_size)
+ {
+ srp_identifier = reader.get_string(1, 1, 255);
+
+ if(srp_identifier.size() + 1 != extension_size)
+ throw Decoding_Error("Bad encoding for SRP identifier extension");
+ }
+
+MemoryVector<byte> SRP_Identifier::serialize() const
+ {
+ MemoryVector<byte> buf;
+
+ const byte* srp_bytes =
+ reinterpret_cast<const byte*>(srp_identifier.data());
+
+ append_tls_length_value(buf, srp_bytes, srp_identifier.size(), 1);
+
+ return buf;
+ }
+
+Renegotation_Extension::Renegotation_Extension(TLS_Data_Reader& reader,
+ u16bit extension_size)
+ {
+ reneg_data = reader.get_range<byte>(1, 0, 255);
+
+ if(reneg_data.size() + 1 != extension_size)
+ throw Decoding_Error("Bad encoding for secure renegotiation extn");
+ }
+
+MemoryVector<byte> Renegotation_Extension::serialize() const
+ {
+ MemoryVector<byte> buf;
+ append_tls_length_value(buf, reneg_data, 1);
+ return buf;
+ }
+
+size_t Maximum_Fragment_Length::fragment_size() const
+ {
+ switch(val)
+ {
+ case 1:
+ return 512;
+ case 2:
+ return 1024;
+ case 3:
+ return 2048;
+ case 4:
+ return 4096;
+ default:
+ throw TLS_Exception(Alert::ILLEGAL_PARAMETER,
+ "Bad value in maximum fragment extension");
+ }
+ }
+
+Maximum_Fragment_Length::Maximum_Fragment_Length(size_t max_fragment)
+ {
+ if(max_fragment == 512)
+ val = 1;
+ else if(max_fragment == 1024)
+ val = 2;
+ else if(max_fragment == 2048)
+ val = 3;
+ else if(max_fragment == 4096)
+ val = 4;
+ else
+ throw std::invalid_argument("Bad setting " +
+ std::to_string(max_fragment) +
+ " for maximum fragment size");
+ }
+
+Maximum_Fragment_Length::Maximum_Fragment_Length(TLS_Data_Reader& reader,
+ u16bit extension_size)
+ {
+ if(extension_size != 1)
+ throw Decoding_Error("Bad size for maximum fragment extension");
+ val = reader.get_byte();
+ }
+
+Next_Protocol_Notification::Next_Protocol_Notification(TLS_Data_Reader& reader,
+ u16bit extension_size)
+ {
+ if(extension_size == 0)
+ return; // empty extension
+
+ size_t bytes_remaining = extension_size;
+
+ while(bytes_remaining)
+ {
+ const std::string p = reader.get_string(1, 0, 255);
+
+ if(bytes_remaining < p.size() + 1)
+ throw Decoding_Error("Bad encoding for next protocol extension");
+
+ bytes_remaining -= (p.size() + 1);
+
+ m_protocols.push_back(p);
+ }
+ }
+
+MemoryVector<byte> Next_Protocol_Notification::serialize() const
+ {
+ MemoryVector<byte> buf;
+
+ for(size_t i = 0; i != m_protocols.size(); ++i)
+ {
+ const std::string p = m_protocols[i];
+
+ if(p != "")
+ append_tls_length_value(buf,
+ reinterpret_cast<const byte*>(p.data()),
+ p.size(),
+ 1);
+ }
+
+ return buf;
+ }
+
+std::string Supported_Elliptic_Curves::curve_id_to_name(u16bit id)
+ {
+ switch(id)
+ {
+ case 15:
+ return "secp160k1";
+ case 16:
+ return "secp160r1";
+ case 17:
+ return "secp160r2";
+ case 18:
+ return "secp192k1";
+ case 19:
+ return "secp192r1";
+ case 20:
+ return "secp224k1";
+ case 21:
+ return "secp224r1";
+ case 22:
+ return "secp256k1";
+ case 23:
+ return "secp256r1";
+ case 24:
+ return "secp384r1";
+ case 25:
+ return "secp521r1";
+ default:
+ return ""; // something we don't know or support
+ }
+ }
+
+u16bit Supported_Elliptic_Curves::name_to_curve_id(const std::string& name)
+ {
+ if(name == "secp160k1")
+ return 15;
+ if(name == "secp160r1")
+ return 16;
+ if(name == "secp160r2")
+ return 17;
+ if(name == "secp192k1")
+ return 18;
+ if(name == "secp192r1")
+ return 19;
+ if(name == "secp224k1")
+ return 20;
+ if(name == "secp224r1")
+ return 21;
+ if(name == "secp256k1")
+ return 22;
+ if(name == "secp256r1")
+ return 23;
+ if(name == "secp384r1")
+ return 24;
+ if(name == "secp521r1")
+ return 25;
+
+ throw Invalid_Argument("name_to_curve_id unknown name " + name);
+ }
+
+MemoryVector<byte> Supported_Elliptic_Curves::serialize() const
+ {
+ MemoryVector<byte> buf(2);
+
+ for(size_t i = 0; i != m_curves.size(); ++i)
+ {
+ const u16bit id = name_to_curve_id(m_curves[i]);
+ buf.push_back(get_byte(0, id));
+ buf.push_back(get_byte(1, id));
+ }
+
+ buf[0] = get_byte<u16bit>(0, buf.size()-2);
+ buf[1] = get_byte<u16bit>(1, buf.size()-2);
+
+ return buf;
+ }
+
+Supported_Elliptic_Curves::Supported_Elliptic_Curves(TLS_Data_Reader& reader,
+ u16bit extension_size)
+ {
+ u16bit len = reader.get_u16bit();
+
+ if(len + 2 != extension_size)
+ throw Decoding_Error("Inconsistent length field in elliptic curve list");
+
+ if(len % 2 == 1)
+ throw Decoding_Error("Elliptic curve list of strange size");
+
+ len /= 2;
+
+ for(size_t i = 0; i != len; ++i)
+ {
+ const u16bit id = reader.get_u16bit();
+ const std::string name = curve_id_to_name(id);
+
+ if(name != "")
+ m_curves.push_back(name);
+ }
+ }
+
+std::string Signature_Algorithms::hash_algo_name(byte code)
+ {
+ switch(code)
+ {
+ // code 1 is MD5 - ignore it
+
+ case 2:
+ return "SHA-1";
+ case 3:
+ return "SHA-224";
+ case 4:
+ return "SHA-256";
+ case 5:
+ return "SHA-384";
+ case 6:
+ return "SHA-512";
+ default:
+ return "";
+ }
+ }
+
+byte Signature_Algorithms::hash_algo_code(const std::string& name)
+ {
+ if(name == "SHA-1")
+ return 2;
+
+ if(name == "SHA-224")
+ return 3;
+
+ if(name == "SHA-256")
+ return 4;
+
+ if(name == "SHA-384")
+ return 5;
+
+ if(name == "SHA-512")
+ return 6;
+
+ throw Internal_Error("Unknown hash ID " + name + " for signature_algorithms");
+ }
+
+std::string Signature_Algorithms::sig_algo_name(byte code)
+ {
+ switch(code)
+ {
+ case 1:
+ return "RSA";
+ case 2:
+ return "DSA";
+ case 3:
+ return "ECDSA";
+ default:
+ return "";
+ }
+ }
+
+byte Signature_Algorithms::sig_algo_code(const std::string& name)
+ {
+ if(name == "RSA")
+ return 1;
+
+ if(name == "DSA")
+ return 2;
+
+ if(name == "ECDSA")
+ return 3;
+
+ throw Internal_Error("Unknown sig ID " + name + " for signature_algorithms");
+ }
+
+MemoryVector<byte> Signature_Algorithms::serialize() const
+ {
+ MemoryVector<byte> buf(2);
+
+ for(size_t i = 0; i != m_supported_algos.size(); ++i)
+ {
+ 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_code);
+ buf.push_back(sig_code);
+ }
+ catch(...)
+ {}
+ }
+
+ buf[0] = get_byte<u16bit>(0, buf.size()-2);
+ buf[1] = get_byte<u16bit>(1, buf.size()-2);
+
+ return buf;
+ }
+
+Signature_Algorithms::Signature_Algorithms(TLS_Data_Reader& reader,
+ u16bit extension_size)
+ {
+ u16bit len = reader.get_u16bit();
+
+ if(len + 2 != extension_size)
+ throw Decoding_Error("Bad encoding on signature algorithms extension");
+
+ while(len)
+ {
+ const std::string hash_code = hash_algo_name(reader.get_byte());
+ const std::string sig_code = sig_algo_name(reader.get_byte());
+
+ len -= 2;
+
+ // If not something we know, ignore it completely
+ if(hash_code == "" || sig_code == "")
+ continue;
+
+ m_supported_algos.push_back(std::make_pair(hash_code, sig_code));
+ }
+ }
+
+Session_Ticket::Session_Ticket(TLS_Data_Reader& reader,
+ u16bit extension_size)
+ {
+ m_ticket = reader.get_elem<byte, MemoryVector<byte> >(extension_size);
+ }
+
+}
+
+}
diff --git a/src/tls/tls_extensions.h b/src/tls/tls_extensions.h
new file mode 100644
index 000000000..3fe3f7399
--- /dev/null
+++ b/src/tls/tls_extensions.h
@@ -0,0 +1,381 @@
+/*
+* TLS Extensions
+* (C) 2011-2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_EXTENSIONS_H__
+#define BOTAN_TLS_EXTENSIONS_H__
+
+#include <botan/secmem.h>
+#include <botan/tls_magic.h>
+#include <vector>
+#include <string>
+#include <map>
+
+namespace Botan {
+
+namespace TLS {
+
+class TLS_Data_Reader;
+
+enum Handshake_Extension_Type {
+ TLSEXT_SERVER_NAME_INDICATION = 0,
+ TLSEXT_MAX_FRAGMENT_LENGTH = 1,
+ TLSEXT_CLIENT_CERT_URL = 2,
+ TLSEXT_TRUSTED_CA_KEYS = 3,
+ TLSEXT_TRUNCATED_HMAC = 4,
+
+ TLSEXT_CERTIFICATE_TYPES = 9,
+ TLSEXT_USABLE_ELLIPTIC_CURVES = 10,
+ TLSEXT_EC_POINT_FORMATS = 11,
+ TLSEXT_SRP_IDENTIFIER = 12,
+ TLSEXT_SIGNATURE_ALGORITHMS = 13,
+ TLSEXT_HEARTBEAT_SUPPORT = 15,
+
+ TLSEXT_SESSION_TICKET = 35,
+
+ TLSEXT_NEXT_PROTOCOL = 13172,
+
+ TLSEXT_SAFE_RENEGOTIATION = 65281,
+};
+
+/**
+* Base class representing a TLS extension of some kind
+*/
+class Extension
+ {
+ public:
+ virtual Handshake_Extension_Type type() const = 0;
+
+ virtual MemoryVector<byte> serialize() const = 0;
+
+ virtual bool empty() const = 0;
+
+ virtual ~Extension() {}
+ };
+
+/**
+* Server Name Indicator extension (RFC 3546)
+*/
+class Server_Name_Indicator : public Extension
+ {
+ public:
+ static Handshake_Extension_Type static_type()
+ { return TLSEXT_SERVER_NAME_INDICATION; }
+
+ Handshake_Extension_Type type() const { return static_type(); }
+
+ Server_Name_Indicator(const std::string& host_name) :
+ sni_host_name(host_name) {}
+
+ Server_Name_Indicator(TLS_Data_Reader& reader,
+ u16bit extension_size);
+
+ std::string host_name() const { return sni_host_name; }
+
+ MemoryVector<byte> serialize() const;
+
+ bool empty() const { return sni_host_name == ""; }
+ private:
+ std::string sni_host_name;
+ };
+
+/**
+* SRP identifier extension (RFC 5054)
+*/
+class SRP_Identifier : public Extension
+ {
+ public:
+ static Handshake_Extension_Type static_type()
+ { return TLSEXT_SRP_IDENTIFIER; }
+
+ Handshake_Extension_Type type() const { return static_type(); }
+
+ SRP_Identifier(const std::string& identifier) :
+ srp_identifier(identifier) {}
+
+ SRP_Identifier(TLS_Data_Reader& reader,
+ u16bit extension_size);
+
+ std::string identifier() const { return srp_identifier; }
+
+ MemoryVector<byte> serialize() const;
+
+ bool empty() const { return srp_identifier == ""; }
+ private:
+ std::string srp_identifier;
+ };
+
+/**
+* Renegotiation Indication Extension (RFC 5746)
+*/
+class Renegotation_Extension : public Extension
+ {
+ public:
+ static Handshake_Extension_Type static_type()
+ { return TLSEXT_SAFE_RENEGOTIATION; }
+
+ Handshake_Extension_Type type() const { return static_type(); }
+
+ Renegotation_Extension() {}
+
+ Renegotation_Extension(const MemoryRegion<byte>& bits) :
+ reneg_data(bits) {}
+
+ Renegotation_Extension(TLS_Data_Reader& reader,
+ u16bit extension_size);
+
+ const MemoryVector<byte>& renegotiation_info() const
+ { return reneg_data; }
+
+ MemoryVector<byte> serialize() const;
+
+ bool empty() const { return false; } // always send this
+ private:
+ MemoryVector<byte> reneg_data;
+ };
+
+/**
+* Maximum Fragment Length Negotiation Extension (RFC 4366 sec 3.2)
+*/
+class Maximum_Fragment_Length : public Extension
+ {
+ public:
+ static Handshake_Extension_Type static_type()
+ { return TLSEXT_MAX_FRAGMENT_LENGTH; }
+
+ Handshake_Extension_Type type() const { return static_type(); }
+
+ bool empty() const { return val != 0; }
+
+ size_t fragment_size() const;
+
+ MemoryVector<byte> serialize() const
+ {
+ return MemoryVector<byte>(&val, 1);
+ }
+
+ /**
+ * @param max_fragment specifies what maximum fragment size to
+ * advertise. Currently must be one of 512, 1024, 2048, or
+ * 4096.
+ */
+ Maximum_Fragment_Length(size_t max_fragment);
+
+ Maximum_Fragment_Length(TLS_Data_Reader& reader,
+ u16bit extension_size);
+
+ private:
+ byte val;
+ };
+
+/**
+* Next Protocol Negotiation
+* http://technotes.googlecode.com/git/nextprotoneg.html
+*
+* This implementation requires the semantics defined in the Google
+* spec (implemented in Chromium); the internet draft leaves the format
+* unspecified.
+*/
+class Next_Protocol_Notification : public Extension
+ {
+ public:
+ static Handshake_Extension_Type static_type()
+ { return TLSEXT_NEXT_PROTOCOL; }
+
+ Handshake_Extension_Type type() const { return static_type(); }
+
+ const std::vector<std::string>& protocols() const
+ { return m_protocols; }
+
+ /**
+ * Empty extension, used by client
+ */
+ Next_Protocol_Notification() {}
+
+ /**
+ * List of protocols, used by server
+ */
+ Next_Protocol_Notification(const std::vector<std::string>& protocols) :
+ m_protocols(protocols) {}
+
+ Next_Protocol_Notification(TLS_Data_Reader& reader,
+ u16bit extension_size);
+
+ MemoryVector<byte> serialize() const;
+
+ bool empty() const { return false; }
+ private:
+ std::vector<std::string> m_protocols;
+ };
+
+class Session_Ticket : public Extension
+ {
+ public:
+ static Handshake_Extension_Type static_type()
+ { return TLSEXT_SESSION_TICKET; }
+
+ Handshake_Extension_Type type() const { return static_type(); }
+
+ const MemoryVector<byte>& contents() const { return m_ticket; }
+
+ /**
+ * Create empty extension, used by both client and server
+ */
+ Session_Ticket() {}
+
+ /**
+ * Extension with ticket, used by client
+ */
+ Session_Ticket(const MemoryRegion<byte>& session_ticket) :
+ m_ticket(session_ticket) {}
+
+ /**
+ * Deserialize a session ticket
+ */
+ Session_Ticket(TLS_Data_Reader& reader, u16bit extension_size);
+
+ MemoryVector<byte> serialize() const { return m_ticket; }
+
+ bool empty() const { return false; }
+ private:
+ MemoryVector<byte> m_ticket;
+ };
+
+/**
+* Supported Elliptic Curves Extension (RFC 4492)
+*/
+class Supported_Elliptic_Curves : public Extension
+ {
+ public:
+ static Handshake_Extension_Type static_type()
+ { return TLSEXT_USABLE_ELLIPTIC_CURVES; }
+
+ Handshake_Extension_Type type() const { return static_type(); }
+
+ static std::string curve_id_to_name(u16bit id);
+ static u16bit name_to_curve_id(const std::string& name);
+
+ const std::vector<std::string>& curves() const { return m_curves; }
+
+ MemoryVector<byte> serialize() const;
+
+ Supported_Elliptic_Curves(const std::vector<std::string>& curves) :
+ m_curves(curves) {}
+
+ Supported_Elliptic_Curves(TLS_Data_Reader& reader,
+ u16bit extension_size);
+
+ bool empty() const { return m_curves.empty(); }
+ private:
+ std::vector<std::string> m_curves;
+ };
+
+/**
+* Signature Algorithms Extension for TLS 1.2 (RFC 5246)
+*/
+class Signature_Algorithms : public Extension
+ {
+ public:
+ static Handshake_Extension_Type static_type()
+ { return TLSEXT_SIGNATURE_ALGORITHMS; }
+
+ Handshake_Extension_Type type() const { return static_type(); }
+
+ static std::string hash_algo_name(byte code);
+ static byte hash_algo_code(const std::string& name);
+
+ static std::string sig_algo_name(byte code);
+ static byte sig_algo_code(const std::string& name);
+
+ std::vector<std::pair<std::string, std::string> >
+ supported_signature_algorthms() const
+ {
+ return m_supported_algos;
+ }
+
+ MemoryVector<byte> serialize() const;
+
+ bool empty() const { return false; }
+
+ Signature_Algorithms(const std::vector<std::pair<std::string, std::string> >& algos) :
+ m_supported_algos(algos) {}
+
+ Signature_Algorithms(TLS_Data_Reader& reader,
+ u16bit extension_size);
+ private:
+ std::vector<std::pair<std::string, std::string> > m_supported_algos;
+ };
+
+/**
+* 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
+ {
+ public:
+ template<typename T>
+ T* get() const
+ {
+ Handshake_Extension_Type type = T::static_type();
+
+ std::map<Handshake_Extension_Type, Extension*>::const_iterator i =
+ extensions.find(type);
+
+ if(i != extensions.end())
+ return dynamic_cast<T*>(i->second);
+ return 0;
+ }
+
+ void add(Extension* extn)
+ {
+ delete extensions[extn->type()]; // or hard error if already exists?
+ extensions[extn->type()] = extn;
+ }
+
+ MemoryVector<byte> serialize() const;
+
+ Extensions() {}
+
+ Extensions(TLS_Data_Reader& reader); // deserialize
+
+ ~Extensions();
+ private:
+ Extensions(const Extensions&) {}
+ Extensions& operator=(const Extensions&) { return (*this); }
+
+ std::map<Handshake_Extension_Type, Extension*> extensions;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/tls/tls_handshake_hash.cpp b/src/tls/tls_handshake_hash.cpp
new file mode 100644
index 000000000..02516632e
--- /dev/null
+++ b/src/tls/tls_handshake_hash.cpp
@@ -0,0 +1,103 @@
+/*
+* TLS Handshake Hash
+* (C) 2004-2006,2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/internal/tls_handshake_hash.h>
+#include <botan/tls_exceptn.h>
+#include <botan/libstate.h>
+#include <botan/hash.h>
+#include <memory>
+
+namespace Botan {
+
+namespace TLS {
+
+void Handshake_Hash::update(Handshake_Type handshake_type,
+ const MemoryRegion<byte>& handshake_msg)
+ {
+ update(static_cast<byte>(handshake_type));
+
+ const size_t record_length = handshake_msg.size();
+ for(size_t i = 0; i != 3; i++)
+ update(get_byte<u32bit>(i+1, record_length));
+
+ update(handshake_msg);
+ }
+
+/**
+* Return a TLS Handshake Hash
+*/
+SecureVector<byte> Handshake_Hash::final(Protocol_Version version,
+ const std::string& mac_algo)
+ {
+ Algorithm_Factory& af = global_state().algorithm_factory();
+
+ std::unique_ptr<HashFunction> hash;
+
+ if(version == Protocol_Version::TLS_V10 || version == Protocol_Version::TLS_V11)
+ {
+ hash.reset(af.make_hash_function("TLS.Digest.0"));
+ }
+ else if(version == Protocol_Version::TLS_V12)
+ {
+ 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));
+ }
+ else
+ throw TLS_Exception(Alert::PROTOCOL_VERSION,
+ "Unknown version for handshake hashes");
+
+ hash->update(data);
+ return hash->final();
+ }
+
+/**
+* Return a SSLv3 Handshake Hash
+*/
+SecureVector<byte> Handshake_Hash::final_ssl3(const MemoryRegion<byte>& secret)
+ {
+ const byte PAD_INNER = 0x36, PAD_OUTER = 0x5C;
+
+ 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"));
+
+ md5->update(data);
+ sha1->update(data);
+
+ md5->update(secret);
+ sha1->update(secret);
+
+ for(size_t i = 0; i != 48; ++i)
+ md5->update(PAD_INNER);
+ for(size_t i = 0; i != 40; ++i)
+ sha1->update(PAD_INNER);
+
+ SecureVector<byte> inner_md5 = md5->final(), inner_sha1 = sha1->final();
+
+ md5->update(secret);
+ sha1->update(secret);
+
+ for(size_t i = 0; i != 48; ++i)
+ md5->update(PAD_OUTER);
+ for(size_t i = 0; i != 40; ++i)
+ sha1->update(PAD_OUTER);
+
+ md5->update(inner_md5);
+ sha1->update(inner_sha1);
+
+ SecureVector<byte> output;
+ output += md5->final();
+ output += sha1->final();
+ return output;
+ }
+
+}
+
+}
diff --git a/src/ssl/tls_handshake_hash.h b/src/tls/tls_handshake_hash.h
index cea612a71..c13f97aa8 100644
--- a/src/ssl/tls_handshake_hash.h
+++ b/src/tls/tls_handshake_hash.h
@@ -1,6 +1,6 @@
/*
* TLS Handshake Hash
-* (C) 2004-2006 Jack Lloyd
+* (C) 2004-2006,2011 Jack Lloyd
*
* Released under the terms of the Botan license
*/
@@ -9,15 +9,19 @@
#define BOTAN_TLS_HANDSHAKE_HASH_H__
#include <botan/secmem.h>
+#include <botan/tls_version.h>
+#include <botan/tls_magic.h>
namespace Botan {
+namespace TLS {
+
using namespace Botan;
/**
* TLS Handshake Hash
*/
-class HandshakeHash
+class Handshake_Hash
{
public:
void update(const byte in[], size_t length)
@@ -29,12 +33,23 @@ class HandshakeHash
void update(byte in)
{ data.push_back(in); }
- SecureVector<byte> final();
- SecureVector<byte> final_ssl3(const MemoryRegion<byte>&);
+ void update(Handshake_Type handshake_type,
+ const MemoryRegion<byte>& handshake_msg);
+
+ SecureVector<byte> final(Protocol_Version version,
+ const std::string& mac_algo);
+
+ SecureVector<byte> final_ssl3(const MemoryRegion<byte>& master_secret);
+
+ const SecureVector<byte>& get_contents() const
+ { return data; }
+
private:
SecureVector<byte> data;
};
}
+}
+
#endif
diff --git a/src/tls/tls_handshake_reader.cpp b/src/tls/tls_handshake_reader.cpp
new file mode 100644
index 000000000..8278a2296
--- /dev/null
+++ b/src/tls/tls_handshake_reader.cpp
@@ -0,0 +1,66 @@
+/*
+* TLS Handshake Reader
+* (C) 2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/internal/tls_handshake_reader.h>
+#include <botan/exceptn.h>
+
+namespace Botan {
+
+namespace TLS {
+
+void Stream_Handshake_Reader::add_input(const byte record[],
+ size_t record_size)
+ {
+ m_queue.write(record, record_size);
+ }
+
+bool Stream_Handshake_Reader::empty() const
+ {
+ return m_queue.empty();
+ }
+
+bool Stream_Handshake_Reader::have_full_record() const
+ {
+ if(m_queue.size() >= 4)
+ {
+ byte head[4] = { 0 };
+ m_queue.peek(head, 4);
+
+ const size_t length = make_u32bit(0, head[1], head[2], head[3]);
+
+ return (m_queue.size() >= length + 4);
+ }
+
+ return false;
+ }
+
+std::pair<Handshake_Type, MemoryVector<byte> > Stream_Handshake_Reader::get_next_record()
+ {
+ if(m_queue.size() >= 4)
+ {
+ byte head[4] = { 0 };
+ m_queue.peek(head, 4);
+
+ const size_t length = make_u32bit(0, head[1], head[2], head[3]);
+
+ if(m_queue.size() >= length + 4)
+ {
+ Handshake_Type type = static_cast<Handshake_Type>(head[0]);
+ MemoryVector<byte> contents(length);
+ m_queue.read(head, 4); // discard
+ m_queue.read(&contents[0], contents.size());
+
+ return std::make_pair(type, contents);
+ }
+ }
+
+ throw Internal_Error("Stream_Handshake_Reader::get_next_record called without a full record");
+ }
+
+}
+
+}
diff --git a/src/tls/tls_handshake_reader.h b/src/tls/tls_handshake_reader.h
new file mode 100644
index 000000000..06a273ced
--- /dev/null
+++ b/src/tls/tls_handshake_reader.h
@@ -0,0 +1,58 @@
+/*
+* TLS Handshake Reader
+* (C) 2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_HANDSHAKE_READER_H__
+#define BOTAN_TLS_HANDSHAKE_READER_H__
+
+#include <botan/tls_magic.h>
+#include <botan/secqueue.h>
+#include <botan/loadstor.h>
+#include <utility>
+
+namespace Botan {
+
+namespace TLS {
+
+/**
+* Handshake Reader Interface
+*/
+class Handshake_Reader
+ {
+ public:
+ virtual void add_input(const byte record[], size_t record_size) = 0;
+
+ virtual bool empty() const = 0;
+
+ virtual bool have_full_record() const = 0;
+
+ virtual std::pair<Handshake_Type, MemoryVector<byte> > get_next_record() = 0;
+
+ virtual ~Handshake_Reader() {}
+ };
+
+/**
+* Reader of TLS handshake messages
+*/
+class Stream_Handshake_Reader : public Handshake_Reader
+ {
+ public:
+ void add_input(const byte record[], size_t record_size);
+
+ bool empty() const;
+
+ bool have_full_record() const;
+
+ std::pair<Handshake_Type, MemoryVector<byte> > get_next_record();
+ private:
+ SecureQueue m_queue;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/tls/tls_handshake_state.cpp b/src/tls/tls_handshake_state.cpp
new file mode 100644
index 000000000..f5a9f899c
--- /dev/null
+++ b/src/tls/tls_handshake_state.cpp
@@ -0,0 +1,330 @@
+/*
+* TLS Handshaking
+* (C) 2004-2006,2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/internal/tls_handshake_state.h>
+#include <botan/internal/tls_messages.h>
+#include <botan/internal/assert.h>
+#include <botan/lookup.h>
+
+namespace Botan {
+
+namespace TLS {
+
+namespace {
+
+u32bit bitmask_for_handshake_type(Handshake_Type type)
+ {
+ switch(type)
+ {
+ case HELLO_REQUEST:
+ return (1 << 0);
+
+ /*
+ * Same code point for both client hello styles
+ */
+ case CLIENT_HELLO:
+ case CLIENT_HELLO_SSLV2:
+ return (1 << 1);
+
+ case SERVER_HELLO:
+ return (1 << 2);
+
+ case CERTIFICATE:
+ return (1 << 3);
+
+ case SERVER_KEX:
+ return (1 << 4);
+
+ case CERTIFICATE_REQUEST:
+ return (1 << 5);
+
+ case SERVER_HELLO_DONE:
+ return (1 << 6);
+
+ case CERTIFICATE_VERIFY:
+ return (1 << 7);
+
+ case CLIENT_KEX:
+ return (1 << 8);
+
+ case NEXT_PROTOCOL:
+ return (1 << 9);
+
+ case NEW_SESSION_TICKET:
+ return (1 << 10);
+
+ case HANDSHAKE_CCS:
+ return (1 << 11);
+
+ case FINISHED:
+ return (1 << 12);
+
+ // allow explicitly disabling new handshakes
+ case HANDSHAKE_NONE:
+ return 0;
+
+ default:
+ throw Internal_Error("Unknown handshake type " +
+ std::to_string(type));
+ }
+
+ return 0;
+ }
+
+}
+
+/*
+* Initialize the SSL/TLS Handshake State
+*/
+Handshake_State::Handshake_State(Handshake_Reader* reader)
+ {
+ client_hello = 0;
+ server_hello = 0;
+ server_certs = 0;
+ server_kex = 0;
+ cert_req = 0;
+ server_hello_done = 0;
+ next_protocol = 0;
+ new_session_ticket = 0;
+
+ client_certs = 0;
+ client_kex = 0;
+ client_verify = 0;
+ client_finished = 0;
+ server_finished = 0;
+
+ m_handshake_reader = reader;
+
+ server_rsa_kex_key = 0;
+
+ m_version = Protocol_Version::SSL_V3;
+
+ hand_expecting_mask = 0;
+ hand_received_mask = 0;
+
+ allow_session_resumption = true;
+ }
+
+void Handshake_State::set_version(const Protocol_Version& version)
+ {
+ m_version = version;
+ }
+
+void Handshake_State::confirm_transition_to(Handshake_Type handshake_msg)
+ {
+ const u32bit mask = bitmask_for_handshake_type(handshake_msg);
+
+ hand_received_mask |= mask;
+
+ const bool ok = (hand_expecting_mask & mask); // overlap?
+
+ if(!ok)
+ throw Unexpected_Message("Unexpected state transition in handshake, got " +
+ std::to_string(handshake_msg) + " mask is " +
+ std::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
+ check will always fail which is what we want.
+ */
+ hand_expecting_mask = 0;
+ }
+
+void Handshake_State::set_expected_next(Handshake_Type handshake_msg)
+ {
+ hand_expecting_mask |= bitmask_for_handshake_type(handshake_msg);
+ }
+
+bool Handshake_State::received_handshake_msg(Handshake_Type handshake_msg) const
+ {
+ const u32bit mask = bitmask_for_handshake_type(handshake_msg);
+
+ 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())
+ return new_session_ticket->ticket();
+
+ return client_hello->session_ticket();
+ }
+
+KDF* Handshake_State::protocol_specific_prf()
+ {
+ if(version() == Protocol_Version::SSL_V3)
+ {
+ return get_kdf("SSL3-PRF");
+ }
+ else if(version() == Protocol_Version::TLS_V10 || version() == Protocol_Version::TLS_V11)
+ {
+ return get_kdf("TLS-PRF");
+ }
+ else if(version() == Protocol_Version::TLS_V12)
+ {
+ 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() + ")");
+ }
+
+ throw Internal_Error("Unknown version code " + version().to_string());
+ }
+
+std::pair<std::string, Signature_Format>
+Handshake_State::choose_sig_format(const Private_Key* key,
+ std::string& hash_algo_out,
+ std::string& sig_algo_out,
+ bool for_client_auth)
+ {
+ const std::string sig_algo = key->algo_name();
+
+ const std::vector<std::pair<std::string, std::string> > supported_algos =
+ (for_client_auth) ? cert_req->supported_algos() : client_hello->supported_algos();
+
+ std::string hash_algo;
+
+ for(size_t i = 0; i != supported_algos.size(); ++i)
+ {
+ if(supported_algos[i].second == sig_algo)
+ {
+ hash_algo = supported_algos[i].first;
+ break;
+ }
+ }
+
+ if(for_client_auth && this->version() == Protocol_Version::SSL_V3)
+ hash_algo = "Raw";
+
+ if(hash_algo == "" && this->version() == Protocol_Version::TLS_V12)
+ hash_algo = "SHA-1"; // TLS 1.2 but no compatible hashes set (?)
+
+ BOTAN_ASSERT(hash_algo != "", "Couldn't figure out hash to use");
+
+ if(this->version() >= Protocol_Version::TLS_V12)
+ {
+ hash_algo_out = hash_algo;
+ sig_algo_out = sig_algo;
+ }
+
+ if(sig_algo == "RSA")
+ {
+ const std::string padding = "EMSA3(" + hash_algo + ")";
+
+ return std::make_pair(padding, IEEE_1363);
+ }
+ else if(sig_algo == "DSA" || sig_algo == "ECDSA")
+ {
+ const std::string padding = "EMSA1(" + hash_algo + ")";
+
+ return std::make_pair(padding, DER_SEQUENCE);
+ }
+
+ throw Invalid_Argument(sig_algo + " is invalid/unknown for TLS signatures");
+ }
+
+std::pair<std::string, Signature_Format>
+Handshake_State::understand_sig_format(const Public_Key* key,
+ std::string hash_algo,
+ std::string sig_algo,
+ bool for_client_auth)
+ {
+ const std::string algo_name = key->algo_name();
+
+ /*
+ FIXME: This should check what was sent against the client hello
+ preferences, or the certificate request, to ensure it was allowed
+ by those restrictions.
+
+ Or not?
+ */
+
+ if(this->version() < Protocol_Version::TLS_V12)
+ {
+ if(hash_algo != "" || sig_algo != "")
+ throw Decoding_Error("Counterparty sent hash/sig IDs with old version");
+ }
+ else
+ {
+ if(hash_algo == "")
+ throw Decoding_Error("Counterparty did not send hash/sig IDS");
+
+ if(sig_algo != algo_name)
+ throw Decoding_Error("Counterparty sent inconsistent key and sig types");
+ }
+
+ if(algo_name == "RSA")
+ {
+ if(for_client_auth && this->version() == Protocol_Version::SSL_V3)
+ {
+ hash_algo = "Raw";
+ }
+ else if(this->version() < Protocol_Version::TLS_V12)
+ {
+ hash_algo = "TLS.Digest.0";
+ }
+
+ const std::string padding = "EMSA3(" + hash_algo + ")";
+ return std::make_pair(padding, IEEE_1363);
+ }
+ else if(algo_name == "DSA" || algo_name == "ECDSA")
+ {
+ if(algo_name == "DSA" && for_client_auth && this->version() == Protocol_Version::SSL_V3)
+ {
+ hash_algo = "Raw";
+ }
+ else if(this->version() < Protocol_Version::TLS_V12)
+ {
+ hash_algo = "SHA-1";
+ }
+
+ const std::string padding = "EMSA1(" + hash_algo + ")";
+
+ return std::make_pair(padding, DER_SEQUENCE);
+ }
+
+ throw Invalid_Argument(algo_name + " is invalid/unknown for TLS signatures");
+ }
+
+/*
+* Destroy the SSL/TLS Handshake State
+*/
+Handshake_State::~Handshake_State()
+ {
+ delete client_hello;
+ delete server_hello;
+ delete server_certs;
+ delete server_kex;
+ delete cert_req;
+ delete server_hello_done;
+ delete next_protocol;
+ delete new_session_ticket;
+
+ delete client_certs;
+ delete client_kex;
+ delete client_verify;
+ delete client_finished;
+ delete server_finished;
+
+ delete m_handshake_reader;
+ }
+
+}
+
+}
diff --git a/src/tls/tls_handshake_state.h b/src/tls/tls_handshake_state.h
new file mode 100644
index 000000000..364c715f8
--- /dev/null
+++ b/src/tls/tls_handshake_state.h
@@ -0,0 +1,112 @@
+/*
+* TLS Handshake State
+* (C) 2004-2006 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_HANDSHAKE_STATE_H__
+#define BOTAN_TLS_HANDSHAKE_STATE_H__
+
+#include <botan/internal/tls_handshake_hash.h>
+#include <botan/internal/tls_handshake_reader.h>
+#include <botan/internal/tls_session_key.h>
+#include <botan/pk_keys.h>
+#include <botan/pubkey.h>
+
+#include <functional>
+#include <utility>
+
+namespace Botan {
+
+class KDF;
+
+namespace TLS {
+
+/**
+* SSL/TLS Handshake State
+*/
+class Handshake_State
+ {
+ public:
+ Handshake_State(Handshake_Reader* reader);
+ ~Handshake_State();
+
+ bool received_handshake_msg(Handshake_Type handshake_msg) const;
+
+ void confirm_transition_to(Handshake_Type handshake_msg);
+ void set_expected_next(Handshake_Type handshake_msg);
+
+ const MemoryRegion<byte>& session_ticket() const;
+
+ std::pair<std::string, Signature_Format>
+ understand_sig_format(const Public_Key* key,
+ std::string hash_algo,
+ std::string sig_algo,
+ bool for_client_auth);
+
+ std::pair<std::string, Signature_Format>
+ choose_sig_format(const Private_Key* key,
+ std::string& hash_algo,
+ std::string& sig_algo,
+ bool for_client_auth);
+
+ std::string srp_identifier() const;
+
+ KDF* protocol_specific_prf();
+
+ Protocol_Version version() const { return m_version; }
+
+ void set_version(const Protocol_Version& version);
+
+ class Client_Hello* client_hello;
+ class Server_Hello* server_hello;
+ class Certificate* server_certs;
+ class Server_Key_Exchange* server_kex;
+ class Certificate_Req* cert_req;
+ class Server_Hello_Done* server_hello_done;
+
+ class Certificate* client_certs;
+ class Client_Key_Exchange* client_kex;
+ class Certificate_Verify* client_verify;
+
+ class Next_Protocol* next_protocol;
+ class New_Session_Ticket* new_session_ticket;
+
+ class Finished* client_finished;
+ class Finished* server_finished;
+
+ // Used by the server only, in case of RSA key exchange
+ Private_Key* server_rsa_kex_key;
+
+ Ciphersuite suite;
+ Session_Keys keys;
+ Handshake_Hash hash;
+
+ /*
+ * Only used by clients for session resumption
+ */
+ 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;
+
+ Handshake_Reader* handshake_reader() { return m_handshake_reader; }
+ private:
+ Handshake_Reader* m_handshake_reader;
+ u32bit hand_expecting_mask, hand_received_mask;
+ Protocol_Version m_version;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/tls/tls_heartbeats.cpp b/src/tls/tls_heartbeats.cpp
new file mode 100644
index 000000000..059772d34
--- /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 " + std::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
new file mode 100644
index 000000000..2972321c9
--- /dev/null
+++ b/src/tls/tls_magic.h
@@ -0,0 +1,69 @@
+/*
+* SSL/TLS Protocol Constants
+* (C) 2004-2010 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_PROTOCOL_MAGIC_H__
+#define BOTAN_TLS_PROTOCOL_MAGIC_H__
+
+namespace Botan {
+
+namespace TLS {
+
+/**
+* Protocol Constants for SSL/TLS
+*/
+enum Size_Limits {
+ TLS_HEADER_SIZE = 5,
+ MAX_PLAINTEXT_SIZE = 16*1024,
+ MAX_COMPRESSED_SIZE = MAX_PLAINTEXT_SIZE + 1024,
+ MAX_CIPHERTEXT_SIZE = MAX_COMPRESSED_SIZE + 1024,
+
+ MAX_TLS_RECORD_SIZE = MAX_CIPHERTEXT_SIZE + TLS_HEADER_SIZE,
+};
+
+enum Connection_Side { CLIENT = 1, SERVER = 2 };
+
+enum Record_Type {
+ CONNECTION_CLOSED = 0,
+
+ CHANGE_CIPHER_SPEC = 20,
+ ALERT = 21,
+ HANDSHAKE = 22,
+ APPLICATION_DATA = 23,
+ HEARTBEAT = 24,
+};
+
+enum Handshake_Type {
+ HELLO_REQUEST = 0,
+ CLIENT_HELLO = 1,
+ CLIENT_HELLO_SSLV2 = 253, // Not a wire value
+ SERVER_HELLO = 2,
+ HELLO_VERIFY_REQUEST = 3,
+ NEW_SESSION_TICKET = 4, // RFC 5077
+ CERTIFICATE = 11,
+ SERVER_KEX = 12,
+ CERTIFICATE_REQUEST = 13,
+ SERVER_HELLO_DONE = 14,
+ CERTIFICATE_VERIFY = 15,
+ CLIENT_KEX = 16,
+ FINISHED = 20,
+
+ NEXT_PROTOCOL = 67,
+
+ HANDSHAKE_CCS = 254, // Not a wire value
+ HANDSHAKE_NONE = 255 // Null value
+};
+
+enum Compression_Method {
+ NO_COMPRESSION = 0x00,
+ DEFLATE_COMPRESSION = 0x01
+};
+
+}
+
+}
+
+#endif
diff --git a/src/tls/tls_messages.h b/src/tls/tls_messages.h
new file mode 100644
index 000000000..d9146dda1
--- /dev/null
+++ b/src/tls/tls_messages.h
@@ -0,0 +1,500 @@
+/*
+* TLS Messages
+* (C) 2004-2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_MESSAGES_H__
+#define BOTAN_TLS_MESSAGES_H__
+
+#include <botan/internal/tls_handshake_state.h>
+#include <botan/tls_session.h>
+#include <botan/tls_policy.h>
+#include <botan/tls_magic.h>
+#include <botan/tls_ciphersuite.h>
+#include <botan/bigint.h>
+#include <botan/pkcs8.h>
+#include <botan/x509cert.h>
+#include <vector>
+
+namespace Botan {
+
+class Credentials_Manager;
+class SRP6_Server_Session;
+
+namespace TLS {
+
+class Record_Writer;
+class Record_Reader;
+
+/**
+* TLS Handshake Message Base Class
+*/
+class Handshake_Message
+ {
+ public:
+ virtual MemoryVector<byte> serialize() const = 0;
+ virtual Handshake_Type type() const = 0;
+
+ Handshake_Message() {}
+ virtual ~Handshake_Message() {}
+ private:
+ Handshake_Message(const Handshake_Message&) {}
+ Handshake_Message& operator=(const Handshake_Message&) { return (*this); }
+ };
+
+MemoryVector<byte> make_hello_random(RandomNumberGenerator& rng);
+
+/**
+* DTLS Hello Verify Request
+*/
+class Hello_Verify_Request : public Handshake_Message
+ {
+ public:
+ MemoryVector<byte> serialize() const;
+ Handshake_Type type() const { return HELLO_VERIFY_REQUEST; }
+
+ MemoryVector<byte> cookie() const { return m_cookie; }
+
+ Hello_Verify_Request(const MemoryRegion<byte>& buf);
+
+ Hello_Verify_Request(const MemoryVector<byte>& client_hello_bits,
+ const std::string& client_identity,
+ const SymmetricKey& secret_key);
+ private:
+ MemoryVector<byte> m_cookie;
+ };
+
+/**
+* Client Hello Message
+*/
+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; }
+
+ const std::vector<std::pair<std::string, std::string> >& supported_algos() const
+ { return m_supported_algos; }
+
+ const std::vector<std::string>& supported_ecc_curves() const
+ { return m_supported_curves; }
+
+ std::vector<u16bit> ciphersuites() const { return m_suites; }
+ std::vector<byte> compression_methods() const { return m_comp_methods; }
+
+ const MemoryVector<byte>& random() const { return m_random; }
+
+ std::string sni_hostname() const { return m_hostname; }
+
+ std::string srp_identifier() const { return m_srp_identifier; }
+
+ bool secure_renegotiation() const { return m_secure_renegotiation; }
+
+ const MemoryVector<byte>& renegotiation_info()
+ { return m_renegotiation_info; }
+
+ bool offered_suite(u16bit ciphersuite) const;
+
+ bool next_protocol_notification() const { return m_next_protocol; }
+
+ size_t fragment_size() const { return m_fragment_size; }
+
+ bool supports_session_ticket() const { return m_supports_session_ticket; }
+
+ const MemoryRegion<byte>& session_ticket() const
+ { return m_session_ticket; }
+
+ 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,
+ RandomNumberGenerator& rng,
+ const MemoryRegion<byte>& reneg_info,
+ bool next_protocol = false,
+ const std::string& hostname = "",
+ const std::string& srp_identifier = "");
+
+ Client_Hello(Record_Writer& writer,
+ Handshake_Hash& hash,
+ const Policy& policy,
+ RandomNumberGenerator& rng,
+ const MemoryRegion<byte>& reneg_info,
+ const Session& resumed_session,
+ bool next_protocol = false);
+
+ Client_Hello(const MemoryRegion<byte>& buf,
+ Handshake_Type type);
+
+ private:
+ MemoryVector<byte> serialize() const;
+ void deserialize(const MemoryRegion<byte>& buf);
+ void deserialize_sslv2(const MemoryRegion<byte>& buf);
+
+ Protocol_Version m_version;
+ MemoryVector<byte> m_session_id, m_random;
+ std::vector<u16bit> m_suites;
+ std::vector<byte> m_comp_methods;
+ std::string m_hostname;
+ std::string m_srp_identifier;
+ bool m_next_protocol;
+
+ size_t m_fragment_size;
+ bool m_secure_renegotiation;
+ MemoryVector<byte> m_renegotiation_info;
+
+ std::vector<std::pair<std::string, std::string> > m_supported_algos;
+ std::vector<std::string> m_supported_curves;
+
+ bool m_supports_session_ticket;
+ MemoryVector<byte> m_session_ticket;
+
+ bool m_supports_heartbeats;
+ bool m_peer_can_send_heartbeats;
+ };
+
+/**
+* Server Hello Message
+*/
+class Server_Hello : public Handshake_Message
+ {
+ public:
+ Handshake_Type type() const { return SERVER_HELLO; }
+
+ 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 m_ciphersuite; }
+
+ byte compression_method() const { return m_comp_method; }
+
+ bool secure_renegotiation() const { return m_secure_renegotiation; }
+
+ bool next_protocol_notification() const { return m_next_protocol; }
+
+ bool supports_session_ticket() const { return m_supports_session_ticket; }
+
+ const std::vector<std::string>& next_protocols() const
+ { return m_next_protocols; }
+
+ size_t fragment_size() const { return m_fragment_size; }
+
+ const MemoryVector<byte>& renegotiation_info()
+ { return m_renegotiation_info; }
+
+ bool supports_heartbeats() const { return m_supports_heartbeats; }
+
+ bool peer_can_send_heartbeats() const { return m_peer_can_send_heartbeats; }
+
+ Server_Hello(Record_Writer& writer,
+ Handshake_Hash& hash,
+ const MemoryRegion<byte>& session_id,
+ Protocol_Version ver,
+ u16bit ciphersuite,
+ byte compression,
+ size_t max_fragment_size,
+ bool client_has_secure_renegotiation,
+ const MemoryRegion<byte>& reneg_info,
+ 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 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;
+ MemoryVector<byte> m_renegotiation_info;
+
+ 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;
+ };
+
+/**
+* Client Key Exchange Message
+*/
+class Client_Key_Exchange : public Handshake_Message
+ {
+ public:
+ Handshake_Type type() const { return CLIENT_KEX; }
+
+ const SecureVector<byte>& pre_master_secret() const
+ { return pre_master; }
+
+ Client_Key_Exchange(Record_Writer& output,
+ 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,
+ const Handshake_State* state,
+ Credentials_Manager& creds,
+ const Policy& policy,
+ RandomNumberGenerator& rng);
+
+ private:
+ MemoryVector<byte> serialize() const { return key_material; }
+
+ SecureVector<byte> key_material, pre_master;
+ };
+
+/**
+* Certificate Message
+*/
+class Certificate : public Handshake_Message
+ {
+ public:
+ Handshake_Type type() const { return CERTIFICATE; }
+ const std::vector<X509_Certificate>& cert_chain() const { return m_certs; }
+
+ size_t count() const { return m_certs.size(); }
+ bool empty() const { return m_certs.empty(); }
+
+ Certificate(Record_Writer& writer,
+ Handshake_Hash& hash,
+ const std::vector<X509_Certificate>& certs);
+
+ Certificate(const MemoryRegion<byte>& buf);
+ private:
+ MemoryVector<byte> serialize() const;
+
+ std::vector<X509_Certificate> m_certs;
+ };
+
+/**
+* Certificate Request Message
+*/
+class Certificate_Req : public Handshake_Message
+ {
+ public:
+ Handshake_Type type() const { return CERTIFICATE_REQUEST; }
+
+ const std::vector<std::string>& acceptable_cert_types() const
+ { return cert_key_types; }
+
+ std::vector<X509_DN> acceptable_CAs() const { return names; }
+
+ std::vector<std::pair<std::string, std::string> > supported_algos() const
+ { return m_supported_algos; }
+
+ Certificate_Req(Record_Writer& writer,
+ Handshake_Hash& hash,
+ const Policy& policy,
+ const std::vector<X509_Certificate>& allowed_cas,
+ Protocol_Version version);
+
+ Certificate_Req(const MemoryRegion<byte>& buf,
+ Protocol_Version version);
+ private:
+ MemoryVector<byte> serialize() const;
+
+ std::vector<X509_DN> names;
+ std::vector<std::string> cert_key_types;
+
+ std::vector<std::pair<std::string, std::string> > m_supported_algos;
+ };
+
+/**
+* Certificate Verify Message
+*/
+class Certificate_Verify : public Handshake_Message
+ {
+ public:
+ Handshake_Type type() const { return CERTIFICATE_VERIFY; }
+
+ /**
+ * Check the signature on a certificate verify message
+ * @param cert the purported certificate
+ * @param state the handshake state
+ */
+ bool verify(const X509_Certificate& cert,
+ Handshake_State* state);
+
+ Certificate_Verify(Record_Writer& writer,
+ Handshake_State* state,
+ RandomNumberGenerator& rng,
+ const Private_Key* key);
+
+ Certificate_Verify(const MemoryRegion<byte>& buf,
+ Protocol_Version version);
+ private:
+ MemoryVector<byte> serialize() const;
+
+ std::string sig_algo; // sig algo used to create signature
+ std::string hash_algo; // hash used to create signature
+ MemoryVector<byte> signature;
+ };
+
+/**
+* Finished Message
+*/
+class Finished : public Handshake_Message
+ {
+ public:
+ Handshake_Type type() const { return FINISHED; }
+
+ MemoryVector<byte> verify_data() const
+ { return verification_data; }
+
+ bool verify(Handshake_State* state,
+ Connection_Side side);
+
+ Finished(Record_Writer& writer,
+ Handshake_State* state,
+ Connection_Side side);
+
+ Finished(const MemoryRegion<byte>& buf);
+ private:
+ MemoryVector<byte> serialize() const;
+
+ Connection_Side side;
+ MemoryVector<byte> verification_data;
+ };
+
+/**
+* Hello Request Message
+*/
+class Hello_Request : public Handshake_Message
+ {
+ public:
+ Handshake_Type type() const { return HELLO_REQUEST; }
+
+ Hello_Request(Record_Writer& writer);
+ Hello_Request(const MemoryRegion<byte>& buf);
+ private:
+ MemoryVector<byte> serialize() const;
+ };
+
+/**
+* Server Key Exchange Message
+*/
+class Server_Key_Exchange : public Handshake_Message
+ {
+ public:
+ Handshake_Type type() const { return SERVER_KEX; }
+
+ const MemoryVector<byte>& params() const { return m_params; }
+
+ bool verify(const X509_Certificate& cert,
+ Handshake_State* state) const;
+
+ // 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,
+ Credentials_Manager& creds,
+ RandomNumberGenerator& rng,
+ const Private_Key* signing_key = 0);
+
+ Server_Key_Exchange(const MemoryRegion<byte>& buf,
+ const std::string& kex_alg,
+ const std::string& sig_alg,
+ Protocol_Version version);
+
+ ~Server_Key_Exchange();
+ private:
+ MemoryVector<byte> serialize() const;
+
+ Private_Key* m_kex_key;
+ SRP6_Server_Session* m_srp_params;
+
+ MemoryVector<byte> m_params;
+
+ std::string m_sig_algo; // sig algo used to create signature
+ std::string m_hash_algo; // hash used to create signature
+ MemoryVector<byte> m_signature;
+ };
+
+/**
+* Server Hello Done Message
+*/
+class Server_Hello_Done : public Handshake_Message
+ {
+ public:
+ Handshake_Type type() const { return SERVER_HELLO_DONE; }
+
+ Server_Hello_Done(Record_Writer& writer, Handshake_Hash& hash);
+ Server_Hello_Done(const MemoryRegion<byte>& buf);
+ private:
+ MemoryVector<byte> serialize() const;
+ };
+
+/**
+* Next Protocol Message
+*/
+class Next_Protocol : public Handshake_Message
+ {
+ public:
+ Handshake_Type type() const { return NEXT_PROTOCOL; }
+
+ std::string protocol() const { return m_protocol; }
+
+ Next_Protocol(Record_Writer& writer,
+ Handshake_Hash& hash,
+ const std::string& protocol);
+
+ Next_Protocol(const MemoryRegion<byte>& buf);
+ private:
+ MemoryVector<byte> serialize() const;
+
+ std::string m_protocol;
+ };
+
+class New_Session_Ticket : public Handshake_Message
+ {
+ public:
+ Handshake_Type type() const { return NEW_SESSION_TICKET; }
+
+ u32bit ticket_lifetime_hint() const { return m_ticket_lifetime_hint; }
+ const MemoryVector<byte>& ticket() const { return m_ticket; }
+
+ New_Session_Ticket(Record_Writer& writer,
+ Handshake_Hash& hash,
+ const MemoryRegion<byte>& ticket,
+ u32bit lifetime);
+
+ New_Session_Ticket(Record_Writer& writer,
+ Handshake_Hash& hash);
+
+ New_Session_Ticket(const MemoryRegion<byte>& buf);
+ private:
+ MemoryVector<byte> serialize() const;
+
+ u32bit m_ticket_lifetime_hint;
+ MemoryVector<byte> m_ticket;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/tls/tls_policy.cpp b/src/tls/tls_policy.cpp
new file mode 100644
index 000000000..f240bebac
--- /dev/null
+++ b/src/tls/tls_policy.cpp
@@ -0,0 +1,265 @@
+/*
+* Policies for TLS
+* (C) 2004-2010,2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_policy.h>
+#include <botan/tls_ciphersuite.h>
+#include <botan/tls_magic.h>
+#include <botan/tls_exceptn.h>
+#include <botan/internal/stl_util.h>
+
+namespace Botan {
+
+namespace TLS {
+
+std::vector<std::string> Policy::allowed_ciphers() const
+ {
+ std::vector<std::string> allowed;
+
+ allowed.push_back("AES-256");
+ allowed.push_back("AES-128");
+ allowed.push_back("3DES");
+ allowed.push_back("ARC4");
+ //allowed.push_back("Camellia");
+ //allowed.push_back("SEED");
+
+ return allowed;
+ }
+
+std::vector<std::string> Policy::allowed_hashes() const
+ {
+ std::vector<std::string> allowed;
+
+ allowed.push_back("SHA-512");
+ allowed.push_back("SHA-384");
+ allowed.push_back("SHA-256");
+ allowed.push_back("SHA-224");
+ allowed.push_back("SHA-1");
+ //allowed.push_back("MD5");
+
+ return allowed;
+ }
+
+std::vector<std::string> Policy::allowed_key_exchange_methods() const
+ {
+ std::vector<std::string> allowed;
+
+ 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");
+
+ return allowed;
+ }
+
+std::vector<std::string> Policy::allowed_signature_methods() const
+ {
+ std::vector<std::string> allowed;
+
+ allowed.push_back("ECDSA");
+ allowed.push_back("RSA");
+ allowed.push_back("DSA");
+ //allowed.push_back("");
+
+ return allowed;
+ }
+
+std::vector<std::string> Policy::allowed_ecc_curves() const
+ {
+ std::vector<std::string> curves;
+ curves.push_back("secp521r1");
+ curves.push_back("secp384r1");
+ curves.push_back("secp256r1");
+ curves.push_back("secp256k1");
+ curves.push_back("secp224r1");
+ curves.push_back("secp224k1");
+ curves.push_back("secp192r1");
+ curves.push_back("secp192k1");
+ curves.push_back("secp160r2");
+ curves.push_back("secp160r1");
+ curves.push_back("secp160k1");
+ 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;
+ }
+
+Protocol_Version Policy::pref_version() const
+ {
+ return Protocol_Version::TLS_V12;
+ }
+
+namespace {
+
+class Ciphersuite_Preference_Ordering
+ {
+ public:
+ Ciphersuite_Preference_Ordering(const std::vector<std::string>& ciphers,
+ const std::vector<std::string>& hashes,
+ const std::vector<std::string>& kex,
+ const std::vector<std::string>& sigs) :
+ m_ciphers(ciphers), m_hashes(hashes), m_kex(kex), m_sigs(sigs) {}
+
+ bool operator()(const Ciphersuite& a, const Ciphersuite& b) const
+ {
+ if(a.kex_algo() != b.kex_algo())
+ {
+ for(size_t i = 0; i != m_kex.size(); ++i)
+ {
+ if(a.kex_algo() == m_kex[i])
+ return true;
+ if(b.kex_algo() == m_kex[i])
+ return false;
+ }
+ }
+
+ if(a.cipher_algo() != b.cipher_algo())
+ {
+ for(size_t i = 0; i != m_ciphers.size(); ++i)
+ {
+ if(a.cipher_algo() == m_ciphers[i])
+ return true;
+ if(b.cipher_algo() == m_ciphers[i])
+ return false;
+ }
+ }
+
+ if(a.cipher_keylen() != b.cipher_keylen())
+ {
+ if(a.cipher_keylen() < b.cipher_keylen())
+ return false;
+ if(a.cipher_keylen() > b.cipher_keylen())
+ return true;
+ }
+
+ if(a.sig_algo() != b.sig_algo())
+ {
+ for(size_t i = 0; i != m_sigs.size(); ++i)
+ {
+ if(a.sig_algo() == m_sigs[i])
+ return true;
+ if(b.sig_algo() == m_sigs[i])
+ return false;
+ }
+ }
+
+ if(a.mac_algo() != b.mac_algo())
+ {
+ for(size_t i = 0; i != m_hashes.size(); ++i)
+ {
+ if(a.mac_algo() == m_hashes[i])
+ return true;
+ if(b.mac_algo() == m_hashes[i])
+ return false;
+ }
+ }
+
+ return false; // equal (?!?)
+ }
+ private:
+ std::vector<std::string> m_ciphers, m_hashes, m_kex, m_sigs;
+
+ };
+
+}
+
+std::vector<u16bit> ciphersuite_list(const Policy& policy,
+ bool have_srp)
+ {
+ 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);
+
+ std::map<Ciphersuite, u16bit, Ciphersuite_Preference_Ordering>
+ ciphersuites(order);
+
+ for(size_t i = 0; i != 65536; ++i)
+ {
+ Ciphersuite suite = Ciphersuite::by_id(i);
+
+ if(!suite.valid())
+ continue; // not a ciphersuite we know, skip
+
+ 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()))
+ {
+ // 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;
+
+ for(std::map<Ciphersuite, u16bit, Ciphersuite_Preference_Ordering>::iterator i = ciphersuites.begin();
+ i != ciphersuites.end(); ++i)
+ {
+ ciphersuite_codes.push_back(i->second);
+ }
+
+ return ciphersuite_codes;
+ }
+
+}
+
+}
diff --git a/src/tls/tls_policy.h b/src/tls/tls_policy.h
new file mode 100644
index 000000000..c3a0fc29e
--- /dev/null
+++ b/src/tls/tls_policy.h
@@ -0,0 +1,127 @@
+/*
+* Policies
+* (C) 2004-2006 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_POLICY_H__
+#define BOTAN_TLS_POLICY_H__
+
+#include <botan/tls_version.h>
+#include <botan/x509cert.h>
+#include <botan/dl_group.h>
+#include <vector>
+
+namespace Botan {
+
+namespace TLS {
+
+/**
+* TLS Policy Base Class
+* Inherit and overload as desired to suit local policy concerns
+*/
+class BOTAN_DLL Policy
+ {
+ public:
+
+ /**
+ * Returns a list of ciphers we are willing to negotiate, in
+ * order of preference. Allowed values: any block cipher name, or
+ * ARC4.
+ */
+ virtual std::vector<std::string> allowed_ciphers() const;
+
+ /**
+ * Returns a list of hash algorithms we are willing to use, in
+ * order of preference. This is used for both MACs and signatures.
+ * Allowed values: any hash name, though currently only MD5,
+ * SHA-1, and the SHA-2 variants are used.
+ */
+ virtual std::vector<std::string> allowed_hashes() const;
+
+ /**
+ * Returns a list of key exchange algorithms we are willing to
+ * use, in order of preference. Allowed values: DH, empty string
+ * (representing RSA using server certificate key)
+ */
+ virtual std::vector<std::string> allowed_key_exchange_methods() const;
+
+ /**
+ * Returns a list of signature algorithms we are willing to
+ * use, in order of preference. Allowed values RSA and DSA.
+ */
+ virtual std::vector<std::string> allowed_signature_methods() const;
+
+ /**
+ * Return list of ECC curves we are willing to use in order of preference
+ */
+ virtual std::vector<std::string> allowed_ecc_curves() const;
+
+ /**
+ * Returns a list of signature algorithms we are willing to use,
+ * in order of preference. Allowed values any value of
+ * Compression_Method.
+ */
+ virtual std::vector<byte> compression() const;
+
+ /**
+ * Choose an elliptic curve to use
+ */
+ virtual std::string choose_curve(const std::vector<std::string>& curve_names) const;
+
+ /**
+ * Require support for RFC 5746 extensions to enable
+ * renegotiation.
+ *
+ * @warning Changing this to false exposes you to injected
+ * plaintext attacks. Read the RFC for background.
+ */
+ virtual bool require_secure_renegotiation() const { return true; }
+
+ /**
+ * Return the group to use for ephemeral Diffie-Hellman key agreement
+ */
+ 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 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;
+
+ /**
+ * @return the version we would prefer to negotiate
+ */
+ virtual Protocol_Version pref_version() const;
+
+ virtual ~Policy() {}
+ };
+
+/**
+* Return allowed ciphersuites, in order of preference
+*/
+std::vector<u16bit> ciphersuite_list(const Policy& policy,
+ bool have_srp);
+
+}
+
+}
+
+#endif
diff --git a/src/ssl/tls_reader.h b/src/tls/tls_reader.h
index 3a45235b5..bf8098bed 100644
--- a/src/ssl/tls_reader.h
+++ b/src/tls/tls_reader.h
@@ -1,6 +1,6 @@
/*
* TLS Data Reader
-* (C) 2010 Jack Lloyd
+* (C) 2010-2011 Jack Lloyd
*
* Released under the terms of the Botan license
*/
@@ -8,11 +8,17 @@
#ifndef BOTAN_TLS_READER_H__
#define BOTAN_TLS_READER_H__
+#include <botan/exceptn.h>
#include <botan/secmem.h>
#include <botan/loadstor.h>
+#include <string>
+#include <vector>
+#include <stdexcept>
namespace Botan {
+namespace TLS {
+
/**
* Helper class for decoding TLS protocol messages
*/
@@ -22,6 +28,12 @@ class TLS_Data_Reader
TLS_Data_Reader(const MemoryRegion<byte>& buf_in) :
buf(buf_in), offset(0) {}
+ void assert_done() const
+ {
+ if(has_remaining())
+ throw Decoding_Error("Extra bytes at end of message");
+ }
+
size_t remaining_bytes() const
{
return buf.size() - offset;
@@ -38,6 +50,15 @@ class TLS_Data_Reader
offset += bytes;
}
+ u16bit get_u32bit()
+ {
+ assert_at_least(4);
+ u16bit result = make_u32bit(buf[offset ], buf[offset+1],
+ buf[offset+2], buf[offset+3]);
+ offset += 4;
+ return result;
+ }
+
u16bit get_u16bit()
{
assert_at_least(2);
@@ -91,6 +112,16 @@ class TLS_Data_Reader
return get_elem<T, std::vector<T> >(num_elems);
}
+ std::string get_string(size_t len_bytes,
+ size_t min_bytes,
+ size_t max_bytes)
+ {
+ std::vector<byte> v =
+ get_range_vector<byte>(len_bytes, min_bytes, max_bytes);
+
+ return std::string(reinterpret_cast<char*>(&v[0]), v.size());
+ }
+
template<typename T>
SecureVector<T> get_fixed(size_t size)
{
@@ -131,7 +162,11 @@ class TLS_Data_Reader
void assert_at_least(size_t n) const
{
if(buf.size() - offset < n)
- throw Decoding_Error("TLS_Data_Reader: Corrupt packet");
+ {
+ throw Decoding_Error("TLS_Data_Reader: Expected " + std::to_string(n) +
+ " bytes remaining, only " + std::to_string(buf.size()-offset) +
+ " left");
+ }
}
const MemoryRegion<byte>& buf;
@@ -181,6 +216,18 @@ void append_tls_length_value(MemoryRegion<byte>& buf,
append_tls_length_value(buf, &vals[0], vals.size(), tag_size);
}
+inline void append_tls_length_value(MemoryRegion<byte>& buf,
+ const std::string& str,
+ size_t tag_size)
+ {
+ append_tls_length_value(buf,
+ reinterpret_cast<const byte*>(&str[0]),
+ str.size(),
+ tag_size);
+ }
+
+}
+
}
#endif
diff --git a/src/tls/tls_record.h b/src/tls/tls_record.h
new file mode 100644
index 000000000..3b44ee1c6
--- /dev/null
+++ b/src/tls/tls_record.h
@@ -0,0 +1,136 @@
+/*
+* TLS Record Handling
+* (C) 2004-2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_RECORDS_H__
+#define BOTAN_TLS_RECORDS_H__
+
+#include <botan/tls_ciphersuite.h>
+#include <botan/tls_alert.h>
+#include <botan/tls_magic.h>
+#include <botan/tls_version.h>
+#include <botan/pipe.h>
+#include <botan/mac.h>
+#include <botan/secqueue.h>
+#include <vector>
+#include <functional>
+
+namespace Botan {
+
+namespace TLS {
+
+class Session_Keys;
+
+/**
+* TLS Record Writer
+*/
+class BOTAN_DLL Record_Writer
+ {
+ public:
+ 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);
+
+ void activate(Connection_Side side,
+ const Ciphersuite& suite,
+ const Session_Keys& keys,
+ byte compression_method);
+
+ void set_version(Protocol_Version version);
+
+ void reset();
+
+ void set_maximum_fragment_size(size_t max_fragment);
+
+ Record_Writer(std::function<void (const byte[], size_t)> output_fn);
+
+ ~Record_Writer() { delete m_mac; }
+ private:
+ Record_Writer(const Record_Writer&) {}
+ Record_Writer& operator=(const Record_Writer&) { return (*this); }
+
+ void send_record(byte type, const byte input[], size_t length);
+
+ std::function<void (const byte[], size_t)> m_output_fn;
+
+ MemoryVector<byte> m_writebuf;
+
+ Pipe m_cipher;
+ MessageAuthenticationCode* m_mac;
+
+ size_t m_block_size, m_mac_size, m_iv_size, m_max_fragment;
+
+ u64bit m_seq_no;
+ Protocol_Version m_version;
+ };
+
+/**
+* TLS Record Reader
+*/
+class BOTAN_DLL Record_Reader
+ {
+ public:
+
+ /**
+ * @param input new input data (may be NULL if input_size == 0)
+ * @param input_size size of input in bytes
+ * @param input_consumed is set to the number of bytes of input
+ * that were consumed
+ * @param msg_type is set to the type of the message just read if
+ * this function returns 0
+ * @param msg is set to the contents of the record
+ * @return number of bytes still needed (minimum), or 0 if success
+ */
+ size_t add_input(const byte input[], size_t input_size,
+ size_t& input_consumed,
+ byte& msg_type,
+ MemoryVector<byte>& msg);
+
+ void activate(Connection_Side side,
+ const Ciphersuite& suite,
+ const Session_Keys& keys,
+ byte compression_method);
+
+ void set_version(Protocol_Version version);
+
+ void reset();
+
+ void set_maximum_fragment_size(size_t max_fragment);
+
+ Record_Reader();
+
+ ~Record_Reader() { delete m_mac; }
+ private:
+ Record_Reader(const Record_Reader&) {}
+ Record_Reader& operator=(const Record_Reader&) { return (*this); }
+
+ size_t fill_buffer_to(const byte*& input,
+ size_t& input_size,
+ size_t& input_consumed,
+ size_t desired);
+
+ MemoryVector<byte> m_readbuf;
+ MemoryVector<byte> m_macbuf;
+ size_t m_readbuf_pos;
+
+ Pipe m_cipher;
+ MessageAuthenticationCode* m_mac;
+ size_t m_block_size, m_iv_size, m_max_fragment;
+ u64bit m_seq_no;
+ Protocol_Version m_version;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/tls/tls_server.cpp b/src/tls/tls_server.cpp
new file mode 100644
index 000000000..1e8c73ec3
--- /dev/null
+++ b/src/tls/tls_server.cpp
@@ -0,0 +1,620 @@
+/*
+* TLS Server
+* (C) 2004-2011,2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_server.h>
+#include <botan/internal/tls_handshake_state.h>
+#include <botan/internal/tls_messages.h>
+#include <botan/internal/stl_util.h>
+#include <botan/internal/assert.h>
+#include <memory>
+
+namespace Botan {
+
+namespace TLS {
+
+namespace {
+
+bool check_for_resume(Session& session_info,
+ Session_Manager& session_manager,
+ Credentials_Manager& credentials,
+ Client_Hello* client_hello,
+ std::chrono::seconds session_ticket_lifetime)
+ {
+ const MemoryVector<byte>& client_session_id = client_hello->session_id();
+ const MemoryVector<byte>& session_ticket = client_hello->session_ticket();
+
+ if(session_ticket.empty())
+ {
+ if(client_session_id.empty()) // not resuming
+ return false;
+
+ // not found
+ if(!session_manager.load_from_session_id(client_session_id, session_info))
+ return false;
+ }
+ else
+ {
+ // If a session ticket was sent, ignore client session ID
+ try
+ {
+ session_info = Session::decrypt(
+ session_ticket,
+ credentials.psk("tls-server", "session-ticket", ""));
+
+ if(session_ticket_lifetime != std::chrono::seconds(0) &&
+ session_info.session_age() > session_ticket_lifetime)
+ return false; // ticket has expired
+ }
+ catch(...)
+ {
+ return false;
+ }
+ }
+
+ // wrong version
+ if(client_hello->version() != session_info.version())
+ return false;
+
+ // client didn't send original ciphersuite
+ if(!value_exists(client_hello->ciphersuites(),
+ session_info.ciphersuite_code()))
+ return false;
+
+ // client didn't send original compression method
+ if(!value_exists(client_hello->compression_methods(),
+ session_info.compression_method()))
+ return false;
+
+ // client sent a different SRP identity
+ if(client_hello->srp_identifier() != "")
+ {
+ if(client_hello->srp_identifier() != session_info.srp_identifier())
+ return false;
+ }
+
+ // client sent a different SNI hostname
+ if(client_hello->sni_hostname() != "")
+ {
+ if(client_hello->sni_hostname() != session_info.sni_hostname())
+ return false;
+ }
+
+ 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)
+ {
+ const char* cert_types[] = { "RSA", "DSA", "ECDSA", 0 };
+
+ std::map<std::string, std::vector<X509_Certificate> > cert_chains;
+
+ for(size_t i = 0; cert_types[i]; ++i)
+ {
+ std::vector<X509_Certificate> certs =
+ creds.cert_chain_single_type(cert_types[i], "tls-server", hostname);
+
+ if(!certs.empty())
+ cert_chains[cert_types[i]] = certs;
+ }
+
+ return cert_chains;
+ }
+
+}
+
+/*
+* 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,
+ Session_Manager& session_manager,
+ Credentials_Manager& creds,
+ const Policy& policy,
+ RandomNumberGenerator& rng,
+ const std::vector<std::string>& next_protocols) :
+ Channel(output_fn, proc_fn, handshake_fn),
+ policy(policy),
+ rng(rng),
+ session_manager(session_manager),
+ creds(creds),
+ m_possible_protocols(next_protocols)
+ {
+ }
+
+/*
+* Send a hello request to the client
+*/
+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);
+ }
+
+void Server::alert_notify(const Alert& alert)
+ {
+ if(alert.type() == Alert::NO_RENEGOTIATION)
+ {
+ if(handshake_completed && state)
+ {
+ delete state;
+ state = 0;
+ }
+ }
+ }
+
+/*
+* Split up and process handshake messages
+*/
+void Server::read_handshake(byte rec_type,
+ const MemoryRegion<byte>& rec_buf)
+ {
+ if(rec_type == HANDSHAKE && !state)
+ {
+ state = new Handshake_State(new Stream_Handshake_Reader);
+ state->set_expected_next(CLIENT_HELLO);
+ }
+
+ Channel::read_handshake(rec_type, rec_buf);
+ }
+
+/*
+* Process a handshake message
+*/
+void Server::process_handshake_msg(Handshake_Type type,
+ const MemoryRegion<byte>& contents)
+ {
+ if(state == 0)
+ throw Unexpected_Message("Unexpected handshake message from client");
+
+ state->confirm_transition_to(type);
+
+ /*
+ * The change cipher spec message isn't technically a handshake
+ * message so it's not included in the hash. The finished and
+ * certificate verify messages are verified based on the current
+ * state of the hash *before* this message so we delay adding them
+ * to the hash computation until we've processed them below.
+ */
+ if(type != HANDSHAKE_CCS && type != FINISHED && type != CERTIFICATE_VERIFY)
+ {
+ if(type == CLIENT_HELLO_SSLV2)
+ state->hash.update(contents);
+ else
+ state->hash.update(type, contents);
+ }
+
+ if(type == CLIENT_HELLO || type == CLIENT_HELLO_SSLV2)
+ {
+ state->client_hello = new Client_Hello(contents, type);
+
+ if(state->client_hello->sni_hostname() != "")
+ m_hostname = state->client_hello->sni_hostname();
+
+ Protocol_Version client_version = state->client_hello->version();
+
+ if(client_version < policy.min_version())
+ throw TLS_Exception(Alert::PROTOCOL_VERSION,
+ "Client version is unacceptable by policy");
+
+ if(client_version <= policy.pref_version())
+ state->set_version(client_version);
+ else
+ state->set_version(policy.pref_version());
+
+ 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 =
+ state->allow_session_resumption &&
+ check_for_resume(session_info,
+ session_manager,
+ creds,
+ state->client_hello,
+ std::chrono::seconds(policy.session_ticket_lifetime()));
+
+ bool have_session_ticket_key = false;
+
+ try
+ {
+ have_session_ticket_key =
+ creds.psk("tls-server", "session-ticket", "").length() > 0;
+ }
+ catch(...) {}
+
+ if(resuming)
+ {
+ // resume session
+
+ state->server_hello = new Server_Hello(
+ writer,
+ state->hash,
+ state->client_hello->session_id(),
+ Protocol_Version(session_info.version()),
+ session_info.ciphersuite_code(),
+ session_info.compression_method(),
+ session_info.fragment_size(),
+ secure_renegotiation.supported(),
+ secure_renegotiation.for_server_hello(),
+ (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());
+ writer.set_maximum_fragment_size(session_info.fragment_size());
+ }
+
+ state->suite = Ciphersuite::by_id(state->server_hello->ciphersuite());
+
+ state->keys = Session_Keys(state, session_info.master_secret(), true);
+
+ if(!handshake_fn(session_info))
+ {
+ 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);
+ }
+
+ if(state->server_hello->supports_session_ticket() && !state->new_session_ticket)
+ {
+ try
+ {
+ const SymmetricKey ticket_key = creds.psk("tls-server", "session-ticket", "");
+
+ state->new_session_ticket =
+ new New_Session_Ticket(writer, state->hash,
+ session_info.encrypt(ticket_key, rng),
+ policy.session_ticket_lifetime());
+ }
+ catch(...) {}
+
+ if(!state->new_session_ticket)
+ state->new_session_ticket = new New_Session_Ticket(writer, state->hash);
+ }
+
+ writer.send(CHANGE_CIPHER_SPEC, 1);
+
+ writer.activate(SERVER, state->suite, state->keys,
+ state->server_hello->compression_method());
+
+ state->server_finished = new Finished(writer, state, SERVER);
+
+ state->set_expected_next(HANDSHAKE_CCS);
+ }
+ else // new session
+ {
+ std::map<std::string, std::vector<X509_Certificate> > cert_chains;
+
+ cert_chains = get_server_certs(m_hostname, creds);
+
+ if(m_hostname != "" && cert_chains.empty())
+ {
+ send_alert(Alert(Alert::UNRECOGNIZED_NAME));
+ cert_chains = get_server_certs("", creds);
+ }
+
+ state->server_hello = new Server_Hello(
+ writer,
+ state->hash,
+ rng.random_vec(32), // new session ID
+ state->version(),
+ 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());
+ writer.set_maximum_fragment_size(state->client_hello->fragment_size());
+ }
+
+ state->suite = Ciphersuite::by_id(state->server_hello->ciphersuite());
+
+ const std::string sig_algo = state->suite.sig_algo();
+ const std::string kex_algo = state->suite.kex_algo();
+
+ if(sig_algo != "")
+ {
+ BOTAN_ASSERT(!cert_chains[sig_algo].empty(),
+ "Attempting to send empty certificate chain");
+
+ state->server_certs = new Certificate(writer,
+ state->hash,
+ cert_chains[sig_algo]);
+ }
+
+ Private_Key* private_key = 0;
+
+ if(kex_algo == "RSA" || sig_algo != "")
+ {
+ private_key = creds.private_key_for(state->server_certs->cert_chain()[0],
+ "tls-server",
+ m_hostname);
+
+ if(!private_key)
+ throw Internal_Error("No private key located for associated server cert");
+ }
+
+ if(kex_algo == "RSA")
+ {
+ state->server_rsa_kex_key = private_key;
+ }
+ else
+ {
+ state->server_kex =
+ new Server_Key_Exchange(writer, state, policy, creds, rng, private_key);
+ }
+
+ std::vector<X509_Certificate> client_auth_CAs =
+ creds.trusted_certificate_authorities("tls-server", m_hostname);
+
+ if(!client_auth_CAs.empty() && state->suite.sig_algo() != "")
+ {
+ state->cert_req = new Certificate_Req(writer,
+ state->hash,
+ policy,
+ client_auth_CAs,
+ state->version());
+
+ state->set_expected_next(CERTIFICATE);
+ }
+
+ /*
+ * If the client doesn't have a cert they want to use they are
+ * allowed to send either an empty cert message or proceed
+ * directly to the client key exchange, so allow either case.
+ */
+ state->set_expected_next(CLIENT_KEX);
+
+ state->server_hello_done = new Server_Hello_Done(writer, state->hash);
+ }
+ }
+ else if(type == CERTIFICATE)
+ {
+ state->client_certs = new Certificate(contents);
+
+ state->set_expected_next(CLIENT_KEX);
+ }
+ else if(type == CLIENT_KEX)
+ {
+ if(state->received_handshake_msg(CERTIFICATE) && !state->client_certs->empty())
+ state->set_expected_next(CERTIFICATE_VERIFY);
+ else
+ state->set_expected_next(HANDSHAKE_CCS);
+
+ state->client_kex = new Client_Key_Exchange(contents, state, creds, policy, rng);
+
+ state->keys = Session_Keys(state, state->client_kex->pre_master_secret(), false);
+ }
+ else if(type == CERTIFICATE_VERIFY)
+ {
+ state->client_verify = new Certificate_Verify(contents, state->version());
+
+ peer_certs = state->client_certs->cert_chain();
+
+ const bool sig_valid =
+ state->client_verify->verify(peer_certs[0], state);
+
+ state->hash.update(type, contents);
+
+ /*
+ * Using DECRYPT_ERROR looks weird here, but per RFC 4346 is for
+ * "A handshake cryptographic operation failed, including being
+ * unable to correctly verify a signature, ..."
+ */
+ if(!sig_valid)
+ throw TLS_Exception(Alert::DECRYPT_ERROR, "Client cert verify failed");
+
+ try
+ {
+ creds.verify_certificate_chain("tls-server", "", peer_certs);
+ }
+ catch(std::exception& e)
+ {
+ throw TLS_Exception(Alert::BAD_CERTIFICATE, e.what());
+ }
+
+ state->set_expected_next(HANDSHAKE_CCS);
+ }
+ else if(type == HANDSHAKE_CCS)
+ {
+ if(state->server_hello->next_protocol_notification())
+ state->set_expected_next(NEXT_PROTOCOL);
+ else
+ state->set_expected_next(FINISHED);
+
+ reader.activate(SERVER, state->suite, state->keys,
+ state->server_hello->compression_method());
+ }
+ else if(type == NEXT_PROTOCOL)
+ {
+ state->set_expected_next(FINISHED);
+
+ state->next_protocol = new Next_Protocol(contents);
+
+ m_next_protocol = state->next_protocol->protocol();
+ }
+ else if(type == FINISHED)
+ {
+ state->set_expected_next(HANDSHAKE_NONE);
+
+ state->client_finished = new Finished(contents);
+
+ if(!state->client_finished->verify(state, CLIENT))
+ throw TLS_Exception(Alert::DECRYPT_ERROR,
+ "Finished message didn't verify");
+
+ if(!state->server_finished)
+ {
+ // already sent finished if resuming, so this is a new session
+
+ state->hash.update(type, contents);
+
+ Session session_info(
+ state->server_hello->session_id(),
+ state->keys.master_secret(),
+ state->server_hello->version(),
+ state->server_hello->ciphersuite(),
+ state->server_hello->compression_method(),
+ SERVER,
+ secure_renegotiation.supported(),
+ state->server_hello->fragment_size(),
+ peer_certs,
+ MemoryVector<byte>(),
+ m_hostname,
+ state->srp_identifier()
+ );
+
+ if(handshake_fn(session_info))
+ {
+ if(state->server_hello->supports_session_ticket())
+ {
+ try
+ {
+ const SymmetricKey ticket_key = creds.psk("tls-server", "session-ticket", "");
+
+ state->new_session_ticket =
+ new New_Session_Ticket(writer, state->hash,
+ session_info.encrypt(ticket_key, rng),
+ policy.session_ticket_lifetime());
+ }
+ catch(...) {}
+ }
+ else
+ session_manager.save(session_info);
+ }
+
+ if(state->server_hello->supports_session_ticket() && !state->new_session_ticket)
+ state->new_session_ticket = new New_Session_Ticket(writer, state->hash);
+
+ writer.send(CHANGE_CIPHER_SPEC, 1);
+
+ writer.activate(SERVER, state->suite, state->keys,
+ state->server_hello->compression_method());
+
+ state->server_finished = new Finished(writer, state, SERVER);
+ }
+
+ secure_renegotiation.update(state->client_finished,
+ state->server_finished);
+
+ delete state;
+ state = 0;
+ handshake_completed = true;
+ }
+ else
+ throw Unexpected_Message("Unknown handshake message received");
+ }
+
+}
+
+}
diff --git a/src/tls/tls_server.h b/src/tls/tls_server.h
new file mode 100644
index 000000000..684021ebc
--- /dev/null
+++ b/src/tls/tls_server.h
@@ -0,0 +1,74 @@
+/*
+* TLS Server
+* (C) 2004-2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_SERVER_H__
+#define BOTAN_TLS_SERVER_H__
+
+#include <botan/tls_channel.h>
+#include <botan/tls_session_manager.h>
+#include <botan/credentials_manager.h>
+#include <vector>
+
+namespace Botan {
+
+namespace TLS {
+
+/**
+* TLS Server
+*/
+class BOTAN_DLL Server : public Channel
+ {
+ public:
+ /**
+ * 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,
+ Session_Manager& session_manager,
+ Credentials_Manager& creds,
+ const Policy& policy,
+ RandomNumberGenerator& rng,
+ const std::vector<std::string>& protocols =
+ std::vector<std::string>());
+
+ void renegotiate(bool force_full_renegotiation);
+
+ /**
+ * Return the server name indicator, if sent by the client
+ */
+ std::string server_name_indicator() const
+ { return m_hostname; }
+
+ /**
+ * Return the protocol negotiated with NPN extension
+ */
+ std::string next_protocol() const
+ { return m_next_protocol; }
+
+ private:
+ void read_handshake(byte, const MemoryRegion<byte>&);
+
+ void process_handshake_msg(Handshake_Type, const MemoryRegion<byte>&);
+
+ void alert_notify(const Alert& alert);
+
+ const Policy& policy;
+ RandomNumberGenerator& rng;
+ Session_Manager& session_manager;
+ Credentials_Manager& creds;
+
+ std::vector<std::string> m_possible_protocols;
+ std::string m_hostname;
+ std::string m_next_protocol;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/tls/tls_session.cpp b/src/tls/tls_session.cpp
new file mode 100644
index 000000000..dac38e67b
--- /dev/null
+++ b/src/tls/tls_session.cpp
@@ -0,0 +1,251 @@
+/*
+* TLS Session State
+* (C) 2011-2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_session.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/asn1_str.h>
+#include <botan/pem.h>
+#include <botan/lookup.h>
+#include <botan/loadstor.h>
+#include <memory>
+
+namespace Botan {
+
+namespace TLS {
+
+Session::Session(const MemoryRegion<byte>& session_identifier,
+ const MemoryRegion<byte>& master_secret,
+ Protocol_Version version,
+ u16bit ciphersuite,
+ byte compression_method,
+ Connection_Side side,
+ bool secure_renegotiation_supported,
+ size_t fragment_size,
+ const std::vector<X509_Certificate>& certs,
+ const MemoryRegion<byte>& ticket,
+ const std::string& sni_hostname,
+ const std::string& srp_identifier) :
+ m_start_time(std::chrono::system_clock::now()),
+ m_identifier(session_identifier),
+ m_session_ticket(ticket),
+ m_master_secret(master_secret),
+ m_version(version),
+ m_ciphersuite(ciphersuite),
+ m_compression_method(compression_method),
+ m_connection_side(side),
+ m_secure_renegotiation_supported(secure_renegotiation_supported),
+ m_fragment_size(fragment_size),
+ m_peer_certs(certs),
+ m_sni_hostname(sni_hostname),
+ m_srp_identifier(srp_identifier)
+ {
+ }
+
+Session::Session(const std::string& pem)
+ {
+ SecureVector<byte> der = PEM_Code::decode_check_label(pem, "SSL SESSION");
+
+ *this = Session(&der[0], der.size());
+ }
+
+Session::Session(const byte ber[], size_t ber_len)
+ {
+ byte side_code = 0;
+ ASN1_String sni_hostname_str;
+ ASN1_String srp_identifier_str;
+
+ byte major_version = 0, minor_version = 0;
+
+ 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(major_version)
+ .decode_integer_type(minor_version)
+ .decode(m_identifier, OCTET_STRING)
+ .decode(m_session_ticket, OCTET_STRING)
+ .decode_integer_type(m_ciphersuite)
+ .decode_integer_type(m_compression_method)
+ .decode_integer_type(side_code)
+ .decode_integer_type(m_fragment_size)
+ .decode(m_secure_renegotiation_supported)
+ .decode(m_master_secret, OCTET_STRING)
+ .decode(peer_cert_bits, OCTET_STRING)
+ .decode(sni_hostname_str)
+ .decode(srp_identifier_str)
+ .end_cons()
+ .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);
+
+ if(!peer_cert_bits.empty())
+ {
+ DataSource_Memory certs(peer_cert_bits);
+
+ while(!certs.end_of_data())
+ m_peer_certs.push_back(X509_Certificate(certs));
+ }
+ }
+
+SecureVector<byte> Session::DER_encode() const
+ {
+ MemoryVector<byte> peer_cert_bits;
+ for(size_t i = 0; i != m_peer_certs.size(); ++i)
+ peer_cert_bits += m_peer_certs[i].BER_encode();
+
+ 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_version.major_version()))
+ .encode(static_cast<size_t>(m_version.minor_version()))
+ .encode(m_identifier, OCTET_STRING)
+ .encode(m_session_ticket, OCTET_STRING)
+ .encode(static_cast<size_t>(m_ciphersuite))
+ .encode(static_cast<size_t>(m_compression_method))
+ .encode(static_cast<size_t>(m_connection_side))
+ .encode(static_cast<size_t>(m_fragment_size))
+ .encode(m_secure_renegotiation_supported)
+ .encode(m_master_secret, OCTET_STRING)
+ .encode(peer_cert_bits, OCTET_STRING)
+ .encode(ASN1_String(m_sni_hostname, UTF8_STRING))
+ .encode(ASN1_String(m_srp_identifier, UTF8_STRING))
+ .end_cons()
+ .get_contents();
+ }
+
+std::string Session::PEM_encode() const
+ {
+ return PEM_Code::encode(this->DER_encode(), "SSL SESSION");
+ }
+
+std::chrono::seconds Session::session_age() const
+ {
+ return std::chrono::duration_cast<std::chrono::seconds>(
+ std::chrono::system_clock::now() - m_start_time);
+ }
+
+namespace {
+
+const u32bit SESSION_CRYPTO_MAGIC = 0x571B0E4E;
+const std::string SESSION_CRYPTO_CIPHER = "AES-256/CBC";
+const std::string SESSION_CRYPTO_MAC = "HMAC(SHA-256)";
+const std::string SESSION_CRYPTO_KDF = "KDF2(SHA-256)";
+
+const size_t MAGIC_LENGTH = 4;
+const size_t MAC_KEY_LENGTH = 32;
+const size_t CIPHER_KEY_LENGTH = 32;
+const size_t CIPHER_IV_LENGTH = 16;
+const size_t MAC_OUTPUT_LENGTH = 32;
+
+}
+
+MemoryVector<byte>
+Session::encrypt(const SymmetricKey& master_key,
+ RandomNumberGenerator& rng) const
+ {
+ std::unique_ptr<KDF> kdf(get_kdf(SESSION_CRYPTO_KDF));
+
+ SymmetricKey cipher_key =
+ kdf->derive_key(CIPHER_KEY_LENGTH,
+ master_key.bits_of(),
+ "tls.session.cipher-key");
+
+ SymmetricKey mac_key =
+ kdf->derive_key(MAC_KEY_LENGTH,
+ master_key.bits_of(),
+ "tls.session.mac-key");
+
+ InitializationVector cipher_iv(rng, 16);
+
+ std::unique_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));
+ pipe.process_msg(this->DER_encode());
+ MemoryVector<byte> ctext = pipe.read_all(0);
+
+ MemoryVector<byte> out(MAGIC_LENGTH);
+ store_be(SESSION_CRYPTO_MAGIC, &out[0]);
+ out += cipher_iv.bits_of();
+ out += ctext;
+
+ mac->update(out);
+
+ out += mac->final();
+ return out;
+ }
+
+Session Session::decrypt(const byte buf[], size_t buf_len,
+ const SymmetricKey& master_key)
+ {
+ try
+ {
+ const size_t MIN_CTEXT_SIZE = 4 * 16; // due to 48 byte master secret
+
+ if(buf_len < (MAGIC_LENGTH +
+ CIPHER_IV_LENGTH +
+ MIN_CTEXT_SIZE +
+ MAC_OUTPUT_LENGTH))
+ throw Decoding_Error("Encrypted TLS session too short to be valid");
+
+ 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));
+
+ 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));
+ mac->set_key(mac_key);
+
+ mac->update(&buf[0], buf_len - MAC_OUTPUT_LENGTH);
+ MemoryVector<byte> computed_mac = mac->final();
+
+ if(!same_mem(&buf[buf_len - MAC_OUTPUT_LENGTH], &computed_mac[0], computed_mac.size()))
+ throw Decoding_Error("MAC verification failed for encrypted session");
+
+ SymmetricKey cipher_key =
+ kdf->derive_key(CIPHER_KEY_LENGTH,
+ master_key.bits_of(),
+ "tls.session.cipher-key");
+
+ InitializationVector cipher_iv(&buf[MAGIC_LENGTH], CIPHER_IV_LENGTH);
+
+ const size_t CTEXT_OFFSET = MAGIC_LENGTH + CIPHER_IV_LENGTH;
+
+ Pipe pipe(get_cipher(SESSION_CRYPTO_CIPHER, cipher_key, cipher_iv, DECRYPTION));
+ pipe.process_msg(&buf[CTEXT_OFFSET],
+ buf_len - (MAC_OUTPUT_LENGTH + CTEXT_OFFSET));
+ SecureVector<byte> ber = pipe.read_all();
+
+ return Session(&ber[0], ber.size());
+ }
+ catch(std::exception& e)
+ {
+ throw Decoding_Error("Failed to decrypt encrypted session -" +
+ std::string(e.what()));
+ }
+ }
+
+}
+
+}
+
diff --git a/src/tls/tls_session.h b/src/tls/tls_session.h
new file mode 100644
index 000000000..a2b341a30
--- /dev/null
+++ b/src/tls/tls_session.h
@@ -0,0 +1,217 @@
+/*
+* TLS Session
+* (C) 2011-2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_SESSION_STATE_H__
+#define BOTAN_TLS_SESSION_STATE_H__
+
+#include <botan/x509cert.h>
+#include <botan/tls_version.h>
+#include <botan/tls_ciphersuite.h>
+#include <botan/tls_magic.h>
+#include <botan/secmem.h>
+#include <botan/symkey.h>
+#include <chrono>
+
+namespace Botan {
+
+namespace TLS {
+
+/**
+* Class representing a TLS session state
+*/
+class BOTAN_DLL Session
+ {
+ public:
+
+ /**
+ * Uninitialized session
+ */
+ Session() :
+ m_start_time(std::chrono::system_clock::time_point::min()),
+ m_version(),
+ m_ciphersuite(0),
+ m_compression_method(0),
+ m_connection_side(static_cast<Connection_Side>(0)),
+ m_secure_renegotiation_supported(false),
+ m_fragment_size(0)
+ {}
+
+ /**
+ * New session (sets session start time)
+ */
+ Session(const MemoryRegion<byte>& session_id,
+ const MemoryRegion<byte>& master_secret,
+ Protocol_Version version,
+ u16bit ciphersuite,
+ byte compression_method,
+ Connection_Side side,
+ bool secure_renegotiation_supported,
+ size_t fragment_size,
+ const std::vector<X509_Certificate>& peer_certs,
+ const MemoryRegion<byte>& session_ticket,
+ const std::string& sni_hostname = "",
+ const std::string& srp_identifier = "");
+
+ /**
+ * Load a session from DER representation (created by DER_encode)
+ */
+ Session(const byte ber[], size_t ber_len);
+
+ /**
+ * Load a session from PEM representation (created by PEM_encode)
+ */
+ Session(const std::string& pem);
+
+ /**
+ * Encode this session data for storage
+ * @warning if the master secret is compromised so is the
+ * session traffic
+ */
+ SecureVector<byte> DER_encode() const;
+
+ /**
+ * Encrypt a session (useful for serialization or session tickets)
+ */
+ MemoryVector<byte> encrypt(const SymmetricKey& key,
+ RandomNumberGenerator& rng) const;
+
+
+ /**
+ * Decrypt a session created by encrypt
+ * @param ctext the ciphertext returned by encrypt
+ * @param ctext_size the size of ctext in bytes
+ * @param key the same key used by the encrypting side
+ */
+ static Session decrypt(const byte ctext[],
+ size_t ctext_size,
+ const SymmetricKey& key);
+
+ /**
+ * Decrypt a session created by encrypt
+ * @param ctext the ciphertext returned by encrypt
+ * @param key the same key used by the encrypting side
+ */
+ static inline Session decrypt(const MemoryRegion<byte>& ctext,
+ const SymmetricKey& key)
+ {
+ return Session::decrypt(&ctext[0], ctext.size(), key);
+ }
+
+ /**
+ * Encode this session data for storage
+ * @warning if the master secret is compromised so is the
+ * session traffic
+ */
+ std::string PEM_encode() const;
+
+ /**
+ * Get the version of the saved session
+ */
+ Protocol_Version version() const { return m_version; }
+
+ /**
+ * Get the ciphersuite code of the saved session
+ */
+ u16bit ciphersuite_code() const { return m_ciphersuite; }
+
+ /**
+ * Get the ciphersuite info of the saved session
+ */
+ Ciphersuite ciphersuite() const { return Ciphersuite::by_id(m_ciphersuite); }
+
+ /**
+ * Get the compression method used in the saved session
+ */
+ byte compression_method() const { return m_compression_method; }
+
+ /**
+ * Get which side of the connection the resumed session we are/were
+ * acting as.
+ */
+ Connection_Side side() const { return m_connection_side; }
+
+ /**
+ * Get the SNI hostname (if sent by the client in the initial handshake)
+ */
+ std::string sni_hostname() const { return m_sni_hostname; }
+
+ /**
+ * Get the SRP identity (if sent by the client in the initial handshake)
+ */
+ std::string srp_identifier() const { return m_srp_identifier; }
+
+ /**
+ * Get the saved master secret
+ */
+ const SecureVector<byte>& master_secret() const
+ { return m_master_secret; }
+
+ /**
+ * Get the session identifier
+ */
+ const MemoryVector<byte>& session_id() const
+ { return m_identifier; }
+
+ /**
+ * Get the negotiated maximum fragment size (or 0 if default)
+ */
+ size_t fragment_size() const { return m_fragment_size; }
+
+ /**
+ * Is secure renegotiation supported?
+ */
+ bool secure_renegotiation() const
+ { return m_secure_renegotiation_supported; }
+
+ /**
+ * Return the certificate chain of the peer (possibly empty)
+ */
+ std::vector<X509_Certificate> peer_certs() const { return m_peer_certs; }
+
+ /**
+ * Get the wall clock time this session began
+ */
+ std::chrono::system_clock::time_point start_time() const
+ { return m_start_time; }
+
+ /**
+ * Return how long this session has existed (in seconds)
+ */
+ std::chrono::seconds session_age() const;
+
+ /**
+ * Return the session ticket the server gave us
+ */
+ const MemoryVector<byte>& session_ticket() const { return m_session_ticket; }
+
+ private:
+ enum { TLS_SESSION_PARAM_STRUCT_VERSION = 0x2994e300 };
+
+ std::chrono::system_clock::time_point m_start_time;
+
+ MemoryVector<byte> m_identifier;
+ MemoryVector<byte> m_session_ticket; // only used by client side
+ SecureVector<byte> m_master_secret;
+
+ Protocol_Version m_version;
+ u16bit m_ciphersuite;
+ byte m_compression_method;
+ Connection_Side m_connection_side;
+
+ bool m_secure_renegotiation_supported;
+ size_t m_fragment_size;
+
+ std::vector<X509_Certificate> m_peer_certs;
+ std::string m_sni_hostname; // optional
+ std::string m_srp_identifier; // optional
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/tls/tls_session_key.cpp b/src/tls/tls_session_key.cpp
new file mode 100644
index 000000000..4d7603ce1
--- /dev/null
+++ b/src/tls/tls_session_key.cpp
@@ -0,0 +1,89 @@
+/*
+* TLS Session Key
+* (C) 2004-2006,2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/internal/tls_session_key.h>
+#include <botan/internal/tls_handshake_state.h>
+#include <botan/internal/tls_messages.h>
+#include <botan/lookup.h>
+#include <memory>
+
+namespace Botan {
+
+namespace TLS {
+
+/**
+* Session_Keys Constructor
+*/
+Session_Keys::Session_Keys(Handshake_State* state,
+ const MemoryRegion<byte>& pre_master_secret,
+ bool resuming)
+ {
+ const size_t mac_keylen = output_length_of(state->suite.mac_algo());
+ const size_t cipher_keylen = state->suite.cipher_keylen();
+
+ size_t cipher_ivlen = 0;
+ if(have_block_cipher(state->suite.cipher_algo()))
+ cipher_ivlen = block_size_of(state->suite.cipher_algo());
+
+ const size_t prf_gen = 2 * (mac_keylen + cipher_keylen + cipher_ivlen);
+
+ const byte MASTER_SECRET_MAGIC[] = {
+ 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74 };
+
+ const byte KEY_GEN_MAGIC[] = {
+ 0x6B, 0x65, 0x79, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6E, 0x73, 0x69, 0x6F, 0x6E };
+
+ std::unique_ptr<KDF> prf(state->protocol_specific_prf());
+
+ if(resuming)
+ {
+ master_sec = pre_master_secret;
+ }
+ else
+ {
+ SecureVector<byte> salt;
+
+ if(state->version() != Protocol_Version::SSL_V3)
+ salt += std::make_pair(MASTER_SECRET_MAGIC, sizeof(MASTER_SECRET_MAGIC));
+
+ salt += state->client_hello->random();
+ salt += state->server_hello->random();
+
+ master_sec = prf->derive_key(48, pre_master_secret, salt);
+ }
+
+ SecureVector<byte> salt;
+ if(state->version() != Protocol_Version::SSL_V3)
+ salt += std::make_pair(KEY_GEN_MAGIC, sizeof(KEY_GEN_MAGIC));
+ salt += state->server_hello->random();
+ salt += state->client_hello->random();
+
+ SymmetricKey keyblock = prf->derive_key(prf_gen, master_sec, salt);
+
+ const byte* key_data = keyblock.begin();
+
+ c_mac = SymmetricKey(key_data, mac_keylen);
+ key_data += mac_keylen;
+
+ s_mac = SymmetricKey(key_data, mac_keylen);
+ key_data += mac_keylen;
+
+ c_cipher = SymmetricKey(key_data, cipher_keylen);
+ key_data += cipher_keylen;
+
+ s_cipher = SymmetricKey(key_data, cipher_keylen);
+ key_data += cipher_keylen;
+
+ c_iv = InitializationVector(key_data, cipher_ivlen);
+ key_data += cipher_ivlen;
+
+ s_iv = InitializationVector(key_data, cipher_ivlen);
+ }
+
+}
+
+}
diff --git a/src/tls/tls_session_key.h b/src/tls/tls_session_key.h
new file mode 100644
index 000000000..25de56aea
--- /dev/null
+++ b/src/tls/tls_session_key.h
@@ -0,0 +1,52 @@
+/*
+* TLS Session Key
+* (C) 2004-2006,2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_SESSION_KEYS_H__
+#define BOTAN_TLS_SESSION_KEYS_H__
+
+#include <botan/tls_ciphersuite.h>
+#include <botan/tls_exceptn.h>
+#include <botan/symkey.h>
+
+namespace Botan {
+
+namespace TLS {
+
+/**
+* TLS Session Keys
+*/
+class Session_Keys
+ {
+ public:
+ SymmetricKey client_cipher_key() const { return c_cipher; }
+ SymmetricKey server_cipher_key() const { return s_cipher; }
+
+ SymmetricKey client_mac_key() const { return c_mac; }
+ SymmetricKey server_mac_key() const { return s_mac; }
+
+ InitializationVector client_iv() const { return c_iv; }
+ InitializationVector server_iv() const { return s_iv; }
+
+ const SecureVector<byte>& master_secret() const { return master_sec; }
+
+ Session_Keys() {}
+
+ Session_Keys(class Handshake_State* state,
+ const MemoryRegion<byte>& pre_master,
+ bool resuming);
+
+ private:
+ SecureVector<byte> master_sec;
+ SymmetricKey c_cipher, s_cipher, c_mac, s_mac;
+ InitializationVector c_iv, s_iv;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/tls/tls_session_manager.cpp b/src/tls/tls_session_manager.cpp
new file mode 100644
index 000000000..d103df35f
--- /dev/null
+++ b/src/tls/tls_session_manager.cpp
@@ -0,0 +1,106 @@
+/*
+* TLS Session Management
+* (C) 2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_session_manager.h>
+#include <botan/hex.h>
+#include <chrono>
+
+namespace Botan {
+
+namespace TLS {
+
+bool Session_Manager_In_Memory::load_from_session_str(
+ const std::string& session_str, Session& session)
+ {
+ // assert(lock is held)
+
+ auto i = m_sessions.find(session_str);
+
+ if(i == m_sessions.end())
+ return false;
+
+ // if session has expired, remove it
+ const auto now = std::chrono::system_clock::now();
+
+ if(i->second.start_time() + session_lifetime() < now)
+ {
+ m_sessions.erase(i);
+ return false;
+ }
+
+ session = i->second;
+ return true;
+ }
+
+bool Session_Manager_In_Memory::load_from_session_id(
+ const MemoryRegion<byte>& session_id, Session& session)
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+
+ return load_from_session_str(hex_encode(session_id), session);
+ }
+
+bool Session_Manager_In_Memory::load_from_host_info(
+ const std::string& hostname, u16bit port, Session& session)
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+
+ std::map<std::string, std::string>::iterator i;
+
+ if(port > 0)
+ i = m_host_sessions.find(hostname + ":" + std::to_string(port));
+ else
+ i = m_host_sessions.find(hostname);
+
+ if(i == m_host_sessions.end())
+ return false;
+
+ if(load_from_session_str(i->second, session))
+ return true;
+
+ // was removed from sessions map, remove m_host_sessions entry
+ m_host_sessions.erase(i);
+
+ return false;
+ }
+
+void Session_Manager_In_Memory::remove_entry(
+ const MemoryRegion<byte>& session_id)
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+
+ auto i = m_sessions.find(hex_encode(session_id));
+
+ if(i != m_sessions.end())
+ m_sessions.erase(i);
+ }
+
+void Session_Manager_In_Memory::save(const Session& session)
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+
+ if(m_max_sessions != 0)
+ {
+ /*
+ This removes randomly based on ordering of session ids.
+ Instead, remove oldest first?
+ */
+ while(m_sessions.size() >= m_max_sessions)
+ m_sessions.erase(m_sessions.begin());
+ }
+
+ const std::string session_id_str = hex_encode(session.session_id());
+
+ m_sessions[session_id_str] = session;
+
+ if(session.side() == CLIENT && session.sni_hostname() != "")
+ m_host_sessions[session.sni_hostname()] = session_id_str;
+ }
+
+}
+
+}
diff --git a/src/tls/tls_session_manager.h b/src/tls/tls_session_manager.h
new file mode 100644
index 000000000..84d51406d
--- /dev/null
+++ b/src/tls/tls_session_manager.h
@@ -0,0 +1,127 @@
+/*
+* TLS Session Manager
+* (C) 2011 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_SESSION_MANAGER_H__
+#define BOTAN_TLS_SESSION_MANAGER_H__
+
+#include <botan/tls_session.h>
+#include <mutex>
+#include <chrono>
+#include <map>
+
+namespace Botan {
+
+namespace TLS {
+
+/**
+* Session_Manager is an interface to systems which can save
+* session parameters for supporting session resumption.
+*
+* Saving sessions is done on a best-effort basis; an implementation is
+* allowed to drop sessions due to space constraints.
+*
+* Implementations should strive to be thread safe
+*/
+class BOTAN_DLL Session_Manager
+ {
+ public:
+ /**
+ * Try to load a saved session (server side)
+ * @param session_id the session identifier we are trying to resume
+ * @param session will be set to the saved session data (if found),
+ or not modified if not found
+ * @return true if session was modified
+ */
+ virtual bool load_from_session_id(const MemoryRegion<byte>& session_id,
+ Session& session) = 0;
+
+ /**
+ * Try to load a saved session (client side)
+ * @param hostname of the host we are connecting to
+ * @param port the port number if we know it, or 0 if unknown
+ * @param session will be set to the saved session data (if found),
+ or not modified if not found
+ * @return true if session was modified
+ */
+ virtual bool load_from_host_info(const std::string& hostname, u16bit port,
+ Session& session) = 0;
+
+ /**
+ * Remove this session id from the cache, if it exists
+ */
+ virtual void remove_entry(const MemoryRegion<byte>& session_id) = 0;
+
+ /**
+ * Save a session on a best effort basis; the manager may not in
+ * fact be able to save the session for whatever reason; this is
+ * not an error. Caller cannot assume that calling save followed
+ * immediately by load_from_* will result in a successful lookup.
+ *
+ * @param session to save
+ */
+ 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 std::chrono::seconds session_lifetime() const = 0;
+
+ virtual ~Session_Manager() {}
+ };
+
+/**
+* A simple implementation of Session_Manager that just saves
+* values in memory, with no persistance abilities
+*/
+class BOTAN_DLL Session_Manager_In_Memory : public Session_Manager
+ {
+ public:
+ /**
+ * @param max_sessions a hint on the maximum number of sessions
+ * to keep in memory at any one time. (If zero, don't cap)
+ * @param session_lifetime sessions are expired after this many
+ * seconds have elapsed from initial handshake.
+ */
+ Session_Manager_In_Memory(size_t max_sessions = 1000,
+ std::chrono::seconds session_lifetime = std::chrono::seconds(7200)) :
+ m_max_sessions(max_sessions),
+ m_session_lifetime(session_lifetime)
+ {}
+
+ bool load_from_session_id(const MemoryRegion<byte>& session_id,
+ Session& session);
+
+ bool load_from_host_info(const std::string& hostname, u16bit port,
+ Session& session);
+
+ void remove_entry(const MemoryRegion<byte>& session_id);
+
+ void save(const Session& session_data);
+
+ std::chrono::seconds session_lifetime() const { return m_session_lifetime; }
+
+ private:
+ bool load_from_session_str(const std::string& session_str,
+ Session& session);
+
+ std::mutex m_mutex;
+
+ size_t m_max_sessions;
+
+ std::chrono::seconds m_session_lifetime;
+
+ std::map<std::string, Session> m_sessions; // hex(session_id) -> session
+ std::map<std::string, std::string> m_host_sessions;
+ };
+
+}
+
+}
+
+#endif
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/tls/tls_version.cpp b/src/tls/tls_version.cpp
new file mode 100644
index 000000000..82dce0be9
--- /dev/null
+++ b/src/tls/tls_version.cpp
@@ -0,0 +1,33 @@
+/*
+* TLS Protocol Version Management
+* (C) 2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_version.h>
+#include <botan/parsing.h>
+
+namespace Botan {
+
+namespace TLS {
+
+std::string Protocol_Version::to_string() const
+ {
+ const byte maj = major_version();
+ const byte min = minor_version();
+
+ // Some very new or very old protocol?
+ if(maj != 3)
+ return "Protocol " + std::to_string(maj) + "." + std::to_string(min);
+
+ if(maj == 3 && min == 0)
+ return "SSL v3";
+
+ // The TLS v1.[0123...] case
+ return "TLS v1." + std::to_string(min-1);
+ }
+
+}
+
+}
diff --git a/src/tls/tls_version.h b/src/tls/tls_version.h
new file mode 100644
index 000000000..aa689b300
--- /dev/null
+++ b/src/tls/tls_version.h
@@ -0,0 +1,87 @@
+/*
+* TLS Protocol Version Management
+* (C) 2012 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_PROTOCOL_VERSION_H__
+#define BOTAN_TLS_PROTOCOL_VERSION_H__
+
+#include <botan/get_byte.h>
+#include <string>
+
+namespace Botan {
+
+namespace TLS {
+
+class BOTAN_DLL Protocol_Version
+ {
+ public:
+ enum Version_Code {
+ SSL_V3 = 0x0300,
+ TLS_V10 = 0x0301,
+ TLS_V11 = 0x0302,
+ TLS_V12 = 0x0303
+ };
+
+ Protocol_Version() : m_version(0) {}
+
+ Protocol_Version(Version_Code named_version) :
+ m_version(static_cast<u16bit>(named_version)) {}
+
+ Protocol_Version(byte major, byte minor) :
+ m_version((static_cast<u16bit>(major) << 8) | minor) {}
+
+ /**
+ * Get the major version of the protocol version
+ */
+ byte major_version() const { return get_byte(0, m_version); }
+
+ /**
+ * Get the minor version of the protocol version
+ */
+ byte minor_version() const { return get_byte(1, m_version); }
+
+ bool operator==(const Protocol_Version& other) const
+ {
+ return (m_version == other.m_version);
+ }
+
+ bool operator!=(const Protocol_Version& other) const
+ {
+ return (m_version != other.m_version);
+ }
+
+ bool operator>=(const Protocol_Version& other) const
+ {
+ return (m_version >= other.m_version);
+ }
+
+ bool operator>(const Protocol_Version& other) const
+ {
+ return (m_version > other.m_version);
+ }
+
+ bool operator<=(const Protocol_Version& other) const
+ {
+ return (m_version <= other.m_version);
+ }
+
+ bool operator<(const Protocol_Version& other) const
+ {
+ return (m_version < other.m_version);
+ }
+
+ std::string to_string() const;
+
+ private:
+ u16bit m_version;
+ };
+
+}
+
+}
+
+#endif
+
diff --git a/src/utils/assert.cpp b/src/utils/assert.cpp
index 29af831d8..3747912d6 100644
--- a/src/utils/assert.cpp
+++ b/src/utils/assert.cpp
@@ -21,7 +21,7 @@ void assertion_failure(const char* expr_str,
format << "Assertion " << expr_str << " failed ";
- if(msg)
+ if(msg && msg[0] != 0)
format << "(" << msg << ") ";
if(func)
diff --git a/src/utils/assert.h b/src/utils/assert.h
index 67ca665e3..d68f683a6 100644
--- a/src/utils/assert.h
+++ b/src/utils/assert.h
@@ -36,6 +36,16 @@ void assertion_failure(const char* expr_str,
__LINE__); \
} while(0)
+#define BOTAN_ASSERT_NONNULL(ptr) \
+ do { \
+ if(static_cast<bool>(ptr) == false) \
+ Botan::assertion_failure(#ptr " is not null", \
+ "", \
+ BOTAN_ASSERT_FUNCTION, \
+ __FILE__, \
+ __LINE__); \
+ } while(0)
+
/*
* Unfortunately getting the function name from the preprocessor
* isn't standard in C++98 (C++0x uses C99's __func__)
diff --git a/src/utils/calendar.cpp b/src/utils/calendar.cpp
new file mode 100644
index 000000000..14f0113f2
--- /dev/null
+++ b/src/utils/calendar.cpp
@@ -0,0 +1,52 @@
+/*
+* Calendar Functions
+* (C) 1999-2010 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/calendar.h>
+#include <botan/exceptn.h>
+#include <ctime>
+
+namespace Botan {
+
+namespace {
+
+std::tm do_gmtime(std::time_t time_val)
+ {
+ std::tm tm;
+
+#if defined(BOTAN_TARGET_OS_HAS_GMTIME_S)
+ gmtime_s(&tm, &time_val); // Windows
+#elif defined(BOTAN_TARGET_OS_HAS_GMTIME_R)
+ gmtime_r(&time_val, &tm); // Unix/SUSv2
+#else
+ std::tm* tm_p = std::gmtime(&time_val);
+ if (tm_p == 0)
+ throw Encoding_Error("time_t_to_tm could not convert");
+ tm = *tm_p;
+#endif
+
+ return tm;
+ }
+
+}
+
+/*
+* Convert a time_point to a calendar_point
+*/
+calendar_point calendar_value(
+ const std::chrono::system_clock::time_point& time_point)
+ {
+ std::tm tm = do_gmtime(std::chrono::system_clock::to_time_t(time_point));
+
+ return calendar_point(tm.tm_year + 1900,
+ tm.tm_mon + 1,
+ tm.tm_mday,
+ tm.tm_hour,
+ tm.tm_min,
+ tm.tm_sec);
+ }
+
+}
diff --git a/src/utils/time.h b/src/utils/calendar.h
index fcc956df2..d617cc9a0 100644
--- a/src/utils/time.h
+++ b/src/utils/calendar.h
@@ -1,14 +1,15 @@
/*
-* Time Functions
+* Calendar Functions
* (C) 1999-2009 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
-#ifndef BOTAN_TIME_H__
-#define BOTAN_TIME_H__
+#ifndef BOTAN_CALENDAR_H__
+#define BOTAN_CALENDAR_H__
#include <botan/types.h>
+#include <chrono>
namespace Botan {
@@ -50,21 +51,12 @@ struct BOTAN_DLL calendar_point
year(y), month(mon), day(d), hour(h), minutes(min), seconds(sec) {}
};
-/**
+/*
* @param time_point a time point from the system clock
* @return calendar_point object representing this time point
*/
-BOTAN_DLL calendar_point calendar_value(u64bit time_point);
-
-/**
-* @return seconds resolution timestamp, unknown epoch
-*/
-BOTAN_DLL u64bit system_time();
-
-/**
-* @return nanoseconds resolution timestamp, unknown epoch
-*/
-BOTAN_DLL u64bit get_nanoseconds_clock();
+BOTAN_DLL calendar_point calendar_value(
+ const std::chrono::system_clock::time_point& time_point);
}
diff --git a/src/utils/charset.cpp b/src/utils/charset.cpp
index 8e20e6492..7ee637f80 100644
--- a/src/utils/charset.cpp
+++ b/src/utils/charset.cpp
@@ -119,7 +119,7 @@ std::string transcode(const std::string& str,
return ucs2_to_latin1(str);
throw Invalid_Argument("Unknown transcoding operation from " +
- to_string(from) + " to " + to_string(to));
+ std::to_string(from) + " to " + std::to_string(to));
}
/*
diff --git a/src/utils/datastor/datastor.cpp b/src/utils/datastor/datastor.cpp
index 49e7b2dda..363136c69 100644
--- a/src/utils/datastor/datastor.cpp
+++ b/src/utils/datastor/datastor.cpp
@@ -14,16 +14,6 @@
namespace Botan {
/*
-* Default Matcher transform operation (identity)
-*/
-std::pair<std::string, std::string>
-Data_Store::Matcher::transform(const std::string& key,
- const std::string& value) const
- {
- return std::make_pair(key, value);
- }
-
-/*
* Data_Store Equality Comparison
*/
bool Data_Store::operator==(const Data_Store& other) const
@@ -42,26 +32,14 @@ bool Data_Store::has_value(const std::string& key) const
/*
* Search based on an arbitrary predicate
*/
-std::multimap<std::string, std::string>
-Data_Store::search_with(const Matcher& matcher) const
+std::multimap<std::string, std::string> Data_Store::search_for(
+ std::function<bool (std::string, std::string)> predicate) const
{
std::multimap<std::string, std::string> out;
- std::multimap<std::string, std::string>::const_iterator i =
- contents.begin();
-
- while(i != contents.end())
- {
- if(matcher(i->first, i->second))
- {
- std::pair<std::string, std::string> p(
- matcher.transform(i->first, i->second));
-
- multimap_insert(out, p.first, p.second);
- }
-
- ++i;
- }
+ for(auto i = contents.begin(); i != contents.end(); ++i)
+ if(predicate(i->first, i->second))
+ out.insert(std::make_pair(i->first, i->second));
return out;
}
@@ -71,12 +49,9 @@ Data_Store::search_with(const Matcher& matcher) const
*/
std::vector<std::string> Data_Store::get(const std::string& looking_for) const
{
- typedef std::multimap<std::string, std::string>::const_iterator iter;
-
- std::pair<iter, iter> range = contents.equal_range(looking_for);
-
std::vector<std::string> out;
- for(iter i = range.first; i != range.second; ++i)
+ auto range = contents.equal_range(looking_for);
+ for(auto i = range.first; i != range.second; ++i)
out.push_back(i->second);
return out;
}
@@ -144,7 +119,7 @@ void Data_Store::add(const std::string& key, const std::string& val)
*/
void Data_Store::add(const std::string& key, u32bit val)
{
- add(key, to_string(val));
+ add(key, std::to_string(val));
}
/*
diff --git a/src/utils/datastor/datastor.h b/src/utils/datastor/datastor.h
index 8d41b07a8..26a0d418c 100644
--- a/src/utils/datastor/datastor.h
+++ b/src/utils/datastor/datastor.h
@@ -9,6 +9,7 @@
#define BOTAN_DATA_STORE_H__
#include <botan/secmem.h>
+#include <functional>
#include <utility>
#include <string>
#include <vector>
@@ -25,22 +26,10 @@ class BOTAN_DLL Data_Store
/**
* A search function
*/
- class BOTAN_DLL Matcher
- {
- public:
- virtual bool operator()(const std::string&,
- const std::string&) const = 0;
-
- virtual std::pair<std::string, std::string>
- transform(const std::string&, const std::string&) const;
-
- virtual ~Matcher() {}
- };
-
bool operator==(const Data_Store&) const;
- std::multimap<std::string, std::string>
- search_with(const Matcher&) const;
+ std::multimap<std::string, std::string> search_for(
+ std::function<bool (std::string, std::string)> predicate) const;
std::vector<std::string> get(const std::string&) const;
diff --git a/src/utils/exceptn.h b/src/utils/exceptn.h
index 3797a5478..02fb16a66 100644
--- a/src/utils/exceptn.h
+++ b/src/utils/exceptn.h
@@ -56,7 +56,7 @@ struct BOTAN_DLL Invalid_Key_Length : public Invalid_Argument
{
Invalid_Key_Length(const std::string& name, size_t length) :
Invalid_Argument(name + " cannot accept a key of length " +
- to_string(length))
+ std::to_string(length))
{}
};
@@ -78,7 +78,7 @@ struct BOTAN_DLL Invalid_Block_Size : public Invalid_Argument
struct BOTAN_DLL Invalid_IV_Length : public Invalid_Argument
{
Invalid_IV_Length(const std::string& mode, size_t bad_len) :
- Invalid_Argument("IV length " + to_string(bad_len) +
+ Invalid_Argument("IV length " + std::to_string(bad_len) +
" is invalid for " + mode)
{}
};
diff --git a/src/utils/info.txt b/src/utils/info.txt
index fcf16bd5a..e2ffd2714 100644
--- a/src/utils/info.txt
+++ b/src/utils/info.txt
@@ -4,12 +4,11 @@ load_on always
<source>
assert.cpp
+calendar.cpp
charset.cpp
cpuid.cpp
mlock.cpp
parsing.cpp
-time.cpp
-ui.cpp
version.cpp
</source>
@@ -25,6 +24,7 @@ xor_buf.h
<header:public>
bswap.h
+calendar.h
charset.h
cpuid.h
exceptn.h
@@ -32,9 +32,7 @@ loadstor.h
mem_ops.h
parsing.h
rotate.h
-time.h
types.h
-ui.h
version.h
get_byte.h
</header:public>
diff --git a/src/utils/parsing.cpp b/src/utils/parsing.cpp
index 9ec00040c..c3d7f00f7 100644
--- a/src/utils/parsing.cpp
+++ b/src/utils/parsing.cpp
@@ -13,53 +13,6 @@
namespace Botan {
/*
-* Convert a string into an integer
-*/
-u32bit to_u32bit(const std::string& number)
- {
- u32bit n = 0;
-
- for(std::string::const_iterator i = number.begin(); i != number.end(); ++i)
- {
- const u32bit OVERFLOW_MARK = 0xFFFFFFFF / 10;
-
- if(*i == ' ')
- continue;
-
- byte digit = Charset::char2digit(*i);
-
- if((n > OVERFLOW_MARK) || (n == OVERFLOW_MARK && digit > 5))
- throw Decoding_Error("to_u32bit: Integer overflow");
- n *= 10;
- n += digit;
- }
- return n;
- }
-
-/*
-* Convert an integer into a string
-*/
-std::string to_string(u64bit n, size_t min_len)
- {
- std::string lenstr;
- if(n)
- {
- while(n > 0)
- {
- lenstr = Charset::digit2char(n % 10) + lenstr;
- n /= 10;
- }
- }
- else
- lenstr = "0";
-
- while(lenstr.size() < min_len)
- lenstr = "0" + lenstr;
-
- return lenstr;
- }
-
-/*
* Convert a string into a time duration
*/
u32bit timespec_to_u32bit(const std::string& timespec)
@@ -106,7 +59,7 @@ std::vector<std::string> parse_algorithm_name(const std::string& namex)
elems.push_back(name.substr(0, name.find('(')));
name = name.substr(name.find('('));
- for(std::string::const_iterator i = name.begin(); i != name.end(); ++i)
+ for(auto i = name.begin(); i != name.end(); ++i)
{
char c = *i;
@@ -155,7 +108,7 @@ std::vector<std::string> split_on(const std::string& str, char delim)
if(str == "") return elems;
std::string substr;
- for(std::string::const_iterator i = str.begin(); i != str.end(); ++i)
+ for(auto i = str.begin(); i != str.end(); ++i)
{
if(*i == delim)
{
@@ -175,6 +128,23 @@ std::vector<std::string> split_on(const std::string& str, char delim)
}
/*
+* Join a string
+*/
+std::string string_join(const std::vector<std::string>& strs, char delim)
+ {
+ std::string out = "";
+
+ for(size_t i = 0; i != strs.size(); ++i)
+ {
+ if(i != 0)
+ out += delim;
+ out += strs[i];
+ }
+
+ return out;
+ }
+
+/*
* Parse an ASN.1 OID string
*/
std::vector<u32bit> parse_asn1_oid(const std::string& oid)
@@ -182,7 +152,7 @@ std::vector<u32bit> parse_asn1_oid(const std::string& oid)
std::string substring;
std::vector<u32bit> oid_elems;
- for(std::string::const_iterator i = oid.begin(); i != oid.end(); ++i)
+ for(auto i = oid.begin(); i != oid.end(); ++i)
{
char c = *i;
@@ -212,8 +182,8 @@ std::vector<u32bit> parse_asn1_oid(const std::string& oid)
*/
bool x500_name_cmp(const std::string& name1, const std::string& name2)
{
- std::string::const_iterator p1 = name1.begin();
- std::string::const_iterator p2 = name2.begin();
+ auto p1 = name1.begin();
+ auto p2 = name2.begin();
while((p1 != name1.end()) && Charset::is_space(*p1)) ++p1;
while((p2 != name2.end()) && Charset::is_space(*p2)) ++p2;
@@ -258,9 +228,9 @@ u32bit string_to_ipv4(const std::string& str)
u32bit ip = 0;
- for(size_t i = 0; i != parts.size(); ++i)
+ for(auto part = parts.begin(); part != parts.end(); ++part)
{
- u32bit octet = to_u32bit(parts[i]);
+ u32bit octet = to_u32bit(*part);
if(octet > 255)
throw Decoding_Error("Invalid IP string " + str);
@@ -282,10 +252,23 @@ std::string ipv4_to_string(u32bit ip)
{
if(i)
str += ".";
- str += to_string(get_byte(i, ip));
+ str += std::to_string(get_byte(i, ip));
}
return str;
}
+std::string replace_char(const std::string& str,
+ char from_char,
+ char to_char)
+ {
+ std::string out = str;
+
+ for(size_t i = 0; i != out.size(); ++i)
+ if(out[i] == from_char)
+ out[i] = to_char;
+
+ return out;
+ }
+
}
diff --git a/src/utils/parsing.h b/src/utils/parsing.h
index 12370bf2b..12a31a7dd 100644
--- a/src/utils/parsing.h
+++ b/src/utils/parsing.h
@@ -32,6 +32,25 @@ BOTAN_DLL std::vector<std::string> split_on(
const std::string& str, char delim);
/**
+* Replace a character in a string
+* @param str the input string
+* @param from_char the character to replace
+* @return to_char the character to replace it with
+*/
+BOTAN_DLL std::string replace_char(const std::string& str,
+ char from_char,
+ char to_char);
+
+/**
+* Join a string
+* @param strs strings to join
+* @param delim the delimitor
+* @return string joined by delim
+*/
+BOTAN_DLL std::string string_join(const std::vector<std::string>& strs,
+ char delim);
+
+/**
* Parse an ASN.1 OID
* @param oid the OID in string form
* @return OID components
@@ -48,19 +67,12 @@ BOTAN_DLL bool x500_name_cmp(const std::string& name1,
const std::string& name2);
/**
-* Convert a number to a string
-* @param n the integer to convert to a string
-* @param min_len the min length of the output string
-* @return n convert to a string
-*/
-BOTAN_DLL std::string to_string(u64bit n, size_t min_len = 0);
-
-/**
* Convert a string to a number
* @param str the string to convert
* @return number value of the string
*/
-BOTAN_DLL u32bit to_u32bit(const std::string& str);
+inline u32bit to_u32bit(const std::string& str)
+ { return std::stoul(str); }
/**
* Convert a time specification to a number
diff --git a/src/utils/rounding.h b/src/utils/rounding.h
index c77ab9b52..4ddd7a432 100644
--- a/src/utils/rounding.h
+++ b/src/utils/rounding.h
@@ -21,6 +21,9 @@ namespace Botan {
template<typename T>
inline T round_up(T n, T align_to)
{
+ if(align_to == 0)
+ return n;
+
if(n % align_to || n == 0)
n += align_to - (n % align_to);
return n;
@@ -35,9 +38,24 @@ inline T round_up(T n, T align_to)
template<typename T>
inline T round_down(T n, T align_to)
{
+ if(align_to == 0)
+ return n;
+
return (n - (n % align_to));
}
+/**
+* Clamp
+*/
+inline size_t clamp(size_t n, size_t lower_bound, size_t upper_bound)
+ {
+ if(n < lower_bound)
+ return lower_bound;
+ if(n > upper_bound)
+ return upper_bound;
+ return n;
+ }
+
}
#endif
diff --git a/src/utils/stl_util.h b/src/utils/stl_util.h
index 0e0617d5b..1a62e8fe7 100644
--- a/src/utils/stl_util.h
+++ b/src/utils/stl_util.h
@@ -8,31 +8,12 @@
#ifndef BOTAN_STL_UTIL_H__
#define BOTAN_STL_UTIL_H__
+#include <vector>
#include <map>
namespace Botan {
-/**
-* Copy-on-Predicate Algorithm
-* @param current the first iterator value
-* @param end the final iterator value
-* @param dest an output iterator
-* @param copy_p the predicate
-*/
-template<typename InputIterator, typename OutputIterator, typename Predicate>
-OutputIterator copy_if(InputIterator current, InputIterator end,
- OutputIterator dest, Predicate copy_p)
- {
- while(current != end)
- {
- if(copy_p(*current))
- *dest++ = *current;
- ++current;
- }
- return dest;
- }
-
-/**
+/*
* Searching through a std::map
* @param mapping the map to search
* @param key is what to look for
@@ -44,32 +25,23 @@ inline V search_map(const std::map<K, V>& mapping,
const K& key,
const V& null_result = V())
{
- typename std::map<K, V>::const_iterator i = mapping.find(key);
+ auto i = mapping.find(key);
if(i == mapping.end())
return null_result;
return i->second;
}
-/**
-* Function adaptor for delete operation
-*/
-template<class T>
-class del_fun : public std::unary_function<T, void>
- {
- public:
- void operator()(T* ptr) { delete ptr; }
- };
-
-/**
-* Delete the second half of a pair of objects
-*/
-template<typename Pair>
-void delete2nd(Pair& pair)
+template<typename K, typename V, typename R>
+inline R search_map(const std::map<K, V>& mapping, const K& key,
+ const R& null_result, const R& found_result)
{
- delete pair.second;
+ auto i = mapping.find(key);
+ if(i == mapping.end())
+ return null_result;
+ return found_result;
}
-/**
+/*
* Insert a key/value pair into a multimap
*/
template<typename K, typename V>
@@ -84,6 +56,19 @@ void multimap_insert(std::multimap<K, V>& multimap,
#endif
}
+/**
+* Existence check for values
+*/
+template<typename T>
+bool value_exists(const std::vector<T>& vec,
+ const T& val)
+ {
+ for(size_t i = 0; i != vec.size(); ++i)
+ if(vec[i] == val)
+ return true;
+ return false;
+ }
+
}
#endif
diff --git a/src/utils/time.cpp b/src/utils/time.cpp
deleted file mode 100644
index 65e808c04..000000000
--- a/src/utils/time.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
-* Time Functions
-* (C) 1999-2010 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#include <botan/time.h>
-#include <botan/exceptn.h>
-#include <ctime>
-
-#if defined(BOTAN_TARGET_OS_HAS_WIN32_GET_SYSTEMTIME)
- #include <windows.h>
-#endif
-
-#if defined(BOTAN_TARGET_OS_HAS_GETTIMEOFDAY)
- #include <sys/time.h>
-#endif
-
-#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
-
- #ifndef _POSIX_C_SOURCE
- #define _POSIX_C_SOURCE 199309
- #endif
-
- #include <time.h>
-
- #ifndef CLOCK_REALTIME
- #define CLOCK_REALTIME 0
- #endif
-
-#endif
-
-namespace Botan {
-
-namespace {
-
-/*
-* Combine a two time values into a single one
-*/
-u64bit combine_timers(u32bit seconds, u32bit parts, u32bit parts_hz)
- {
- static const u64bit NANOSECONDS_UNITS = 1000000000;
-
- u64bit res = seconds * NANOSECONDS_UNITS;
- res += parts * (NANOSECONDS_UNITS / parts_hz);
- return res;
- }
-
-std::tm do_gmtime(time_t time_val)
- {
- std::tm tm;
-
-#if defined(BOTAN_TARGET_OS_HAS_GMTIME_S)
- gmtime_s(&tm, &time_val); // Windows
-#elif defined(BOTAN_TARGET_OS_HAS_GMTIME_R)
- gmtime_r(&time_val, &tm); // Unix/SUSv2
-#else
- std::tm* tm_p = std::gmtime(&time_val);
- if (tm_p == 0)
- throw Encoding_Error("time_t_to_tm could not convert");
- tm = *tm_p;
-#endif
-
- return tm;
- }
-
-}
-
-/*
-* Get the system clock
-*/
-u64bit system_time()
- {
- return static_cast<u64bit>(std::time(0));
- }
-
-/*
-* Convert a time_point to a calendar_point
-*/
-calendar_point calendar_value(u64bit a_time_t)
- {
- std::tm tm = do_gmtime(static_cast<std::time_t>(a_time_t));
-
- return calendar_point(tm.tm_year + 1900,
- tm.tm_mon + 1,
- tm.tm_mday,
- tm.tm_hour,
- tm.tm_min,
- tm.tm_sec);
- }
-
-u64bit get_nanoseconds_clock()
- {
-#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
-
- struct ::timespec tv;
- ::clock_gettime(CLOCK_REALTIME, &tv);
- return combine_timers(tv.tv_sec, tv.tv_nsec, 1000000000);
-
-#elif defined(BOTAN_TARGET_OS_HAS_GETTIMEOFDAY)
-
- struct ::timeval tv;
- ::gettimeofday(&tv, 0);
- return combine_timers(tv.tv_sec, tv.tv_usec, 1000000);
-
-#elif defined(BOTAN_TARGET_OS_HAS_WIN32_GET_SYSTEMTIME)
-
- // Returns time since January 1, 1601 in 100-ns increments
- ::FILETIME tv;
- ::GetSystemTimeAsFileTime(&tv);
- u64bit tstamp = (static_cast<u64bit>(tv.dwHighDateTime) << 32) |
- tv.dwLowDateTime;
-
- return (tstamp * 100); // Scale to 1 nanosecond units
-
-#else
-
- return combine_timers(static_cast<u32bit>(std::time(0)),
- std::clock(), CLOCKS_PER_SEC);
-
-#endif
- }
-
-}
diff --git a/src/utils/types.h b/src/utils/types.h
index 61a55368c..255311580 100644
--- a/src/utils/types.h
+++ b/src/utils/types.h
@@ -39,15 +39,7 @@ typedef signed int s32bit;
/**
* Typedef representing an unsigned 64-bit quantity
*/
-#if defined(_MSC_VER) || defined(__BORLANDC__)
- typedef unsigned __int64 u64bit;
-#elif defined(__KCC)
- typedef unsigned __long_long u64bit;
-#elif defined(__GNUG__)
- __extension__ typedef unsigned long long u64bit;
-#else
- typedef unsigned long long u64bit;
-#endif
+typedef unsigned long long u64bit;
/**
* A default buffer size; typically a memory page
diff --git a/src/utils/ui.cpp b/src/utils/ui.cpp
deleted file mode 100644
index e6c3430ff..000000000
--- a/src/utils/ui.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-* User Interface
-* (C) 1999-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#include <botan/ui.h>
-
-namespace Botan {
-
-/*
-* Get a passphrase from the user
-*/
-std::string User_Interface::get_passphrase(const std::string&,
- const std::string&,
- UI_Result& action) const
- {
- action = OK;
-
- if(!first_try)
- action = CANCEL_ACTION;
-
- return preset_passphrase;
- }
-
-/*
-* User_Interface Constructor
-*/
-User_Interface::User_Interface(const std::string& preset) :
- preset_passphrase(preset)
- {
- first_try = true;
- }
-
-}
diff --git a/src/utils/ui.h b/src/utils/ui.h
deleted file mode 100644
index f69bb2c6d..000000000
--- a/src/utils/ui.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-* User Interface
-* (C) 1999-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_UI_H__
-#define BOTAN_UI_H__
-
-#include <botan/build.h>
-#include <string>
-
-namespace Botan {
-
-/**
-* User Interface
-* Only really used for callbacks for PKCS #8 decryption
-*/
-class BOTAN_DLL User_Interface
- {
- public:
- enum UI_Result { OK, CANCEL_ACTION };
-
- virtual std::string get_passphrase(const std::string&,
- const std::string&,
- UI_Result&) const;
- User_Interface(const std::string& = "");
- virtual ~User_Interface() {}
- protected:
- std::string preset_passphrase;
- mutable bool first_try;
- };
-
-}
-
-#endif
diff --git a/src/wrap/python/core.cpp b/src/wrap/python/core.cpp
index 7dac7be7f..6dcceee74 100644
--- a/src/wrap/python/core.cpp
+++ b/src/wrap/python/core.cpp
@@ -178,7 +178,7 @@ std::string python_kdf2(const std::string& param,
const std::string& masterkey,
u32bit outputlength)
{
- std::auto_ptr<KDF> kdf(get_kdf("KDF2(SHA-1)"));
+ std::unique_ptr<KDF> kdf(get_kdf("KDF2(SHA-1)"));
return make_string(
kdf->derive_key(outputlength,
diff --git a/src/wrap/python/filter.cpp b/src/wrap/python/filter.cpp
index e329ed708..eef8b202c 100644
--- a/src/wrap/python/filter.cpp
+++ b/src/wrap/python/filter.cpp
@@ -107,19 +107,19 @@ Filter* make_filter4(const std::string& name,
name);
}
-void append_filter(Pipe& pipe, std::auto_ptr<Filter> filter)
+void append_filter(Pipe& pipe, std::unique_ptr<Filter> filter)
{
pipe.append(filter.get());
filter.release();
}
-void prepend_filter(Pipe& pipe, std::auto_ptr<Filter> filter)
+void prepend_filter(Pipe& pipe, std::unique_ptr<Filter> filter)
{
pipe.prepend(filter.get());
filter.release();
}
-void do_send(std::auto_ptr<FilterWrapper> filter, const std::string& data)
+void do_send(std::unique_ptr<FilterWrapper> filter, const std::string& data)
{
filter->send_str(data);
}
@@ -128,7 +128,7 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(rallas_ovls, read_all_as_string, 0, 1)
void export_filters()
{
- class_<Filter, std::auto_ptr<Filter>, boost::noncopyable>
+ class_<Filter, std::unique_ptr<Filter>, boost::noncopyable>
("__Internal_FilterObj", no_init);
def("make_filter", make_filter1,
@@ -142,7 +142,7 @@ void export_filters()
// This might not work - Pipe will delete the filter, but Python
// might have allocated the space with malloc() or who-knows-what -> bad
- class_<FilterWrapper, std::auto_ptr<FilterWrapper>,
+ class_<FilterWrapper, std::unique_ptr<FilterWrapper>,
bases<Filter>, boost::noncopyable>
("FilterObj")
.def("write", pure_virtual(&Py_Filter::write_str))
@@ -150,8 +150,8 @@ void export_filters()
.def("start_msg", &Filter::start_msg, &FilterWrapper::default_start_msg)
.def("end_msg", &Filter::end_msg, &FilterWrapper::default_end_msg);
- implicitly_convertible<std::auto_ptr<FilterWrapper>,
- std::auto_ptr<Filter> >();
+ implicitly_convertible<std::unique_ptr<FilterWrapper>,
+ std::unique_ptr<Filter> >();
void (Pipe::*pipe_write_str)(const std::string&) = &Pipe::write;
void (Pipe::*pipe_process_str)(const std::string&) = &Pipe::process_msg;
diff --git a/src/wrap/python/python_botan.h b/src/wrap/python/python_botan.h
index a7a2e505e..ac0a17d7f 100644
--- a/src/wrap/python/python_botan.h
+++ b/src/wrap/python/python_botan.h
@@ -24,7 +24,8 @@ class Bad_Size : public Exception
public:
Bad_Size(u32bit got, u32bit expected) :
Exception("Bad size detected in Python/C++ conversion layer: got " +
- to_string(got) + " bytes, expected " + to_string(expected))
+ std::to_string(got) + " bytes, expected " +
+ std::to_string(expected))
{}
};