aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--checks/ec_tests.cpp43
-rw-r--r--checks/gfpmath.cpp162
-rw-r--r--checks/validate.cpp13
-rwxr-xr-xconfigure.py27
-rw-r--r--doc/examples/tls_client.cpp51
-rw-r--r--doc/examples/tls_server.cpp81
-rw-r--r--doc/log.txt3
-rw-r--r--src/cert/cvc/cvc_ado.cpp45
-rw-r--r--src/cert/cvc/cvc_ado.h4
-rw-r--r--src/cert/cvc/cvc_ca.cpp3
-rw-r--r--src/cert/cvc/cvc_cert.cpp6
-rw-r--r--src/cert/cvc/cvc_cert.h2
-rw-r--r--src/cert/cvc/cvc_gen_cert.h11
-rw-r--r--src/cert/cvc/cvc_req.cpp15
-rw-r--r--src/cert/cvc/cvc_req.h2
-rw-r--r--src/cert/cvc/cvc_self.cpp14
-rw-r--r--src/cert/cvc/eac_obj.h8
-rw-r--r--src/cert/cvc/freestore.h77
-rw-r--r--src/cert/cvc/info.txt2
-rw-r--r--src/cms/cms_dec.cpp4
-rw-r--r--src/cms/cms_dec.h6
-rw-r--r--src/cms/cms_ealg.cpp6
-rw-r--r--src/cms/cms_enc.h4
-rw-r--r--src/libstate/policy.cpp3
-rw-r--r--src/math/gfpmath/curve_gfp.cpp149
-rw-r--r--src/math/gfpmath/curve_gfp.h62
-rw-r--r--src/math/gfpmath/gfp_element.cpp248
-rw-r--r--src/math/gfpmath/gfp_element.h98
-rw-r--r--src/math/gfpmath/gfp_modulus.h44
-rw-r--r--src/math/gfpmath/point_gfp.cpp703
-rw-r--r--src/math/gfpmath/point_gfp.h90
-rw-r--r--src/pubkey/ec_dompar/ec_dompar.cpp20
-rw-r--r--src/pubkey/ecc_key/ecc_key.h1
-rw-r--r--src/pubkey/gost_3410/gost_3410.cpp351
-rw-r--r--src/pubkey/gost_3410/gost_3410.h164
-rw-r--r--src/pubkey/gost_3410/info.txt14
-rw-r--r--src/pubkey/pk_algs.cpp12
-rw-r--r--src/s2k/s2k.h4
-rw-r--r--src/ssl/c_kex.cpp174
-rw-r--r--src/ssl/cert_req.cpp156
-rw-r--r--src/ssl/cert_ver.cpp109
-rw-r--r--src/ssl/finished.cpp100
-rw-r--r--src/ssl/handshake_hash.cpp60
-rw-r--r--src/ssl/handshake_hash.h38
-rw-r--r--src/ssl/handshake_state.cpp59
-rw-r--r--src/ssl/hello.cpp265
-rw-r--r--src/ssl/info.txt1
-rw-r--r--src/ssl/rec_read.cpp204
-rw-r--r--src/ssl/rec_wri.cpp258
-rw-r--r--src/ssl/s_kex.cpp195
-rw-r--r--src/ssl/socket.h49
-rw-r--r--src/ssl/tls_alerts.h46
-rw-r--r--src/ssl/tls_client.cpp571
-rw-r--r--src/ssl/tls_client.h79
-rw-r--r--src/ssl/tls_connection.h36
-rw-r--r--src/ssl/tls_exceptn.h43
-rw-r--r--src/ssl/tls_magic.h120
-rw-r--r--src/ssl/tls_messages.h282
-rw-r--r--src/ssl/tls_policy.cpp124
-rw-r--r--src/ssl/tls_policy.h57
-rw-r--r--src/ssl/tls_record.h79
-rw-r--r--src/ssl/tls_server.cpp465
-rw-r--r--src/ssl/tls_server.h69
-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.h53
-rw-r--r--src/ssl/tls_suites.cpp77
-rw-r--r--src/ssl/tls_suites.h42
-rw-r--r--src/ssl/unix_socket/info.txt21
-rw-r--r--src/ssl/unix_socket/unx_sock.cpp200
-rw-r--r--src/ssl/unix_socket/unx_sock.h62
71 files changed, 5417 insertions, 1451 deletions
diff --git a/checks/ec_tests.cpp b/checks/ec_tests.cpp
index fdd333b1f..1820db1b6 100644
--- a/checks/ec_tests.cpp
+++ b/checks/ec_tests.cpp
@@ -85,16 +85,16 @@ void test_point_turn_on_sp_red_mul()
CHECK_MESSAGE(r1 == r2, "error with point mul after extra turn on sp red mul");
CHECK(r1.get_affine_x().get_value() != BigInt("0"));
- std::shared_ptr<PointGFp> p_r1(new PointGFp(r1));
- std::shared_ptr<PointGFp> p_r2(new PointGFp(r2));
-
- p_r1->mult2_in_place(); // wird für Fehler nicht gebraucht
- p_r2->turn_on_sp_red_mul(); // 1. t_o() macht nur p_r2 kaputt
- p_r2->turn_on_sp_red_mul(); // 2. t_o() macht auch p_r1 kaputt!!!
- p_r2->mult2_in_place(); // wird für Fehler nicht gebraucht
- CHECK_MESSAGE(p_r1->get_affine_x() == p_r2->get_affine_x(), "error with mult2 after extra turn on sp red mul");
- CHECK(p_r1->get_affine_x().get_value() != BigInt("0"));
- CHECK(p_r2->get_affine_x().get_value() != BigInt("0"));
+ PointGFp p_r1 = r1;
+ PointGFp p_r2 = r2;
+
+ p_r1.mult2_in_place(); // wird für Fehler nicht gebraucht
+ p_r2.turn_on_sp_red_mul(); // 1. t_o() macht nur p_r2 kaputt
+ p_r2.turn_on_sp_red_mul(); // 2. t_o() macht auch p_r1 kaputt!!!
+ p_r2.mult2_in_place(); // wird für Fehler nicht gebraucht
+ CHECK_MESSAGE(p_r1.get_affine_x() == p_r2.get_affine_x(), "error with mult2 after extra turn on sp red mul");
+ CHECK(p_r1.get_affine_x().get_value() != BigInt("0"));
+ CHECK(p_r2.get_affine_x().get_value() != BigInt("0"));
r1.mult2_in_place();
r2.turn_on_sp_red_mul();
@@ -1072,28 +1072,6 @@ void test_mult_sec_mass(RandomNumberGenerator& rng)
}
}
-/**
-* The following test verifies that PointGFps copy-ctor and assignment operator
-* produce non-sharing Objects
-*/
-void test_point_ctors_ass_unshared()
- {
- std::cout << "." << std::flush;
-
- EC_Domain_Params dom_pars(get_EC_Dom_Pars_by_oid("1.3.132.0.8"));
- PointGFp p = dom_pars.get_base_point();
- PointGFp ind_cpy(p);
-
- // doesn´t work this way, because getters of point return an independent copy!
- CHECK(p.get_jac_proj_x().get_ptr_mod().get() != ind_cpy.get_jac_proj_x().get_ptr_mod().get());
- //CHECK(p.get_x().get_ptr_r().get() != ind_cpy.get_x().get_ptr_r().get());
-
- PointGFp ind_ass(p);
- ind_ass = p;
- CHECK(p.get_jac_proj_x().get_ptr_mod().get() != ind_ass.get_jac_proj_x().get_ptr_mod().get());
- //CHECK(p.get_x().get_ptr_r().get() != ind_ass.get_x().get_ptr_r().get());
- }
-
void test_curve_cp_ctor()
{
std::cout << "." << std::flush;
@@ -1216,7 +1194,6 @@ void do_ec_tests(RandomNumberGenerator& rng)
test_point_swap(rng);
test_mult_sec();
test_mult_sec_mass(rng);
- test_point_ctors_ass_unshared();
test_curve_cp_ctor();
test_ec_key_cp_and_assignment(rng);
test_ec_key_cast(rng);
diff --git a/checks/gfpmath.cpp b/checks/gfpmath.cpp
index 6d8e406e3..50e1818c7 100644
--- a/checks/gfpmath.cpp
+++ b/checks/gfpmath.cpp
@@ -471,181 +471,23 @@ bool test_gfp_mult_u32bit()
return pass;
}
-/**
-* This tests verifies the functionality of sharing pointers for modulus dependent values
-*/
-bool test_gfp_shared_vals()
- {
- std::cout << '.' << std::flush;
-
- bool pass = true;
-
- BigInt p("5334243285367");
- GFpElement a(p, BigInt("234090"));
- GFpElement shcpy_a(1,0);
- shcpy_a.share_assign(a);
- std::shared_ptr<GFpModulus> ptr1 = a.get_ptr_mod();
- std::shared_ptr<GFpModulus> ptr2 = shcpy_a.get_ptr_mod();
- CHECK_MESSAGE(ptr1.get() == ptr2.get(), "shared pointers for moduli aren´t equal");
-
- GFpElement b(1,0);
- b = a; // create a non shared copy
- std::shared_ptr<GFpModulus> ptr_b_p = b.get_ptr_mod();
- CHECK_MESSAGE(ptr1.get() != ptr_b_p.get(), "non shared pointers for moduli are equal");
-
- a.turn_on_sp_red_mul();
- GFpElement c1 = a * shcpy_a;
- GFpElement c2 = a * a;
- GFpElement c3 = shcpy_a * shcpy_a;
- GFpElement c4 = shcpy_a * a;
- shcpy_a.turn_on_sp_red_mul();
- GFpElement c5 = shcpy_a * shcpy_a;
-
- if(c1 != c2 || c2 != c3 || c3 != c4 || c4 != c5)
- {
- std::cout << "test_gfp_shared_vals failed"
- << " a=" << a
- << " shcpy_a=" << shcpy_a
- << " c1=" << c1 << " c2=" << c2
- << " c3=" << c3 << " c4=" << c4
- << " c5=" << c5 << "\n";
- pass = false;
- }
-
- swap(a,shcpy_a);
- std::shared_ptr<GFpModulus> ptr3 = a.get_ptr_mod();
- std::shared_ptr<GFpModulus> ptr4 = shcpy_a.get_ptr_mod();
- CHECK_MESSAGE(ptr3.get() == ptr4.get(), "shared pointers for moduli aren´t equal after swap");
- CHECK(ptr1.get() == ptr4.get());
- CHECK(ptr2.get() == ptr3.get());
-
- swap(a,b);
- std::shared_ptr<GFpModulus> ptr_a = a.get_ptr_mod();
- std::shared_ptr<GFpModulus> ptr_b = shcpy_a.get_ptr_mod();
- CHECK(ptr_a.get() == ptr_b_p.get());
- CHECK(ptr_b.get() == ptr3.get());
- return pass;
- }
-
-/**
-* The following test checks the behaviour of GFpElements assignment operator, which
-* has quite complex behaviour with respect to sharing groups and precomputed values
-* (with respect to montgomery mult.)
-*/
-bool test_gfpel_ass_op()
- {
- std::cout << '.' << std::flush;
-
- bool pass = true;
-
-
- // test different moduli
- GFpElement a(23,4);
- GFpElement b(11,6);
-
- GFpElement b2(11,6);
-
- a = b;
- CHECK(a==b2);
- CHECK(a.get_value() == b2.get_value());
- CHECK(a.get_p() == b2.get_p());
- CHECK(a.get_ptr_mod().get() != b.get_ptr_mod().get()); // sharing groups
- // may not be fused!
-
- // also test some share_assign()...
- a.share_assign(b);
- CHECK(a==b2);
- CHECK(a.get_value() == b2.get_value());
- CHECK(a.get_p() == b2.get_p());
- CHECK(a.get_ptr_mod().get() == b.get_ptr_mod().get()); // sharing groups
- // shall be fused!
- //---------------------------
-
- // test assignment within sharing group
- // with montg.mult.
- GFpElement c(5,2);
- GFpElement d(5,2);
- d.share_assign(c);
- CHECK(d.get_ptr_mod().get() == c.get_ptr_mod().get());
- CHECK(d.get_ptr_mod()->get_p() == c.get_ptr_mod()->get_p());
- CHECK(c.get_ptr_mod()->get_r().is_zero());
- c.turn_on_sp_red_mul();
- CHECK(d.get_ptr_mod().get() == c.get_ptr_mod().get());
- CHECK(d.get_ptr_mod()->get_p() == c.get_ptr_mod()->get_p());
- CHECK(!c.get_ptr_mod()->get_p().is_zero());
- GFpElement f(11,5);
- d = f;
- CHECK(f.get_ptr_mod().get() != c.get_ptr_mod().get());
-
- GFpElement e = c*c;
- GFpElement g = d*d;
- GFpElement h = f*f;
- CHECK(h == g);
-
- GFpElement c2(5,2);
- GFpElement d2(5,2);
- d2.share_assign(c2);
- GFpElement f2(11,5);
- d2 = f2;
- c2.turn_on_sp_red_mul();
- CHECK(d2.get_ptr_mod().get() != c2.get_ptr_mod().get()); // the sharing group was left
- CHECK(d2.get_ptr_mod()->get_r() == f2.get_ptr_mod()->get_r());
- CHECK(c2.get_p() == 5); // c2´s shared values weren´t modified because
- // the sharing group with d2 was separated by
- // the assignment "d2 = f2"
-
- d2.turn_on_sp_red_mul();
- CHECK(d2.get_ptr_mod()->get_p() != c2.get_ptr_mod()->get_p());
- GFpElement e2 = c2*c2;
- GFpElement g2 = d2*d2;
- GFpElement h2 = f2*f2;
- CHECK(h2 == g2);
-
- GFpElement c3(5,2);
- GFpElement d3(5,2);
- d3.share_assign(c3);
- GFpElement f3(11,2);
- d3 = f3;
- GFpElement e3 = c3*c3;
- GFpElement g3 = d3*d3;
-
- CHECK(e == e2);
- CHECK(g == g2);
-
- CHECK(e == e3);
- CHECK(g == g2);
- return pass;
- }
-
bool test_gfp_swap()
{
std::cout << '.' << std::flush;
bool pass = true;
-
BigInt p("173");
GFpElement a(p, BigInt("2342"));
GFpElement b(p, BigInt("423420"));
- GFpModulus* a_mod = a.get_ptr_mod().get();
- GFpModulus* b_mod = b.get_ptr_mod().get();
-
- //GFpModulus* a_d = a.get_ptr_mod()->get_p_dash();
- //GFpModulus* b_d = b.get_ptr_mod()->get_p_dash();
-
swap(a,b);
CHECK_MESSAGE(b.get_value() == 2342%173, "actual value of b was: " << b.get_value() );
CHECK_MESSAGE(a.get_value() == 423420%173, "actual value of a was: " << a.get_value() );
- CHECK(a_mod == b.get_ptr_mod().get());
- CHECK(b_mod == a.get_ptr_mod().get());
- //CHECK(a_d == b.get_ptr_mod()->get_p_dash());
- //CHECK(b_d == a.get_ptr_p_dash()->get_p_dash());
-
GFpElement c(p, BigInt("2342329"));
GFpElement d(1,1);
- d.share_assign(c);
+ d = c;
d += d;
c.swap(d);
CHECK(d.get_value() == 2342329%173);
@@ -792,8 +634,6 @@ u32bit do_gfpmath_tests(Botan::RandomNumberGenerator& rng)
failed += !test_gfp_sub();
failed += !test_more_gfp_div();
failed += !test_gfp_mult_u32bit();
- failed += !test_gfp_shared_vals();
- failed += !test_gfpel_ass_op();
failed += !test_gfp_swap();
failed += !test_inv_in_place();
failed += !test_op_eq();
diff --git a/checks/validate.cpp b/checks/validate.cpp
index b0a877b94..093d5e3b7 100644
--- a/checks/validate.cpp
+++ b/checks/validate.cpp
@@ -70,18 +70,26 @@ bool test_passhash(RandomNumberGenerator& rng)
{
#if defined(BOTAN_HAS_PASSHASH9)
+ std::cout << "Testing Password Hashing: " << std::flush;
+
const std::string input = "secret";
const std::string fixed_hash =
"$9$AAAKhiHXTIUhNhbegwBXJvk03XXJdzFMy+i3GFMIBYKtthTTmXZA";
+ std::cout << "." << std::flush;
+
if(!check_passhash9(input, fixed_hash))
return false;
+ std::cout << "." << std::flush;
+
std::string gen_hash = generate_passhash9(input, rng, 5);
if(!check_passhash9(input, gen_hash))
return false;
+ std::cout << "." << std::endl;;
+
#endif
return true;
@@ -206,14 +214,15 @@ u32bit do_validation_tests(const std::string& filename,
}
+ if(should_pass)
+ std::cout << std::endl;
+
if(should_pass && !test_passhash(rng))
{
std::cout << "Passhash9 tests failed" << std::endl;
errors++;
}
- if(should_pass)
- std::cout << std::endl;
return errors;
}
diff --git a/configure.py b/configure.py
index 9a566f716..4388cb0a0 100755
--- a/configure.py
+++ b/configure.py
@@ -464,9 +464,9 @@ class ModuleInfo(object):
return os.path.join(os.path.split(self.lives_in)[0],
*filename.split(':'))
- self.source = map(add_dir_name, self.source)
- self.header_internal = map(add_dir_name, self.header_internal)
- self.header_public = map(add_dir_name, self.header_public)
+ self.source = [add_dir_name(s) for s in self.source]
+ self.header_internal = [add_dir_name(s) for s in self.header_internal]
+ self.header_public = [add_dir_name(s) for s in self.header_public]
self.mp_bits = int(self.mp_bits)
@@ -518,9 +518,9 @@ class ModuleInfo(object):
about any that do not
"""
def dependencies_exist(self, modules):
- all_deps = map(lambda s: s.split('|'), self.dependencies())
+ all_deps = [s.split('|') for s in self.dependencies()]
- for missing in filter(lambda s: s not in modules, flatten(all_deps)):
+ for missing in [s for s in flatten(all_deps) if s not in modules]:
logging.warn("Module '%s', dep of '%s', does not exist" % (
missing, self.basename))
@@ -1055,8 +1055,7 @@ def choose_modules_to_use(modules, archinfo, options):
while dependency_failure:
dependency_failure = False
for modname in to_load:
- for deplist in map(lambda s: s.split('|'),
- modules[modname].dependencies()):
+ for deplist in [s.split('|') for s in modules[modname].dependencies()]:
dep_met = False
for mod in deplist:
@@ -1338,8 +1337,8 @@ def generate_amalgamation(build_config):
botan_all_h.write("\n#endif\n")
internal_header_amalag = Amalgamation_Generator(
- filter(lambda s: s.find('asm_macr_') == -1,
- build_config.internal_headers))
+ [s for s in build_config.internal_headers
+ if s.find('asm_macr_') == -1])
botan_all_cpp = open('botan_all.cpp', 'w')
@@ -1466,6 +1465,16 @@ def main(argv = None):
logging.info('Setting -fpermissive to work around gcc bug')
options.extra_flags = ' -fpermissive'
+ if options.gen_amalgamation:
+ if options.asm_ok:
+ logging.info('Disabling assembly code, cannot use in amalgamation')
+ options.asm_ok = False
+
+ for mod in ['sha1_sse2', 'serpent_simd']:
+ if mod not in options.disabled_modules:
+ logging.info('Disabling %s, cannot use in amalgamation' % (mod))
+ options.disabled_modules.append(mod)
+
modules_to_use = choose_modules_to_use(modules,
archinfo[options.arch],
options)
diff --git a/doc/examples/tls_client.cpp b/doc/examples/tls_client.cpp
new file mode 100644
index 000000000..9e6b510f2
--- /dev/null
+++ b/doc/examples/tls_client.cpp
@@ -0,0 +1,51 @@
+/*
+* (C) 2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/init.h>
+#include <botan/tls_client.h>
+#include <botan/unx_sock.h>
+
+using namespace Botan;
+
+#include <stdio.h>
+#include <string>
+#include <iostream>
+#include <memory>
+
+int main()
+ {
+ try
+ {
+ LibraryInitializer init;
+
+ Unix_Socket sock("www.randombit.net", 443);
+
+ std::auto_ptr<Botan::RandomNumberGenerator> rng(
+ Botan::RandomNumberGenerator::make_rng());
+
+ TLS_Client tls(*rng, sock);
+
+ std::string http_command = "GET /bitbashing\r\n";
+ tls.write((const byte*)http_command.c_str(), http_command.length());
+
+ while(true)
+ {
+ if(tls.is_closed())
+ break;
+
+ byte buf[16+1] = { 0 };
+ u32bit got = tls.read(buf, sizeof(buf)-1);
+ printf("%s", buf);
+ fflush(0);
+ }
+ }
+ catch(std::exception& e)
+ {
+ printf("%s\n", e.what());
+ return 1;
+ }
+ return 0;
+ }
diff --git a/doc/examples/tls_server.cpp b/doc/examples/tls_server.cpp
new file mode 100644
index 000000000..39453dbfd
--- /dev/null
+++ b/doc/examples/tls_server.cpp
@@ -0,0 +1,81 @@
+/*
+* (C) 2008 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/init.h>
+#include <botan/tls_server.h>
+#include <botan/unx_sock.h>
+
+#include <botan/rsa.h>
+#include <botan/dsa.h>
+#include <botan/x509self.h>
+
+using namespace Botan;
+
+#include <stdio.h>
+#include <string>
+#include <iostream>
+#include <memory>
+
+int main(int argc, char* argv[])
+ {
+
+ int port = 4433;
+
+ if(argc == 2)
+ port = to_u32bit(argv[1]);
+
+ try
+ {
+ LibraryInitializer init;
+
+ std::auto_ptr<RandomNumberGenerator> rng(
+ RandomNumberGenerator::make_rng());
+
+ RSA_PrivateKey key(*rng, 512);
+ //DSA_PrivateKey key(get_dl_group("DSA-1024"));
+
+ X509_Cert_Options options(
+ "www.randombit.net/US/Syn Ack Labs/Mathematical Munitions Dept");
+
+ X509_Certificate cert =
+ X509::create_self_signed_cert(options, key, "SHA-1", *rng);
+
+ Unix_Server_Socket listener(port);
+
+ printf("Now listening on port %d...\n", port);
+
+ while(true)
+ {
+ try {
+ Socket* sock = listener.accept();
+
+ printf("Got new connection\n");
+
+ TLS_Server tls(*rng, *sock, cert, key);
+
+ printf("Writing some text\n");
+
+ char msg[] = "Foo\nBar\nBaz\nQuux\n";
+ tls.write((const byte*)msg, strlen(msg));
+
+ printf("Now trying a read...\n");
+
+ char buf[10] = { 0 };
+ u32bit got = tls.read((byte*)buf, 9);
+ printf("%d: '%s'\n", got, buf);
+
+ tls.close();
+ }
+ catch(std::exception& e) { printf("%s\n", e.what()); }
+ }
+ }
+ catch(std::exception& e)
+ {
+ printf("%s\n", e.what());
+ return 1;
+ }
+ return 0;
+ }
diff --git a/doc/log.txt b/doc/log.txt
index 847bf8596..09564a01f 100644
--- a/doc/log.txt
+++ b/doc/log.txt
@@ -1,5 +1,7 @@
* 1.9.4-dev, ????-??-??
+ - Add the Ajisai SSL/TLS implementation
+ - Add GOST 34.10-2001 public key signature scheme
- Add SIMD implementation of Noekeon
- Add SSE2 implementation of IDEA
- Perform XTS encryption and decryption in parallel where possible
@@ -9,6 +11,7 @@
- Add support for password hashing for authentication (passhash9.h)
- Add support for Win32 high resolution system timers
- Changed S2K interface: derive_key now takes salt, iteration count
+ - Remove dependency on TR1 for ECC and CVC code
- Fix crash in GMP_Engine if library is shutdown and reinitialized
- Fix an invalid memory read in MD4
- Remove Timer class entirely
diff --git a/src/cert/cvc/cvc_ado.cpp b/src/cert/cvc/cvc_ado.cpp
index 47c972c72..782922354 100644
--- a/src/cert/cvc/cvc_ado.cpp
+++ b/src/cert/cvc/cvc_ado.cpp
@@ -8,11 +8,10 @@
#include <botan/cvc_ado.h>
#include <fstream>
-#include <assert.h>
namespace Botan {
-EAC1_1_ADO::EAC1_1_ADO(std::shared_ptr<DataSource> in)
+EAC1_1_ADO::EAC1_1_ADO(DataSource& in)
{
init(in);
do_decode();
@@ -20,7 +19,7 @@ EAC1_1_ADO::EAC1_1_ADO(std::shared_ptr<DataSource> in)
EAC1_1_ADO::EAC1_1_ADO(const std::string& in)
{
- std::shared_ptr<DataSource> stream(new DataSource_Stream(in, true));
+ DataSource_Stream stream(in, true);
init(stream);
do_decode();
}
@@ -41,7 +40,7 @@ void EAC1_1_ADO::force_decode()
.end_cons()
.get_contents();
- std::shared_ptr<DataSource> req_source(new DataSource_Memory(req_bits));
+ DataSource_Memory req_source(req_bits);
m_req = EAC1_1_Req(req_source);
sig_algo = m_req.sig_algo;
}
@@ -52,15 +51,14 @@ MemoryVector<byte> EAC1_1_ADO::make_signed(
RandomNumberGenerator& rng)
{
SecureVector<byte> concat_sig =
- EAC1_1_obj<EAC1_1_ADO>::make_signature(signer, tbs_bits, rng);
- assert(concat_sig.size() % 2 == 0);
- MemoryVector<byte> result = DER_Encoder()
+ EAC1_1_obj<EAC1_1_ADO>::make_signature(signer.get(), tbs_bits, rng);
+
+ return DER_Encoder()
.start_cons(ASN1_Tag(7), APPLICATION)
.raw_bytes(tbs_bits)
.encode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION)
.end_cons()
.get_contents();
- return result;
}
ASN1_Car EAC1_1_ADO::get_car() const
@@ -68,14 +66,15 @@ ASN1_Car EAC1_1_ADO::get_car() const
return m_car;
}
-void EAC1_1_ADO::decode_info(SharedPtrConverter<DataSource> source,
+void EAC1_1_ADO::decode_info(DataSource& source,
SecureVector<byte> & res_tbs_bits,
ECDSA_Signature & res_sig)
{
SecureVector<byte> concat_sig;
SecureVector<byte> cert_inner_bits;
ASN1_Car car;
- BER_Decoder(*source.get_ptr().get())
+
+ BER_Decoder(source)
.start_cons(ASN1_Tag(7))
.start_cons(ASN1_Tag(33))
.raw_bytes(cert_inner_bits)
@@ -89,28 +88,30 @@ void EAC1_1_ADO::decode_info(SharedPtrConverter<DataSource> source,
.raw_bytes(cert_inner_bits)
.end_cons()
.get_contents();
+
SecureVector<byte> enc_car = DER_Encoder()
.encode(car)
.get_contents();
+
res_tbs_bits = enc_cert;
res_tbs_bits.append(enc_car);
res_sig = decode_concatenation(concat_sig);
-
-
}
+
void EAC1_1_ADO::encode(Pipe& out, X509_Encoding encoding) const
{
- SecureVector<byte> concat_sig(EAC1_1_obj<EAC1_1_ADO>::m_sig.get_concatenation());
- SecureVector<byte> der = DER_Encoder()
- .start_cons(ASN1_Tag(7), APPLICATION)
- .raw_bytes(tbs_bits)
- .encode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION)
- .end_cons()
- .get_contents();
if(encoding == PEM)
throw Invalid_Argument("EAC1_1_ADO::encode() cannot PEM encode an EAC object");
- else
- out.write(der);
+
+ SecureVector<byte> concat_sig(
+ EAC1_1_obj<EAC1_1_ADO>::m_sig.get_concatenation());
+
+ out.write(DER_Encoder()
+ .start_cons(ASN1_Tag(7), APPLICATION)
+ .raw_bytes(tbs_bits)
+ .encode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION)
+ .end_cons()
+ .get_contents());
}
SecureVector<byte> EAC1_1_ADO::tbs_data() const
@@ -120,8 +121,6 @@ SecureVector<byte> EAC1_1_ADO::tbs_data() const
bool EAC1_1_ADO::operator==(EAC1_1_ADO const& rhs) const
{
- assert(((this->m_req == rhs.m_req) && (this->tbs_data() == rhs.tbs_data())) ||
- ((this->m_req != rhs.m_req) && (this->tbs_data() != rhs.tbs_data())));
return (this->get_concat_sig() == rhs.get_concat_sig()
&& this->tbs_data() == rhs.tbs_data()
&& this->get_car() == rhs.get_car());
diff --git a/src/cert/cvc/cvc_ado.h b/src/cert/cvc/cvc_ado.h
index 5968b1ba4..100888d29 100644
--- a/src/cert/cvc/cvc_ado.h
+++ b/src/cert/cvc/cvc_ado.h
@@ -38,7 +38,7 @@ class BOTAN_DLL EAC1_1_ADO : public EAC1_1_obj<EAC1_1_ADO>
* Construct a CVC ADO request from a data source
* @param source the data source
*/
- EAC1_1_ADO(std::shared_ptr<DataSource> source);
+ EAC1_1_ADO(DataSource& source);
/**
* Create a signed CVC ADO request from to be signed (TBS) data
@@ -83,7 +83,7 @@ class BOTAN_DLL EAC1_1_ADO : public EAC1_1_obj<EAC1_1_ADO>
EAC1_1_Req m_req;
void force_decode();
- static void decode_info(SharedPtrConverter<DataSource> source,
+ static void decode_info(DataSource& source,
SecureVector<byte> & res_tbs_bits,
ECDSA_Signature & res_sig);
};
diff --git a/src/cert/cvc/cvc_ca.cpp b/src/cert/cvc/cvc_ca.cpp
index b51c1f4ff..af40fcd05 100644
--- a/src/cert/cvc/cvc_ca.cpp
+++ b/src/cert/cvc/cvc_ca.cpp
@@ -37,8 +37,7 @@ EAC1_1_CVC EAC1_1_CVC_CA::make_cert(PK_Signer& signer,
EAC1_1_CVC::build_cert_body(tbs),
rng);
- std::shared_ptr<DataSource> source(new DataSource_Memory(signed_cert));
-
+ DataSource_Memory source(signed_cert);
return EAC1_1_CVC(source);
}
diff --git a/src/cert/cvc/cvc_cert.cpp b/src/cert/cvc/cvc_cert.cpp
index 5c2e28c39..4274e143b 100644
--- a/src/cert/cvc/cvc_cert.cpp
+++ b/src/cert/cvc/cvc_cert.cpp
@@ -56,7 +56,7 @@ void EAC1_1_CVC::force_decode()
throw Decoding_Error("CertificateHolderAuthorizationValue was not of length 1");
if(cpi != 0)
- throw Decoding_Error("EAC1_1 certificate´s cpi was not 0");
+ throw Decoding_Error("EAC1_1 certificate's cpi was not 0");
// FIXME: PK algos have no notion of EAC encoder/decoder currently
#if 0
@@ -78,7 +78,7 @@ void EAC1_1_CVC::force_decode()
/*
* CVC Certificate Constructor
*/
-EAC1_1_CVC::EAC1_1_CVC(std::shared_ptr<DataSource>& in)
+EAC1_1_CVC::EAC1_1_CVC(DataSource& in)
{
init(in);
self_signed = false;
@@ -87,7 +87,7 @@ EAC1_1_CVC::EAC1_1_CVC(std::shared_ptr<DataSource>& in)
EAC1_1_CVC::EAC1_1_CVC(const std::string& in)
{
- std::shared_ptr<DataSource> stream(new DataSource_Stream(in, true));
+ DataSource_Stream stream(in, true);
init(stream);
self_signed = false;
do_decode();
diff --git a/src/cert/cvc/cvc_cert.h b/src/cert/cvc/cvc_cert.h
index 0bc162c0c..ae0c21d7b 100644
--- a/src/cert/cvc/cvc_cert.h
+++ b/src/cert/cvc/cvc_cert.h
@@ -59,7 +59,7 @@ class BOTAN_DLL EAC1_1_CVC : public EAC1_1_gen_CVC<EAC1_1_CVC>//Signed_Object
* Construct a CVC from a data source
* @param source the data source
*/
- EAC1_1_CVC(std::shared_ptr<DataSource>& source);
+ EAC1_1_CVC(DataSource& source);
/**
* Construct a CVC from a file
diff --git a/src/cert/cvc/cvc_gen_cert.h b/src/cert/cvc/cvc_gen_cert.h
index 059a82562..d64812e1e 100644
--- a/src/cert/cvc/cvc_gen_cert.h
+++ b/src/cert/cvc/cvc_gen_cert.h
@@ -16,7 +16,6 @@
#include <botan/ecdsa.h>
#include <botan/ecdsa_sig.h>
#include <string>
-#include <assert.h>
namespace Botan {
@@ -87,7 +86,7 @@ class BOTAN_DLL EAC1_1_gen_CVC : public EAC1_1_obj<Derived> // CRTP continuation
ASN1_Chr m_chr;
bool self_signed;
- static void decode_info(SharedPtrConverter<DataSource> source,
+ static void decode_info(DataSource& source,
SecureVector<byte> & res_tbs_bits,
ECDSA_Signature & res_sig);
@@ -108,8 +107,8 @@ template<typename Derived> MemoryVector<byte> EAC1_1_gen_CVC<Derived>::make_sign
const MemoryRegion<byte>& tbs_bits,
RandomNumberGenerator& rng) // static
{
- SecureVector<byte> concat_sig = EAC1_1_obj<Derived>::make_signature(signer, tbs_bits, rng);
- assert(concat_sig.size() % 2 == 0);
+ SecureVector<byte> concat_sig = EAC1_1_obj<Derived>::make_signature(signer.get(), tbs_bits, rng);
+
return DER_Encoder()
.start_cons(ASN1_Tag(33), APPLICATION)
.raw_bytes(tbs_bits)
@@ -156,12 +155,12 @@ template<typename Derived> void EAC1_1_gen_CVC<Derived>::encode(Pipe& out, X509_
template<typename Derived>
void EAC1_1_gen_CVC<Derived>::decode_info(
- SharedPtrConverter<DataSource> source,
+ DataSource& source,
SecureVector<byte> & res_tbs_bits,
ECDSA_Signature & res_sig)
{
SecureVector<byte> concat_sig;
- BER_Decoder(*source.get_shared().get())
+ BER_Decoder(source)
.start_cons(ASN1_Tag(33))
.start_cons(ASN1_Tag(78))
.raw_bytes(res_tbs_bits)
diff --git a/src/cert/cvc/cvc_req.cpp b/src/cert/cvc/cvc_req.cpp
index aa29d8ee6..6df6157ad 100644
--- a/src/cert/cvc/cvc_req.cpp
+++ b/src/cert/cvc/cvc_req.cpp
@@ -10,19 +10,17 @@
#include <botan/ber_dec.h>
#include <botan/pem.h>
#include <botan/parsing.h>
-#include <assert.h>
#include <botan/cvc_key.h>
#include <botan/oids.h>
#include <botan/look_pk.h>
#include <botan/cvc_req.h>
-#include <botan/freestore.h>
namespace Botan {
bool EAC1_1_Req::operator==(EAC1_1_Req const& rhs) const
{
- return (this->tbs_data() == rhs.tbs_data()
- && this->get_concat_sig() == rhs.get_concat_sig());
+ return (this->tbs_data() == rhs.tbs_data() &&
+ this->get_concat_sig() == rhs.get_concat_sig());
}
void EAC1_1_Req::force_decode()
@@ -36,10 +34,9 @@ void EAC1_1_Req::force_decode()
.end_cons()
.decode(m_chr)
.verify_end();
+
if(cpi != 0)
- {
- throw Decoding_Error("EAC1_1 request´s cpi was not 0");
- }
+ throw Decoding_Error("EAC1_1 requests cpi was not 0");
// FIXME: No EAC support in ECDSA
#if 0
@@ -50,7 +47,7 @@ void EAC1_1_Req::force_decode()
#endif
}
-EAC1_1_Req::EAC1_1_Req(std::shared_ptr<DataSource> in)
+EAC1_1_Req::EAC1_1_Req(DataSource& in)
{
init(in);
self_signed = true;
@@ -59,7 +56,7 @@ EAC1_1_Req::EAC1_1_Req(std::shared_ptr<DataSource> in)
EAC1_1_Req::EAC1_1_Req(const std::string& in)
{
- std::shared_ptr<DataSource> stream(new DataSource_Stream(in, true));
+ DataSource_Stream stream(in, true);
init(stream);
self_signed = true;
do_decode();
diff --git a/src/cert/cvc/cvc_req.h b/src/cert/cvc/cvc_req.h
index ea05fc157..2abc72c9a 100644
--- a/src/cert/cvc/cvc_req.h
+++ b/src/cert/cvc/cvc_req.h
@@ -35,7 +35,7 @@ class BOTAN_DLL EAC1_1_Req : public EAC1_1_gen_CVC<EAC1_1_Req>
* Construct a CVC request from a data source.
* @param source the data source
*/
- EAC1_1_Req(std::shared_ptr<DataSource> source);
+ EAC1_1_Req(DataSource& source);
/**
* Construct a CVC request from a DER encoded CVC reqeust file.
diff --git a/src/cert/cvc/cvc_self.cpp b/src/cert/cvc/cvc_self.cpp
index dae8f1804..8d782983d 100644
--- a/src/cert/cvc/cvc_self.cpp
+++ b/src/cert/cvc/cvc_self.cpp
@@ -16,6 +16,7 @@
#include <botan/cvc_ado.h>
#include <chrono>
#include <sstream>
+#include <assert.h>
namespace Botan {
@@ -42,6 +43,7 @@ std::string padding_and_hash_from_oid(OID const& oid)
padding_and_hash.erase(0, padding_and_hash.find("/",0) + 1);
return padding_and_hash;
}
+
std::string fixed_len_seqnr(u32bit seqnr, u32bit len)
{
std::stringstream ss;
@@ -132,11 +134,9 @@ EAC1_1_Req create_cvc_req(Private_Key const& key,
.encode(chr)
.get_contents();
- MemoryVector<byte> signed_cert =
- EAC1_1_gen_CVC<EAC1_1_Req>::make_signed(*signer.get(),
- EAC1_1_gen_CVC<EAC1_1_Req>::build_cert_body(tbs), rng);
+ MemoryVector<byte> signed_cert = EAC1_1_gen_CVC<EAC1_1_Req>::make_signed(signer, EAC1_1_gen_CVC<EAC1_1_Req>::build_cert_body(tbs), rng);
- std::shared_ptr<DataSource> source(new DataSource_Memory(signed_cert));
+ DataSource_Memory source(signed_cert);
return EAC1_1_Req(source);
}
@@ -158,9 +158,9 @@ EAC1_1_ADO create_ado_req(Private_Key const& key,
SecureVector<byte> tbs_bits = req.BER_encode();
tbs_bits.append(DER_Encoder().encode(car).get_contents());
+ MemoryVector<byte> signed_cert = EAC1_1_ADO::make_signed(signer, tbs_bits, rng);
- MemoryVector<byte> signed_cert = EAC1_1_ADO::make_signed(*signer.get(), tbs_bits, rng);
- std::shared_ptr<DataSource> source(new DataSource_Memory(signed_cert));
+ DataSource_Memory source(signed_cert);
return EAC1_1_ADO(source);
}
@@ -214,7 +214,7 @@ EAC1_1_CVC link_cvca(EAC1_1_CVC const& signer,
}
if (signer.signature_algorithm() != signee.signature_algorithm())
{
- throw Invalid_Argument("link_cvca(): signature algorithms of signer and signee don´t match");
+ throw Invalid_Argument("link_cvca(): signature algorithms of signer and signee don't match");
}
AlgorithmIdentifier sig_algo = signer.signature_algorithm();
std::string padding_and_hash = padding_and_hash_from_oid(sig_algo.oid);
diff --git a/src/cert/cvc/eac_obj.h b/src/cert/cvc/eac_obj.h
index 74d7460dd..419929a19 100644
--- a/src/cert/cvc/eac_obj.h
+++ b/src/cert/cvc/eac_obj.h
@@ -18,7 +18,6 @@
#include <botan/oids.h>
#include <botan/look_pk.h>
#include <botan/ecdsa_sig.h>
-#include <botan/freestore.h>
#include <string>
namespace Botan {
@@ -50,7 +49,7 @@ class BOTAN_DLL EAC1_1_obj : public EAC_Signed_Object
virtual bool check_signature(Public_Key& pub_key) const;
protected:
- void init(SharedPtrConverter<DataSource> in);
+ void init(DataSource& in);
static SecureVector<byte> make_signature(PK_Signer& signer,
const MemoryRegion<byte>& tbs_bits,
@@ -78,11 +77,12 @@ EAC1_1_obj<Derived>::make_signature(PK_Signer& signer,
return concat_sig;
}
-template<typename Derived> void EAC1_1_obj<Derived>::init(SharedPtrConverter<DataSource> in)
+template<typename Derived>
+void EAC1_1_obj<Derived>::init(DataSource& in)
{
try
{
- Derived::decode_info(in.get_shared(), tbs_bits, m_sig);
+ Derived::decode_info(in, tbs_bits, m_sig);
}
catch(Decoding_Error)
{
diff --git a/src/cert/cvc/freestore.h b/src/cert/cvc/freestore.h
deleted file mode 100644
index 3049dbd13..000000000
--- a/src/cert/cvc/freestore.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-* (C) 2007 Christoph Ludwig
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_FREESTORE_H__
-#define BOTAN_FREESTORE_H__
-
-#include <botan/build.h>
-#include <memory>
-
-namespace Botan {
-
-/**
-* This class is intended as an function call parameter type and
-* enables convenient automatic conversions between plain and smart
-* pointer types. It internally stores a SharedPointer which can be
-* accessed.
-*/
-template<typename T>
-class BOTAN_DLL SharedPtrConverter
- {
- public:
- typedef std::shared_ptr<T> SharedPtr;
-
- /**
- * Construct a null pointer equivalent object.
- */
- SharedPtrConverter() : ptr() {}
-
- /**
- * Copy constructor.
- */
- SharedPtrConverter(SharedPtrConverter const& other) :
- ptr(other.ptr) {}
-
- /**
- * Construct a converter object from another pointer type.
- * @param p the pointer which shall be set as the internally stored
- * pointer value of this converter.
- */
- template<typename Ptr>
- SharedPtrConverter(Ptr p)
- : ptr(p) {}
-
- /**
- * Get the internally stored shared pointer.
- * @return the internally stored shared pointer
- */
- SharedPtr const& get_ptr() const { return this->ptr; }
-
- /**
- * Get the internally stored shared pointer.
- * @return the internally stored shared pointer
- */
- SharedPtr get_ptr() { return this->ptr; }
-
- /**
- * Get the internally stored shared pointer.
- * @return the internally stored shared pointer
- */
- SharedPtr const& get_shared() const { return this->ptr; }
-
- /**
- * Get the internally stored shared pointer.
- * @return the internally stored shared pointer
- */
- SharedPtr get_shared() { return this->ptr; }
-
- private:
- SharedPtr ptr;
- };
-
-}
-
-#endif
diff --git a/src/cert/cvc/info.txt b/src/cert/cvc/info.txt
index b89441a03..285838379 100644
--- a/src/cert/cvc/info.txt
+++ b/src/cert/cvc/info.txt
@@ -1,5 +1,4 @@
define CARD_VERIFIABLE_CERTIFICATES
-
load_on auto
<header:public>
@@ -13,7 +12,6 @@ cvc_self.h
eac_asn_obj.h
eac_obj.h
ecdsa_sig.h
-freestore.h
signed_obj.h
</header:public>
diff --git a/src/cms/cms_dec.cpp b/src/cms/cms_dec.cpp
index 222399f6c..038d01869 100644
--- a/src/cms/cms_dec.cpp
+++ b/src/cms/cms_dec.cpp
@@ -17,7 +17,7 @@ namespace Botan {
* CMS_Decoder Constructor
*/
CMS_Decoder::CMS_Decoder(DataSource& in, const X509_Store& x509store,
- User_Interface& ui_ref, PKCS8_PrivateKey* key) :
+ User_Interface& ui_ref, Private_Key* key) :
ui(ui_ref), store(x509store)
{
status = GOOD;
@@ -57,7 +57,7 @@ void CMS_Decoder::initial_read(DataSource&)
/*
* Add another private key to use
*/
-void CMS_Decoder::add_key(PKCS8_PrivateKey* key)
+void CMS_Decoder::add_key(Private_Key* key)
{
if(!key)
return;
diff --git a/src/cms/cms_dec.h b/src/cms/cms_dec.h
index 75b61c9cb..a00b44766 100644
--- a/src/cms/cms_dec.h
+++ b/src/cms/cms_dec.h
@@ -37,10 +37,10 @@ class BOTAN_DLL CMS_Decoder
void next_layer() { decode_layer(); }
- void add_key(PKCS8_PrivateKey*);
+ void add_key(Private_Key*);
CMS_Decoder(DataSource&, const X509_Store&, User_Interface&,
- PKCS8_PrivateKey* = 0);
+ Private_Key* = 0);
private:
std::string get_passphrase(const std::string&);
void read_econtent(BER_Decoder&);
@@ -52,7 +52,7 @@ class BOTAN_DLL CMS_Decoder
X509_Store store;
std::vector<std::string> passphrases;
- std::vector<PKCS8_PrivateKey*> keys;
+ std::vector<Private_Key*> keys;
OID type, next_type;
SecureVector<byte> data;
diff --git a/src/cms/cms_ealg.cpp b/src/cms/cms_ealg.cpp
index 5efa33254..60479a820 100644
--- a/src/cms/cms_ealg.cpp
+++ b/src/cms/cms_ealg.cpp
@@ -97,7 +97,7 @@ void CMS_Encoder::encrypt(RandomNumberGenerator& rng,
{
const std::string cipher = choose_algo(user_cipher, "TripleDES");
- std::auto_ptr<X509_PublicKey> key(to.subject_public_key());
+ std::auto_ptr<Public_Key> key(to.subject_public_key());
const std::string algo = key->algo_name();
Key_Constraints constraints = to.constraints();
@@ -165,7 +165,7 @@ void CMS_Encoder::encrypt_ktri(RandomNumberGenerator& rng,
*/
void CMS_Encoder::encrypt_kari(RandomNumberGenerator&,
const X509_Certificate&,
- X509_PublicKey*,
+ Public_Key*,
const std::string&)
{
throw Internal_Error("FIXME: unimplemented");
@@ -287,7 +287,7 @@ SecureVector<byte> CMS_Encoder::do_encrypt(RandomNumberGenerator& rng,
* Sign a message
*/
void CMS_Encoder::sign(const X509_Certificate& cert,
- const PKCS8_PrivateKey& key,
+ const Private_Key& key,
RandomNumberGenerator& rng,
const std::vector<X509_Certificate>& chain,
const std::string& hash,
diff --git a/src/cms/cms_enc.h b/src/cms/cms_enc.h
index 6fdd2b726..b1e18ef7d 100644
--- a/src/cms/cms_enc.h
+++ b/src/cms/cms_enc.h
@@ -36,7 +36,7 @@ class BOTAN_DLL CMS_Encoder
void authenticate(const SymmetricKey&, const std::string& = "");
void sign(const X509_Certificate& cert,
- const PKCS8_PrivateKey& key,
+ const Private_Key& key,
RandomNumberGenerator& rng,
const std::vector<X509_Certificate>& cert_chain,
const std::string& hash,
@@ -62,7 +62,7 @@ class BOTAN_DLL CMS_Encoder
const X509_Certificate&, PK_Encrypting_Key*,
const std::string&);
void encrypt_kari(RandomNumberGenerator&,
- const X509_Certificate&, X509_PublicKey*,
+ const X509_Certificate&, Public_Key*,
const std::string&);
SecureVector<byte> do_encrypt(RandomNumberGenerator& rng,
diff --git a/src/libstate/policy.cpp b/src/libstate/policy.cpp
index c11fc28ce..3e9c8e122 100644
--- a/src/libstate/policy.cpp
+++ b/src/libstate/policy.cpp
@@ -38,6 +38,7 @@ void set_default_oids(Library_State& config)
add_oid(config, "1.3.6.1.4.1.25258.1.1", "RW");
add_oid(config, "1.3.6.1.4.1.25258.1.2", "NR");
add_oid(config, "1.2.840.10045.2.1", "ECDSA"); // X9.62
+ add_oid(config, "1.2.643.2.2.19", "GOST-34.10"); // RFC 4491
/* Ciphers */
add_oid(config, "1.3.14.3.2.7", "DES/CBC");
@@ -103,6 +104,8 @@ void set_default_oids(Library_State& config)
add_oid(config, "1.2.840.10045.4.3.3", "ECDSA/EMSA1(SHA-384)");
add_oid(config, "1.2.840.10045.4.3.4", "ECDSA/EMSA1(SHA-512)");
+ add_oid(config, "1.2.643.2.2.3", "GOST-34.10/EMSA1(GOST-R-34.11-94)");
+
add_oid(config, "1.3.6.1.4.1.25258.2.1.1.1", "RW/EMSA2(RIPEMD-160)");
add_oid(config, "1.3.6.1.4.1.25258.2.1.1.2", "RW/EMSA2(SHA-160)");
add_oid(config, "1.3.6.1.4.1.25258.2.1.1.3", "RW/EMSA2(SHA-224)");
diff --git a/src/math/gfpmath/curve_gfp.cpp b/src/math/gfpmath/curve_gfp.cpp
index d88146dd5..e6e69ab0f 100644
--- a/src/math/gfpmath/curve_gfp.cpp
+++ b/src/math/gfpmath/curve_gfp.cpp
@@ -2,7 +2,7 @@
* Elliptic curves over GF(p)
*
* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke
-* 2008 Jack Lloyd
+* 2008-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
@@ -14,152 +14,45 @@
namespace Botan {
-void CurveGFp::set_shrd_mod(const std::shared_ptr<GFpModulus> mod)
- {
- mp_mod = mod;
- mA.turn_off_sp_red_mul();// m.m. is not needed, must be trf. back
- mB.turn_off_sp_red_mul();// m.m. is not needed, must be trf. back
- //ok, above we destroy any evantually computated montg. mult. values,
- // but that won't influence performance in usual applications
- mA.set_shrd_mod(mod);
- mB.set_shrd_mod(mod);
- }
-
CurveGFp::CurveGFp(const GFpElement& a, const GFpElement& b,
- const BigInt& p)
- : mA(a),
- mB(b)
+ const BigInt& p) :
+ modulus(p), mA(a), mB(b),
+ mres_a(mA), mres_b(mB), mres_one(p, 1)
{
- if(!((p == mA.get_p()) && (p == mB.get_p())))
- {
+ if(p != mA.get_p() || p != mB.get_p())
throw Invalid_Argument("could not construct curve: moduli of arguments differ");
- }
- std::shared_ptr<GFpModulus> p_mod = std::shared_ptr<GFpModulus>(new GFpModulus(p));
- // the above is the creation of the GFpModuls object which will be shared point-wide
- // (in the context of a point of course)
- set_shrd_mod(p_mod);
- }
-// copy constructor
-CurveGFp::CurveGFp(const CurveGFp& other)
- : mA(other.get_a()),
- mB(other.get_b())
- {
- mp_mod = std::shared_ptr<GFpModulus>(new GFpModulus(*other.mp_mod));
- assert(mp_mod->p_equal_to(mA.get_p()));
- assert(mp_mod->p_equal_to(mB.get_p()));
- set_shrd_mod(mp_mod);
- if(other.mp_mres_a.get())
- {
- mp_mres_a = std::shared_ptr<GFpElement>(new GFpElement(*other.mp_mres_a));
- }
- if(other.mp_mres_b.get())
- {
- mp_mres_b = std::shared_ptr<GFpElement>(new GFpElement(*other.mp_mres_b));
- }
- if(other.mp_mres_one.get())
- {
- mp_mres_one = std::shared_ptr<GFpElement>(new GFpElement(*other.mp_mres_one));
- }
-
- }
-// assignment operator
-const CurveGFp& CurveGFp::operator=(const CurveGFp& other)
- {
- // for exception safety...
- GFpElement a_tmp = other.mA;
- GFpElement b_tmp = other.mB;
- mA.swap(a_tmp);
- mB.swap(b_tmp);
-
- std::shared_ptr<GFpModulus> p_mod = std::shared_ptr<GFpModulus>(new GFpModulus(*other.mp_mod));
- set_shrd_mod(p_mod);
-
- // exception safety note: no problem if we have a throw from here on...
- if(other.mp_mres_a.get())
- {
- mp_mres_a = std::shared_ptr<GFpElement>(new GFpElement(*other.mp_mres_a));
- }
- if(other.mp_mres_b.get())
- {
- mp_mres_b = std::shared_ptr<GFpElement>(new GFpElement(*other.mp_mres_b));
- }
- if(other.mp_mres_one.get())
- {
- mp_mres_one = std::shared_ptr<GFpElement>(new GFpElement(*other.mp_mres_one));
- }
- return *this;
- }
-
-// getters
-const GFpElement& CurveGFp::get_a() const
- {
- return mA;
- }
+ mres_a.turn_on_sp_red_mul();
+ mres_a.get_mres();
-const GFpElement& CurveGFp::get_b() const
- {
- return mB;
- }
+ mres_b.turn_on_sp_red_mul();
+ mres_b.get_mres();
-const BigInt CurveGFp::get_p() const
- {
- assert(mp_mod.get() != 0);
- return mp_mod->get_p();
+ mres_one.turn_on_sp_red_mul();
+ mres_one.get_mres();
}
// swaps the states of *this and other, does not throw
void CurveGFp::swap(CurveGFp& other)
{
- mA.swap(other.mA);
- mB.swap(other.mB);
- mp_mod.swap(other.mp_mod);
- std::swap(mp_mres_a, other.mp_mres_a);
- std::swap(mp_mres_b, other.mp_mres_b);
- std::swap(mp_mres_one, other.mp_mres_one);
- }
-
-GFpElement const CurveGFp::get_mres_a() const
- {
- if(mp_mres_a.get() == 0)
- {
- mp_mres_a = std::shared_ptr<GFpElement>(new GFpElement(mA));
- mp_mres_a->turn_on_sp_red_mul();
- mp_mres_a->get_mres();
- }
- return GFpElement(*mp_mres_a);
- }
-
-GFpElement const CurveGFp::get_mres_b() const
- {
- if(mp_mres_b.get() == 0)
- {
- mp_mres_b = std::shared_ptr<GFpElement>(new GFpElement(mB));
- mp_mres_b->turn_on_sp_red_mul();
- mp_mres_b->get_mres();
- }
- return GFpElement(*mp_mres_b);
- }
-
-std::shared_ptr<GFpElement const> const CurveGFp::get_mres_one() const
- {
- if(mp_mres_one.get() == 0)
- {
- mp_mres_one = std::shared_ptr<GFpElement>(new GFpElement(mp_mod->get_p(), 1));
- mp_mres_one->turn_on_sp_red_mul();
- mp_mres_one->get_mres();
- }
- return mp_mres_one;
+ std::swap(mA, other.mA);
+ std::swap(mB, other.mB);
+ std::swap(modulus, other.modulus);
+ std::swap(mres_a, other.mres_a);
+ std::swap(mres_b, other.mres_b);
+ std::swap(mres_one, other.mres_one);
}
bool operator==(const CurveGFp& lhs, const CurveGFp& rhs)
{
- return (lhs.get_p() == rhs.get_p() && lhs.get_a() == rhs.get_a() && lhs.get_b() == rhs.get_b());
+ return (lhs.get_p() == rhs.get_p() &&
+ lhs.get_a() == rhs.get_a() &&
+ lhs.get_b() == rhs.get_b());
}
std::ostream& operator<<(std::ostream& output, const CurveGFp& elem)
{
- return output << "y^2f = x^3 + (" << elem.get_a() << ")x + (" << elem.get_b() << ")";
+ return output << "y^2 = x^3 + (" << elem.get_a() << ")x + (" << elem.get_b() << ")";
}
}
diff --git a/src/math/gfpmath/curve_gfp.h b/src/math/gfpmath/curve_gfp.h
index 5b0ec0558..d2ca437fb 100644
--- a/src/math/gfpmath/curve_gfp.h
+++ b/src/math/gfpmath/curve_gfp.h
@@ -2,6 +2,7 @@
* Elliptic curves over GF(p)
*
* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke
+* 2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
@@ -31,28 +32,8 @@ class BOTAN_DLL CurveGFp
CurveGFp(const GFpElement& a, const GFpElement& b,
const BigInt& p);
- /**
- * Copy constructor
- * @param other The curve to clone
- */
- CurveGFp(const CurveGFp& other);
-
- /**
- * Assignment operator
- * @param other The curve to use as source for the assignment
- */
- const CurveGFp& operator=(const CurveGFp& other);
-
- /**
- * Set the shared GFpModulus object.
- * Warning: do not use this function unless you know in detail how
- * the sharing of values
- * in the various EC related objects works.
- * Do NOT spread pointers to a GFpModulus over different threads!
- * @param mod a shared pointer to a GFpModulus object suitable for
- * *this.
- */
- void set_shrd_mod(const std::shared_ptr<GFpModulus> mod);
+ // CurveGFp(const CurveGFp& other) = default;
+ // CurveGFp& operator=(const CurveGFp& other) = default;
// getters
@@ -60,13 +41,13 @@ class BOTAN_DLL CurveGFp
* Get coefficient a
* @result coefficient a
*/
- const GFpElement& get_a() const;
+ const GFpElement& get_a() const { return mA; }
/**
* Get coefficient b
* @result coefficient b
*/
- const GFpElement& get_b() const;
+ const GFpElement& get_b() const { return mB; }
/**
* Get the GFpElement coefficient a transformed
@@ -75,7 +56,7 @@ class BOTAN_DLL CurveGFp
* function.
* @result the coefficient a, transformed to its m-residue
*/
- GFpElement const get_mres_a() const;
+ const GFpElement& get_mres_a() const { return mres_a; }
/**
* Get the GFpElement coefficient b transformed
@@ -84,8 +65,7 @@ class BOTAN_DLL CurveGFp
* function.
* @result the coefficient b, transformed to its m-residue
*/
- GFpElement const get_mres_b() const;
-
+ const GFpElement& get_mres_b() const { return mres_b; }
/**
* Get the GFpElement 1 transformed
@@ -94,31 +74,13 @@ class BOTAN_DLL CurveGFp
* function.
* @result the GFpElement 1, transformed to its m-residue
*/
- std::shared_ptr<GFpElement const> const get_mres_one() const;
+ const GFpElement& get_mres_one() { return mres_one; }
/**
* Get prime modulus of the field of the curve
* @result prime modulus of the field of the curve
*/
- BigInt const get_p() const;
- /*inline std::shared_ptr<BigInt> const get_ptr_p() const
- {
- return mp_p;
- }*/
-
- /**
- * Retrieve a shared pointer to the curves GFpModulus object for
- * efficient storage and computation of montgomery multiplication
- * related data members and functions. Warning: do not use this
- * function unless you know in detail how the sharing of values
- * in the various EC related objects works. Do NOT spread
- * pointers to a GFpModulus over different threads!
- * @result a shared pointer to a GFpModulus object
- */
- inline std::shared_ptr<GFpModulus> const get_ptr_mod() const
- {
- return mp_mod;
- }
+ const BigInt& get_p() const { return modulus.get_p(); }
/**
* swaps the states of *this and other, does not throw
@@ -127,12 +89,10 @@ class BOTAN_DLL CurveGFp
void swap(CurveGFp& other);
private:
- std::shared_ptr<GFpModulus> mp_mod;
+ GFpModulus modulus;
GFpElement mA;
GFpElement mB;
- mutable std::shared_ptr<GFpElement> mp_mres_a;
- mutable std::shared_ptr<GFpElement> mp_mres_b;
- mutable std::shared_ptr<GFpElement> mp_mres_one;
+ GFpElement mres_a, mres_b, mres_one;
};
// relational operators
diff --git a/src/math/gfpmath/gfp_element.cpp b/src/math/gfpmath/gfp_element.cpp
index 3f028f34f..3bb4d0002 100644
--- a/src/math/gfpmath/gfp_element.cpp
+++ b/src/math/gfpmath/gfp_element.cpp
@@ -165,47 +165,20 @@ BigInt montg_trf_to_ordres(const BigInt& m_res, const BigInt& m, const BigInt& r
}
-GFpElement::GFpElement(const BigInt& p, const BigInt& value, bool use_montgm)
- : mp_mod(),
- m_value(value %p),
- m_use_montgm(use_montgm),
- m_is_trf(false)
- {
- assert(mp_mod.get() == 0);
- mp_mod = std::shared_ptr<GFpModulus>(new GFpModulus(p));
- assert(mp_mod->m_p_dash == 0);
+GFpElement::GFpElement(const BigInt& p, const BigInt& value, bool use_montgomery)
+ : modulus(p), m_value(value %p), m_use_montgm(use_montgomery), m_is_trf(false)
+ {
if(m_use_montgm)
ensure_montgm_precomp();
}
-GFpElement::GFpElement(std::shared_ptr<GFpModulus> const mod, const BigInt& value, bool use_montgm)
- : mp_mod(),
- m_value(value % mod->m_p),
- m_use_montgm(use_montgm),
- m_is_trf(false)
- {
- assert(mp_mod.get() == 0);
- mp_mod = mod;
- }
-
-GFpElement::GFpElement(const GFpElement& other)
- : m_value(other.m_value),
- m_use_montgm(other.m_use_montgm),
- m_is_trf(other.m_is_trf)
-
- {
- //creates an independent copy
- assert((other.m_is_trf && other.m_use_montgm) || !other.m_is_trf);
- mp_mod.reset(new GFpModulus(*other.mp_mod)); // copy-ctor of GFpModulus
- }
-
-void GFpElement::turn_on_sp_red_mul() const
+void GFpElement::turn_on_sp_red_mul()
{
ensure_montgm_precomp();
m_use_montgm = true;
}
-void GFpElement::turn_off_sp_red_mul() const
+void GFpElement::turn_off_sp_red_mul()
{
if(m_is_trf)
{
@@ -216,40 +189,25 @@ void GFpElement::turn_off_sp_red_mul() const
m_use_montgm = false;
}
-void GFpElement::ensure_montgm_precomp() const
+void GFpElement::ensure_montgm_precomp()
{
- if((!mp_mod->m_r.is_zero()) && (!mp_mod->m_r_inv.is_zero()) && (!mp_mod->m_p_dash.is_zero()))
+ if((!modulus.get_r().is_zero()) && (!modulus.get_r_inv().is_zero()) && (!modulus.get_p_dash().is_zero()))
{
// values are already set, nothing more to do
}
else
{
- BigInt tmp_r(montgm_calc_r_oddmod(mp_mod->m_p));
-
- BigInt tmp_r_inv(inverse_mod(tmp_r, mp_mod->m_p));
+ BigInt tmp_r(montgm_calc_r_oddmod(modulus.get_p()));
- BigInt tmp_p_dash(montgm_calc_m_dash(tmp_r, mp_mod->m_p, tmp_r_inv));
+ BigInt tmp_r_inv(inverse_mod(tmp_r, modulus.get_p()));
- mp_mod->m_r.grow_reg(tmp_r.size());
- mp_mod->m_r_inv.grow_reg(tmp_r_inv.size());
- mp_mod->m_p_dash.grow_reg(tmp_p_dash.size());
+ BigInt tmp_p_dash(montgm_calc_m_dash(tmp_r, modulus.get_p(), tmp_r_inv));
- mp_mod->m_r = tmp_r;
- mp_mod->m_r_inv = tmp_r_inv;
- mp_mod->m_p_dash = tmp_p_dash;
-
- assert(!mp_mod->m_r.is_zero());
- assert(!mp_mod->m_r_inv.is_zero());
- assert(!mp_mod->m_p_dash.is_zero());
+ modulus.reset_values(tmp_p_dash, tmp_r, tmp_r_inv);
}
}
-void GFpElement::set_shrd_mod(std::shared_ptr<GFpModulus> const p_mod)
- {
- mp_mod = p_mod;
- }
-
void GFpElement::trf_to_mres() const
{
if(!m_use_montgm)
@@ -257,27 +215,27 @@ void GFpElement::trf_to_mres() const
throw Illegal_Transformation("GFpElement is not allowed to be transformed to m-residue");
}
assert(m_is_trf == false);
- assert(!mp_mod->m_r_inv.is_zero());
- assert(!mp_mod->m_p_dash.is_zero());
- m_value = montg_trf_to_mres(m_value, mp_mod->m_r, mp_mod->m_p);
+ assert(!modulus.get_r_inv().is_zero());
+ assert(!modulus.get_p_dash().is_zero());
+ m_value = montg_trf_to_mres(m_value, modulus.get_r(), modulus.get_p());
m_is_trf = true;
}
void GFpElement::trf_to_ordres() const
{
assert(m_is_trf == true);
- m_value = montg_trf_to_ordres(m_value, mp_mod->m_p, mp_mod->m_r_inv);
+ m_value = montg_trf_to_ordres(m_value, modulus.get_p(), modulus.get_r_inv());
m_is_trf = false;
}
bool GFpElement::align_operands_res(const GFpElement& lhs, const GFpElement& rhs) //static
{
- assert(lhs.mp_mod->m_p == rhs.mp_mod->m_p);
+ assert(lhs.modulus.get_p() == rhs.modulus.get_p());
if(lhs.m_use_montgm && rhs.m_use_montgm)
{
- assert(rhs.mp_mod->m_p_dash == lhs.mp_mod->m_p_dash);
- assert(rhs.mp_mod->m_r == lhs.mp_mod->m_r);
- assert(rhs.mp_mod->m_r_inv == lhs.mp_mod->m_r_inv);
+ assert(rhs.modulus.get_p_dash() == lhs.modulus.get_p_dash());
+ assert(rhs.modulus.get_r() == lhs.modulus.get_r());
+ assert(rhs.modulus.get_r_inv() == lhs.modulus.get_r_inv());
if(!lhs.m_is_trf && !rhs.m_is_trf)
{
return false;
@@ -327,7 +285,7 @@ bool GFpElement::is_trf_to_mres() const
const BigInt& GFpElement::get_p() const
{
- return (mp_mod->m_p);
+ return (modulus.get_p());
}
const BigInt& GFpElement::get_value() const
@@ -345,7 +303,7 @@ const BigInt& GFpElement::get_mres() const
if(!m_use_montgm)
{
// does the following exception really make sense?
- // wouldn´t it be better to simply turn on montg.mult. when
+ // wouldn't it be better to simply turn on montg.mult. when
// this explicit request is made?
throw Illegal_Transformation("GFpElement is not allowed to be transformed to m-residue");
}
@@ -357,107 +315,17 @@ const BigInt& GFpElement::get_mres() const
return m_value;
}
-const GFpElement& GFpElement::operator=(const GFpElement& other)
- {
- m_value.grow_reg(other.m_value.size()); // grow first for exception safety
-
- //m_value = other.m_value;
-
- // m_use_montgm = other.m_use_montgm;
- // m_is_trf = other.m_is_trf;
- // we want to keep the member pointers, which might be part of a "sharing group"
- // but we may not simply overwrite the BigInt values with those of the argument!!
- // if ours already contains precomputations, it would be hazardous to
- // set them back to zero.
- // thus we first check for equality of the moduli,
- // then whether either of the two objects already contains
- // precomputed values.
-
- // we also deal with the case were the pointers themsevles are equal:
- if(mp_mod.get() == other.mp_mod.get())
- {
- // everything ok, we are in the same sharing group anyway, nothing to do
- m_value = other.m_value; // cannot throw
- m_use_montgm = other.m_use_montgm;
- m_is_trf = other.m_is_trf;
- return *this;
- }
- if(mp_mod->m_p != other.mp_mod->m_p)
- {
- // the moduli are different, this is a special case
- // which will not occur in usual applications,
- // so we don´t hesitate to simply create new objects
- // (we do want to create an independent copy)
- mp_mod.reset(new GFpModulus(*other.mp_mod)); // this could throw,
- // and because of this
- // we haven't modified
- // anything so far
- m_value = other.m_value; // can't throw
- m_use_montgm = other.m_use_montgm;
- m_is_trf = other.m_is_trf;
- return *this;
- }
- // exception safety note: from now on we are on the safe
- // side with respect to the modulus,
- // so we can assign the value now:
- m_value = other.m_value;
- m_use_montgm = other.m_use_montgm;
- m_is_trf = other.m_is_trf;
- // the moduli are equal, but we deal with different sharing groups.
- // we will NOT fuse the sharing goups
- // and we will NOT reset already precomputed values
- if(mp_mod->has_precomputations())
- {
- // our own sharing group already has precomputed values,
- // so nothing to do.
- return *this;
- }
- else
- {
- // let´s see whether the argument has something for us...
- if(other.mp_mod->has_precomputations())
- {
- // fetch them for our sharing group
- // exc. safety note: grow first
- mp_mod->m_p_dash.grow_reg(other.mp_mod->m_p_dash.size());
- mp_mod->m_r.grow_reg(other.mp_mod->m_r.size());
- mp_mod->m_r_inv.grow_reg(other.mp_mod->m_r_inv.size());
-
- mp_mod->m_p_dash = other.mp_mod->m_p_dash;
- mp_mod->m_r = other.mp_mod->m_r;
- mp_mod->m_r_inv = other.mp_mod->m_r_inv;
- return *this;
- }
- }
- // our precomputations aren´t set, the arguments neither,
- // so we let them alone
- return *this;
- }
-
-void GFpElement::share_assign(const GFpElement& other)
- {
- assert((other.m_is_trf && other.m_use_montgm) || !other.m_is_trf);
-
- // use grow_to to make it exc safe
- m_value.grow_reg(other.m_value.size());
- m_value = other.m_value;
-
- m_use_montgm = other.m_use_montgm;
- m_is_trf = other.m_is_trf;
- mp_mod = other.mp_mod; // cannot throw
- }
-
GFpElement& GFpElement::operator+=(const GFpElement& rhs)
{
GFpElement::align_operands_res(*this, rhs);
- workspace = m_value;
+ BigInt workspace = m_value;
workspace += rhs.m_value;
- if(workspace >= mp_mod->m_p)
- workspace -= mp_mod->m_p;
+ if(workspace >= modulus.get_p())
+ workspace -= modulus.get_p();
m_value = workspace;
- assert(m_value < mp_mod->m_p);
+ assert(m_value < modulus.get_p());
assert(m_value >= 0);
return *this;
@@ -467,39 +335,39 @@ GFpElement& GFpElement::operator-=(const GFpElement& rhs)
{
GFpElement::align_operands_res(*this, rhs);
- workspace = m_value;
+ BigInt workspace = m_value;
workspace -= rhs.m_value;
if(workspace.is_negative())
- workspace += mp_mod->m_p;
+ workspace += modulus.get_p();
m_value = workspace;
- assert(m_value < mp_mod->m_p);
+ assert(m_value < modulus.get_p());
assert(m_value >= 0);
return *this;
}
GFpElement& GFpElement::operator*= (u32bit rhs)
{
- workspace = m_value;
+ BigInt workspace = m_value;
workspace *= rhs;
- workspace %= mp_mod->m_p;
+ workspace %= modulus.get_p();
m_value = workspace;
return *this;
}
GFpElement& GFpElement::operator*=(const GFpElement& rhs)
{
- assert(rhs.mp_mod->m_p == mp_mod->m_p);
+ assert(rhs.modulus.get_p() == modulus.get_p());
// here, we do not use align_operands_res() for one simple reason:
// we want to enforce the transformation to an m-residue, otherwise it would
// never happen
if(m_use_montgm && rhs.m_use_montgm)
{
- assert(rhs.mp_mod->m_p == mp_mod->m_p); // is montgm. mult is on, then precomps must be there
- assert(rhs.mp_mod->m_p_dash == mp_mod->m_p_dash);
- assert(rhs.mp_mod->m_r == mp_mod->m_r);
+ assert(rhs.modulus.get_p() == modulus.get_p()); // is montgm. mult is on, then precomps must be there
+ assert(rhs.modulus.get_p_dash() == modulus.get_p_dash());
+ assert(rhs.modulus.get_r() == modulus.get_r());
if(!m_is_trf)
{
trf_to_mres();
@@ -508,8 +376,8 @@ GFpElement& GFpElement::operator*=(const GFpElement& rhs)
{
rhs.trf_to_mres();
}
- workspace = m_value;
- montg_mult(m_value, workspace, rhs.m_value, mp_mod->m_p, mp_mod->m_p_dash, mp_mod->m_r);
+ BigInt workspace = m_value;
+ montg_mult(m_value, workspace, rhs.m_value, modulus.get_p(), modulus.get_p_dash(), modulus.get_r());
}
else // ordinary multiplication
{
@@ -524,9 +392,9 @@ GFpElement& GFpElement::operator*=(const GFpElement& rhs)
rhs.trf_to_ordres();
}
- workspace = m_value;
+ BigInt workspace = m_value;
workspace *= rhs.m_value;
- workspace %= mp_mod->m_p;
+ workspace %= modulus.get_p();
m_value = workspace;
}
return *this;
@@ -536,18 +404,17 @@ GFpElement& GFpElement::operator/=(const GFpElement& rhs)
{
bool use_mres = GFpElement::align_operands_res(*this, rhs);
assert((this->m_is_trf && rhs.m_is_trf) || !(this->m_is_trf && rhs.m_is_trf));
- // (internal note: see C86)
+
if(use_mres)
{
assert(m_use_montgm && rhs.m_use_montgm);
GFpElement rhs_ordres(rhs);
rhs_ordres.trf_to_ordres();
rhs_ordres.inverse_in_place();
- workspace = m_value;
- workspace *= rhs_ordres.get_value();
- workspace %= mp_mod->m_p;
+ BigInt workspace = m_value;
+ workspace *= rhs_ordres.get_value();
+ workspace %= modulus.get_p();
m_value = workspace;
-
}
else
{
@@ -566,30 +433,31 @@ bool GFpElement::is_zero()
GFpElement& GFpElement::inverse_in_place()
{
- m_value = inverse_mod(m_value, mp_mod->m_p);
+ m_value = inverse_mod(m_value, modulus.get_p());
+
if(m_is_trf)
{
assert(m_use_montgm);
- m_value *= mp_mod->m_r;
- m_value *= mp_mod->m_r;
- m_value %= mp_mod->m_p;
+ m_value *= modulus.get_r();
+ m_value *= modulus.get_r();
+ m_value %= modulus.get_p();
}
- assert(m_value <= mp_mod->m_p);
+ assert(m_value <= modulus.get_p());
return *this;
}
GFpElement& GFpElement::negate()
{
- m_value = mp_mod->m_p - m_value;
- assert(m_value <= mp_mod->m_p);
+ m_value = modulus.get_p() - m_value;
+ assert(m_value <= modulus.get_p());
return *this;
}
void GFpElement::swap(GFpElement& other)
{
- m_value.swap(other.m_value);
- mp_mod.swap(other.mp_mod);
+ std::swap(m_value, other.m_value);
+ std::swap(modulus, other.modulus);
std::swap<bool>(m_use_montgm,other.m_use_montgm);
std::swap<bool>(m_is_trf,other.m_is_trf);
}
@@ -601,15 +469,9 @@ std::ostream& operator<<(std::ostream& output, const GFpElement& elem)
bool operator==(const GFpElement& lhs, const GFpElement& rhs)
{
- // for effeciency reasons we firstly check whether
- //the modulus pointers are different in the first place:
- if(lhs.get_ptr_mod() != rhs.get_ptr_mod())
- {
- if(lhs.get_p() != rhs.get_p())
- {
- return false;
- }
- }
+ if(lhs.get_p() != rhs.get_p())
+ return false;
+
// so the modulus is equal, now check the values
bool use_mres = GFpElement::align_operands_res(lhs, rhs);
diff --git a/src/math/gfpmath/gfp_element.h b/src/math/gfpmath/gfp_element.h
index a4d9ac250..538d41a47 100644
--- a/src/math/gfpmath/gfp_element.h
+++ b/src/math/gfpmath/gfp_element.h
@@ -2,6 +2,7 @@
* Arithmetic for prime fields GF(p)
*
* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke
+* 2009-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
@@ -12,7 +13,6 @@
#include <botan/bigint.h>
#include <botan/gfp_modulus.h>
#include <iosfwd>
-#include <memory>
namespace Botan {
@@ -38,57 +38,21 @@ class BOTAN_DLL GFpElement
* @param value the element value
* @param use_montgm whether this object will use Montgomery multiplication
*/
- explicit GFpElement (const BigInt& p, const BigInt& value, bool use_montgm = false);
+ GFpElement(const BigInt& p, const BigInt& value, bool use_montgm = true);
+ // GFpElement(const GFpElement& other) = default;
- /** construct an element of GF(p) with the given value (defaults
- * to 0). use_montg defaults to false and determines wether
- * montgomery multiplications will be use when applying operators
- * '*' , '*='. Use this constructor for efficient use of
- * Montgomery multiplication in a context with a fixed a modulus.
- * Warning: do not use this function unless you know in detail
- * about the implications of using the shared GFpModulus objects!
- * @param mod shared pointer to the GFpModulus to be shared
- * @param value the element value
- * @param use_montgm whether this object will use Montgomery multiplication
- */
- explicit GFpElement(std::shared_ptr<GFpModulus> const mod,
- const BigInt& value, bool use_mongm = false);
-
- /**
- * Copy constructor
- * @param other The element to clone
- */
- GFpElement(const GFpElement& other);
-
- /**
- * Assignment operator.
- * makes *this a totally independent object
- * (gives *this independent modulus specific values).
-
- * @param other The element to assign to our object
- */
- const GFpElement& operator=(const GFpElement& other);
-
- /**
- * Works like the assignment operator, but lets
- * *this share the modulus dependend value with other.
- * Warning: do not use this function unless you know in detail about
- * the implications of using
- * the shared GFpModulus objects!
- * @param other The element to assign to our object
- */
- void share_assign(const GFpElement& other);
+ // const GFpElement& operator=(const GFpElement& other) = default;
/**
* Switch Montgomery multiplcation optimizations ON
*/
- void turn_on_sp_red_mul() const;
+ void turn_on_sp_red_mul();
/**
* Switch Montgomery multiplcation optimizations OFF
*/
- void turn_off_sp_red_mul() const;
+ void turn_off_sp_red_mul();
/**
* += Operator
@@ -122,7 +86,7 @@ class BOTAN_DLL GFpElement
* @param rhs the value to multiply with the local value
* @result *this
*/
- GFpElement& operator*= (u32bit rhs);
+ GFpElement& operator*=(u32bit rhs);
/**
* Negate internal value(*this *= -1 )
@@ -157,31 +121,9 @@ class BOTAN_DLL GFpElement
const BigInt& get_value() const;
/**
- * Returns the shared pointer to the GFpModulus of *this.
- * Warning: do not use this function unless you know in detail about
- * the implications of using
- * the shared GFpModulus objects!
- * @result the shared pointer to the GFpModulus of *this
- */
- inline std::shared_ptr<GFpModulus> const get_ptr_mod() const
- {
- return mp_mod;
- }
-
-
- /**
- * Sets the shared pointer to the GFpModulus of *this.
- * Warning: do not use this function unless you know in detail about
- * the implications of using
- * the shared GFpModulus objects!
- * @param mod a shared pointer to a GFpModulus that will be held in *this
- */
- void set_shrd_mod(std::shared_ptr<GFpModulus> const mod);
-
- /**
- * Tells whether this GFpElement is currently transformed to it´ m-residue,
+ * Tells whether this GFpElement is currently transformed to an m-residue,
* i.e. in the form x_bar = x * r mod m.
- * @result true if it is currently transformed to it´s m-residue.
+ * @result true if it is currently transformed to its m-residue.
*/
bool is_trf_to_mres() const;
@@ -206,7 +148,7 @@ class BOTAN_DLL GFpElement
* in ordinary residue representation (returns false).
* m-residue is prefered in case of ambiguity.
* does not toggle m_use_montgm of the arguments.
- * Don´t be confused about the constness of the arguments:
+ * Don't be confused about the constness of the arguments:
* the transformation between normal residue and m-residue is
* considered as leaving the object const.
* @param lhs the first operand to be aligned
@@ -216,30 +158,22 @@ class BOTAN_DLL GFpElement
*/
static bool align_operands_res(const GFpElement& lhs, const GFpElement& rhs);
- //friend declarations for non-member functions
-
- friend class Point_Coords_GFp;
-
/**
* swaps the states of *this and other, does not throw!
* @param other The value to swap with
*/
void swap(GFpElement& other);
private:
- void ensure_montgm_precomp() const;
+ void ensure_montgm_precomp();
void trf_to_mres() const;
void trf_to_ordres() const;
- std::shared_ptr<GFpModulus> mp_mod;
+ GFpModulus modulus;
mutable BigInt m_value; // ordinary residue or m-residue respectively
- mutable BigInt workspace;
// data members for montgomery multiplication
- mutable bool m_use_montgm;
- //mutable BigInt m_mres;
- // this bool tells use whether the m_mres carries
- // the actual value (in this case mValue doesn´t)
- mutable bool m_is_trf;
+ bool m_use_montgm;
+ mutable bool m_is_trf; // if m_value is montgomery
};
// relational operators
@@ -256,8 +190,8 @@ GFpElement BOTAN_DLL operator-(const GFpElement& lhs);
GFpElement BOTAN_DLL operator*(const GFpElement& lhs, const GFpElement& rhs);
GFpElement BOTAN_DLL operator/(const GFpElement& lhs, const GFpElement& rhs);
-GFpElement BOTAN_DLL operator* (const GFpElement& lhs, u32bit rhs);
-GFpElement BOTAN_DLL operator* (u32bit rhs, const GFpElement& lhs);
+GFpElement BOTAN_DLL operator*(const GFpElement& lhs, u32bit rhs);
+GFpElement BOTAN_DLL operator*(u32bit rhs, const GFpElement& lhs);
/**
diff --git a/src/math/gfpmath/gfp_modulus.h b/src/math/gfpmath/gfp_modulus.h
index 03e8a19e0..fcdd13ee1 100644
--- a/src/math/gfpmath/gfp_modulus.h
+++ b/src/math/gfpmath/gfp_modulus.h
@@ -22,24 +22,26 @@ class GFpElement;
class BOTAN_DLL GFpModulus
{
public:
- friend class GFpElement;
/**
* Construct a GF(P)-Modulus from a BigInt
*/
- GFpModulus(BigInt p)
+ GFpModulus(const BigInt& p)
: m_p(p),
m_p_dash(),
m_r(),
m_r_inv()
{}
+ // GFpModulus(const GFpModulus& other) = default;
+ // GFpModulus& operator=(const GFpModulus& other) = default;
+
/**
* Tells whether the precomputations necessary for the use of the
* montgomery multiplication have yet been established.
* @result true if the precomputated value are already available.
*/
- inline bool has_precomputations() const
+ bool has_precomputations() const
{
return(!m_p_dash.is_zero() && !m_r.is_zero() && !m_r_inv.is_zero());
}
@@ -48,12 +50,12 @@ class BOTAN_DLL GFpModulus
* Swaps this with another GFpModulus, does not throw.
* @param other the GFpModulus to swap *this with.
*/
- inline void swap(GFpModulus& other)
+ void swap(GFpModulus& other)
{
- m_p.swap(other.m_p);
- m_p_dash.swap(other.m_p_dash);
- m_r.swap(other.m_r);
- m_r_inv.swap(other.m_r_inv);
+ std::swap(m_p, other.m_p);
+ std::swap(m_p_dash, other.m_p_dash);
+ std::swap(m_r, other.m_r);
+ std::swap(m_r_inv, other.m_r_inv);
}
/**
@@ -61,7 +63,7 @@ class BOTAN_DLL GFpModulus
* @param mod the modulus to compare this with
* @result true if the modulus of *this and the argument are equal.
*/
- inline bool p_equal_to(const BigInt& mod) const
+ bool p_equal_to(const BigInt& mod) const
{
return (m_p == mod);
}
@@ -70,7 +72,7 @@ class BOTAN_DLL GFpModulus
* Return the modulus of this GFpModulus.
* @result the modulus of *this.
*/
- inline const BigInt& get_p() const
+ const BigInt& get_p() const
{
return m_p;
}
@@ -81,7 +83,7 @@ class BOTAN_DLL GFpModulus
* performed!
* @result r
*/
- inline const BigInt& get_r() const
+ const BigInt& get_r() const
{
return m_r;
}
@@ -92,7 +94,7 @@ class BOTAN_DLL GFpModulus
* performed!
* @result r^{-1}
*/
- inline const BigInt& get_r_inv() const
+ const BigInt& get_r_inv() const
{
return m_r_inv;
}
@@ -103,17 +105,25 @@ class BOTAN_DLL GFpModulus
* performed!
* @result p'
*/
- inline const BigInt& get_p_dash() const
+ const BigInt& get_p_dash() const
{
return m_p_dash;
}
- // default cp-ctor, op= are fine
+
+ void reset_values(const BigInt& new_p_dash,
+ const BigInt& new_r,
+ const BigInt& new_r_inv)
+ {
+ m_p_dash = new_p_dash;
+ m_r = new_r;
+ m_r_inv = new_r_inv;
+ }
private:
BigInt m_p; // the modulus itself
- mutable BigInt m_p_dash;
- mutable BigInt m_r;
- mutable BigInt m_r_inv;
+ BigInt m_p_dash;
+ BigInt m_r;
+ BigInt m_r_inv;
};
}
diff --git a/src/math/gfpmath/point_gfp.cpp b/src/math/gfpmath/point_gfp.cpp
index 050fd0f50..00331f25b 100644
--- a/src/math/gfpmath/point_gfp.cpp
+++ b/src/math/gfpmath/point_gfp.cpp
@@ -13,295 +13,114 @@
namespace Botan {
// construct the point at infinity or a random point
-PointGFp::PointGFp(const CurveGFp& curve)
- : mC(curve),
- mX(curve.get_p(), 0),
- mY(curve.get_p(), 1),
- mZ(curve.get_p(), 0),
- mZpow2(curve.get_p(),0),
- mZpow3(curve.get_p(),0),
- mAZpow4(curve.get_p(),0),
- mZpow2_set(false),
- mZpow3_set(false),
- mAZpow4_set(false)
+nPointGFp::PointGFp(const CurveGFp& curve) :
+ mC(curve),
+ mX(curve.get_p(), 0),
+ mY(curve.get_p(), 1),
+ mZ(curve.get_p(), 0)
{
- // first set the point wide pointer
-
- set_shrd_mod(mC.get_ptr_mod());
-
}
// construct a point given its jacobian projective coordinates
PointGFp::PointGFp(const CurveGFp& curve, const GFpElement& x,
- const GFpElement& y, const GFpElement& z)
- : mC(curve),
- mX(x),
- mY(y),
- mZ(z),
- mZpow2(curve.get_p(),0),
- mZpow3(curve.get_p(),0),
- mAZpow4(curve.get_p(),0),
- mZpow2_set(false),
- mZpow3_set(false),
- mAZpow4_set(false)
- {
- set_shrd_mod(mC.get_ptr_mod());
- }
-PointGFp::PointGFp ( const CurveGFp& curve, const GFpElement& x,
- const GFpElement& y )
- :mC(curve),
- mX(x),
- mY(y),
- mZ(curve.get_p(),1),
- mZpow2(curve.get_p(),0),
- mZpow3(curve.get_p(),0),
- mAZpow4(curve.get_p(),0),
- mZpow2_set(false),
- mZpow3_set(false),
- mAZpow4_set(false)
- {
- set_shrd_mod(mC.get_ptr_mod());
- }
-
-// copy constructor
-PointGFp::PointGFp(const PointGFp& other)
- : mC(other.mC),
- mX(other.mX),
- mY(other.mY),
- mZ(other.mZ),
- mZpow2(other.mZpow2),
- mZpow3(other.mZpow3),
- mAZpow4(other.mAZpow4),
- mZpow2_set(other.mZpow2_set),
- mZpow3_set(other.mZpow3_set),
- mAZpow4_set(other.mAZpow4_set)
+ const GFpElement& y, const GFpElement& z) :
+ mC(curve),
+ mX(x),
+ mY(y),
+ mZ(z)
{
- set_shrd_mod(mC.get_ptr_mod());
}
-// assignment operator
-const PointGFp& PointGFp::operator=(PointGFp const& other)
+PointGFp::PointGFp(const CurveGFp& curve,
+ const GFpElement& x,
+ const GFpElement& y) :
+ mC(curve),
+ mX(x),
+ mY(y),
+ mZ(curve.get_p(),1)
{
- mC = other.get_curve();
- mX = other.get_jac_proj_x();
- mY = other.get_jac_proj_y();
- mZ = other.get_jac_proj_z();
- mZpow2 = GFpElement(other.mZpow2);
- mZpow3 = GFpElement(other.mZpow3);
- mAZpow4 = GFpElement(other.mAZpow4);
- mZpow2_set = other.mZpow2_set;
- mZpow3_set = other.mZpow3_set;
- mAZpow4_set = other.mAZpow4_set;
- set_shrd_mod(mC.get_ptr_mod());
- return *this;
- }
-
-const PointGFp& PointGFp::assign_within_same_curve(PointGFp const& other)
- {
- mX = other.get_jac_proj_x();
- mY = other.get_jac_proj_y();
- mZ = other.get_jac_proj_z();
- mZpow2_set = false;
- mZpow3_set = false;
- mAZpow4_set = false;
- // the rest stays!
- return *this;
- }
-
-void PointGFp::set_shrd_mod(std::shared_ptr<GFpModulus> p_mod)
- {
- mX.set_shrd_mod(p_mod);
- mY.set_shrd_mod(p_mod);
- mZ.set_shrd_mod(p_mod);
- mZpow2.set_shrd_mod(p_mod);
- mZpow3.set_shrd_mod(p_mod);
- mAZpow4.set_shrd_mod(p_mod);
- }
-
-void PointGFp::ensure_worksp() const
- {
- if (mp_worksp_gfp_el.get() != 0)
- {
- if ((*mp_worksp_gfp_el).size() == GFPEL_WKSP_SIZE)
- {
- return;
- }
- else
- {
- throw Invalid_State("encountered incorrect size for PointGFp´s GFpElement workspace");
- }
- }
-
- mp_worksp_gfp_el = std::shared_ptr<std::vector<GFpElement> >(new std::vector<GFpElement>);
- mp_worksp_gfp_el->reserve(9);
- for (u32bit i=0; i<GFPEL_WKSP_SIZE; i++)
- {
- mp_worksp_gfp_el->push_back(GFpElement(1,0));
-
- }
}
// arithmetic operators
PointGFp& PointGFp::operator+=(const PointGFp& rhs)
{
- if (is_zero())
+ if(is_zero())
{
*this = rhs;
return *this;
}
- if (rhs.is_zero())
+ if(rhs.is_zero())
{
return *this;
}
- ensure_worksp();
-
- if (rhs.mZ == *(mC.get_mres_one()))
- {
- //U1 = mX;
- (*mp_worksp_gfp_el)[0].share_assign(mX);
-
- //S1 = mY;
- (*mp_worksp_gfp_el)[2].share_assign(mY);
- }
- else
- {
- if ((!rhs.mZpow2_set) || (!rhs.mZpow3_set))
- {
- rhs.mZpow2 = rhs.mZ;
- rhs.mZpow2 *= rhs.mZ;
- rhs.mZpow3 = rhs.mZpow2;
- rhs.mZpow3 *= rhs.mZ;
-
- rhs.mZpow2_set = true;
- rhs.mZpow3_set = true;
- }
- //U1 = mX * rhs.mZpow2;
- (*mp_worksp_gfp_el)[0].share_assign(mX);
- (*mp_worksp_gfp_el)[0] *= rhs.mZpow2;
- //S1 = mY * rhs.mZpow3;
- (*mp_worksp_gfp_el)[2].share_assign(mY);
- (*mp_worksp_gfp_el)[2] *= rhs.mZpow3;
+ GFpElement U1 = mX;
+ GFpElement S1 = mY;
- }
- if (mZ == *(mC.get_mres_one()))
+ if(rhs.mZ != mC.get_mres_one())
{
- //U2 = rhs.mX;
- (*mp_worksp_gfp_el)[1].share_assign(rhs.mX);
+ GFpElement rhs_z2 = rhs.mZ * rhs.mZ;
- //S2 = rhs.mY;
- (*mp_worksp_gfp_el)[3].share_assign(rhs.mY);
+ U1 *= rhs_z2;
+ S1 *= rhs_z2 * rhs.mZ;
}
- else
- {
- if ((!mZpow2_set) || (!mZpow3_set))
- {
- // precomputation can´t be used, because *this changes anyway
- mZpow2 = mZ;
- mZpow2 *= mZ;
- mZpow3 = mZpow2;
- mZpow3 *= mZ;
- }
- //U2 = rhs.mX * mZpow2;
- (*mp_worksp_gfp_el)[1].share_assign(rhs.mX);
- (*mp_worksp_gfp_el)[1] *= mZpow2;
+ GFpElement U2 = rhs.mX;
+ GFpElement S2 = rhs.mY;
- //S2 = rhs.mY * mZpow3;
- (*mp_worksp_gfp_el)[3].share_assign(rhs.mY);
- (*mp_worksp_gfp_el)[3] *= mZpow3;
+ if(mZ != mC.get_mres_one())
+ {
+ GFpElement lhs_z2 = mZ * mZ;
+ U2 *= lhs_z2;
+ S2 *= lhs_z2 * mZ;
}
- //GFpElement H(U2 - U1);
-
- (*mp_worksp_gfp_el)[4].share_assign((*mp_worksp_gfp_el)[1]);
- (*mp_worksp_gfp_el)[4] -= (*mp_worksp_gfp_el)[0];
- //GFpElement r(S2 - S1);
- (*mp_worksp_gfp_el)[5].share_assign((*mp_worksp_gfp_el)[3]);
- (*mp_worksp_gfp_el)[5] -= (*mp_worksp_gfp_el)[2];
-
- //if(H.is_zero())
- if ((*mp_worksp_gfp_el)[4].is_zero())
+ GFpElement H(U2 - U1);
+ GFpElement r(S2 - S1);
+ if(H.is_zero())
{
- if ((*mp_worksp_gfp_el)[5].is_zero())
-
+ if(r.is_zero())
{
mult2_in_place();
return *this;
}
+
*this = PointGFp(mC); // setting myself to zero
return *this;
}
- //U2 = H * H;
- (*mp_worksp_gfp_el)[1].share_assign((*mp_worksp_gfp_el)[4]);
- (*mp_worksp_gfp_el)[1] *= (*mp_worksp_gfp_el)[4];
+ U2 = H * H;
- //S2 = U2 * H;
- (*mp_worksp_gfp_el)[3].share_assign((*mp_worksp_gfp_el)[1]);
- (*mp_worksp_gfp_el)[3] *= (*mp_worksp_gfp_el)[4];
+ S2 = U2 * H;
- //U2 *= U1;
- (*mp_worksp_gfp_el)[1] *= (*mp_worksp_gfp_el)[0];
+ U2 *= U1;
- //GFpElement x(r*r - S2 - (U2+U2));
- (*mp_worksp_gfp_el)[6].share_assign((*mp_worksp_gfp_el)[5]);
- (*mp_worksp_gfp_el)[6] *= (*mp_worksp_gfp_el)[5];
- (*mp_worksp_gfp_el)[6] -= (*mp_worksp_gfp_el)[3];
- (*mp_worksp_gfp_el)[6] -= (*mp_worksp_gfp_el)[1];
- (*mp_worksp_gfp_el)[6] -= (*mp_worksp_gfp_el)[1];
+ GFpElement x(r*r - S2 - (U2+U2));
- //GFpElement z(S1 * S2);
- (*mp_worksp_gfp_el)[8].share_assign((*mp_worksp_gfp_el)[2]);
- (*mp_worksp_gfp_el)[8] *= (*mp_worksp_gfp_el)[3];
+ GFpElement z(S1 * S2);
- //GFpElement y(r * (U2-x) - z);
- (*mp_worksp_gfp_el)[7].share_assign((*mp_worksp_gfp_el)[1]);
- (*mp_worksp_gfp_el)[7] -= (*mp_worksp_gfp_el)[6];
- (*mp_worksp_gfp_el)[7] *= (*mp_worksp_gfp_el)[5];
- (*mp_worksp_gfp_el)[7] -= (*mp_worksp_gfp_el)[8];
+ GFpElement y(r * (U2-x) - z);
- if (mZ == *(mC.get_mres_one()))
+ if(mZ == mC.get_mres_one())
{
- if (rhs.mZ != *(mC.get_mres_one()))
- {
- //z = rhs.mZ * H;
- (*mp_worksp_gfp_el)[8].share_assign(rhs.mZ);
- (*mp_worksp_gfp_el)[8] *= (*mp_worksp_gfp_el)[4];
- }
+ if(rhs.mZ != mC.get_mres_one())
+ z = rhs.mZ * H;
else
- {
- //z = H;
- (*mp_worksp_gfp_el)[8].share_assign((*mp_worksp_gfp_el)[4]);
- }
+ z = H;
}
- else if (rhs.mZ != *(mC.get_mres_one()))
+ else if(rhs.mZ != mC.get_mres_one())
{
- //U1 = mZ * rhs.mZ;
- (*mp_worksp_gfp_el)[0].share_assign(mZ);
- (*mp_worksp_gfp_el)[0] *= rhs.mZ;
-
- //z = U1 * H;
- (*mp_worksp_gfp_el)[8].share_assign((*mp_worksp_gfp_el)[0]);
- (*mp_worksp_gfp_el)[8] *= (*mp_worksp_gfp_el)[4];
-
+ U1 = mZ * rhs.mZ;
+ z = U1 * H;
}
else
- {
- //z = mZ * H;
- (*mp_worksp_gfp_el)[8].share_assign(mZ);
- (*mp_worksp_gfp_el)[8] *= (*mp_worksp_gfp_el)[4];
+ z = mZ * H;
- }
- mZpow2_set = false;
- mZpow3_set = false;
- mAZpow4_set = false;
-
- mX = (*mp_worksp_gfp_el)[6];
- mY = (*mp_worksp_gfp_el)[7];
- mZ = (*mp_worksp_gfp_el)[8];
+ mX = x;
+ mY = y;
+ mZ = z;
return *this;
@@ -310,7 +129,7 @@ PointGFp& PointGFp::operator-=(const PointGFp& rhs)
{
PointGFp minus_rhs = PointGFp(rhs).negate();
- if (is_zero())
+ if(is_zero())
{
*this = minus_rhs;
}
@@ -336,92 +155,39 @@ PointGFp& PointGFp::mult_this_secure(const BigInt& scalar,
// use montgomery mult. in this operation
this->turn_on_sp_red_mul();
- std::shared_ptr<PointGFp> H(new PointGFp(this->mC));
- std::shared_ptr<PointGFp> tmp; // used for AADA
+ PointGFp H(mC);
PointGFp P(*this);
BigInt m(scalar);
- if (m < BigInt(0))
+ if(m < BigInt(0))
{
m = -m;
P.negate();
}
- if (P.is_zero() || (m == BigInt(0)))
+ if(P.is_zero() || (m == BigInt(0)))
{
- *this = *H;
+ *this = H;
return *this;
}
- if (m == BigInt(1))
- {
+ if(m == BigInt(1))
return *this;
- }
- //
-#ifdef CM_AADA
-#ifndef CM_RAND_EXP
- int max_secr_bits = max_secr.bits();
-#endif
-#endif
-
- int mul_bits = m.bits(); // this is used for a determined number of loop runs in
- // the mult_loop where leading zero´s are padded if necessary.
- // Here we assign the value that will be used when no countermeasures are specified
-#ifdef CM_RAND_EXP
- u32bit rand_r_bit_len = 20; // Coron(99) proposes 20 bit for r
-#ifdef CM_AADA
+ int mul_bits = m.bits();
- BigInt r_max(1);
-
-#endif // CM_AADA
-
- // use randomized exponent
-#ifdef TA_COLL_T
- static BigInt r_randexp;
- if (new_rand)
+ for(int i = mul_bits - 1; i >= 0; i--)
{
- r_randexp = random_integer(rand_r_bit_len);
- }
- //assert(!r_randexp.is_zero());
-#else
- BigInt r_randexp(random_integer(rand_r_bit_len));
-#endif
-
- m += r_randexp * point_order;
- // determine mul_bits...
-#ifdef CM_AADA
- // AADA with rand. Exp.
- //assert(rand_r_bit_len > 0);
- r_max <<= rand_r_bit_len;
- r_max -= 1;
- //assert(r_max.bits() == rand_r_bit_len);
- mul_bits = (max_secr + point_order * r_max).bits();
-#else
- // rand. Exp. without AADA
- mul_bits = m.bits();
-#endif // CM_AADA
-
-
-#endif // CM_RAND_EXP
-
- // determine mul_bits...
-#if (CM_AADA == 1 && CM_RAND_EXP != 1)
-
- mul_bits = max_secr_bits;
-#endif // CM_AADA without CM_RAND_EXP
-
- //assert(mul_bits != 0);
+ H.mult2_in_place();
+ if(m.get_bit(i))
+ H += P;
+ }
- H = mult_loop(mul_bits-1, m, H, tmp, P);
+ if(!H.is_zero()) // cannot convert if H == O
+ *this = H.get_z_to_one();
+ else
+ *this = H;
- if (!H->is_zero()) // cannot convert if H == O
- {
- *this = H->get_z_to_one();
- }else
- {
- *this = *H;
- }
mX.turn_off_sp_red_mul();
mY.turn_off_sp_red_mul();
mZ.turn_off_sp_red_mul();
@@ -439,226 +205,100 @@ PointGFp& PointGFp::operator*=(const BigInt& scalar)
PointGFp P(*this);
P.turn_on_sp_red_mul();
BigInt m(scalar);
- if (m < BigInt(0))
+
+ if(m < BigInt(0))
{
m = -m;
P.negate();
}
- if (P.is_zero() || (m == BigInt(0)))
+
+ if(P.is_zero() || (m == BigInt(0)))
{
*this = H;
return *this;
}
- if (m == BigInt(1))
- {
- //*this == P already
+
+ if(m == BigInt(1)) //*this == P already
return *this;
- }
const int l = m.bits() - 1;
- for (int i=l; i >=0; i--)
+ for(int i = l; i >= 0; --i)
{
-
H.mult2_in_place();
- if (m.get_bit(i))
- {
+ if(m.get_bit(i))
H += P;
- }
}
- if (!H.is_zero()) // cannot convert if H == O
- {
+ if(!H.is_zero()) // cannot convert if H == O
*this = H.get_z_to_one();
- }else
- {
+ else
*this = H;
- }
- return *this;
- }
-
-inline std::shared_ptr<PointGFp> PointGFp::mult_loop(int l,
- const BigInt& m,
- std::shared_ptr<PointGFp> H,
- std::shared_ptr<PointGFp> tmp,
- const PointGFp& P)
- {
- //assert(l >= (int)m.bits()- 1);
- tmp = H;
- std::shared_ptr<PointGFp> to_add(new PointGFp(P)); // we just need some point
- // so that we can use op=
- // inside the loop
- for (int i=l; i >=0; i--)
- {
- H->mult2_in_place();
-
-#ifndef CM_AADA
-
- if (m.get_bit(i))
- {
- *H += P;
- }
-#else // (CM_AADA is in)
-
- if (H.get() == to_add.get())
- {
- to_add = tmp; // otherwise all pointers might point to the same object
- // and we always need two objects to be able to switch around
- }
- to_add->assign_within_same_curve(*H);
- tmp = H;
- *tmp += P; // tmp already points to H
-
- if (m.get_bit(i))
- {
- H = tmp; // NOTE: assign the pointer, not the value!
- // (so that the operation is fast and thus as difficult
- // to detect as possible)
- }
- else
- {
- H = to_add; // NOTE: this is necessary, because the assignment
- // "*tmp = ..." already changed what H pointed to
-
-
- }
-#endif // CM_AADA
- }
- return H;
+ return *this;
}
PointGFp& PointGFp::negate()
{
- if (!is_zero())
- {
+ if(!is_zero())
mY.negate();
- }
+
return *this;
}
// *this *= 2
PointGFp& PointGFp::mult2_in_place()
{
- if (is_zero())
- {
+ if(is_zero())
return *this;
- }
- if (mY.is_zero())
+ else if(mY.is_zero())
{
-
*this = PointGFp(mC); // setting myself to zero
return *this;
}
- ensure_worksp();
- (*mp_worksp_gfp_el)[0].share_assign(mY);
- (*mp_worksp_gfp_el)[0] *= mY;
+ GFpElement Y_squared = mY*mY;
- //GFpElement S(mX * z);
- (*mp_worksp_gfp_el)[1].share_assign(mX);
- (*mp_worksp_gfp_el)[1] *= (*mp_worksp_gfp_el)[0];
+ GFpElement S = mX * Y_squared;
- //GFpElement x(S + S);
- (*mp_worksp_gfp_el)[2].share_assign((*mp_worksp_gfp_el)[1]);
- (*mp_worksp_gfp_el)[2] += (*mp_worksp_gfp_el)[1];
+ GFpElement x = S + S;
- //S = x + x;
- (*mp_worksp_gfp_el)[1].share_assign((*mp_worksp_gfp_el)[2]);
- (*mp_worksp_gfp_el)[1] += (*mp_worksp_gfp_el)[2];
+ S = x + x;
- if (!mAZpow4_set)
+ GFpElement a_z4 = mC.get_mres_a();
+ if(mZ != mC.get_mres_one())
{
- if (mZ == *(mC.get_mres_one()))
- {
- mAZpow4 = mC.get_mres_a();
- mAZpow4_set = true;
- }
- else
- {
- if (!mZpow2_set)
- {
- mZpow2 = mZ;
- mZpow2 *= mZ;
+ GFpElement z2 = mZ * mZ;
+ a_z4 *= z2;
+ a_z4 *= z2;
+ }
- mZpow2_set = true;
- }
- //x = mZpow2 * mZpow2;
- (*mp_worksp_gfp_el)[2].share_assign(mZpow2);
- (*mp_worksp_gfp_el)[2] *= mZpow2;
+ GFpElement y(mX * mX);
- //mAZpow4 = mC.get_mres_a() * x;
- mAZpow4 = mC.get_mres_a();
- mAZpow4 *= (*mp_worksp_gfp_el)[2];
+ GFpElement M(y + y + y + a_z4);
- }
+ x = M * M - (S+S);
- }
+ y = Y_squared * Y_squared;
- //GFpElement y(mX * mX);
- (*mp_worksp_gfp_el)[3].share_assign(mX);
- (*mp_worksp_gfp_el)[3] *= mX;
-
- //GFpElement M(y + y + y + mAZpow4);
- (*mp_worksp_gfp_el)[4].share_assign((*mp_worksp_gfp_el)[3]);
- (*mp_worksp_gfp_el)[4] += (*mp_worksp_gfp_el)[3];
- (*mp_worksp_gfp_el)[4] += (*mp_worksp_gfp_el)[3];
- (*mp_worksp_gfp_el)[4] += mAZpow4;
-
- //x = M * M - (S+S);
- (*mp_worksp_gfp_el)[2].share_assign((*mp_worksp_gfp_el)[4]);
- (*mp_worksp_gfp_el)[2] *= (*mp_worksp_gfp_el)[4];
- (*mp_worksp_gfp_el)[2] -= (*mp_worksp_gfp_el)[1];
- (*mp_worksp_gfp_el)[2] -= (*mp_worksp_gfp_el)[1];
-
- //y = z * z;
- (*mp_worksp_gfp_el)[3].share_assign((*mp_worksp_gfp_el)[0]);
- (*mp_worksp_gfp_el)[3] *= (*mp_worksp_gfp_el)[0];
-
- //GFpElement U(y + y);
- (*mp_worksp_gfp_el)[5].share_assign((*mp_worksp_gfp_el)[3]);
- (*mp_worksp_gfp_el)[5] += (*mp_worksp_gfp_el)[3];
-
- //z = U + U;
- (*mp_worksp_gfp_el)[0].share_assign((*mp_worksp_gfp_el)[5]);
- (*mp_worksp_gfp_el)[0] += (*mp_worksp_gfp_el)[5];
-
- //U = z + z;
- (*mp_worksp_gfp_el)[5].share_assign((*mp_worksp_gfp_el)[0]);
- (*mp_worksp_gfp_el)[5] += (*mp_worksp_gfp_el)[0];
-
- //y = M * (S - x) - U;
- (*mp_worksp_gfp_el)[3].share_assign((*mp_worksp_gfp_el)[1]);
- (*mp_worksp_gfp_el)[3] -= (*mp_worksp_gfp_el)[2];
- (*mp_worksp_gfp_el)[3] *= (*mp_worksp_gfp_el)[4];
- (*mp_worksp_gfp_el)[3] -= (*mp_worksp_gfp_el)[5];
-
- if (mZ != *(mC.get_mres_one()))
- {
- //z = mY * mZ;
- (*mp_worksp_gfp_el)[0].share_assign(mY);
- (*mp_worksp_gfp_el)[0] *= mZ;
+ GFpElement U(y + y);
- }
+ GFpElement z = U + U;
+
+ U = z + z;
+
+ y = M * (S - x) - U;
+
+ if(mZ != mC.get_mres_one())
+ z = mY * mZ;
else
- {
- //z = mY;
- (*mp_worksp_gfp_el)[0].share_assign(mY);
+ z = mY;
+
+ z = z + z;
+
+ mX = x;
+ mY = y;
+ mZ = z;
- }
- //z = z + z;
- (*mp_worksp_gfp_el)[6].share_assign((*mp_worksp_gfp_el)[0]);
- (*mp_worksp_gfp_el)[0] += (*mp_worksp_gfp_el)[6];
-
- //mX = x;
- //mY = y;
- //mZ = z;
- mX = (*mp_worksp_gfp_el)[2];
- mY = (*mp_worksp_gfp_el)[3];
- mZ = (*mp_worksp_gfp_el)[0];
-
- mZpow2_set = false;
- mZpow3_set = false;
- mAZpow4_set = false;
return *this;
}
@@ -676,19 +316,14 @@ void PointGFp::turn_on_sp_red_mul() const
mX.get_mres();
mY.get_mres();
mZ.get_mres();
-
- mZpow2.turn_on_sp_red_mul();
- mZpow3.turn_on_sp_red_mul();
- mAZpow4.turn_on_sp_red_mul();
}
-// getters
/**
* returns a point equivalent to *this but were
* Z has value one, i.e. x and y correspond to
* their values in affine coordinates
*/
-PointGFp const PointGFp::get_z_to_one() const
+PointGFp PointGFp::get_z_to_one() const
{
return PointGFp(*this).set_z_to_one();
}
@@ -701,7 +336,7 @@ PointGFp const PointGFp::get_z_to_one() const
*/
const PointGFp& PointGFp::set_z_to_one() const
{
- if (!(mZ.get_value() == BigInt(1)) && !(mZ.get_value() == BigInt(0)))
+ if(!(mZ.get_value() == BigInt(1)) && !(mZ.get_value() == BigInt(0)))
{
GFpElement z = inverse(mZ);
GFpElement z2 = z * z;
@@ -714,7 +349,7 @@ const PointGFp& PointGFp::set_z_to_one() const
}
else
{
- if (mZ.get_value() == BigInt(0))
+ if(mZ.get_value() == BigInt(0))
{
throw Illegal_Transformation("cannot convert Z to one");
}
@@ -722,58 +357,35 @@ const PointGFp& PointGFp::set_z_to_one() const
return *this; // mZ = 1 already
}
-const CurveGFp PointGFp::get_curve() const
+GFpElement PointGFp::get_affine_x() const
{
- return mC;
- }
-
-GFpElement const PointGFp::get_affine_x() const
- {
-
- if (is_zero())
- {
+ if(is_zero())
throw Illegal_Transformation("cannot convert to affine");
- }
- /*if(!mZpow2_set)
- {*/
- mZpow2 = mZ * mZ;
- mZpow2_set = true;
- //}
- //assert(mZpow2 == mZ*mZ);
- GFpElement z2 = mZpow2;
+ GFpElement z2 = mZ * mZ;
return mX * z2.inverse_in_place();
}
-GFpElement const PointGFp::get_affine_y() const
+GFpElement PointGFp::get_affine_y() const
{
-
- if (is_zero())
- {
+ if(is_zero())
throw Illegal_Transformation("cannot convert to affine");
- }
- /*if(!mZpow3_set )
- {*/
- mZpow3 = mZ * mZ * mZ;
- mZpow3_set = true;
- //}
- //assert(mZpow3 == mZ * mZ *mZ);
- GFpElement z3 = mZpow3;
+ GFpElement z3 = mZ * mZ * mZ;
return mY * z3.inverse_in_place();
}
-GFpElement const PointGFp::get_jac_proj_x() const
+GFpElement PointGFp::get_jac_proj_x() const
{
return GFpElement(mX);
}
-GFpElement const PointGFp::get_jac_proj_y() const
+GFpElement PointGFp::get_jac_proj_y() const
{
return GFpElement(mY);
}
-GFpElement const PointGFp::get_jac_proj_z() const
+GFpElement PointGFp::get_jac_proj_z() const
{
return GFpElement(mZ);
}
@@ -794,14 +406,14 @@ bool PointGFp::is_zero() const
void PointGFp::check_invariants() const
{
- if (is_zero())
+ if(is_zero())
{
return;
}
const GFpElement y2 = mY * mY;
const GFpElement x3 = mX * mX * mX;
- if (mZ.get_value() == BigInt(1))
+ if(mZ.get_value() == BigInt(1))
{
GFpElement ax = mC.get_a() * mX;
if(y2 != (x3 + ax + mC.get_b()))
@@ -811,16 +423,13 @@ void PointGFp::check_invariants() const
}
- mZpow2 = mZ * mZ;
- mZpow2_set = true;
- mZpow3 = mZpow2 * mZ;
- mZpow3_set = true;
- mAZpow4 = mZpow3 * mZ * mC.get_a();
- mAZpow4_set = true;
- const GFpElement aXZ4 = mAZpow4 * mX;
- const GFpElement bZ6 = mC.get_b() * mZpow3 * mZpow3;
+ GFpElement Zpow2 = mZ * mZ;
+ GFpElement Zpow3 = Zpow2 * mZ;
+ GFpElement AZpow4 = Zpow3 * mZ * mC.get_a();
+ const GFpElement aXZ4 = AZpow4 * mX;
+ const GFpElement bZ6 = mC.get_b() * Zpow3 * Zpow3;
- if (y2 != (x3 + aXZ4 + bZ6))
+ if(y2 != (x3 + aXZ4 + bZ6))
throw Illegal_Point();
}
@@ -831,12 +440,6 @@ void PointGFp::swap(PointGFp& other)
mX.swap(other.mX);
mY.swap(other.mY);
mZ.swap(other.mZ);
- mZpow2.swap(other.mZpow2);
- mZpow3.swap(other.mZpow3);
- mAZpow4.swap(other.mAZpow4);
- std::swap<bool>(mZpow2_set, other.mZpow2_set);
- std::swap<bool>(mZpow3_set, other.mZpow3_set);
- std::swap<bool>(mAZpow4_set, other.mAZpow4_set);
}
PointGFp mult2(const PointGFp& point)
@@ -846,11 +449,11 @@ PointGFp mult2(const PointGFp& point)
bool operator==(const PointGFp& lhs, PointGFp const& rhs)
{
- if (lhs.is_zero() && rhs.is_zero())
+ if(lhs.is_zero() && rhs.is_zero())
{
return true;
}
- if ((lhs.is_zero() && !rhs.is_zero()) || (!lhs.is_zero() && rhs.is_zero()))
+ if((lhs.is_zero() && !rhs.is_zero()) || (!lhs.is_zero() && rhs.is_zero()))
{
return false;
}
@@ -906,16 +509,16 @@ PointGFp mult_point_secure(const PointGFp& point, const BigInt& scalar,
SecureVector<byte> EC2OSP(const PointGFp& point, byte format)
{
SecureVector<byte> result;
- if (format == PointGFp::UNCOMPRESSED)
+ if(format == PointGFp::UNCOMPRESSED)
{
result = encode_uncompressed(point);
}
- else if (format == PointGFp::COMPRESSED)
+ else if(format == PointGFp::COMPRESSED)
{
result = encode_compressed(point);
}
- else if (format == PointGFp::HYBRID)
+ else if(format == PointGFp::HYBRID)
{
result = encode_hybrid(point);
}
@@ -929,7 +532,7 @@ SecureVector<byte> encode_compressed(const PointGFp& point)
{
- if (point.is_zero())
+ if(point.is_zero())
{
SecureVector<byte> result (1);
result[0] = 0;
@@ -938,7 +541,7 @@ SecureVector<byte> encode_compressed(const PointGFp& point)
}
u32bit l = point.get_curve().get_p().bits();
int dummy = l & 7;
- if (dummy != 0)
+ if(dummy != 0)
{
l += 8 - dummy;
}
@@ -949,7 +552,7 @@ SecureVector<byte> encode_compressed(const PointGFp& point)
SecureVector<byte> bX = BigInt::encode_1363(x, l);
result.copy(1, bX.begin(), bX.size());
BigInt y = point.get_affine_y().get_value();
- if (y.get_bit(0))
+ if(y.get_bit(0))
{
result[0] |= 1;
}
@@ -959,7 +562,7 @@ SecureVector<byte> encode_compressed(const PointGFp& point)
SecureVector<byte> encode_uncompressed(const PointGFp& point)
{
- if (point.is_zero())
+ if(point.is_zero())
{
SecureVector<byte> result (1);
result[0] = 0;
@@ -967,7 +570,7 @@ SecureVector<byte> encode_uncompressed(const PointGFp& point)
}
u32bit l = point.get_curve().get_p().bits();
int dummy = l & 7;
- if (dummy != 0)
+ if(dummy != 0)
{
l += 8 - dummy;
}
@@ -986,7 +589,7 @@ SecureVector<byte> encode_uncompressed(const PointGFp& point)
SecureVector<byte> encode_hybrid(const PointGFp& point)
{
- if (point.is_zero())
+ if(point.is_zero())
{
SecureVector<byte> result (1);
result[0] = 0;
@@ -994,7 +597,7 @@ SecureVector<byte> encode_hybrid(const PointGFp& point)
}
u32bit l = point.get_curve().get_p().bits();
int dummy = l & 7;
- if (dummy != 0)
+ if(dummy != 0)
{
l += 8 - dummy;
}
@@ -1007,7 +610,7 @@ SecureVector<byte> encode_hybrid(const PointGFp& point)
SecureVector<byte> bY = BigInt::encode_1363(y, l);
result.copy(1, bX.begin(), bX.size());
result.copy(l+1, bY.begin(), bY.size());
- if (y.get_bit(0))
+ if(y.get_bit(0))
{
result[0] |= 1;
}
@@ -1016,7 +619,7 @@ SecureVector<byte> encode_hybrid(const PointGFp& point)
PointGFp OS2ECP(MemoryRegion<byte> const& os, const CurveGFp& curve)
{
- if (os.size() == 1 && os[0] == 0)
+ if(os.size() == 1 && os[0] == 0)
{
return PointGFp(curve); // return zero
}
@@ -1038,10 +641,6 @@ PointGFp OS2ECP(MemoryRegion<byte> const& os, const CurveGFp& curve)
bX = SecureVector<byte>(os.size() - 1);
bX.copy(os.begin()+1, os.size()-1);
- /* Problem wäre, wenn decode() das erste bit als Vorzeichen interpretiert.
- *---------------------
- * AW(FS): decode() interpretiert das erste Bit nicht als Vorzeichen
- */
bi_dec_x = BigInt::decode(bX, bX.size());
x = GFpElement(curve.get_p(), bi_dec_x);
bool yMod2;
@@ -1072,7 +671,7 @@ PointGFp OS2ECP(MemoryRegion<byte> const& os, const CurveGFp& curve)
bX.copy(os.begin() + 1, l);
bY.copy(os.begin()+1+l, l);
yMod2 = (pc & 0x01) == 1;
- if (!(PointGFp::decompress(yMod2, x, curve) == y))
+ if(!(PointGFp::decompress(yMod2, x, curve) == y))
{
throw Illegal_Point("error during decoding hybrid format");
}
@@ -1107,7 +706,7 @@ GFpElement PointGFp::decompress(bool yMod2, const GFpElement& x,
throw Illegal_Point("error during decompression");
bool zMod2 = z.get_bit(0);
- if ((zMod2 && ! yMod2) || (!zMod2 && yMod2))
+ if((zMod2 && ! yMod2) || (!zMod2 && yMod2))
{
z = curve.get_p() - z;
}
diff --git a/src/math/gfpmath/point_gfp.h b/src/math/gfpmath/point_gfp.h
index 10fc404bf..276635f56 100644
--- a/src/math/gfpmath/point_gfp.h
+++ b/src/math/gfpmath/point_gfp.h
@@ -2,7 +2,7 @@
* Arithmetic for point groups of elliptic curves over GF(p)
*
* (C) 2007 Martin Doering, Christoph Ludwig, Falko Strenzke
-* 2008 Jack Lloyd
+* 2008-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
@@ -11,9 +11,6 @@
#define BOTAN_POINT_GFP_H__
#include <botan/curve_gfp.h>
-#include <botan/gfp_element.h>
-#include <botan/bigint.h>
-#include <botan/exceptn.h>
#include <vector>
namespace Botan {
@@ -24,7 +21,7 @@ struct BOTAN_DLL Illegal_Point : public Exception
};
/**
-* This class represents one point on a curve of GF(p).
+* This class represents one point on a curve of GF(p)
*/
class BOTAN_DLL PointGFp
{
@@ -48,7 +45,7 @@ class BOTAN_DLL PointGFp
* Construct the point O
* @param curve The base curve
*/
- explicit PointGFp(const CurveGFp& curve);
+ PointGFp(const CurveGFp& curve);
/**
* Construct a point given its affine coordinates
@@ -56,8 +53,9 @@ class BOTAN_DLL PointGFp
* @param x affine x coordinate
* @param y affine y coordinate
*/
- explicit PointGFp(const CurveGFp& curve, GFpElement const& x,
- GFpElement const& y);
+ PointGFp(const CurveGFp& curve,
+ const GFpElement& x,
+ const GFpElement& y);
/**
* Construct a point given its jacobian projective coordinates
@@ -66,28 +64,13 @@ class BOTAN_DLL PointGFp
* @param y jacobian projective y coordinate
* @param z jacobian projective y coordinate
*/
- explicit PointGFp(const CurveGFp& curve, GFpElement const& x,
- GFpElement const& y, GFpElement const& z);
-
- /**
- * copy constructor
- * @param other the value to clone
- */
- PointGFp(const PointGFp& other);
-
- /**
- * assignment operator
- * @param other The point to use as source for the assignment
- */
- const PointGFp& operator=(const PointGFp& other);
-
- /**
- * assign another point which is on the same curve as *this
- * @param other The point to use as source for the assignment
- */
- const PointGFp& assign_within_same_curve(const PointGFp& other);
-
+ PointGFp(const CurveGFp& curve,
+ const GFpElement& x,
+ const GFpElement& y,
+ const GFpElement& z);
+ //PointGFp(const PointGFp& other) = default;
+ //PointGFp& operator=(const PointGFp& other) = default;
/**
* += Operator
@@ -126,8 +109,7 @@ class BOTAN_DLL PointGFp
*/
PointGFp& mult_this_secure(const BigInt& scalar,
const BigInt& point_order,
- const BigInt& max_secr
- );
+ const BigInt& max_secr);
/**
* Negate internal value(*this *= -1 )
@@ -162,43 +144,43 @@ class BOTAN_DLL PointGFp
* thus x and y have just the affine values.
* @result *this
*/
- PointGFp const get_z_to_one() const;
+ PointGFp get_z_to_one() const;
/**
* Return base curve of this point
* @result the curve over GF(p) of this point
*/
- CurveGFp const get_curve() const;
+ const CurveGFp& get_curve() const { return mC; }
/**
* get affine x coordinate
* @result affine x coordinate
*/
- GFpElement const get_affine_x() const;
+ GFpElement get_affine_x() const;
/**
* get affine y coordinate
* @result affine y coordinate
*/
- GFpElement const get_affine_y() const;
+ GFpElement get_affine_y() const;
/**
* get the jacobian projective x coordinate
* @result jacobian projective x coordinate
*/
- GFpElement const get_jac_proj_x() const;
+ GFpElement get_jac_proj_x() const;
/**
* get the jacobian projective y coordinate
* @result jacobian projective y coordinate
*/
- GFpElement const get_jac_proj_y() const;
+ GFpElement get_jac_proj_y() const;
/**
* get the jacobian projective z coordinate
* @result jacobian projective z coordinate
*/
- GFpElement const get_jac_proj_z() const;
+ GFpElement get_jac_proj_z() const;
/**
* Is this the point at infinity?
@@ -214,49 +196,19 @@ class BOTAN_DLL PointGFp
*/
void check_invariants() const;
-
/**
- * swaps the states of *this and other, does not throw!
+ * swaps the states of *this and other, does not throw!
* @param other the object to swap values with
*/
void swap(PointGFp& other);
- /**
- * Sets the shared pointer to the GFpModulus that will be
- * held in *this, specifically the various members of *this.
- * Warning: do not use this function unless you know in detail about
- * the implications of using
- * the shared GFpModulus objects!
- * Do NOT spread a shared pointer to GFpModulus over different
- * threads!
- * @param mod a shared pointer to a GFpModulus that will
- * be held in the members *this
- */
- void set_shrd_mod(std::shared_ptr<GFpModulus> p_mod);
-
static GFpElement decompress(bool yMod2, GFpElement const& x, const CurveGFp& curve);
private:
- static const u32bit GFPEL_WKSP_SIZE = 9;
- void ensure_worksp() const;
-
- inline std::shared_ptr<PointGFp> mult_loop(int l, const BigInt& m,
- std::shared_ptr<PointGFp> H,
- std::shared_ptr<PointGFp> tmp,
- const PointGFp& P);
-
CurveGFp mC;
mutable GFpElement mX; // NOTE: these values must be mutable (affine<->proj)
mutable GFpElement mY;
mutable GFpElement mZ;
- mutable GFpElement mZpow2; // mZ^2
- mutable GFpElement mZpow3; // mZ^3
- mutable GFpElement mAZpow4; // mA*mZ^4
- mutable bool mZpow2_set;
- mutable bool mZpow3_set;
- mutable bool mAZpow4_set;
- mutable std::shared_ptr<std::vector<GFpElement> > mp_worksp_gfp_el;
-
};
// relational operators
diff --git a/src/pubkey/ec_dompar/ec_dompar.cpp b/src/pubkey/ec_dompar/ec_dompar.cpp
index e05b01465..3719153f0 100644
--- a/src/pubkey/ec_dompar/ec_dompar.cpp
+++ b/src/pubkey/ec_dompar/ec_dompar.cpp
@@ -409,6 +409,18 @@ std::vector<std::string> get_standard_domain_parameter(const std::string& oid)
return dom_par;
}
+ if(oid == "1.2.643.2.2.35.1" || oid == "1.2.643.2.2.36.0") // GostR3410-2001-CryptoPro-A-ParamSet
+ {
+ std::vector<std::string> dom_par;
+ dom_par.push_back("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97");
+ dom_par.push_back("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94");
+ dom_par.push_back("166");
+ dom_par.push_back("0400000000000000000000000000000000000000000000000000000000000000018D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14");
+ dom_par.push_back("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893");
+ dom_par.push_back("1");
+ return dom_par;
+ }
+
throw Invalid_Argument("No such ECC curve " + oid);
}
@@ -552,18 +564,16 @@ EC_Domain_Params decode_ber_ec_dompar(SecureVector<byte> const& encoded)
{
BER_Decoder dec(encoded);
BER_Object obj = dec.get_next_object();
- ASN1_Tag tag = obj.type_tag;
- std::unique_ptr<EC_Domain_Params> p_result;
- if(tag == OBJECT_ID)
+ if(obj.type_tag == OBJECT_ID)
{
OID dom_par_oid;
BER_Decoder(encoded).decode(dom_par_oid);
return EC_Domain_Params(get_ec_dompar(dom_par_oid.as_string()));
}
- else if(tag == SEQUENCE)
+ else if(obj.type_tag == SEQUENCE)
return EC_Domain_Params(decode_ber_ec_dompar_explicit(encoded));
- else if(tag == NULL_TAG)
+ else if(obj.type_tag == NULL_TAG)
throw Decoding_Error("cannot decode ECDSA parameters that are ImplicitCA");
throw Decoding_Error("encountered unexpected when trying to decode domain parameters");
diff --git a/src/pubkey/ecc_key/ecc_key.h b/src/pubkey/ecc_key/ecc_key.h
index 9d5f57d9f..ea0f3f4ad 100644
--- a/src/pubkey/ecc_key/ecc_key.h
+++ b/src/pubkey/ecc_key/ecc_key.h
@@ -16,6 +16,7 @@
#include <botan/ec_dompar.h>
#include <botan/x509_key.h>
#include <botan/pkcs8.h>
+#include <memory>
namespace Botan {
diff --git a/src/pubkey/gost_3410/gost_3410.cpp b/src/pubkey/gost_3410/gost_3410.cpp
new file mode 100644
index 000000000..c2ddabe63
--- /dev/null
+++ b/src/pubkey/gost_3410/gost_3410.cpp
@@ -0,0 +1,351 @@
+/*
+* GOST 34.10-2001 implemenation
+* (C) 2007 Falko Strenzke, FlexSecure GmbH
+* Manuel Hartl, FlexSecure GmbH
+* (C) 2008-2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/gost_3410.h>
+#include <botan/numthry.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/secmem.h>
+#include <botan/point_gfp.h>
+
+namespace Botan {
+
+GOST_3410_PrivateKey::GOST_3410_PrivateKey(RandomNumberGenerator& rng,
+ const EC_Domain_Params& dom_pars)
+ {
+ mp_dom_pars = std::auto_ptr<EC_Domain_Params>(new EC_Domain_Params(dom_pars));
+ generate_private_key(rng);
+
+ try
+ {
+ mp_public_point->check_invariants();
+ }
+ catch(Illegal_Point& e)
+ {
+ throw Invalid_State("GOST_3410 key generation failed");
+ }
+ }
+
+GOST_3410_PrivateKey::GOST_3410_PrivateKey(const EC_Domain_Params& domain,
+ const BigInt& x)
+ {
+ mp_dom_pars = std::auto_ptr<EC_Domain_Params>(new EC_Domain_Params(domain));
+
+ m_private_value = x;
+ mp_public_point = std::auto_ptr<PointGFp>(new PointGFp (mp_dom_pars->get_base_point()));
+ mp_public_point->mult_this_secure(m_private_value,
+ mp_dom_pars->get_order(),
+ mp_dom_pars->get_order()-1);
+
+ try
+ {
+ mp_public_point->check_invariants();
+ }
+ catch(Illegal_Point)
+ {
+ throw Invalid_State("GOST_3410 key generation failed");
+ }
+ }
+
+X509_Encoder* GOST_3410_PublicKey::x509_encoder() const
+ {
+ class GOST_3410_Key_Encoder : public X509_Encoder
+ {
+ public:
+ AlgorithmIdentifier alg_id() const
+ {
+ key->affirm_init();
+
+ SecureVector<byte> params =
+ encode_der_ec_dompar(key->domain_parameters(), key->m_param_enc);
+
+ return AlgorithmIdentifier(key->get_oid(), params);
+ }
+
+ MemoryVector<byte> key_bits() const
+ {
+ key->affirm_init();
+
+ // Trust CryptoPro to come up with something obnoxious
+ const BigInt x = key->mp_public_point->get_affine_x().get_value();
+ const BigInt y = key->mp_public_point->get_affine_y().get_value();
+
+ SecureVector<byte> bits(2*std::max(x.bytes(), y.bytes()));
+
+ y.binary_encode(bits + (bits.size() / 2 - y.bytes()));
+ x.binary_encode(bits + (bits.size() - y.bytes()));
+
+ return DER_Encoder().encode(bits, OCTET_STRING).get_contents();
+ }
+
+ GOST_3410_Key_Encoder(const GOST_3410_PublicKey* k): key(k) {}
+ private:
+ const GOST_3410_PublicKey* key;
+ };
+
+ return new GOST_3410_Key_Encoder(this);
+ }
+
+X509_Decoder* GOST_3410_PublicKey::x509_decoder()
+ {
+ class GOST_3410_Key_Decoder : public X509_Decoder
+ {
+ public:
+ void alg_id(const AlgorithmIdentifier& alg_id)
+ {
+ // Also includes hash and cipher OIDs... brilliant design guys
+ OID ecc_param_id;
+
+ BER_Decoder ber(alg_id.parameters);
+ ber.start_cons(SEQUENCE).decode(ecc_param_id);
+
+ EC_Domain_Params ecc_params = get_EC_Dom_Pars_by_oid(ecc_param_id.as_string());
+
+ key->mp_dom_pars.reset(new EC_Domain_Params(ecc_params));
+ }
+
+ void key_bits(const MemoryRegion<byte>& bits)
+ {
+
+ SecureVector<byte> key_bits;
+ BER_Decoder ber(bits);
+ ber.decode(key_bits, OCTET_STRING);
+
+ const u32bit part_size = key_bits.size() / 2;
+
+ BigInt y(key_bits, part_size);
+ BigInt x(key_bits + part_size, part_size);
+
+ const BigInt p = key->domain_parameters().get_curve().get_p();
+
+ key->mp_public_point.reset(
+ new PointGFp(key->domain_parameters().get_curve(),
+ GFpElement(x, p),
+ GFpElement(y, p)));
+
+ key->X509_load_hook();
+ }
+
+ GOST_3410_Key_Decoder(GOST_3410_PublicKey* k): key(k) {}
+ private:
+ GOST_3410_PublicKey* key;
+ };
+
+ return new GOST_3410_Key_Decoder(this);
+ }
+
+/*
+* GOST_3410_PublicKey
+*/
+void GOST_3410_PublicKey::affirm_init() const // virtual
+ {
+ EC_PublicKey::affirm_init();
+ }
+
+void GOST_3410_PublicKey::set_domain_parameters(const EC_Domain_Params& dom_pars)
+ {
+ if(mp_dom_pars.get())
+ {
+ // they are already set, we must ensure that they are equal to the arg
+ if(dom_pars != *mp_dom_pars.get())
+ throw Invalid_Argument("EC_PublicKey::set_domain_parameters - cannot reset to a new value");
+
+ return;
+ }
+
+ if(m_enc_public_point.size() == 0)
+ throw Invalid_State("EC_PublicKey::set_domain_parameters(): encoded public point isn't set");
+
+ // now try to decode the public key ...
+ PointGFp tmp_pp(OS2ECP(m_enc_public_point, dom_pars.get_curve()));
+ try
+ {
+ tmp_pp.check_invariants();
+ }
+ catch(Illegal_Point e)
+ {
+ throw Invalid_State("EC_PublicKey::set_domain_parameters(): point does not lie on provided curve");
+ }
+
+ std::auto_ptr<EC_Domain_Params> p_tmp_pars(new EC_Domain_Params(dom_pars));
+ mp_public_point.reset(new PointGFp(tmp_pp));
+ mp_dom_pars = p_tmp_pars;
+ }
+
+void GOST_3410_PublicKey::set_all_values(const GOST_3410_PublicKey& other)
+ {
+ m_param_enc = other.m_param_enc;
+ m_enc_public_point = other.m_enc_public_point;
+ if(other.mp_dom_pars.get())
+ mp_dom_pars.reset(new EC_Domain_Params(other.domain_parameters()));
+
+ if(other.mp_public_point.get())
+ mp_public_point.reset(new PointGFp(other.public_point()));
+ }
+
+GOST_3410_PublicKey::GOST_3410_PublicKey(const GOST_3410_PublicKey& other)
+ : Public_Key(),
+ EC_PublicKey(),
+ PK_Verifying_wo_MR_Key()
+ {
+ set_all_values(other);
+ }
+
+const GOST_3410_PublicKey& GOST_3410_PublicKey::operator=(const GOST_3410_PublicKey& rhs)
+ {
+ set_all_values(rhs);
+ return *this;
+ }
+
+bool GOST_3410_PublicKey::verify(const byte msg[], u32bit msg_len,
+ const byte sig[], u32bit sig_len) const
+ {
+ affirm_init();
+
+ const BigInt& n = mp_dom_pars->get_order();
+
+ if(sig_len != n.bytes()*2)
+ return false;
+
+ // NOTE: it is not checked whether the public point is set
+ if(mp_dom_pars->get_curve().get_p() == 0)
+ throw Internal_Error("domain parameters not set");
+
+ BigInt e(msg, msg_len);
+
+ BigInt r(sig, sig_len / 2);
+ BigInt s(sig + sig_len / 2, sig_len / 2);
+
+ if(r < 0 || r >= n || s < 0 || s >= n)
+ return false;
+
+ e %= n;
+ if(e == 0)
+ e = 1;
+
+ BigInt v = inverse_mod(e, n);
+
+ BigInt z1 = (s*v) % n;
+ BigInt z2 = (-r*v) % n;
+
+ PointGFp R = (z1 * mp_dom_pars->get_base_point() + z2 * *mp_public_point);
+
+ return (R.get_affine_x().get_value() == r);
+ }
+
+GOST_3410_PublicKey::GOST_3410_PublicKey(const EC_Domain_Params& dom_par,
+ const PointGFp& public_point)
+ {
+ mp_dom_pars = std::auto_ptr<EC_Domain_Params>(new EC_Domain_Params(dom_par));
+ mp_public_point = std::auto_ptr<PointGFp>(new PointGFp(public_point));
+ m_param_enc = ENC_EXPLICIT;
+ }
+
+void GOST_3410_PublicKey::X509_load_hook()
+ {
+ EC_PublicKey::X509_load_hook();
+ EC_PublicKey::affirm_init();
+ }
+
+u32bit GOST_3410_PublicKey::max_input_bits() const
+ {
+ if(!mp_dom_pars.get())
+ {
+ throw Invalid_State("GOST_3410_PublicKey::max_input_bits(): domain parameters not set");
+ }
+ return mp_dom_pars->get_order().bits();
+ }
+
+/*************************
+* GOST_3410_PrivateKey
+*************************/
+void GOST_3410_PrivateKey::affirm_init() const // virtual
+ {
+ EC_PrivateKey::affirm_init();
+ }
+
+void GOST_3410_PrivateKey::PKCS8_load_hook(bool generated)
+ {
+ EC_PrivateKey::PKCS8_load_hook(generated);
+ EC_PrivateKey::affirm_init();
+ }
+
+void GOST_3410_PrivateKey::set_all_values(const GOST_3410_PrivateKey& other)
+ {
+ m_private_value = other.m_private_value;
+ m_param_enc = other.m_param_enc;
+ m_enc_public_point = other.m_enc_public_point;
+
+ if(other.mp_dom_pars.get())
+ mp_dom_pars.reset(new EC_Domain_Params(other.domain_parameters()));
+
+ if(other.mp_public_point.get())
+ mp_public_point.reset(new PointGFp(other.public_point()));
+ }
+
+GOST_3410_PrivateKey::GOST_3410_PrivateKey(GOST_3410_PrivateKey const& other)
+ : Public_Key(),
+ EC_PublicKey(),
+ Private_Key(),
+ GOST_3410_PublicKey(),
+ EC_PrivateKey(),
+ PK_Signing_Key()
+ {
+ set_all_values(other);
+ }
+
+const GOST_3410_PrivateKey& GOST_3410_PrivateKey::operator=(const GOST_3410_PrivateKey& rhs)
+ {
+ set_all_values(rhs);
+ return *this;
+ }
+
+SecureVector<byte>
+GOST_3410_PrivateKey::sign(const byte msg[],
+ u32bit msg_len,
+ RandomNumberGenerator& rng) const
+ {
+ affirm_init();
+
+ const BigInt& n = mp_dom_pars->get_order();
+
+ BigInt k;
+ do
+ k.randomize(rng, n.bits()-1);
+ while(k >= n);
+
+ if(m_private_value == 0)
+ throw Internal_Error("GOST_3410::sign(): no private key");
+
+ if(n == 0)
+ throw Internal_Error("GOST_3410::sign(): domain parameters not set");
+
+ BigInt e(msg, msg_len);
+
+ e %= n;
+ if(e == 0)
+ e = 1;
+
+ PointGFp k_times_P(mp_dom_pars->get_base_point());
+ k_times_P.mult_this_secure(k, n, n-1);
+ k_times_P.check_invariants();
+ BigInt r = k_times_P.get_affine_x().get_value() % n;
+
+ if(r == 0)
+ throw Internal_Error("GOST_3410::sign: r was zero");
+
+ BigInt s = (r*m_private_value + k*e) % n;
+
+ SecureVector<byte> output(2*n.bytes());
+ r.binary_encode(output + (output.size() / 2 - r.bytes()));
+ s.binary_encode(output + (output.size() - s.bytes()));
+ return output;
+ }
+
+}
diff --git a/src/pubkey/gost_3410/gost_3410.h b/src/pubkey/gost_3410/gost_3410.h
new file mode 100644
index 000000000..460aca9bf
--- /dev/null
+++ b/src/pubkey/gost_3410/gost_3410.h
@@ -0,0 +1,164 @@
+/*
+* GOST 34.10-2001
+* (C) 2007 Falko Strenzke, FlexSecure GmbH
+* Manuel Hartl, FlexSecure GmbH
+* (C) 2008-2009 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_GOST_3410_KEY_H__
+#define BOTAN_GOST_3410_KEY_H__
+
+#include <botan/ecc_key.h>
+
+namespace Botan {
+
+/**
+* This class represents GOST_3410 Public Keys.
+*/
+class BOTAN_DLL GOST_3410_PublicKey : public virtual EC_PublicKey,
+ public PK_Verifying_wo_MR_Key
+ {
+ public:
+
+ /**
+ * Get this keys algorithm name.
+ * @result this keys algorithm name
+ */
+ std::string algo_name() const { return "GOST-34.10"; }
+
+ /**
+ * Get the maximum number of bits allowed to be fed to this key.
+ * This is the bitlength of the order of the base point.
+
+ * @result the maximum number of input bits
+ */
+ u32bit max_input_bits() const;
+
+ u32bit message_parts() const { return 2; }
+
+ u32bit message_part_size() const
+ { return mp_dom_pars->get_order().bytes(); }
+
+ /**
+ * Verify a message with this key.
+ * @param message the byte array containing the message
+ * @param mess_len the number of bytes in the message byte array
+ * @param signature the byte array containing the signature
+ * @param sig_len the number of bytes in the signature byte array
+ */
+ bool verify(const byte message[], u32bit mess_len,
+ const byte signature[], u32bit sig_len) const;
+
+ /**
+ * Default constructor. Use this one if you want to later fill
+ * this object with data from an encoded key.
+ */
+ GOST_3410_PublicKey() {}
+
+ /**
+ * Construct a public key from a given public point.
+ * @param dom_par the domain parameters associated with this key
+ * @param public_point the public point defining this key
+ */
+ GOST_3410_PublicKey(const EC_Domain_Params& dom_par,
+ const PointGFp& public_point); // sets core
+
+ GOST_3410_PublicKey const& operator=(const GOST_3410_PublicKey& rhs);
+
+ GOST_3410_PublicKey(const GOST_3410_PublicKey& other);
+
+ /**
+ * Set the domain parameters of this key. This function has to be
+ * used when a key encoded without domain parameters was decoded into
+ * this key. Otherwise it will not be able to verify a signature.
+ * @param dom_pars the domain_parameters associated with this key
+ * @throw Invalid_Argument if the point was found not to be satisfying the
+ * curve equation of the provided domain parameters
+ * or if this key already has domain parameters set
+ * and these are differing from those given as the parameter
+ */
+ void set_domain_parameters(const EC_Domain_Params& dom_pars);
+
+ /**
+ * Ensure that the public point and domain parameters of this key are set.
+ * @throw Invalid_State if either of the two data members is not set
+ */
+ virtual void affirm_init() const;
+
+ /**
+ * Get an x509_encoder that can be used to encode this key.
+ * @result an x509_encoder for this key
+ */
+ X509_Encoder* x509_encoder() const;
+
+ /**
+ * Get an x509_decoder that can be used to decode a stored key into
+ * this key.
+ * @result an x509_decoder for this key
+ */
+ X509_Decoder* x509_decoder();
+
+ protected:
+ void X509_load_hook();
+ void set_all_values(const GOST_3410_PublicKey& other);
+ };
+
+/**
+* This class represents GOST_3410 Private Keys
+*/
+class BOTAN_DLL GOST_3410_PrivateKey : public GOST_3410_PublicKey,
+ public EC_PrivateKey,
+ public PK_Signing_Key
+ {
+ public:
+ /**
+ * Default constructor. Use this one if you want to later fill
+ * this object with data from an encoded key.
+ */
+ GOST_3410_PrivateKey() {}
+
+ /**
+ * Generate a new private key
+ * @param the domain parameters to used for this key
+ */
+ GOST_3410_PrivateKey(RandomNumberGenerator& rng,
+ const EC_Domain_Params& domain);
+
+ /**
+ * Load a private key
+ * @param domain parameters
+ * @param x the private key
+ */
+ GOST_3410_PrivateKey(const EC_Domain_Params& domain, const BigInt& x);
+
+ GOST_3410_PrivateKey(const GOST_3410_PrivateKey& other);
+ GOST_3410_PrivateKey const& operator=(const GOST_3410_PrivateKey& rhs);
+
+ /**
+ * Sign a message with this key.
+ * @param message the byte array representing the message to be signed
+ * @param mess_len the length of the message byte array
+ * @result the signature
+ */
+
+ SecureVector<byte> sign(const byte message[], u32bit mess_len,
+ RandomNumberGenerator& rng) const;
+
+ /**
+ * Make sure that the public key parts of this object are set
+ * (calls EC_PublicKey::affirm_init()) as well as the private key
+ * value.
+ * @throw Invalid_State if the above conditions are not satisfied
+ */
+ virtual void affirm_init() const;
+
+ private:
+ void set_all_values(const GOST_3410_PrivateKey& other);
+ void PKCS8_load_hook(bool = false);
+ };
+
+}
+
+#endif
diff --git a/src/pubkey/gost_3410/info.txt b/src/pubkey/gost_3410/info.txt
new file mode 100644
index 000000000..1d6c1ed17
--- /dev/null
+++ b/src/pubkey/gost_3410/info.txt
@@ -0,0 +1,14 @@
+define GOST_34_10_2001
+
+load_on auto
+
+<requires>
+alloc
+asn1
+ec_dompar
+ecc_key
+gfpmath
+libstate
+numbertheory
+rng
+</requires>
diff --git a/src/pubkey/pk_algs.cpp b/src/pubkey/pk_algs.cpp
index c040e006b..dd62eb5ac 100644
--- a/src/pubkey/pk_algs.cpp
+++ b/src/pubkey/pk_algs.cpp
@@ -23,6 +23,10 @@
#include <botan/ecdsa.h>
#endif
+#if defined(BOTAN_HAS_GOST_34_10_2001)
+ #include <botan/gost_3410.h>
+#endif
+
#if defined(BOTAN_HAS_NYBERG_RUEPPEL)
#include <botan/nr.h>
#endif
@@ -70,6 +74,10 @@ Public_Key* get_public_key(const std::string& alg_name)
if(alg_name == "ECDSA") return new ECDSA_PublicKey;
#endif
+#if defined(BOTAN_HAS_GOST_34_10_2001)
+ if(alg_name == "GOST-34.10") return new GOST_3410_PublicKey;
+#endif
+
return 0;
}
@@ -106,6 +114,10 @@ Private_Key* get_private_key(const std::string& alg_name)
if(alg_name == "ECDSA") return new ECDSA_PrivateKey;
#endif
+#if defined(BOTAN_HAS_GOST_34_10_2001)
+ if(alg_name == "GOST-34.10") return new GOST_3410_PrivateKey;
+#endif
+
return 0;
}
diff --git a/src/s2k/s2k.h b/src/s2k/s2k.h
index f3b8b3901..db59a5fe8 100644
--- a/src/s2k/s2k.h
+++ b/src/s2k/s2k.h
@@ -18,9 +18,9 @@ namespace Botan {
class BOTAN_DLL S2K
{
public:
+
/**
- * Create a copy of this object.
- * @return an auto_ptr to a copy of this object
+ * @return a new instance of this same algorithm
*/
virtual S2K* clone() const = 0;
diff --git a/src/ssl/c_kex.cpp b/src/ssl/c_kex.cpp
new file mode 100644
index 000000000..802946bb9
--- /dev/null
+++ b/src/ssl/c_kex.cpp
@@ -0,0 +1,174 @@
+/**
+* Client Key Exchange Message
+* (C) 2004-2008 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_messages.h>
+#include <botan/dh.h>
+#include <botan/rsa.h>
+#include <botan/rng.h>
+#include <botan/look_pk.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)
+ {
+ const DH_PublicKey* dh_pub = dynamic_cast<const DH_PublicKey*>(pub_key);
+ const RSA_PublicKey* rsa_pub = dynamic_cast<const RSA_PublicKey*>(pub_key);
+
+ include_length = true;
+
+ if(dh_pub)
+ {
+ DH_PrivateKey priv_key(rng, dh_pub->get_domain());
+ pre_master = priv_key.derive_key(dh_pub->get_y());
+ key_material = priv_key.public_value();
+ }
+ else if(rsa_pub)
+ {
+ pre_master.resize(48);
+ rng.randomize(pre_master, 48);
+ pre_master[0] = (pref_version >> 8) & 0xFF;
+ pre_master[1] = (pref_version ) & 0xFF;
+
+ std::auto_ptr<PK_Encryptor> encryptor(get_pk_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() == CipherSuite::NO_KEX ||
+ suite.kex_type() == CipherSuite::RSA_KEX))
+ include_length = false;
+
+ deserialize(contents);
+ }
+
+/**
+* Serialize a Client Key Exchange message
+*/
+SecureVector<byte> Client_Key_Exchange::serialize() const
+ {
+ SecureVector<byte> buf;
+
+ if(include_length)
+ {
+ u16bit key_size = key_material.size();
+ buf.append(get_byte(0, key_size));
+ buf.append(get_byte(1, key_size));
+ }
+ buf.append(key_material);
+
+ return buf;
+ }
+
+/**
+* Deserialize a Client Key Exchange message
+*/
+void Client_Key_Exchange::deserialize(const MemoryRegion<byte>& buf)
+ {
+ if(include_length)
+ {
+ if(buf.size() < 2)
+ throw Decoding_Error("Client_Key_Exchange: Packet corrupted");
+
+ u32bit size = make_u16bit(buf[0], buf[1]);
+ if(size + 2 != buf.size())
+ throw Decoding_Error("Client_Key_Exchange: Packet corrupted");
+
+ key_material.set(buf + 2, size);
+ }
+ 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)
+ {
+ const DH_PrivateKey* dh_priv = dynamic_cast<const DH_PrivateKey*>(priv_key);
+ const RSA_PrivateKey* rsa_priv =
+ dynamic_cast<const RSA_PrivateKey*>(priv_key);
+
+ if(dh_priv)
+ {
+ try {
+ pre_master = dh_priv->derive_key(key_material, key_material.size());
+ }
+ catch(std::exception& e)
+ {
+ pre_master.resize(dh_priv->public_value().size());
+ rng.randomize(pre_master, pre_master.size());
+ }
+
+ return pre_master;
+ }
+ else if(rsa_priv)
+ {
+ std::auto_ptr<PK_Decryptor> decryptor(get_pk_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(std::exception)
+ {
+ pre_master.resize(48);
+ rng.randomize(pre_master, pre_master.size());
+ 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
new file mode 100644
index 000000000..4431a4a39
--- /dev/null
+++ b/src/ssl/cert_req.cpp
@@ -0,0 +1,156 @@
+/**
+* Certificate Request Message
+* (C) 2004-2006 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_messages.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(u32bit j = 0; j != certs.size(); j++)
+ names.push_back(certs[j].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;
+
+ buf.append(types.size());
+ for(u32bit j = 0; j != types.size(); j++)
+ buf.append(types[j]);
+
+ DER_Encoder encoder;
+ for(u32bit j = 0; j != names.size(); j++)
+ encoder.encode(names[j]);
+
+ SecureVector<byte> der_names = encoder.get_contents();
+ u16bit names_size = der_names.size();
+
+ buf.append(get_byte(0, names_size));
+ buf.append(get_byte(1, names_size));
+ buf.append(der_names);
+
+ 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");
+
+ u32bit types_size = buf[0];
+
+ if(buf.size() < types_size + 3)
+ throw Decoding_Error("Certificate_Req: Bad certificate request");
+
+ for(u32bit j = 0; j != types_size; j++)
+ types.push_back(static_cast<Certificate_Type>(buf[j+1]));
+
+ u32bit 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.begin() + 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(u32bit j = 0; j != certs.size(); j++)
+ {
+ SecureVector<byte> raw_cert = certs[j].BER_encode();
+ u32bit cert_size = raw_cert.size();
+ for(u32bit j = 0; j != 3; j++)
+ buf.append(get_byte(j+1, cert_size));
+ buf.append(raw_cert);
+ }
+
+ u32bit buf_size = buf.size() - 3;
+ for(u32bit j = 0; j != 3; j++)
+ buf[j] = get_byte(j+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");
+
+ u32bit 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);
+ u32bit cert_size = make_u32bit(0, len[0], len[1], len[2]);
+
+ u32bit 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
new file mode 100644
index 000000000..5ac28dd2e
--- /dev/null
+++ b/src/ssl/cert_ver.cpp
@@ -0,0 +1,109 @@
+/**
+* Certificate Verify Message
+* (C) 2004-2006 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_messages.h>
+#include <botan/look_pk.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)
+ {
+ const PK_Signing_Key* sign_key =
+ dynamic_cast<const PK_Signing_Key*>(priv_key);
+
+ if(sign_key)
+ {
+ PK_Signer* signer = 0;
+ try
+ {
+ if(dynamic_cast<const RSA_PrivateKey*>(sign_key))
+ signer = get_pk_signer(*sign_key, "EMSA3(TLS.Digest.0)");
+ else if(dynamic_cast<const DSA_PrivateKey*>(sign_key))
+ signer = get_pk_signer(*sign_key, "EMSA1(SHA-1)");
+ else
+ throw Invalid_Argument("Unknown PK algo for TLS signature");
+
+ signature = signer->sign_message(hash.final(), rng);
+ delete signer;
+ }
+ catch(...)
+ {
+ delete signer;
+ throw;
+ }
+
+ send(writer, hash);
+ }
+ }
+
+/**
+* Serialize a Certificate Verify message
+*/
+SecureVector<byte> Certificate_Verify::serialize() const
+ {
+ SecureVector<byte> buf;
+
+ u16bit sig_len = signature.size();
+ buf.append(get_byte(0, sig_len));
+ buf.append(get_byte(1, sig_len));
+ buf.append(signature);
+
+ return buf;
+ }
+
+/**
+* Deserialize a Certificate Verify message
+*/
+void Certificate_Verify::deserialize(const MemoryRegion<byte>& buf)
+ {
+ if(buf.size() < 2)
+ throw Decoding_Error("Certificate_Verify: Corrupted packet");
+
+ u32bit sig_len = make_u16bit(buf[0], buf[1]);
+ if(buf.size() != 2 + sig_len)
+ throw Decoding_Error("Certificate_Verify: Corrupted packet");
+
+ signature.set(buf + 2, sig_len);
+ }
+
+/**
+* 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());
+
+ DSA_PublicKey* dsa_pub = dynamic_cast<DSA_PublicKey*>(key.get());
+ RSA_PublicKey* rsa_pub = dynamic_cast<RSA_PublicKey*>(key.get());
+
+ std::auto_ptr<PK_Verifier> verifier;
+
+ if(dsa_pub)
+ verifier.reset(get_pk_verifier(*dsa_pub, "EMSA1(SHA-1)", DER_SEQUENCE));
+ else if(rsa_pub)
+ verifier.reset(get_pk_verifier(*rsa_pub, "EMSA3(TLS.Digest.0)"));
+ else
+ throw Invalid_Argument("Client did not provide a RSA/DSA cert");
+
+ // FIXME: WRONG
+ return verifier->verify_message(hash.final(), signature);
+ }
+
+}
diff --git a/src/ssl/finished.cpp b/src/ssl/finished.cpp
new file mode 100644
index 000000000..edbd4a3fe
--- /dev/null
+++ b/src/ssl/finished.cpp
@@ -0,0 +1,100 @@
+/**
+* Finished Message
+* (C) 2004-2006 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/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)
+ {
+ 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.append(TLS_CLIENT_LABEL, sizeof(TLS_CLIENT_LABEL));
+ else
+ input.append(TLS_SERVER_LABEL, sizeof(TLS_SERVER_LABEL));
+ input.append(hash.final());
+
+ return prf.derive_key(12, secret, input);
+ }
+ else
+ throw Invalid_Argument("Finished message: Unknown protocol version");
+ }
+
+}
diff --git a/src/ssl/handshake_hash.cpp b/src/ssl/handshake_hash.cpp
new file mode 100644
index 000000000..d94fa0178
--- /dev/null
+++ b/src/ssl/handshake_hash.cpp
@@ -0,0 +1,60 @@
+/**
+* TLS Handshake Hash
+* (C) 2004-2006 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/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);
+
+ return SecureVector<byte>(md5.final(), sha1.final());
+ }
+
+/**
+* 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(u32bit j = 0; j != 48; j++) md5.update(PAD_INNER);
+ for(u32bit j = 0; j != 40; j++) sha1.update(PAD_INNER);
+
+ SecureVector<byte> inner_md5 = md5.final(), inner_sha1 = sha1.final();
+
+ md5.update(secret);
+ sha1.update(secret);
+ for(u32bit j = 0; j != 48; j++) md5.update(PAD_OUTER);
+ for(u32bit j = 0; j != 40; j++) sha1.update(PAD_OUTER);
+ md5.update(inner_md5);
+ sha1.update(inner_sha1);
+
+ return SecureVector<byte>(md5.final(), sha1.final());
+ }
+
+}
diff --git a/src/ssl/handshake_hash.h b/src/ssl/handshake_hash.h
new file mode 100644
index 000000000..cfb351765
--- /dev/null
+++ b/src/ssl/handshake_hash.h
@@ -0,0 +1,38 @@
+/**
+* TLS Handshake Hash
+* (C) 2004-2006 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_HANDSHAKE_HASH_H__
+#define BOTAN_TLS_HANDSHAKE_HASH_H__
+
+#include <botan/secmem.h>
+
+namespace Botan {
+
+using namespace Botan;
+
+/**
+* TLS Handshake Hash
+*/
+class BOTAN_DLL HandshakeHash
+ {
+ public:
+ void update(const byte in[], u32bit length)
+ { data.append(in, length); }
+ void update(const MemoryRegion<byte>& in)
+ { update(in.begin(), in.size()); }
+ void update(byte in)
+ { update(&in, 1); }
+
+ SecureVector<byte> final();
+ SecureVector<byte> final_ssl3(const MemoryRegion<byte>&);
+ private:
+ SecureVector<byte> data;
+ };
+
+}
+
+#endif
diff --git a/src/ssl/handshake_state.cpp b/src/ssl/handshake_state.cpp
new file mode 100644
index 000000000..314625057
--- /dev/null
+++ b/src/ssl/handshake_state.cpp
@@ -0,0 +1,59 @@
+/**
+* TLS Handshaking
+* (C) 2004-2006 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/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/hello.cpp b/src/ssl/hello.cpp
new file mode 100644
index 000000000..53f680fba
--- /dev/null
+++ b/src/ssl/hello.cpp
@@ -0,0 +1,265 @@
+/**
+* TLS Hello Messages
+* (C) 2004-2006 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_messages.h>
+#include <botan/loadstor.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);
+
+ u32bit buf_size = buf.size();
+
+ send_buf[0] = type();
+ send_buf[1] = get_byte(1, buf_size);
+ send_buf[2] = get_byte(2, buf_size);
+ send_buf[3] = get_byte(3, buf_size);
+
+ send_buf.append(buf);
+
+ hash.update(send_buf);
+
+ writer.send(HANDSHAKE, send_buf, 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.resize(32);
+ rng.randomize(c_random, c_random.size());
+
+ 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.append(static_cast<byte>(c_version >> 8));
+ buf.append(static_cast<byte>(c_version ));
+ buf.append(c_random);
+ buf.append(static_cast<byte>(sess_id.size()));
+ buf.append(sess_id);
+
+ u16bit suites_size = 2*suites.size();
+
+ buf.append(get_byte(0, suites_size));
+ buf.append(get_byte(1, suites_size));
+ for(u32bit j = 0; j != suites.size(); j++)
+ {
+ buf.append(get_byte(0, suites[j]));
+ buf.append(get_byte(1, suites[j]));
+ }
+
+ buf.append(static_cast<byte>(comp_algos.size()));
+ for(u32bit j = 0; j != comp_algos.size(); j++)
+ buf.append(comp_algos[j]);
+
+ return buf;
+ }
+
+/**
+* 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");
+
+ c_version = static_cast<Version_Code>(make_u16bit(buf[0], buf[1]));
+ if(c_version != SSL_V3 && c_version != TLS_V10)
+ throw TLS_Exception(PROTOCOL_VERSION, "Client_Hello: Bad version code");
+
+ c_random.set(buf + 2, 32);
+
+ u32bit session_id_len = buf[34];
+ if(session_id_len > 32 || session_id_len + 41 > buf.size())
+ throw Decoding_Error("Client_Hello: Packet corrupted");
+ sess_id.copy(buf + 35, session_id_len);
+
+ u32bit offset = 2+32+1+session_id_len;
+
+ u16bit suites_size = make_u16bit(buf[offset], buf[offset+1]);
+ offset += 2;
+ if(suites_size % 2 == 1 || offset + suites_size + 2 > buf.size())
+ throw Decoding_Error("Client_Hello: Packet corrupted");
+
+ for(u32bit j = 0; j != suites_size; j += 2)
+ {
+ u16bit suite = make_u16bit(buf[offset+j], buf[offset+j+1]);
+ suites.push_back(suite);
+ }
+ offset += suites_size;
+
+ byte comp_algo_size = buf[offset];
+ offset += 1;
+ if(offset + comp_algo_size > buf.size())
+ throw Decoding_Error("Client_Hello: Packet corrupted");
+
+ for(u32bit j = 0; j != comp_algo_size; j++)
+ comp_algos.push_back(buf[offset+j]);
+ }
+
+/**
+* Check if we offered this ciphersuite
+*/
+bool Client_Hello::offered_suite(u16bit ciphersuite) const
+ {
+ for(u32bit j = 0; j != suites.size(); j++)
+ if(suites[j] == 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(u32bit j = 0; j != certs.size(); j++)
+ {
+ Public_Key* key = certs[j].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);
+ comp_algo = policy->choose_compression(c_hello.compression_algos());
+
+ s_version = ver;
+ s_random.resize(32);
+ rng.randomize(s_random, s_random.size());
+
+ send(writer, hash);
+ }
+
+/**
+* Serialize a Server Hello message
+*/
+SecureVector<byte> Server_Hello::serialize() const
+ {
+ SecureVector<byte> buf;
+
+ buf.append(static_cast<byte>(s_version >> 8));
+ buf.append(static_cast<byte>(s_version ));
+ buf.append(s_random);
+ buf.append(static_cast<byte>(sess_id.size()));
+ buf.append(sess_id);
+
+ buf.append(get_byte(0, suite));
+ buf.append(get_byte(1, suite));
+
+ buf.append(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");
+
+ s_version = static_cast<Version_Code>(make_u16bit(buf[0], buf[1]));
+ if(s_version != SSL_V3 && s_version != TLS_V10)
+ throw TLS_Exception(PROTOCOL_VERSION,
+ "Server_Hello: Unsupported server version");
+
+ s_random.set(buf + 2, 32);
+
+ u32bit session_id_len = buf[2+32];
+ if(session_id_len > 32 || session_id_len + 38 != buf.size())
+ throw Decoding_Error("Server_Hello: Packet corrupted");
+ sess_id.copy(buf + 2 + 32 + 1, session_id_len);
+
+ suite = make_u16bit(buf[2+32+1+session_id_len],
+ buf[2+32+1+session_id_len+1]);
+ comp_algo = buf[2+32+1+session_id_len+2];
+ }
+
+
+/**
+* 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
new file mode 100644
index 000000000..73e4207d8
--- /dev/null
+++ b/src/ssl/info.txt
@@ -0,0 +1 @@
+define SSL_TLS
diff --git a/src/ssl/rec_read.cpp b/src/ssl/rec_read.cpp
new file mode 100644
index 000000000..95059dbf2
--- /dev/null
+++ b/src/ssl/rec_read.cpp
@@ -0,0 +1,204 @@
+/**
+* TLS Record Reading
+* (C) 2004-2006 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/debug.h>
+
+namespace Botan {
+
+/**
+* Record_Reader Constructor
+*/
+Record_Reader::Record_Reader(Socket& sock) : socket(sock)
+ {
+ reset();
+ }
+
+/**
+* Reset the state
+*/
+void Record_Reader::reset()
+ {
+ compress.reset();
+ cipher.reset();
+ mac.reset();
+ do_compress = false;
+ mac_size = pad_amount = 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)
+ throw Invalid_Argument("Record_Reader: Invalid protocol version");
+
+ major = (version >> 8) & 0xFF;
+ minor = (version & 0xFF);
+ }
+
+/**
+* Set the compression algorithm
+*/
+void Record_Reader::set_compressor(Filter* compressor)
+ {
+ compress.append(compressor);
+ do_compress = true;
+ }
+
+/**
+* Set the keys for reading
+*/
+void Record_Reader::set_keys(const CipherSuite& suite, const SessionKeys& keys,
+ Connection_Side side)
+ {
+ cipher.reset();
+ mac.reset();
+
+ 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)
+ );
+ pad_amount = block_size_of(cipher_algo);
+ }
+ else if(have_stream_cipher(cipher_algo))
+ {
+ cipher.append(get_cipher(cipher_algo, cipher_key, DECRYPTION));
+ pad_amount = 0;
+ }
+ else
+ throw Invalid_Argument("Record_Reader: Unknown cipher " + cipher_algo);
+
+ if(have_hash(mac_algo))
+ {
+ if(major == 3 && minor == 0)
+ mac.append(new MAC_Filter("SSL3-MAC(" + mac_algo + ")", mac_key));
+ else
+ mac.append(new MAC_Filter("HMAC(" + mac_algo + ")", mac_key));
+
+ mac_size = output_length_of(mac_algo);
+ }
+ else
+ throw Invalid_Argument("Record_Reader: Unknown hash " + mac_algo);
+ }
+
+/**
+* Retrieve the next record
+*/
+SecureVector<byte> Record_Reader::get_record(byte& msg_type)
+ {
+ byte header[5] = { 0 };
+
+ u32bit got = socket.read(header, sizeof(header));
+
+ if(got == 0)
+ {
+ msg_type = CONNECTION_CLOSED;
+ return SecureVector<byte>();
+ }
+ else if(got != sizeof(header))
+ throw Decoding_Error("Record_Reader: Record truncated");
+
+ msg_type = header[0];
+
+ const u16bit version = make_u16bit(header[1], header[2]);
+
+ if(major && (header[1] != major || header[2] != minor))
+ throw TLS_Exception(PROTOCOL_VERSION,
+ "Record_Reader: Got unexpected version");
+
+ SecureVector<byte> buffer(make_u16bit(header[3], header[4]));
+ if(socket.read(buffer, buffer.size()) != buffer.size())
+ throw Decoding_Error("Record_Reader: Record truncated");
+
+ if(mac_size == 0)
+ return buffer;
+
+ cipher.process_msg(buffer);
+ SecureVector<byte> plaintext = cipher.read_all(Pipe::LAST_MESSAGE);
+
+ u32bit pad_size = 0;
+ if(pad_amount)
+ {
+ byte pad_value = plaintext[plaintext.size()-1];
+ pad_size = pad_value + 1;
+
+ if(version == SSL_V3)
+ {
+ if(pad_value > pad_amount)
+ throw TLS_Exception(BAD_RECORD_MAC,
+ "Record_Reader: Bad padding");
+ }
+ else
+ {
+ for(u32bit j = 0; j != pad_size; j++)
+ if(plaintext[plaintext.size()-j-1] != pad_value)
+ throw TLS_Exception(BAD_RECORD_MAC,
+ "Record_Reader: Bad padding");
+ }
+ }
+
+ if(plaintext.size() < mac_size + pad_size)
+ throw Decoding_Error("Record_Reader: Record truncated");
+
+ const u32bit mac_offset = plaintext.size() - (mac_size + pad_size);
+ SecureVector<byte> recieved_mac(plaintext.begin() + mac_offset,
+ mac_size);
+
+ const u16bit plain_length = plaintext.size() - (mac_size + pad_size);
+
+ mac.start_msg();
+ for(u32bit j = 0; j != 8; j++)
+ mac.write(get_byte(j, seq_no));
+ mac.write(msg_type);
+
+ if(version != SSL_V3)
+ for(u32bit j = 0; j != 2; j++)
+ mac.write(get_byte(j, version));
+
+ for(u32bit j = 0; j != 2; j++)
+ mac.write(get_byte(j, plain_length));
+ mac.write(plaintext, plain_length);
+ mac.end_msg();
+
+ ++seq_no;
+
+ SecureVector<byte> computed_mac = mac.read_all(Pipe::LAST_MESSAGE);
+
+ if(recieved_mac != computed_mac)
+ throw TLS_Exception(BAD_RECORD_MAC, "Record_Reader: MAC failure");
+
+ return SecureVector<byte>(plaintext, mac_offset);
+ }
+
+}
diff --git a/src/ssl/rec_wri.cpp b/src/ssl/rec_wri.cpp
new file mode 100644
index 000000000..258b4ec17
--- /dev/null
+++ b/src/ssl/rec_wri.cpp
@@ -0,0 +1,258 @@
+/**
+* TLS Record Writing
+* (C) 2004-2006 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_record.h>
+#include <botan/handshake_hash.h>
+#include <botan/lookup.h>
+#include <botan/loadstor.h>
+
+namespace Botan {
+
+/**
+* Record_Writer Constructor
+*/
+Record_Writer::Record_Writer(Socket& sock) :
+ socket(sock), buffer(DEFAULT_BUFFERSIZE)
+ {
+ reset();
+ }
+
+/**
+* Reset the state
+*/
+void Record_Writer::reset()
+ {
+ compress.reset();
+ cipher.reset();
+ mac.reset();
+ buffer.clear();
+ do_compress = false;
+ major = minor = buf_type = 0;
+ pad_amount = mac_size = buf_pos = 0;
+ seq_no = 0;
+ }
+
+/**
+* Set the version to use
+*/
+void Record_Writer::set_version(Version_Code version)
+ {
+ if(version != SSL_V3 && version != TLS_V10)
+ throw Invalid_Argument("Record_Writer: Invalid protocol version");
+
+ major = (version >> 8) & 0xFF;
+ minor = (version & 0xFF);
+ }
+
+/**
+* Set the compression algorithm
+*/
+void Record_Writer::set_compressor(Filter* compressor)
+ {
+ throw TLS_Exception(INTERNAL_ERROR, "Compression not implemented (FIXME)");
+ compress.append(compressor);
+ }
+
+/**
+* Set the keys for writing
+*/
+void Record_Writer::set_keys(const CipherSuite& suite, const SessionKeys& keys,
+ Connection_Side side)
+ {
+ cipher.reset();
+ mac.reset();
+
+ 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)
+ );
+ pad_amount = block_size_of(cipher_algo);
+ }
+ else if(have_stream_cipher(cipher_algo))
+ {
+ cipher.append(get_cipher(cipher_algo, cipher_key, ENCRYPTION));
+ pad_amount = 0;
+ }
+ else
+ throw Invalid_Argument("Record_Writer: Unknown cipher " + cipher_algo);
+
+ if(have_hash(mac_algo))
+ {
+ if(major == 3 && minor == 0)
+ mac.append(new MAC_Filter("SSL3-MAC(" + mac_algo + ")", mac_key));
+ else
+ mac.append(new MAC_Filter("HMAC(" + mac_algo + ")", mac_key));
+
+ mac_size = output_length_of(mac_algo);
+ }
+ 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, byte input)
+ {
+ send(type, &input, 1);
+ }
+
+/**
+* Send one or more records to the other side
+*/
+void Record_Writer::send(byte type, const byte input[], u32bit length)
+ {
+ if(type != buf_type)
+ flush();
+
+ const u32bit 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, 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.begin();
+ u32bit offset = 0;
+
+ while(offset != buf_pos)
+ {
+ u32bit 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[], u32bit 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.start_msg();
+ for(u32bit j = 0; j != 8; j++)
+ mac.write(get_byte(j, seq_no));
+ mac.write(type);
+
+ if(major > 3 || (major == 3 && minor != 0))
+ {
+ mac.write(major);
+ mac.write(minor);
+ }
+
+ mac.write(get_byte(2, length));
+ mac.write(get_byte(3, length));
+ mac.write(buf, length);
+ mac.end_msg();
+
+ SecureVector<byte> buf_mac = mac.read_all(Pipe::LAST_MESSAGE);
+
+ cipher.start_msg();
+ cipher.write(buf, length);
+ cipher.write(buf_mac);
+ if(pad_amount)
+ {
+ u32bit pad_val =
+ (pad_amount - (1 + length + buf_mac.size())) % pad_amount;
+
+ for(u32bit j = 0; j != pad_val + 1; j++)
+ cipher.write(pad_val);
+ }
+ cipher.end_msg();
+
+ SecureVector<byte> output = cipher.read_all(Pipe::LAST_MESSAGE);
+
+ send_record(type, major, minor, output, output.size());
+
+ seq_no++;
+ }
+ }
+
+/**
+* Send a final record packet
+*/
+void Record_Writer::send_record(byte type, byte major, byte minor,
+ const byte out[], u32bit 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(u32bit j = 0; j != 2; j++)
+ header[j+3] = get_byte<u16bit>(j, length);
+
+ // FIXME: tradoff of TCP/syscall overhead vs copy overhead
+ socket.write(header, 5);
+ socket.write(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
new file mode 100644
index 000000000..fd49fcb8c
--- /dev/null
+++ b/src/ssl/s_kex.cpp
@@ -0,0 +1,195 @@
+/**
+* Server Key Exchange Message
+* (C) 2004-2010 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_messages.h>
+#include <botan/dh.h>
+#include <botan/rsa.h>
+#include <botan/dsa.h>
+#include <botan/look_pk.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");
+
+ // FIXME: dup of stuff in cert_ver.cpp
+ // FIXME: it's OK for the server to be anonymous....
+ const PK_Signing_Key* sign_key =
+ dynamic_cast<const PK_Signing_Key*>(priv_key);
+
+ if(!sign_key)
+ throw Invalid_Argument("Server Kex: Private key not for signing");
+
+ PK_Signer* signer = 0;
+ try {
+ if(dynamic_cast<const RSA_PrivateKey*>(sign_key))
+ signer = get_pk_signer(*sign_key, "EMSA3(TLS.Digest.0)");
+ else if(dynamic_cast<const DSA_PrivateKey*>(sign_key))
+ {
+ signer = get_pk_signer(*sign_key, "EMSA1(SHA-1)");
+ signer->set_output_format(DER_SEQUENCE);
+ }
+ else
+ throw Invalid_Argument("Bad key for TLS signature: not RSA or DSA");
+
+ signer->update(c_random);
+ signer->update(s_random);
+ signer->update(serialize_params());
+ signature = signer->signature(rng);
+
+ delete signer;
+ }
+ catch(...)
+ {
+ delete signer;
+ throw;
+ }
+
+ send(writer, hash);
+ }
+
+/**
+* Serialize a Server Key Exchange message
+*/
+SecureVector<byte> Server_Key_Exchange::serialize() const
+ {
+ SecureVector<byte> buf = serialize_params();
+ u16bit sig_len = signature.size();
+ buf.append(get_byte(0, sig_len));
+ buf.append(get_byte(1, sig_len));
+ buf.append(signature);
+ return buf;
+ }
+
+/**
+* Serialize the ServerParams structure
+*/
+SecureVector<byte> Server_Key_Exchange::serialize_params() const
+ {
+ SecureVector<byte> buf;
+ for(u32bit j = 0; j != params.size(); j++)
+ {
+ SecureVector<byte> param = BigInt::encode(params[j]);
+ u16bit param_size = param.size();
+
+ buf.append(get_byte(0, param_size));
+ buf.append(get_byte(1, param_size));
+ buf.append(param);
+ }
+ 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];
+ u32bit so_far = 0;
+
+ for(u32bit j = 0; j != 4; j++)
+ {
+ 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[j].set(buf + so_far, len);
+ so_far += len;
+
+ if(j == 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());
+
+ DSA_PublicKey* dsa_pub = dynamic_cast<DSA_PublicKey*>(key.get());
+ RSA_PublicKey* rsa_pub = dynamic_cast<RSA_PublicKey*>(key.get());
+
+ std::auto_ptr<PK_Verifier> verifier;
+
+ if(dsa_pub)
+ {
+ verifier.reset(get_pk_verifier(*dsa_pub, "EMSA1(SHA-1)", DER_SEQUENCE));
+ verifier->set_input_format(DER_SEQUENCE);
+ }
+ else if(rsa_pub)
+ verifier.reset(get_pk_verifier(*rsa_pub, "EMSA3(TLS.Digest.0)"));
+ else
+ throw Invalid_Argument("Server did not provide a RSA/DSA cert");
+
+ SecureVector<byte> params_got = serialize_params();
+ verifier->update(c_random);
+ verifier->update(s_random);
+ verifier->update(params_got);
+
+ return verifier->check_signature(signature, signature.size());
+ }
+
+}
diff --git a/src/ssl/socket.h b/src/ssl/socket.h
new file mode 100644
index 000000000..3d893ea77
--- /dev/null
+++ b/src/ssl/socket.h
@@ -0,0 +1,49 @@
+/**
+* Socket Interface
+* (C) 2004-2006 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_SOCKET_H__
+#define BOTAN_TLS_SOCKET_H__
+
+#include <botan/types.h>
+#include <string>
+
+namespace Botan {
+
+/**
+* Socket Base Class
+*/
+class BOTAN_DLL Socket
+ {
+ public:
+ virtual u32bit read(byte[], u32bit) = 0;
+ virtual void write(const byte[], u32bit) = 0;
+
+ u32bit read(byte& x) { return read(&x, 1); }
+ void write(byte x) { write(&x, 1); }
+
+ virtual std::string peer_id() const = 0;
+
+ virtual void close() = 0;
+
+ virtual ~Socket() {}
+ };
+
+/**
+* Server Socket Base Class
+*/
+class BOTAN_DLL Server_Socket
+ {
+ public:
+ virtual Socket* accept() = 0;
+ virtual void close() = 0;
+
+ virtual ~Server_Socket() {}
+ };
+
+}
+
+#endif
diff --git a/src/ssl/tls_alerts.h b/src/ssl/tls_alerts.h
new file mode 100644
index 000000000..894bca4af
--- /dev/null
+++ b/src/ssl/tls_alerts.h
@@ -0,0 +1,46 @@
+/**
+* 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 BOTAN_DLL Alert
+ {
+ public:
+ bool is_fatal() const { return fatal; }
+ Alert_Type type() const { return type_code; }
+
+ /**
+ * Deserialize an Alert message
+ */
+ 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
new file mode 100644
index 000000000..ce33573f5
--- /dev/null
+++ b/src/ssl/tls_client.cpp
@@ -0,0 +1,571 @@
+/**
+* TLS Client
+* (C) 2004-2006 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_client.h>
+#include <botan/tls_alerts.h>
+#include <botan/tls_state.h>
+#include <botan/loadstor.h>
+#include <botan/rsa.h>
+#include <botan/dsa.h>
+#include <botan/dh.h>
+
+namespace Botan {
+
+namespace {
+
+// FIXME: checks are wrong for session reuse (add a flag for that)
+/**
+* Verify the state transition is allowed
+*/
+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(RandomNumberGenerator& r,
+ Socket& sock, const TLS_Policy* pol) :
+ rng(r), writer(sock), reader(sock), policy(pol ? pol : new TLS_Policy)
+ {
+ peer_id = sock.peer_id();
+
+ initialize();
+ }
+
+/**
+* TLS Client Constructor
+*/
+TLS_Client::TLS_Client(RandomNumberGenerator& r,
+ Socket& sock, const X509_Certificate& cert,
+ const Private_Key& key, const TLS_Policy* pol) :
+ rng(r), writer(sock), reader(sock), policy(pol ? pol : new TLS_Policy)
+ {
+ peer_id = sock.peer_id();
+
+ certs.push_back(cert);
+ keys.push_back(PKCS8::copy_key(key, rng));
+
+ initialize();
+ }
+
+/**
+* TLS Client Destructor
+*/
+TLS_Client::~TLS_Client()
+ {
+ close();
+ for(u32bit j = 0; j != keys.size(); j++)
+ delete keys[j];
+ delete policy;
+ delete state;
+ }
+
+/**
+* Initialize a TLS client connection
+*/
+void TLS_Client::initialize()
+ {
+ 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_type = e.type();
+ }
+ catch(std::exception& e)
+ {
+ 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");
+ }
+ }
+
+/**
+* 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[], u32bit 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
+*/
+u32bit TLS_Client::read(byte out[], u32bit length)
+ {
+ if(!active)
+ return 0;
+
+ writer.flush();
+
+ while(read_buf.size() == 0)
+ {
+ state_machine();
+ if(active == false)
+ break;
+ }
+
+ u32bit got = std::min(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;
+ SecureVector<byte> record = reader.get_record(rec_type);
+
+ if(rec_type == CONNECTION_CLOSED)
+ {
+ active = false;
+ reader.reset();
+ writer.reset();
+ }
+ else if(rec_type == APPLICATION_DATA)
+ {
+ if(active)
+ read_buf.write(record, 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 recieved");
+ }
+
+/**
+* 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, 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 u32bit 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, 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)
+ {
+ 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 u32bit record_length = contents.size();
+ for(u32bit j = 0; j != 3; j++)
+ state->hash.update(get_byte(j+1, record_length));
+ state->hash.update(contents);
+ }
+
+ if(type == 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() == CipherSuite::NO_SIG)
+ 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, peer_id))
+ 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 recieved in server kex");
+
+ if((is_dsa && state->suite.sig_type() != CipherSuite::DSA_SIG) ||
+ (is_rsa && state->suite.sig_type() != CipherSuite::RSA_SIG))
+ 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() == CipherSuite::NO_KEX)
+ 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 recieved in server kex");
+
+ if((is_dh && state->suite.kex_type() != CipherSuite::DH_KEX) ||
+ (is_rsa && state->suite.kex_type() != CipherSuite::RSA_KEX))
+ throw TLS_Exception(ILLEGAL_PARAMETER,
+ "Certificate key type did not match ciphersuite");
+
+ if(state->suite.sig_type() != CipherSuite::NO_SIG)
+ {
+ 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 recieved");
+ }
+
+/**
+* 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");
+
+ state_machine();
+ }
+ }
+
+}
diff --git a/src/ssl/tls_client.h b/src/ssl/tls_client.h
new file mode 100644
index 000000000..896decdf9
--- /dev/null
+++ b/src/ssl/tls_client.h
@@ -0,0 +1,79 @@
+/**
+* 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_state.h>
+#include <vector>
+#include <string>
+
+namespace Botan {
+
+/**
+* TLS Client
+*/
+
+// FIXME: much of this can probably be moved up to TLS_Connection
+class BOTAN_DLL TLS_Client : public TLS_Connection
+ {
+ public:
+ u32bit read(byte buf[], u32bit buf_len);
+ void write(const byte buf[], u32bit buf_len);
+
+ std::vector<X509_Certificate> peer_cert_chain() const;
+
+ void close();
+ bool is_closed() const;
+
+ TLS_Client(RandomNumberGenerator& rng,
+ Socket& peer,
+ const TLS_Policy* policy = 0);
+
+#if 0
+ void add_cert(const X509_Certificate& cert,
+ const Private_Key& cert_key);
+#endif
+
+ // FIXME: support multiple cert/key pairs
+ TLS_Client(RandomNumberGenerator& rng,
+ Socket& peer,
+ const X509_Certificate& cert,
+ const Private_Key& cert_key,
+ const TLS_Policy* policy = 0);
+
+ ~TLS_Client();
+ private:
+ void close(Alert_Level, Alert_Type);
+
+ void initialize();
+ void do_handshake();
+
+ void state_machine();
+ void read_handshake(byte, const MemoryRegion<byte>&);
+ void process_handshake_msg(Handshake_Type, const MemoryRegion<byte>&);
+
+ RandomNumberGenerator& rng;
+
+ Record_Writer writer;
+ Record_Reader reader;
+ const TLS_Policy* policy;
+
+ std::vector<X509_Certificate> certs, peer_certs;
+ std::vector<Private_Key*> keys;
+
+ Handshake_State* state;
+ SecureVector<byte> session_id;
+ SecureQueue read_buf;
+ std::string peer_id;
+ bool active;
+ };
+
+}
+
+#endif
diff --git a/src/ssl/tls_connection.h b/src/ssl/tls_connection.h
new file mode 100644
index 000000000..ff55cceab
--- /dev/null
+++ b/src/ssl/tls_connection.h
@@ -0,0 +1,36 @@
+/**
+* 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 u32bit read(byte[], u32bit) = 0;
+ virtual void write(const byte[], u32bit) = 0;
+ u32bit 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_exceptn.h b/src/ssl/tls_exceptn.h
new file mode 100644
index 000000000..3ba852875
--- /dev/null
+++ b/src/ssl/tls_exceptn.h
@@ -0,0 +1,43 @@
+/**
+* Exceptions
+* (C) 2004-2006 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_EXCEPTION_H__
+#define BOTAN_TLS_EXCEPTION_H__
+
+#include <botan/exceptn.h>
+#include <botan/tls_magic.h>
+
+namespace Botan {
+
+/**
+* Exception Base Class
+*/
+class BOTAN_DLL TLS_Exception : public Exception
+ {
+ public:
+ Alert_Type type() const throw() { return alert_type; }
+
+ TLS_Exception(Alert_Type type,
+ const std::string& err_msg = "Unknown error") :
+ Exception(err_msg), alert_type(type) {}
+
+ private:
+ Alert_Type alert_type;
+ };
+
+/**
+* Unexpected_Message Exception
+*/
+struct Unexpected_Message : public TLS_Exception
+ {
+ Unexpected_Message(const std::string& err) :
+ TLS_Exception(UNEXPECTED_MESSAGE, err) {}
+ };
+
+}
+
+#endif
diff --git a/src/ssl/tls_magic.h b/src/ssl/tls_magic.h
new file mode 100644
index 000000000..41fb756e9
--- /dev/null
+++ b/src/ssl/tls_magic.h
@@ -0,0 +1,120 @@
+/**
+* SSL/TLS Protocol Constants
+* (C) 2004-2006 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,
+ 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 {
+ RSA_RC4_MD5 = 0x0004,
+ RSA_RC4_SHA = 0x0005,
+ RSA_3DES_SHA = 0x000A,
+ RSA_AES128_SHA = 0x002F,
+ RSA_AES256_SHA = 0x0035,
+
+ DHE_RSA_3DES_SHA = 0x0016,
+ DHE_RSA_AES128_SHA = 0x0033,
+ DHE_RSA_AES256_SHA = 0x0039,
+
+ DHE_DSS_3DES_SHA = 0x0013,
+ DHE_DSS_AES128_SHA = 0x0032,
+ DHE_DSS_AES256_SHA = 0x0038
+};
+
+enum Compression_Algo {
+ NO_COMPRESSION = 0x00
+};
+
+}
+
+#endif
diff --git a/src/ssl/tls_messages.h b/src/ssl/tls_messages.h
new file mode 100644
index 000000000..4b512a963
--- /dev/null
+++ b/src/ssl/tls_messages.h
@@ -0,0 +1,282 @@
+/**
+* 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/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 BOTAN_DLL 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 BOTAN_DLL Client_Hello : public HandshakeMessage
+ {
+ public:
+ Handshake_Type type() const { return CLIENT_HELLO; }
+ Version_Code version() const { return c_version; }
+ SecureVector<byte> session_id() const { return sess_id; }
+ std::vector<u16bit> ciphersuites() const { return suites; }
+ std::vector<byte> compression_algos() const { return comp_algos; }
+
+ SecureVector<byte> random() const { return c_random; }
+
+ bool offered_suite(u16bit) const;
+
+ Client_Hello(RandomNumberGenerator& rng,
+ Record_Writer&, const TLS_Policy*, HandshakeHash&);
+
+ Client_Hello(const MemoryRegion<byte>& buf) { deserialize(buf); }
+ private:
+ SecureVector<byte> serialize() const;
+ void deserialize(const MemoryRegion<byte>&);
+
+ Version_Code c_version;
+ SecureVector<byte> sess_id, c_random;
+ std::vector<u16bit> suites;
+ std::vector<byte> comp_algos;
+ };
+
+/**
+* Client Key Exchange Message
+*/
+class BOTAN_DLL 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 BOTAN_DLL 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 BOTAN_DLL 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 BOTAN_DLL 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 BOTAN_DLL 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 BOTAN_DLL 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 BOTAN_DLL Server_Hello : public HandshakeMessage
+ {
+ public:
+ Handshake_Type type() const { return SERVER_HELLO; }
+ Version_Code version() { return s_version; }
+ SecureVector<byte> session_id() const { return sess_id; }
+ u16bit ciphersuite() const { return suite; }
+ byte compression_algo() const { return comp_algo; }
+
+ 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 BOTAN_DLL 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 BOTAN_DLL 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
new file mode 100644
index 000000000..6138ae193
--- /dev/null
+++ b/src/ssl/tls_policy.cpp
@@ -0,0 +1,124 @@
+/**
+* Policies
+* (C) 2004-2006 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(DHE_DSS_AES256_SHA);
+ suites.push_back(DHE_DSS_AES128_SHA);
+ suites.push_back(DHE_DSS_3DES_SHA);
+ }
+
+ if(use_edh_rsa)
+ {
+ suites.push_back(DHE_RSA_AES256_SHA);
+ suites.push_back(DHE_RSA_AES128_SHA);
+ suites.push_back(DHE_RSA_3DES_SHA);
+ }
+
+ if(use_rsa)
+ {
+ suites.push_back(RSA_AES256_SHA);
+ suites.push_back(RSA_AES128_SHA);
+ suites.push_back(RSA_3DES_SHA);
+ suites.push_back(RSA_RC4_SHA);
+ suites.push_back(RSA_RC4_MD5);
+ }
+
+ 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(u32bit j = 0; j != s_suites.size(); j++)
+ for(u32bit k = 0; k != c_suites.size(); k++)
+ if(s_suites[j] == c_suites[k])
+ return s_suites[j];
+
+ 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(u32bit j = 0; j != s_comp.size(); j++)
+ for(u32bit k = 0; k != c_comp.size(); k++)
+ if(s_comp[j] == c_comp[k])
+ return s_comp[j];
+
+ return NO_COMPRESSION;
+ }
+
+/**
+* Return the group to use for empheral DH
+*/
+DL_Group TLS_Policy::dh_group() const
+ {
+ return DL_Group("modp/ietf/1024");
+ }
+
+/**
+* Default certificate check
+*/
+bool TLS_Policy::check_cert(const std::vector<X509_Certificate>&,
+ const std::string&) const
+ {
+ return true;
+ }
+
+}
diff --git a/src/ssl/tls_policy.h b/src/ssl/tls_policy.h
new file mode 100644
index 000000000..98297181c
--- /dev/null
+++ b/src/ssl/tls_policy.h
@@ -0,0 +1,57 @@
+/**
+* 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 u32bit rsa_export_keysize() const { return 512; }
+
+ virtual Version_Code min_version() const { return SSL_V3; }
+ virtual Version_Code pref_version() const { return TLS_V10; }
+
+ virtual bool check_cert(const std::vector<X509_Certificate>&,
+ const std::string&) const;
+
+ 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
new file mode 100644
index 000000000..3bec2e8ef
--- /dev/null
+++ b/src/ssl/tls_record.h
@@ -0,0 +1,79 @@
+/**
+* TLS Record Handling
+* (C) 2004-2006 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/socket.h>
+#include <botan/tls_suites.h>
+#include <botan/pipe.h>
+#include <vector>
+
+namespace Botan {
+
+/**
+* TLS Record Writer
+*/
+class BOTAN_DLL Record_Writer
+ {
+ public:
+ void send(byte, const byte[], u32bit);
+ void send(byte, byte);
+ void flush();
+
+ void alert(Alert_Level, Alert_Type);
+
+ void set_keys(const CipherSuite&, const SessionKeys&, Connection_Side);
+ void set_compressor(Filter*);
+
+ void set_version(Version_Code);
+
+ void reset();
+
+ Record_Writer(Socket&);
+ private:
+ void send_record(byte, const byte[], u32bit);
+ void send_record(byte, byte, byte, const byte[], u32bit);
+
+ Socket& socket;
+ Pipe compress, cipher, mac;
+ SecureVector<byte> buffer;
+ u32bit pad_amount, mac_size, buf_pos;
+ u64bit seq_no;
+ byte major, minor, buf_type;
+ bool do_compress;
+ };
+
+/**
+* TLS Record Reader
+*/
+class BOTAN_DLL Record_Reader
+ {
+ public:
+ SecureVector<byte> get_record(byte&);
+
+ void set_keys(const CipherSuite&, const SessionKeys&, Connection_Side);
+ void set_compressor(Filter*);
+
+ void set_version(Version_Code);
+
+ void reset();
+
+ Record_Reader(Socket&);
+ private:
+ Socket& socket;
+ Pipe compress, cipher, mac;
+ u32bit pad_amount, mac_size;
+ u64bit seq_no;
+ byte major, minor;
+ bool do_compress;
+ };
+
+}
+
+#endif
diff --git a/src/ssl/tls_server.cpp b/src/ssl/tls_server.cpp
new file mode 100644
index 000000000..37d9dbcd1
--- /dev/null
+++ b/src/ssl/tls_server.cpp
@@ -0,0 +1,465 @@
+/**
+* TLS Server
+* (C) 2004-2010 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_server.h>
+#include <botan/tls_alerts.h>
+#include <botan/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)
+ return client;
+ return TLS_V10;
+ }
+
+// 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)
+ {
+ 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(RandomNumberGenerator& r,
+ Socket& sock, const X509_Certificate& cert,
+ const Private_Key& key, const TLS_Policy* pol) :
+ rng(r), writer(sock), reader(sock), policy(pol ? pol : new TLS_Policy)
+ {
+ peer_id = sock.peer_id();
+
+ state = 0;
+
+ cert_chain.push_back(cert);
+ private_key = PKCS8::copy_key(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("TLS_Server: Handshake failed");
+ }
+ }
+
+/**
+* TLS Server Destructor
+*/
+TLS_Server::~TLS_Server()
+ {
+ close();
+ delete private_key;
+ delete policy;
+ 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[], u32bit length)
+ {
+ if(!active)
+ throw Internal_Error("TLS_Server::write called while closed");
+
+ writer.send(APPLICATION_DATA, buf, length);
+ }
+
+/**
+* Read from a TLS connection
+*/
+u32bit TLS_Server::read(byte out[], u32bit 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;
+ }
+
+ u32bit got = std::min(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;
+ SecureVector<byte> record = reader.get_record(rec_type);
+
+ if(rec_type == CONNECTION_CLOSED)
+ {
+ active = false;
+ reader.reset();
+ writer.reset();
+ }
+ else if(rec_type == APPLICATION_DATA)
+ {
+ if(active)
+ read_buf.write(record, 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 recieved");
+ }
+
+/**
+* Split up and process handshake messages
+*/
+void TLS_Server::read_handshake(byte rec_type,
+ const MemoryRegion<byte>& rec_buf)
+ {
+ if(rec_type == HANDSHAKE)
+ state->queue.write(rec_buf, 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 u32bit 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, 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)
+ {
+ if(type == CLIENT_HELLO)
+ {
+ if(state == 0)
+ state = new Handshake_State();
+ else
+ return;
+ }
+
+ if(state == 0)
+ throw Unexpected_Message("Unexpected handshake message");
+
+ if(type != HANDSHAKE_CCS && type != FINISHED)
+ {
+ state->hash.update(static_cast<byte>(type));
+ u32bit record_length = contents.size();
+ for(u32bit j = 0; j != 3; j++)
+ state->hash.update(get_byte(j+1, record_length));
+ state->hash.update(contents);
+ }
+
+ if(type == CLIENT_HELLO)
+ {
+ server_check_state(type, state);
+
+ state->client_hello = new Client_Hello(contents);
+
+ 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() != CipherSuite::NO_SIG)
+ {
+ // 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() != CipherSuite::NO_KEX)
+ {
+ if(state->suite.kex_type() == CipherSuite::RSA_KEX)
+ {
+ state->kex_priv = new RSA_PrivateKey(rng,
+ policy->rsa_export_keysize());
+ }
+ else if(state->suite.kex_type() == CipherSuite::DH_KEX)
+ {
+ 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));
+ u32bit record_length = contents.size();
+ for(u32bit j = 0; j != 3; j++)
+ state->hash.update(get_byte(j+1, record_length));
+ state->hash.update(contents);
+
+ 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 recieved");
+ }
+
+/**
+* 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
new file mode 100644
index 000000000..683c3413a
--- /dev/null
+++ b/src/ssl/tls_server.h
@@ -0,0 +1,69 @@
+/**
+* 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_state.h>
+#include <vector>
+
+namespace Botan {
+
+/**
+* TLS Server
+*/
+
+class BOTAN_DLL TLS_Server : public TLS_Connection
+ {
+ public:
+ u32bit read(byte buf[], u32bit buf_len);
+ void write(const byte buf[], u32bit buf_len);
+
+ std::vector<X509_Certificate> peer_cert_chain() const;
+
+ void close();
+ bool is_closed() const;
+
+ // FIXME: support cert chains (!)
+ // FIXME: support anonymous servers
+ TLS_Server(RandomNumberGenerator& rng,
+ Socket& peer,
+ const X509_Certificate& cert,
+ const Private_Key& cert_key,
+ const TLS_Policy* policy = 0);
+
+ ~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>&);
+
+ RandomNumberGenerator& rng;
+
+ Record_Writer writer;
+ Record_Reader reader;
+ const TLS_Policy* policy;
+
+ // FIXME: rename to match TLS_Client
+ std::vector<X509_Certificate> cert_chain, peer_certs;
+ Private_Key* private_key;
+
+ Handshake_State* state;
+ SecureVector<byte> session_id;
+ SecureQueue read_buf;
+ std::string peer_id;
+ bool active;
+ };
+
+}
+
+#endif
diff --git a/src/ssl/tls_session_key.cpp b/src/ssl/tls_session_key.cpp
new file mode 100644
index 000000000..83c06ba07
--- /dev/null
+++ b/src/ssl/tls_session_key.cpp
@@ -0,0 +1,170 @@
+/**
+* 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(u32bit prf_gen,
+ const MemoryRegion<byte>& pre_master,
+ const MemoryRegion<byte>& client_random,
+ const MemoryRegion<byte>& server_random)
+ {
+ SSL3_PRF prf;
+
+ SecureVector<byte> salt;
+ salt.append(client_random);
+ salt.append(server_random);
+
+ master_sec = prf.derive_key(48, pre_master, salt);
+
+ salt.destroy();
+ salt.append(server_random);
+ salt.append(client_random);
+
+ return prf.derive_key(prf_gen, master_sec, salt);
+ }
+
+/**
+* Generate TLS 1.0 session keys
+*/
+SymmetricKey SessionKeys::tls1_keygen(u32bit 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.append(MASTER_SECRET_MAGIC, sizeof(MASTER_SECRET_MAGIC));
+ salt.append(client_random);
+ salt.append(server_random);
+
+ master_sec = prf.derive_key(48, pre_master, salt);
+
+ salt.destroy();
+ salt.append(KEY_GEN_MAGIC, sizeof(KEY_GEN_MAGIC));
+ salt.append(server_random);
+ salt.append(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)
+ throw Invalid_Argument("SessionKeys: Unknown version code");
+
+ const u32bit mac_keylen = output_length_of(suite.mac_algo());
+ u32bit cipher_keylen = suite.cipher_keylen();
+
+ u32bit cipher_ivlen = 0;
+ if(have_block_cipher(suite.cipher_algo()))
+ cipher_ivlen = block_size_of(suite.cipher_algo());
+
+ const u32bit 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
new file mode 100644
index 000000000..b0eba2eb1
--- /dev/null
+++ b/src/ssl/tls_session_key.h
@@ -0,0 +1,52 @@
+/**
+* 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(u32bit, const MemoryRegion<byte>&,
+ const MemoryRegion<byte>&,
+ const MemoryRegion<byte>&);
+ SymmetricKey tls1_keygen(u32bit, 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.h b/src/ssl/tls_state.h
new file mode 100644
index 000000000..ddf03a822
--- /dev/null
+++ b/src/ssl/tls_state.h
@@ -0,0 +1,53 @@
+/**
+* TLS Handshaking
+* (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/tls_messages.h>
+#include <botan/secqueue.h>
+
+namespace Botan {
+
+/**
+* SSL/TLS Handshake State
+*/
+class BOTAN_DLL 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
new file mode 100644
index 000000000..26fa75428
--- /dev/null
+++ b/src/ssl/tls_suites.cpp
@@ -0,0 +1,77 @@
+/**
+* TLS Cipher Suites
+* (C) 2004-2006 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/tls_suites.h>
+#include <botan/tls_exceptn.h>
+#include <botan/parsing.h>
+#include <vector>
+#include <string>
+
+namespace Botan {
+
+namespace {
+
+/**
+* Convert an SSL/TLS ciphersuite to a string
+*/
+std::string lookup_ciphersuite(u16bit suite)
+ {
+ if(suite == RSA_RC4_MD5) return "RSA/NONE/ARC4/16/MD5";
+ if(suite == RSA_RC4_SHA) return "RSA/NONE/ARC4/16/SHA1";
+ if(suite == RSA_3DES_SHA) return "RSA/NONE/3DES/24/SHA1";
+ if(suite == RSA_AES128_SHA) return "RSA/NONE/AES/16/SHA1";
+ if(suite == RSA_AES256_SHA) return "RSA/NONE/AES/32/SHA1";
+
+ if(suite == DHE_RSA_3DES_SHA) return "RSA/DH/3DES/24/SHA1";
+ if(suite == DHE_RSA_AES128_SHA) return "RSA/DH/AES/16/SHA1";
+ if(suite == DHE_RSA_AES256_SHA) return "RSA/DH/AES/32/SHA1";
+
+ if(suite == DHE_DSS_3DES_SHA) return "DSA/DH/3DES/24/SHA1";
+ if(suite == DHE_DSS_AES128_SHA) return "DSA/DH/AES/16/SHA1";
+ if(suite == DHE_DSS_AES256_SHA) return "DSA/DH/AES/32/SHA1";
+
+ return "";
+ }
+
+}
+
+/**
+* CipherSuite Constructor
+*/
+CipherSuite::CipherSuite(u16bit suite_code)
+ {
+ if(suite_code == 0)
+ return;
+
+ std::string suite_string = lookup_ciphersuite(suite_code);
+
+ if(suite_string == "")
+ throw Invalid_Argument("Unknown ciphersuite: " +
+ to_string(suite_code));
+
+ std::vector<std::string> suite_info = split_on(suite_string, '/');
+
+ if(suite_info[0] == "RSA") sig_algo = RSA_SIG;
+ else if(suite_info[0] == "DSA") sig_algo = DSA_SIG;
+ else if(suite_info[0] == "NONE") sig_algo = NO_SIG;
+ else
+ throw TLS_Exception(INTERNAL_ERROR,
+ "CipherSuite: Unknown sig type " + suite_info[0]);
+
+ if(suite_info[1] == "DH") kex_algo = DH_KEX;
+ else if(suite_info[1] == "RSA") kex_algo = RSA_KEX;
+ else if(suite_info[1] == "NONE") kex_algo = NO_KEX;
+ else
+ throw TLS_Exception(INTERNAL_ERROR,
+ "CipherSuite: Unknown kex type " + suite_info[1]);
+
+ cipher = suite_info[2];
+ cipher_key_length = to_u32bit(suite_info[3]);
+ mac = suite_info[4];
+ }
+
+}
diff --git a/src/ssl/tls_suites.h b/src/ssl/tls_suites.h
new file mode 100644
index 000000000..b7008e8db
--- /dev/null
+++ b/src/ssl/tls_suites.h
@@ -0,0 +1,42 @@
+/**
+* Cipher Suites
+* (C) 2004-2006 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 <string>
+
+namespace Botan {
+
+/**
+* Ciphersuite Information
+*/
+class BOTAN_DLL CipherSuite
+ {
+ public:
+ enum Kex_Type { NO_KEX, RSA_KEX, DH_KEX };
+ enum Sig_Type { NO_SIG, RSA_SIG, DSA_SIG };
+
+ std::string cipher_algo() const { return cipher; }
+ std::string mac_algo() const { return mac; }
+
+ u32bit cipher_keylen() const { return cipher_key_length; }
+ Kex_Type kex_type() const { return kex_algo; }
+ Sig_Type sig_type() const { return sig_algo; }
+
+ CipherSuite(u16bit = 0);
+ private:
+ Kex_Type kex_algo;
+ Sig_Type sig_algo;
+ std::string cipher, mac;
+ u32bit cipher_key_length;
+ };
+
+}
+
+#endif
diff --git a/src/ssl/unix_socket/info.txt b/src/ssl/unix_socket/info.txt
new file mode 100644
index 000000000..205d0c700
--- /dev/null
+++ b/src/ssl/unix_socket/info.txt
@@ -0,0 +1,21 @@
+define UNIX_SOCKET
+
+<source>
+unx_sock.cpp
+</source>
+
+<header:public>
+unx_sock.h
+</header:public>
+
+<requires>
+ssl
+</requires>
+
+<os>
+linux
+freebsd
+netbsd
+openbsd
+solaris
+</os>
diff --git a/src/ssl/unix_socket/unx_sock.cpp b/src/ssl/unix_socket/unx_sock.cpp
new file mode 100644
index 000000000..ca4d476b7
--- /dev/null
+++ b/src/ssl/unix_socket/unx_sock.cpp
@@ -0,0 +1,200 @@
+/**
+* Unix Socket
+* (C) 2004-2006 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#include <botan/unx_sock.h>
+#include <botan/exceptn.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+namespace Botan {
+
+/**
+* Unix Socket Constructor
+*/
+Unix_Socket::Unix_Socket(const std::string& host, u16bit port) : peer(host)
+ {
+ sockfd = -1;
+
+ hostent* host_addr = ::gethostbyname(host.c_str());
+
+ if(host_addr == 0)
+ throw Stream_IO_Error("Unix_Socket: gethostbyname failed for " + host);
+ if(host_addr->h_addrtype != AF_INET) // FIXME
+ throw Stream_IO_Error("Unix_Socket: " + host + " has IPv6 address");
+
+ int fd = ::socket(PF_INET, SOCK_STREAM, 0);
+ if(fd == -1)
+ throw Stream_IO_Error("Unix_Socket: Unable to acquire socket");
+
+ sockaddr_in socket_info;
+ ::memset(&socket_info, 0, sizeof(socket_info));
+ socket_info.sin_family = AF_INET;
+ socket_info.sin_port = htons(port);
+ socket_info.sin_addr = *(struct in_addr*)host_addr->h_addr; // FIXME
+
+ if(::connect(fd, (sockaddr*)&socket_info, sizeof(struct sockaddr)) != 0)
+ {
+ ::close(fd);
+ throw Stream_IO_Error("Unix_Socket: connect failed");
+ }
+
+ sockfd = fd;
+ }
+
+/**
+* Unix Socket Constructor
+*/
+Unix_Socket::Unix_Socket(int fd, const std::string& peer_id)
+ {
+ sockfd = fd;
+ peer = peer_id;
+ }
+
+/**
+* Read from a Unix socket
+*/
+u32bit Unix_Socket::read(byte buf[], u32bit length)
+ {
+ if(sockfd == -1)
+ throw Stream_IO_Error("Unix_Socket::read: Socket not connected");
+
+ u32bit got = 0;
+
+ while(length)
+ {
+ ssize_t this_time = ::recv(sockfd, buf + got, length, MSG_NOSIGNAL);
+
+ if(this_time == 0)
+ break;
+
+ if(this_time == -1)
+ {
+ if(errno == EINTR)
+ this_time = 0;
+ else
+ throw Stream_IO_Error("Unix_Socket::read: Socket read failed");
+ }
+
+ got += this_time;
+ length -= this_time;
+ }
+ return got;
+ }
+
+/**
+* Write to a Unix socket
+*/
+void Unix_Socket::write(const byte buf[], u32bit length)
+ {
+ if(sockfd == -1)
+ throw Stream_IO_Error("Unix_Socket::write: Socket not connected");
+
+ u32bit offset = 0;
+ while(length)
+ {
+ ssize_t sent = ::send(sockfd, buf + offset, length, MSG_NOSIGNAL);
+
+ if(sent == -1)
+ {
+ if(errno == EINTR)
+ sent = 0;
+ else
+ throw Stream_IO_Error("Unix_Socket::write: Socket write failed");
+ }
+
+ offset += sent;
+ length -= sent;
+ }
+ }
+
+/**
+* Close a Unix socket
+*/
+void Unix_Socket::close()
+ {
+ if(sockfd != -1)
+ {
+ if(::close(sockfd) != 0)
+ throw Stream_IO_Error("Unix_Socket::close failed");
+ sockfd = -1;
+ }
+ }
+
+/**
+* Return the peer's name
+*/
+std::string Unix_Socket::peer_id() const
+ {
+ return peer;
+ }
+
+/**
+* Unix Server Socket Constructor
+*/
+Unix_Server_Socket::Unix_Server_Socket(u16bit port)
+ {
+ sockfd = -1;
+
+ int fd = ::socket(PF_INET, SOCK_STREAM, 0);
+ if(fd == -1)
+ throw Stream_IO_Error("Unix_Server_Socket: Unable to acquire socket");
+
+ sockaddr_in socket_info;
+ ::memset(&socket_info, 0, sizeof(socket_info));
+ socket_info.sin_family = AF_INET;
+ socket_info.sin_port = htons(port);
+
+ // FIXME: support limiting listeners
+ socket_info.sin_addr.s_addr = INADDR_ANY;
+
+ if(::bind(fd, (sockaddr*)&socket_info, sizeof(struct sockaddr)) != 0)
+ {
+ ::close(fd);
+ throw Stream_IO_Error("Unix_Server_Socket: bind failed");
+ }
+
+ if(listen(fd, 100) != 0) // FIXME: totally arbitrary
+ {
+ ::close(fd);
+ throw Stream_IO_Error("Unix_Server_Socket: listen failed");
+ }
+
+ sockfd = fd;
+ }
+
+/**
+* Close a Unix socket
+*/
+void Unix_Server_Socket::close()
+ {
+ if(sockfd != -1)
+ {
+ if(::close(sockfd) != 0)
+ throw Stream_IO_Error("Unix_Server_Socket::close failed");
+ sockfd = -1;
+ }
+ }
+
+/**
+* Accept a new connection
+*/
+Socket* Unix_Server_Socket::accept()
+ {
+ // FIXME: grab IP of remote side, use gethostbyaddr, store as peer_id
+ int retval = ::accept(sockfd, 0, 0);
+ if(retval == -1)
+ throw Stream_IO_Error("Unix_Server_Socket: accept failed");
+ return new Unix_Socket(retval);
+ }
+
+}
diff --git a/src/ssl/unix_socket/unx_sock.h b/src/ssl/unix_socket/unx_sock.h
new file mode 100644
index 000000000..c1ff53ae3
--- /dev/null
+++ b/src/ssl/unix_socket/unx_sock.h
@@ -0,0 +1,62 @@
+/*
+* Unix Socket
+* (C) 2004-2006 Jack Lloyd
+*
+* Released under the terms of the Botan license
+*/
+
+#ifndef BOTAN_TLS_SOCKET_UNIX_H__
+#define BOTAN_TLS_SOCKET_UNIX_H__
+
+#include <botan/socket.h>
+
+namespace Botan {
+
+/**
+ FIXME: the current socket interface is totally unusable
+ It has to handle (cleanly):
+ - TCP, UDP, and SCTP, where UDP is only usable with DTLS and
+ TCP/SCTP is only usable with TLS.
+ - Alternate socket interfaces (ACE, Netxx, whatever) with
+ minimal wrapping needed.
+*/
+
+
+/**
+* Unix Socket Base Class
+*/
+class BOTAN_DLL Unix_Socket : public Socket
+ {
+ public:
+ u32bit read(byte[], u32bit);
+ void write(const byte[], u32bit);
+
+ std::string peer_id() const;
+
+ void close();
+ Unix_Socket(int, const std::string& = "");
+ Unix_Socket(const std::string&, u16bit);
+ ~Unix_Socket() { close(); }
+ private:
+ std::string peer;
+ int sockfd;
+ };
+
+/**
+* Unix Server Socket Base Class
+*/
+class BOTAN_DLL Unix_Server_Socket : public Server_Socket
+ {
+ public:
+ Socket* accept();
+ void close();
+
+ Unix_Server_Socket(u16bit);
+ ~Unix_Server_Socket() { close(); }
+ private:
+ int sockfd;
+ };
+
+}
+
+#endif