aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2016-08-31 12:58:58 -0400
committerJack Lloyd <[email protected]>2016-08-31 12:58:58 -0400
commitdfab07a7bc00dc00f98ab86c70d536306073f34f (patch)
treed3dbb140764f259c932171d6f229d033dee685ca /src/lib
parente29024608fca1b811aa72a7aafd930a42740b968 (diff)
parent1b9cf39063194fe91dc8e5d78f73d7251c5d16fc (diff)
Merge master into this branch, resolving conflicts with #457/#576
which recently landed on master.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/asn1/asn1_time.cpp5
-rw-r--r--src/lib/asn1/asn1_time.h3
-rw-r--r--src/lib/asn1/oid_lookup/default.cpp16
-rw-r--r--src/lib/base/secmem.h5
-rw-r--r--src/lib/block/threefish_avx2/threefish_avx2.cpp241
-rw-r--r--src/lib/cert/cvc/asn1_eac_str.cpp127
-rw-r--r--src/lib/cert/cvc/asn1_eac_tm.cpp297
-rw-r--r--src/lib/cert/cvc/cvc_ado.cpp127
-rw-r--r--src/lib/cert/cvc/cvc_ado.h98
-rw-r--r--src/lib/cert/cvc/cvc_cert.cpp135
-rw-r--r--src/lib/cert/cvc/cvc_cert.h116
-rw-r--r--src/lib/cert/cvc/cvc_gen_cert.h180
-rw-r--r--src/lib/cert/cvc/cvc_req.cpp53
-rw-r--r--src/lib/cert/cvc/cvc_req.h59
-rw-r--r--src/lib/cert/cvc/cvc_self.cpp339
-rw-r--r--src/lib/cert/cvc/cvc_self.h180
-rw-r--r--src/lib/cert/cvc/eac_asn_obj.h239
-rw-r--r--src/lib/cert/cvc/eac_obj.h55
-rw-r--r--src/lib/cert/cvc/ecdsa_sig.cpp59
-rw-r--r--src/lib/cert/cvc/ecdsa_sig.h61
-rw-r--r--src/lib/cert/cvc/info.txt35
-rw-r--r--src/lib/cert/cvc/signed_obj.cpp95
-rw-r--r--src/lib/cert/cvc/signed_obj.h95
-rw-r--r--src/lib/cert/x509/key_constraint.cpp63
-rw-r--r--src/lib/cert/x509/key_constraint.h28
-rw-r--r--src/lib/cert/x509/name_constraint.cpp4
-rw-r--r--src/lib/cert/x509/ocsp.cpp2
-rw-r--r--src/lib/cert/x509/ocsp_types.cpp2
-rw-r--r--src/lib/cert/x509/x509_ca.cpp20
-rw-r--r--src/lib/cert/x509/x509_ca.h1
-rw-r--r--src/lib/cert/x509/x509_ext.cpp18
-rw-r--r--src/lib/cert/x509/x509cert.cpp46
-rw-r--r--src/lib/cert/x509/x509cert.h32
-rw-r--r--src/lib/cert/x509/x509opt.cpp13
-rw-r--r--src/lib/cert/x509/x509self.cpp39
-rw-r--r--src/lib/cert/x509/x509self.h5
-rw-r--r--src/lib/entropy/beos_stats/es_beos.cpp23
-rw-r--r--src/lib/entropy/beos_stats/es_beos.h2
-rw-r--r--src/lib/entropy/cryptoapi_rng/es_capi.cpp70
-rw-r--r--src/lib/entropy/cryptoapi_rng/es_capi.h18
-rw-r--r--src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp8
-rw-r--r--src/lib/entropy/darwin_secrandom/darwin_secrandom.h2
-rw-r--r--src/lib/entropy/dev_random/dev_random.cpp92
-rw-r--r--src/lib/entropy/dev_random/dev_random.h7
-rw-r--r--src/lib/entropy/egd/es_egd.cpp12
-rw-r--r--src/lib/entropy/egd/es_egd.h3
-rw-r--r--src/lib/entropy/entropy_src.h80
-rw-r--r--src/lib/entropy/entropy_srcs.cpp29
-rw-r--r--src/lib/entropy/hres_timer/hres_timer.cpp60
-rw-r--r--src/lib/entropy/hres_timer/hres_timer.h30
-rw-r--r--src/lib/entropy/hres_timer/info.txt13
-rw-r--r--src/lib/entropy/info.txt4
-rw-r--r--src/lib/entropy/proc_walk/proc_walk.cpp15
-rw-r--r--src/lib/entropy/proc_walk/proc_walk.h2
-rw-r--r--src/lib/entropy/rdrand/info.txt16
-rw-r--r--src/lib/entropy/rdrand/rdrand.cpp37
-rw-r--r--src/lib/entropy/rdrand/rdrand.h2
-rw-r--r--src/lib/entropy/rdseed/rdseed.cpp34
-rw-r--r--src/lib/entropy/rdseed/rdseed.h2
-rw-r--r--src/lib/entropy/unix_procs/unix_procs.cpp69
-rw-r--r--src/lib/entropy/unix_procs/unix_procs.h4
-rw-r--r--src/lib/entropy/win32_stats/es_win32.cpp85
-rw-r--r--src/lib/entropy/win32_stats/es_win32.h2
-rw-r--r--src/lib/ffi/ffi.cpp7
-rw-r--r--src/lib/ffi/ffi.h3
-rw-r--r--src/lib/ffi/info.txt1
-rw-r--r--src/lib/hash/par_hash/par_hash.cpp2
-rw-r--r--src/lib/kdf/hkdf/hkdf.cpp4
-rw-r--r--src/lib/kdf/hkdf/hkdf.h3
-rw-r--r--src/lib/kdf/kdf.cpp8
-rw-r--r--src/lib/kdf/kdf.h45
-rw-r--r--src/lib/kdf/kdf1/kdf1.cpp4
-rw-r--r--src/lib/kdf/kdf1/kdf1.h3
-rw-r--r--src/lib/kdf/kdf1_iso18033/info.txt1
-rw-r--r--src/lib/kdf/kdf1_iso18033/kdf1_iso18033.cpp37
-rw-r--r--src/lib/kdf/kdf1_iso18033/kdf1_iso18033.h38
-rw-r--r--src/lib/kdf/kdf2/kdf2.cpp4
-rw-r--r--src/lib/kdf/kdf2/kdf2.h3
-rw-r--r--src/lib/kdf/prf_tls/prf_tls.cpp23
-rw-r--r--src/lib/kdf/prf_tls/prf_tls.h6
-rw-r--r--src/lib/kdf/prf_x942/prf_x942.cpp10
-rw-r--r--src/lib/kdf/prf_x942/prf_x942.h3
-rw-r--r--src/lib/kdf/sp800_108/sp800_108.cpp43
-rw-r--r--src/lib/kdf/sp800_108/sp800_108.h60
-rw-r--r--src/lib/kdf/sp800_56c/sp800_56c.cpp7
-rw-r--r--src/lib/kdf/sp800_56c/sp800_56c.h20
-rw-r--r--src/lib/mac/siphash/siphash.cpp7
-rw-r--r--src/lib/math/bigint/big_code.cpp11
-rw-r--r--src/lib/math/bigint/big_ops2.cpp6
-rw-r--r--src/lib/math/bigint/big_ops3.cpp5
-rw-r--r--src/lib/math/bigint/bigint.h9
-rw-r--r--src/lib/math/ec_gfp/curve_gfp.cpp19
-rw-r--r--src/lib/math/mp/info.txt10
-rw-r--r--src/lib/math/mp/mp_asmi.h820
-rw-r--r--src/lib/math/mp/mp_core.cpp (renamed from src/lib/math/mp/mp_asm.cpp)186
-rw-r--r--src/lib/math/mp/mp_core.h13
-rw-r--r--src/lib/math/mp/mp_generic/info.txt6
-rw-r--r--src/lib/math/mp/mp_generic/mp_asmi.h203
-rw-r--r--src/lib/math/mp/mp_karat.cpp58
-rw-r--r--src/lib/math/mp/mp_madd.h (renamed from src/lib/math/mp/mp_generic/mp_madd.h)78
-rw-r--r--src/lib/math/mp/mp_misc.cpp79
-rw-r--r--src/lib/math/mp/mp_monty.cpp25
-rw-r--r--src/lib/math/mp/mp_shift.cpp133
-rw-r--r--src/lib/math/mp/mp_x86_32/info.txt18
-rw-r--r--src/lib/math/mp/mp_x86_32/mp_asmi.h236
-rw-r--r--src/lib/math/mp/mp_x86_32/mp_madd.h63
-rw-r--r--src/lib/math/mp/mp_x86_32_msvc/info.txt16
-rw-r--r--src/lib/math/mp/mp_x86_32_msvc/mp_asmi.h454
-rw-r--r--src/lib/math/mp/mp_x86_64/info.txt18
-rw-r--r--src/lib/math/mp/mp_x86_64/mp_asmi.h244
-rw-r--r--src/lib/math/mp/mp_x86_64/mp_madd.h65
-rw-r--r--src/lib/math/numbertheory/mp_numth.cpp16
-rw-r--r--src/lib/math/numbertheory/powm_mnt.cpp28
-rw-r--r--src/lib/modes/aead/gcm/gcm.cpp2
-rw-r--r--src/lib/modes/mode_pad/mode_pad.cpp4
-rw-r--r--src/lib/modes/mode_pad/mode_pad.h3
-rw-r--r--src/lib/pk_pad/eme_oaep/oaep.cpp4
-rw-r--r--src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp20
-rw-r--r--src/lib/pk_pad/emsa.cpp21
-rw-r--r--src/lib/pk_pad/emsa.h13
-rw-r--r--src/lib/pk_pad/emsa1/emsa1.cpp5
-rw-r--r--src/lib/pk_pad/emsa1/emsa1.h6
-rw-r--r--src/lib/pk_pad/emsa1_bsi/emsa1_bsi.cpp29
-rw-r--r--src/lib/pk_pad/emsa1_bsi/emsa1_bsi.h35
-rw-r--r--src/lib/pk_pad/emsa1_bsi/info.txt5
-rw-r--r--src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.h4
-rw-r--r--src/lib/pk_pad/emsa_pssr/pssr.h2
-rw-r--r--src/lib/pk_pad/emsa_raw/emsa_raw.h3
-rw-r--r--src/lib/pk_pad/emsa_x931/emsa_x931.h2
-rw-r--r--src/lib/pk_pad/hash_id/hash_id.cpp8
-rw-r--r--src/lib/prov/openssl/openssl_rc4.cpp11
-rw-r--r--src/lib/prov/pkcs11/info.txt48
-rw-r--r--src/lib/prov/pkcs11/p11.cpp769
-rw-r--r--src/lib/prov/pkcs11/p11.h2861
-rw-r--r--src/lib/prov/pkcs11/p11_ecc_key.cpp137
-rw-r--r--src/lib/prov/pkcs11/p11_ecc_key.h228
-rw-r--r--src/lib/prov/pkcs11/p11_ecdh.cpp141
-rw-r--r--src/lib/prov/pkcs11/p11_ecdh.h122
-rw-r--r--src/lib/prov/pkcs11/p11_ecdsa.cpp229
-rw-r--r--src/lib/prov/pkcs11/p11_ecdsa.h127
-rw-r--r--src/lib/prov/pkcs11/p11_mechanism.cpp250
-rw-r--r--src/lib/prov/pkcs11/p11_mechanism.h108
-rw-r--r--src/lib/prov/pkcs11/p11_module.cpp41
-rw-r--r--src/lib/prov/pkcs11/p11_module.h79
-rw-r--r--src/lib/prov/pkcs11/p11_object.cpp217
-rw-r--r--src/lib/prov/pkcs11/p11_object.h743
-rw-r--r--src/lib/prov/pkcs11/p11_randomgenerator.cpp31
-rw-r--r--src/lib/prov/pkcs11/p11_randomgenerator.h70
-rw-r--r--src/lib/prov/pkcs11/p11_rsa.cpp377
-rw-r--r--src/lib/prov/pkcs11/p11_rsa.h212
-rw-r--r--src/lib/prov/pkcs11/p11_session.cpp89
-rw-r--r--src/lib/prov/pkcs11/p11_session.h105
-rw-r--r--src/lib/prov/pkcs11/p11_slot.cpp60
-rw-r--r--src/lib/prov/pkcs11/p11_slot.h79
-rw-r--r--src/lib/prov/pkcs11/p11_x509.cpp37
-rw-r--r--src/lib/prov/pkcs11/p11_x509.h115
-rw-r--r--src/lib/prov/pkcs11/pkcs11.h264
-rw-r--r--src/lib/prov/pkcs11/pkcs11f.h938
-rw-r--r--src/lib/prov/pkcs11/pkcs11t.h2002
-rw-r--r--src/lib/prov/tpm/tpm.h24
-rw-r--r--src/lib/pubkey/curve25519/donna.cpp76
-rw-r--r--src/lib/pubkey/dh/dh.cpp9
-rw-r--r--src/lib/pubkey/dlies/dlies.cpp257
-rw-r--r--src/lib/pubkey/dlies/dlies.h101
-rw-r--r--src/lib/pubkey/dlies/info.txt3
-rw-r--r--src/lib/pubkey/dsa/dsa.cpp26
-rw-r--r--src/lib/pubkey/dsa/info.txt3
-rw-r--r--src/lib/pubkey/ec_group/named.cpp10
-rw-r--r--src/lib/pubkey/ecdsa/ecdsa.cpp23
-rw-r--r--src/lib/pubkey/ecdsa/info.txt3
-rw-r--r--src/lib/pubkey/ecgdsa/ecgdsa.cpp7
-rw-r--r--src/lib/pubkey/ecgdsa/info.txt2
-rw-r--r--src/lib/pubkey/ecies/ecies.cpp398
-rw-r--r--src/lib/pubkey/ecies/ecies.h293
-rw-r--r--src/lib/pubkey/ecies/info.txt8
-rw-r--r--src/lib/pubkey/eckcdsa/eckcdsa.cpp200
-rw-r--r--src/lib/pubkey/eckcdsa/eckcdsa.h91
-rw-r--r--src/lib/pubkey/eckcdsa/info.txt13
-rw-r--r--src/lib/pubkey/pk_algs.cpp14
-rw-r--r--src/lib/pubkey/pk_ops.cpp28
-rw-r--r--src/lib/pubkey/pk_ops_impl.h37
-rw-r--r--src/lib/pubkey/pubkey.cpp6
-rw-r--r--src/lib/pubkey/rfc6979/rfc6979.cpp23
-rw-r--r--src/lib/pubkey/rfc6979/rfc6979.h8
-rw-r--r--src/lib/pubkey/rsa/info.txt2
-rw-r--r--src/lib/pubkey/rsa/rsa.cpp2
-rw-r--r--src/lib/rng/auto_rng/auto_rng.cpp116
-rw-r--r--src/lib/rng/auto_rng/auto_rng.h58
-rw-r--r--src/lib/rng/auto_rng/info.txt10
-rw-r--r--src/lib/rng/hmac_drbg/hmac_drbg.cpp179
-rw-r--r--src/lib/rng/hmac_drbg/hmac_drbg.h93
-rw-r--r--src/lib/rng/hmac_drbg/info.txt1
-rw-r--r--src/lib/rng/hmac_rng/hmac_rng.cpp166
-rw-r--r--src/lib/rng/hmac_rng/hmac_rng.h71
-rw-r--r--src/lib/rng/hmac_rng/info.txt1
-rw-r--r--src/lib/rng/info.txt3
-rw-r--r--src/lib/rng/rdrand_rng/info.txt16
-rw-r--r--src/lib/rng/rdrand_rng/rdrand_rng.cpp84
-rw-r--r--src/lib/rng/rdrand_rng/rdrand_rng.h60
-rw-r--r--src/lib/rng/rng.cpp62
-rw-r--r--src/lib/rng/rng.h196
-rw-r--r--src/lib/rng/stateful_rng/info.txt2
-rw-r--r--src/lib/rng/stateful_rng/stateful_rng.cpp112
-rw-r--r--src/lib/rng/stateful_rng/stateful_rng.h118
-rw-r--r--src/lib/rng/system_rng/system_rng.cpp90
-rw-r--r--src/lib/rng/system_rng/system_rng.h23
-rw-r--r--src/lib/rng/x931_rng/info.txt4
-rw-r--r--src/lib/rng/x931_rng/x931_rng.cpp10
-rw-r--r--src/lib/rng/x931_rng/x931_rng.h9
-rw-r--r--src/lib/stream/chacha/chacha.cpp28
-rw-r--r--src/lib/stream/chacha/chacha.h4
-rw-r--r--src/lib/stream/ctr/ctr.cpp21
-rw-r--r--src/lib/stream/ctr/ctr.h5
-rw-r--r--src/lib/stream/ofb/ofb.cpp5
-rw-r--r--src/lib/stream/ofb/ofb.h2
-rw-r--r--src/lib/stream/rc4/rc4.cpp10
-rw-r--r--src/lib/stream/rc4/rc4.h4
-rw-r--r--src/lib/stream/salsa20/salsa20.cpp4
-rw-r--r--src/lib/stream/salsa20/salsa20.h2
-rw-r--r--src/lib/stream/stream_cipher.cpp6
-rw-r--r--src/lib/stream/stream_cipher.h8
-rw-r--r--src/lib/tls/info.txt5
-rw-r--r--src/lib/tls/msg_client_hello.cpp21
-rw-r--r--src/lib/tls/msg_finished.cpp7
-rw-r--r--src/lib/tls/msg_server_hello.cpp19
-rw-r--r--src/lib/tls/tls_blocking.cpp14
-rw-r--r--src/lib/tls/tls_blocking.h5
-rw-r--r--src/lib/tls/tls_callbacks.h203
-rw-r--r--src/lib/tls/tls_channel.cpp275
-rw-r--r--src/lib/tls/tls_channel.h40
-rw-r--r--src/lib/tls/tls_ciphersuite.cpp149
-rw-r--r--src/lib/tls/tls_ciphersuite.h69
-rw-r--r--src/lib/tls/tls_client.cpp53
-rw-r--r--src/lib/tls/tls_client.h53
-rw-r--r--src/lib/tls/tls_extensions.h2
-rw-r--r--src/lib/tls/tls_handshake_hash.cpp9
-rw-r--r--src/lib/tls/tls_handshake_msg.h4
-rw-r--r--src/lib/tls/tls_handshake_state.cpp10
-rw-r--r--src/lib/tls/tls_handshake_state.h14
-rw-r--r--src/lib/tls/tls_messages.h64
-rw-r--r--src/lib/tls/tls_record.cpp165
-rw-r--r--src/lib/tls/tls_record.h87
-rw-r--r--src/lib/tls/tls_server.cpp826
-rw-r--r--src/lib/tls/tls_server.h73
-rw-r--r--src/lib/tls/tls_session_key.cpp12
-rw-r--r--src/lib/tls/tls_suite_info.cpp823
-rw-r--r--src/lib/utils/calendar.cpp11
-rw-r--r--src/lib/utils/cpuid.cpp8
-rw-r--r--src/lib/utils/donna128.h18
-rw-r--r--src/lib/utils/dyn_load/dyn_load.cpp2
-rw-r--r--src/lib/utils/dyn_load/dyn_load.h3
-rw-r--r--src/lib/utils/dyn_load/info.txt12
-rw-r--r--src/lib/utils/exceptn.h10
-rw-r--r--src/lib/utils/filesystem.cpp2
-rw-r--r--src/lib/utils/mul128.h14
-rw-r--r--src/lib/utils/os_utils.cpp10
-rw-r--r--src/lib/utils/os_utils.h2
-rw-r--r--src/lib/utils/simd/info.txt4
-rw-r--r--src/lib/utils/simd/simd_32.h478
-rw-r--r--src/lib/utils/simd/simd_altivec/info.txt9
-rw-r--r--src/lib/utils/simd/simd_altivec/simd_altivec.h213
-rw-r--r--src/lib/utils/simd/simd_scalar/info.txt7
-rw-r--r--src/lib/utils/simd/simd_scalar/simd_scalar.h213
-rw-r--r--src/lib/utils/simd/simd_sse2/info.txt9
-rw-r--r--src/lib/utils/simd/simd_sse2/simd_sse2.h167
-rw-r--r--src/lib/utils/zero_mem.cpp7
266 files changed, 17395 insertions, 7487 deletions
diff --git a/src/lib/asn1/asn1_time.cpp b/src/lib/asn1/asn1_time.cpp
index 67fc8b5ac..b091c4160 100644
--- a/src/lib/asn1/asn1_time.cpp
+++ b/src/lib/asn1/asn1_time.cpp
@@ -250,6 +250,11 @@ bool X509_Time::passes_sanity_check() const
return true;
}
+std::chrono::system_clock::time_point X509_Time::to_std_timepoint() const
+ {
+ return calendar_point(m_year, m_month, m_day, m_hour, m_minute, m_second).to_std_timepoint();
+ }
+
/*
* Compare two X509_Times for in various ways
*/
diff --git a/src/lib/asn1/asn1_time.h b/src/lib/asn1/asn1_time.h
index ba5b84838..ee30221ee 100644
--- a/src/lib/asn1/asn1_time.h
+++ b/src/lib/asn1/asn1_time.h
@@ -46,6 +46,9 @@ class BOTAN_DLL X509_Time final : public ASN1_Object
/// Create an X509_Time from string
X509_Time(const std::string& t_spec, ASN1_Tag tag);
+ /// Returns a STL timepoint object
+ std::chrono::system_clock::time_point to_std_timepoint() const;
+
private:
void set_to(const std::string& t_spec, ASN1_Tag);
bool passes_sanity_check() const;
diff --git a/src/lib/asn1/oid_lookup/default.cpp b/src/lib/asn1/oid_lookup/default.cpp
index 9e16cfc0b..0d64a8bef 100644
--- a/src/lib/asn1/oid_lookup/default.cpp
+++ b/src/lib/asn1/oid_lookup/default.cpp
@@ -33,6 +33,9 @@ const char* default_oid_list()
// ecgPublicKey (see https://www.teletrust.de/projekte/oid/)
"1.3.36.3.3.2.5.2.1 = ECGDSA" "\n"
+ // EC-KCDSA mechanism (Elliptic Curve KCDSA)
+ "1.0.14888.3.0.5 = ECKCDSA" "\n"
+
"1.2.643.2.2.19 = GOST-34.10" "\n"
// Block ciphers
@@ -102,13 +105,6 @@ const char* default_oid_list()
"2.16.840.1.101.3.4.3.1 = DSA/EMSA1(SHA-224)" "\n"
"2.16.840.1.101.3.4.3.2 = DSA/EMSA1(SHA-256)" "\n"
- "0.4.0.127.0.7.1.1.4.1.1 = ECDSA/EMSA1_BSI(SHA-160)" "\n"
- "0.4.0.127.0.7.1.1.4.1.2 = ECDSA/EMSA1_BSI(SHA-224)" "\n"
- "0.4.0.127.0.7.1.1.4.1.3 = ECDSA/EMSA1_BSI(SHA-256)" "\n"
- "0.4.0.127.0.7.1.1.4.1.4 = ECDSA/EMSA1_BSI(SHA-384)" "\n"
- "0.4.0.127.0.7.1.1.4.1.5 = ECDSA/EMSA1_BSI(SHA-512)" "\n"
- "0.4.0.127.0.7.1.1.4.1.6 = ECDSA/EMSA1_BSI(RIPEMD-160)" "\n"
-
"1.2.840.10045.4.1 = ECDSA/EMSA1(SHA-160)" "\n"
"1.2.840.10045.4.3.1 = ECDSA/EMSA1(SHA-224)" "\n"
"1.2.840.10045.4.3.2 = ECDSA/EMSA1(SHA-256)" "\n"
@@ -122,6 +118,10 @@ const char* default_oid_list()
"1.3.36.3.3.2.5.4.5 = ECGDSA/EMSA1(SHA-384)" "\n"
"1.3.36.3.3.2.5.4.6 = ECGDSA/EMSA1(SHA-512)" "\n"
+ "1.2.410.200004.1.100.4.3 = ECKCDSA/EMSA1(SHA-1)" "\n"
+ "1.2.410.200004.1.100.4.4 = ECKCDSA/EMSA1(SHA-224)" "\n"
+ "1.2.410.200004.1.100.4.5 = ECKCDSA/EMSA1(SHA-256)" "\n"
+
"1.2.643.2.2.3 = GOST-34.10/EMSA1(GOST-R-34.11-94)" "\n"
"1.3.6.1.4.1.25258.2.1.1.1 = RW/EMSA2(RIPEMD-160)" "\n"
@@ -247,6 +247,8 @@ const char* default_oid_list()
"1.2.643.2.2.36.0 = gost_256A" "\n"
"0.4.0.127.0.7.3.1.2.1 = CertificateHolderAuthorizationTemplate" "\n"
+
+ "1.2.250.1.223.101.256.1 = frp256v1" "\n"
;
}
diff --git a/src/lib/base/secmem.h b/src/lib/base/secmem.h
index 63d4e5296..01024a104 100644
--- a/src/lib/base/secmem.h
+++ b/src/lib/base/secmem.h
@@ -82,7 +82,12 @@ class secure_allocator
::new(static_cast<void*>(p)) U(std::forward<Args>(args)...);
}
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4100)
template<typename U> void destroy(U* p) { p->~U(); }
+#pragma warning(pop)
+#endif
};
template<typename T, typename U> inline bool
diff --git a/src/lib/block/threefish_avx2/threefish_avx2.cpp b/src/lib/block/threefish_avx2/threefish_avx2.cpp
index bed98fafa..9b808a221 100644
--- a/src/lib/block/threefish_avx2/threefish_avx2.cpp
+++ b/src/lib/block/threefish_avx2/threefish_avx2.cpp
@@ -1,6 +1,6 @@
/*
* Threefish-512 using AVX2
-* (C) 2013 Jack Lloyd
+* (C) 2013,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -34,6 +34,41 @@ inline void deinterleave_epi64(__m256i& X0, __m256i& X1)
X1 = _mm256_unpackhi_epi64(T0, T1);
}
+inline void rotate_keys(__m256i& R0, __m256i& R1, __m256i R2)
+ {
+ /*
+ Behold. The key schedule progresses like so. The values
+ loop back to the originals after the rounds are complete.
+
+ R0 R1 R2
+ K1,K2,K3 (7,5,3,1),(8,6,4,2),(0,7,5,3)
+ K3,K4,K5 (0,7,5,3),(1,8,6,4),(2,0,7,5)
+ K5,K6,K7 (2,0,7,5),(3,1,8,6),(4,2,0,7)
+
+ K7,K8,K0 (4,2,0,7),(5,3,1,8),(6,4,2,0)
+ K0,K1,K2 (6,4,2,0),(7,5,3,1),(8,6,4,2)
+ K2,K3,K4 (8,6,4,2),(0,7,5,3),(1,8,6,4)
+
+ K4,K5,K6 (1,8,6,4),(2,0,7,5),(3,1,8,6)
+ K6,K7,K8 (3,1,8,6),(4,2,0,7),(5,3,1,8)
+ K8,K0,K1 (5,3,1,8),(6,4,2,0),(7,5,3,1)
+
+ To compute the values for the next round:
+ X0 is X2 from the last round
+ X1 becomes (X0[4],X1[1:3])
+ X2 becomes (X1[4],X2[1:3])
+
+ Uses 3 permutes and 2 blends, is there a faster way?
+ */
+ __m256i T0 = _mm256_permute4x64_epi64(R0, _MM_SHUFFLE(0,0,0,0));
+ __m256i T1 = _mm256_permute4x64_epi64(R1, _MM_SHUFFLE(0,3,2,1));
+ __m256i T2 = _mm256_permute4x64_epi64(R2, _MM_SHUFFLE(0,3,2,1));
+
+ R0 = _mm256_blend_epi32(T1, T0, 0xC0);
+ R1 = _mm256_blend_epi32(T2, T1, 0xC0);
+ }
+
+
}
void Threefish_512_AVX2::encrypt_n(const byte in[], byte out[], size_t blocks) const
@@ -81,10 +116,9 @@ void Threefish_512_AVX2::encrypt_n(const byte in[], byte out[], size_t blocks) c
const __m256i T1 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(0, T1I, 0, 0)); \
X0 = _mm256_add_epi64(X0, K0); \
X1 = _mm256_add_epi64(X1, K1); \
- X1 = _mm256_add_epi64(X1, R); \
+ X1 = _mm256_add_epi64(X1, _mm256_set_epi64x(R,0,0,0)); \
X0 = _mm256_add_epi64(X0, T0); \
X1 = _mm256_add_epi64(X1, T1); \
- R = _mm256_add_epi64(R, ONE); \
} while(0)
#define THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R, K0, K1, T0I, T1I) \
@@ -95,64 +129,52 @@ void Threefish_512_AVX2::encrypt_n(const byte in[], byte out[], size_t blocks) c
X2 = _mm256_add_epi64(X2, K0); \
X1 = _mm256_add_epi64(X1, K1); \
X3 = _mm256_add_epi64(X3, K1); \
- T1 = _mm256_add_epi64(T1, R); \
+ T1 = _mm256_add_epi64(T1, _mm256_set_epi64x(R,0,0,0)); \
X0 = _mm256_add_epi64(X0, T0); \
X2 = _mm256_add_epi64(X2, T0); \
X1 = _mm256_add_epi64(X1, T1); \
X3 = _mm256_add_epi64(X3, T1); \
- R = _mm256_add_epi64(R, ONE); \
} while(0)
-#define THREEFISH_ENC_8_ROUNDS(X0, X1, R, K1, K2, K3, T0, T1, T2) \
+#define THREEFISH_ENC_8_ROUNDS(X0, X1, R, K0, K1, K2, T0, T1, T2) \
do { \
+ rotate_keys(K1, K2, K0); \
THREEFISH_ROUND(X0, X1, ROTATE_1); \
THREEFISH_ROUND(X0, X1, ROTATE_2); \
THREEFISH_ROUND(X0, X1, ROTATE_3); \
THREEFISH_ROUND(X0, X1, ROTATE_4); \
- THREEFISH_INJECT_KEY(X0, X1, R, K1, K2, T0, T1); \
+ THREEFISH_INJECT_KEY(X0, X1, R, K0, K1, T0, T1); \
\
THREEFISH_ROUND(X0, X1, ROTATE_5); \
THREEFISH_ROUND(X0, X1, ROTATE_6); \
THREEFISH_ROUND(X0, X1, ROTATE_7); \
THREEFISH_ROUND(X0, X1, ROTATE_8); \
- THREEFISH_INJECT_KEY(X0, X1, R, K2, K3, T2, T0); \
+ THREEFISH_INJECT_KEY(X0, X1, R+1, K1, K2, T2, T0); \
} while(0)
-#define THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K1, K2, K3, T0, T1, T2) \
+#define THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K0, K1, K2, T0, T1, T2) \
do { \
+ rotate_keys(K1, K2, K0); \
THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_1); \
THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_2); \
THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_3); \
THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_4); \
- THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R, K1, K2, T0, T1); \
+ THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R, K0, K1, T0, T1); \
\
THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_5); \
THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_6); \
THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_7); \
THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_8); \
- THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R, K2, K3, T2, T0); \
+ THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R+1, K1, K2, T2, T0); \
} while(0)
- /*
- v1.0 key schedule: 9 ymm registers (only need 2 or 3)
- (0,1,2,3),(4,5,6,7) [8]
- then mutating with vpermq
- */
- const __m256i K0 = _mm256_set_epi64x(K[6], K[4], K[2], K[0]);
- const __m256i K1 = _mm256_set_epi64x(K[7], K[5], K[3], K[1]);
- const __m256i K2 = _mm256_set_epi64x(K[8], K[6], K[4], K[2]);
- const __m256i K3 = _mm256_set_epi64x(K[0], K[7], K[5], K[3]);
- const __m256i K4 = _mm256_set_epi64x(K[1], K[8], K[6], K[4]);
- const __m256i K5 = _mm256_set_epi64x(K[2], K[0], K[7], K[5]);
- const __m256i K6 = _mm256_set_epi64x(K[3], K[1], K[8], K[6]);
- const __m256i K7 = _mm256_set_epi64x(K[4], K[2], K[0], K[7]);
- const __m256i K8 = _mm256_set_epi64x(K[5], K[3], K[1], K[8]);
-
- const __m256i ONE = _mm256_set_epi64x(1, 0, 0, 0);
+ __m256i K0 = _mm256_set_epi64x(K[5], K[3], K[1], K[8]);
+ __m256i K1 = _mm256_set_epi64x(K[6], K[4], K[2], K[0]);
+ __m256i K2 = _mm256_set_epi64x(K[7], K[5], K[3], K[1]);
const __m256i* in_mm = reinterpret_cast<const __m256i*>(in);
__m256i* out_mm = reinterpret_cast<__m256i*>(out);
-
+
while(blocks >= 2)
{
__m256i X0 = _mm256_loadu_si256(in_mm++);
@@ -162,24 +184,20 @@ void Threefish_512_AVX2::encrypt_n(const byte in[], byte out[], size_t blocks) c
const __m256i T = _mm256_set_epi64x(T_64[0], T_64[1], T_64[2], 0);
- __m256i R = _mm256_set_epi64x(0, 0, 0, 0);
-
interleave_epi64(X0, X1);
interleave_epi64(X2, X3);
- THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R, K0, K1, 2, 3);
+ THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, 0, K1, K2, 2, 3);
- THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K1,K2,K3, 1, 2, 3);
- THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K3,K4,K5, 2, 3, 1);
- THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K5,K6,K7, 3, 1, 2);
-
- THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K7,K8,K0, 1, 2, 3);
- THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K0,K1,K2, 2, 3, 1);
- THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K2,K3,K4, 3, 1, 2);
-
- THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K4,K5,K6, 1, 2, 3);
- THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K6,K7,K8, 2, 3, 1);
- THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, R, K8,K0,K1, 3, 1, 2);
+ THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 1, K2,K0,K1, 1, 2, 3);
+ THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 3, K1,K2,K0, 2, 3, 1);
+ THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 5, K0,K1,K2, 3, 1, 2);
+ THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 7, K2,K0,K1, 1, 2, 3);
+ THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 9, K1,K2,K0, 2, 3, 1);
+ THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 11, K0,K1,K2, 3, 1, 2);
+ THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 13, K2,K0,K1, 1, 2, 3);
+ THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 15, K1,K2,K0, 2, 3, 1);
+ THREEFISH_ENC_2_8_ROUNDS(X0, X1, X2, X3, 17, K0,K1,K2, 3, 1, 2);
deinterleave_epi64(X0, X1);
deinterleave_epi64(X2, X3);
@@ -191,7 +209,7 @@ void Threefish_512_AVX2::encrypt_n(const byte in[], byte out[], size_t blocks) c
blocks -= 2;
}
-
+
for(size_t i = 0; i != blocks; ++i)
{
__m256i X0 = _mm256_loadu_si256(in_mm++);
@@ -199,23 +217,19 @@ void Threefish_512_AVX2::encrypt_n(const byte in[], byte out[], size_t blocks) c
const __m256i T = _mm256_set_epi64x(T_64[0], T_64[1], T_64[2], 0);
- __m256i R = _mm256_set_epi64x(0, 0, 0, 0);
-
interleave_epi64(X0, X1);
- THREEFISH_INJECT_KEY(X0, X1, R, K0, K1, 2, 3);
-
- THREEFISH_ENC_8_ROUNDS(X0, X1, R, K1,K2,K3, 1, 2, 3);
- THREEFISH_ENC_8_ROUNDS(X0, X1, R, K3,K4,K5, 2, 3, 1);
- THREEFISH_ENC_8_ROUNDS(X0, X1, R, K5,K6,K7, 3, 1, 2);
-
- THREEFISH_ENC_8_ROUNDS(X0, X1, R, K7,K8,K0, 1, 2, 3);
- THREEFISH_ENC_8_ROUNDS(X0, X1, R, K0,K1,K2, 2, 3, 1);
- THREEFISH_ENC_8_ROUNDS(X0, X1, R, K2,K3,K4, 3, 1, 2);
+ THREEFISH_INJECT_KEY(X0, X1, 0, K1, K2, 2, 3);
- THREEFISH_ENC_8_ROUNDS(X0, X1, R, K4,K5,K6, 1, 2, 3);
- THREEFISH_ENC_8_ROUNDS(X0, X1, R, K6,K7,K8, 2, 3, 1);
- THREEFISH_ENC_8_ROUNDS(X0, X1, R, K8,K0,K1, 3, 1, 2);
+ THREEFISH_ENC_8_ROUNDS(X0, X1, 1, K2,K0,K1, 1, 2, 3);
+ THREEFISH_ENC_8_ROUNDS(X0, X1, 3, K1,K2,K0, 2, 3, 1);
+ THREEFISH_ENC_8_ROUNDS(X0, X1, 5, K0,K1,K2, 3, 1, 2);
+ THREEFISH_ENC_8_ROUNDS(X0, X1, 7, K2,K0,K1, 1, 2, 3);
+ THREEFISH_ENC_8_ROUNDS(X0, X1, 9, K1,K2,K0, 2, 3, 1);
+ THREEFISH_ENC_8_ROUNDS(X0, X1, 11, K0,K1,K2, 3, 1, 2);
+ THREEFISH_ENC_8_ROUNDS(X0, X1, 13, K2,K0,K1, 1, 2, 3);
+ THREEFISH_ENC_8_ROUNDS(X0, X1, 15, K1,K2,K0, 2, 3, 1);
+ THREEFISH_ENC_8_ROUNDS(X0, X1, 17, K0,K1,K2, 3, 1, 2);
deinterleave_epi64(X0, X1);
@@ -226,7 +240,7 @@ void Threefish_512_AVX2::encrypt_n(const byte in[], byte out[], size_t blocks) c
#undef THREEFISH_ENC_8_ROUNDS
#undef THREEFISH_ROUND
#undef THREEFISH_INJECT_KEY
-#undef THREEFISH_ENC_2_8_ROUNDS
+#undef THREEFISH_DEC_2_8_ROUNDS
#undef THREEFISH_ROUND_2
#undef THREEFISH_INJECT_KEY_2
}
@@ -255,21 +269,35 @@ void Threefish_512_AVX2::decrypt_n(const byte in[], byte out[], size_t blocks) c
X0 = _mm256_sub_epi64(X0, X1); \
} while(0)
+#define THREEFISH_ROUND_2(X0, X1, X2, X3, SHR) \
+ do { \
+ const __m256i SHL = _mm256_sub_epi64(_mm256_set1_epi64x(64), SHR); \
+ X0 = _mm256_permute4x64_epi64(X0, _MM_SHUFFLE(2, 1, 0, 3)); \
+ X2 = _mm256_permute4x64_epi64(X2, _MM_SHUFFLE(2, 1, 0, 3)); \
+ X1 = _mm256_permute4x64_epi64(X1, _MM_SHUFFLE(1, 2, 3, 0)); \
+ X3 = _mm256_permute4x64_epi64(X3, _MM_SHUFFLE(1, 2, 3, 0)); \
+ X1 = _mm256_xor_si256(X1, X0); \
+ X3 = _mm256_xor_si256(X3, X2); \
+ X1 = _mm256_or_si256(_mm256_sllv_epi64(X1, SHL), _mm256_srlv_epi64(X1, SHR)); \
+ X3 = _mm256_or_si256(_mm256_sllv_epi64(X3, SHL), _mm256_srlv_epi64(X3, SHR)); \
+ X0 = _mm256_sub_epi64(X0, X1); \
+ X2 = _mm256_sub_epi64(X2, X3); \
+ } while(0)
+
#define THREEFISH_INJECT_KEY(X0, X1, R, K0, K1, T0I, T1I) \
do { \
const __m256i T0 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(T0I, 0, 0, 0)); \
const __m256i T1 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(0, T1I, 0, 0)); \
X0 = _mm256_sub_epi64(X0, K0); \
X1 = _mm256_sub_epi64(X1, K1); \
- X1 = _mm256_sub_epi64(X1, R); \
- R = _mm256_sub_epi64(R, ONE); \
+ X1 = _mm256_sub_epi64(X1, _mm256_set_epi64x(R, 0, 0, 0)); \
X0 = _mm256_sub_epi64(X0, T0); \
X1 = _mm256_sub_epi64(X1, T1); \
} while(0)
#define THREEFISH_DEC_8_ROUNDS(X0, X1, R, K1, K2, K3, T0, T1, T2) \
do { \
- THREEFISH_INJECT_KEY(X0, X1, R, K2, K3, T2, T0); \
+ THREEFISH_INJECT_KEY(X0, X1, R+1, K2, K3, T2, T0); \
THREEFISH_ROUND(X0, X1, ROTATE_8); \
THREEFISH_ROUND(X0, X1, ROTATE_7); \
THREEFISH_ROUND(X0, X1, ROTATE_6); \
@@ -282,6 +310,36 @@ void Threefish_512_AVX2::decrypt_n(const byte in[], byte out[], size_t blocks) c
THREEFISH_ROUND(X0, X1, ROTATE_1); \
} while(0)
+#define THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R, K0, K1, T0I, T1I) \
+ do { \
+ const __m256i T0 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(T0I, 0, 0, 0)); \
+ __m256i T1 = _mm256_permute4x64_epi64(T, _MM_SHUFFLE(0, T1I, 0, 0)); \
+ X0 = _mm256_sub_epi64(X0, K0); \
+ X2 = _mm256_sub_epi64(X2, K0); \
+ X1 = _mm256_sub_epi64(X1, K1); \
+ X3 = _mm256_sub_epi64(X3, K1); \
+ T1 = _mm256_add_epi64(T1, _mm256_set_epi64x(R,0,0,0)); \
+ X0 = _mm256_sub_epi64(X0, T0); \
+ X2 = _mm256_sub_epi64(X2, T0); \
+ X1 = _mm256_sub_epi64(X1, T1); \
+ X3 = _mm256_sub_epi64(X3, T1); \
+ } while(0)
+
+#define THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, R, K1, K2, K3, T0, T1, T2) \
+ do { \
+ THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R+1, K2, K3, T2, T0); \
+ THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_8); \
+ THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_7); \
+ THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_6); \
+ THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_5); \
+ \
+ THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, R, K1, K2, T0, T1); \
+ THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_4); \
+ THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_3); \
+ THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_2); \
+ THREEFISH_ROUND_2(X0, X1, X2, X3, ROTATE_1); \
+ } while(0)
+
/*
v1.0 key schedule: 9 ymm registers (only need 2 or 3)
(0,1,2,3),(4,5,6,7) [8]
@@ -297,33 +355,64 @@ void Threefish_512_AVX2::decrypt_n(const byte in[], byte out[], size_t blocks) c
const __m256i K7 = _mm256_set_epi64x(K[4], K[2], K[0], K[7]);
const __m256i K8 = _mm256_set_epi64x(K[5], K[3], K[1], K[8]);
- const __m256i ONE = _mm256_set_epi64x(1, 0, 0, 0);
-
const __m256i* in_mm = reinterpret_cast<const __m256i*>(in);
__m256i* out_mm = reinterpret_cast<__m256i*>(out);
- for(size_t i = 0; i != blocks; ++i)
+ while(blocks >= 2)
{
__m256i X0 = _mm256_loadu_si256(in_mm++);
__m256i X1 = _mm256_loadu_si256(in_mm++);
+ __m256i X2 = _mm256_loadu_si256(in_mm++);
+ __m256i X3 = _mm256_loadu_si256(in_mm++);
const __m256i T = _mm256_set_epi64x(T_64[0], T_64[1], T_64[2], 0);
- __m256i R = _mm256_set_epi64x(18, 0, 0, 0);
+ interleave_epi64(X0, X1);
+ interleave_epi64(X2, X3);
+
+ THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 17, K8,K0,K1, 3, 1, 2);
+ THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 15, K6,K7,K8, 2, 3, 1);
+ THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 13, K4,K5,K6, 1, 2, 3);
+ THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 11, K2,K3,K4, 3, 1, 2);
+ THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 9, K0,K1,K2, 2, 3, 1);
+ THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 7, K7,K8,K0, 1, 2, 3);
+ THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 5, K5,K6,K7, 3, 1, 2);
+ THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 3, K3,K4,K5, 2, 3, 1);
+ THREEFISH_DEC_2_8_ROUNDS(X0, X1, X2, X3, 1, K1,K2,K3, 1, 2, 3);
+
+ THREEFISH_INJECT_KEY_2(X0, X1, X2, X3, 0, K0, K1, 2, 3);
+
+ deinterleave_epi64(X0, X1);
+ deinterleave_epi64(X2, X3);
+
+ _mm256_storeu_si256(out_mm++, X0);
+ _mm256_storeu_si256(out_mm++, X1);
+ _mm256_storeu_si256(out_mm++, X2);
+ _mm256_storeu_si256(out_mm++, X3);
+
+ blocks -= 2;
+ }
+
+ for(size_t i = 0; i != blocks; ++i)
+ {
+ __m256i X0 = _mm256_loadu_si256(in_mm++);
+ __m256i X1 = _mm256_loadu_si256(in_mm++);
+
+ const __m256i T = _mm256_set_epi64x(T_64[0], T_64[1], T_64[2], 0);
interleave_epi64(X0, X1);
- THREEFISH_DEC_8_ROUNDS(X0, X1, R, K8,K0,K1, 3, 1, 2);
- THREEFISH_DEC_8_ROUNDS(X0, X1, R, K6,K7,K8, 2, 3, 1);
- THREEFISH_DEC_8_ROUNDS(X0, X1, R, K4,K5,K6, 1, 2, 3);
- THREEFISH_DEC_8_ROUNDS(X0, X1, R, K2,K3,K4, 3, 1, 2);
- THREEFISH_DEC_8_ROUNDS(X0, X1, R, K0,K1,K2, 2, 3, 1);
- THREEFISH_DEC_8_ROUNDS(X0, X1, R, K7,K8,K0, 1, 2, 3);
- THREEFISH_DEC_8_ROUNDS(X0, X1, R, K5,K6,K7, 3, 1, 2);
- THREEFISH_DEC_8_ROUNDS(X0, X1, R, K3,K4,K5, 2, 3, 1);
- THREEFISH_DEC_8_ROUNDS(X0, X1, R, K1,K2,K3, 1, 2, 3);
-
- THREEFISH_INJECT_KEY(X0, X1, R, K0, K1, 2, 3);
+ THREEFISH_DEC_8_ROUNDS(X0, X1, 17, K8,K0,K1, 3, 1, 2);
+ THREEFISH_DEC_8_ROUNDS(X0, X1, 15, K6,K7,K8, 2, 3, 1);
+ THREEFISH_DEC_8_ROUNDS(X0, X1, 13, K4,K5,K6, 1, 2, 3);
+ THREEFISH_DEC_8_ROUNDS(X0, X1, 11, K2,K3,K4, 3, 1, 2);
+ THREEFISH_DEC_8_ROUNDS(X0, X1, 9, K0,K1,K2, 2, 3, 1);
+ THREEFISH_DEC_8_ROUNDS(X0, X1, 7, K7,K8,K0, 1, 2, 3);
+ THREEFISH_DEC_8_ROUNDS(X0, X1, 5, K5,K6,K7, 3, 1, 2);
+ THREEFISH_DEC_8_ROUNDS(X0, X1, 3, K3,K4,K5, 2, 3, 1);
+ THREEFISH_DEC_8_ROUNDS(X0, X1, 1, K1,K2,K3, 1, 2, 3);
+
+ THREEFISH_INJECT_KEY(X0, X1, 0, K0, K1, 2, 3);
deinterleave_epi64(X0, X1);
diff --git a/src/lib/cert/cvc/asn1_eac_str.cpp b/src/lib/cert/cvc/asn1_eac_str.cpp
deleted file mode 100644
index 72ad24926..000000000
--- a/src/lib/cert/cvc/asn1_eac_str.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
-* Simple ASN.1 String Types
-* (C) 2007 FlexSecure GmbH
-* 2008-2011 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/eac_asn_obj.h>
-#include <botan/der_enc.h>
-#include <botan/ber_dec.h>
-#include <botan/charset.h>
-#include <botan/parsing.h>
-#include <sstream>
-#include <ios>
-
-namespace Botan {
-
-/*
-* Create an ASN1_EAC_String
-*/
-ASN1_EAC_String::ASN1_EAC_String(const std::string& str, ASN1_Tag t) : m_tag(t)
- {
- m_iso_8859_str = Charset::transcode(str, LOCAL_CHARSET, LATIN1_CHARSET);
-
- if(!sanity_check())
- throw Invalid_Argument("ASN1_EAC_String contains illegal characters");
- }
-
-/*
-* Return this string in ISO 8859-1 encoding
-*/
-std::string ASN1_EAC_String::iso_8859() const
- {
- return m_iso_8859_str;
- }
-
-/*
-* Return this string in local encoding
-*/
-std::string ASN1_EAC_String::value() const
- {
- return Charset::transcode(m_iso_8859_str, LATIN1_CHARSET, LOCAL_CHARSET);
- }
-
-/*
-* Return the type of this string object
-*/
-ASN1_Tag ASN1_EAC_String::tagging() const
- {
- return m_tag;
- }
-
-/*
-* DER encode an ASN1_EAC_String
-*/
-void ASN1_EAC_String::encode_into(DER_Encoder& encoder) const
- {
- std::string value = iso_8859();
- encoder.add_object(tagging(), APPLICATION, value);
- }
-
-/*
-* Decode a BER encoded ASN1_EAC_String
-*/
-void ASN1_EAC_String::decode_from(BER_Decoder& source)
- {
- BER_Object obj = source.get_next_object();
-
- if(obj.type_tag != m_tag)
- {
- std::stringstream ss;
-
- ss << "ASN1_EAC_String tag mismatch, tag was "
- << std::hex << obj.type_tag
- << " expected "
- << std::hex << m_tag;
-
- throw Decoding_Error(ss.str());
- }
-
- Character_Set charset_is;
- charset_is = LATIN1_CHARSET;
-
- try
- {
- *this = ASN1_EAC_String(
- Charset::transcode(ASN1::to_string(obj), LOCAL_CHARSET, charset_is),
- obj.type_tag);
- }
- catch(Invalid_Argument& inv_arg)
- {
- throw Decoding_Error(std::string("ASN1_EAC_String decoding failed: ") +
- inv_arg.what());
- }
- }
-
-// checks for compliance to the alphabet defined in TR-03110 v1.10, 2007-08-20
-// p. 43
-bool ASN1_EAC_String::sanity_check() const
- {
- const byte* rep = reinterpret_cast<const byte*>(m_iso_8859_str.data());
- const size_t rep_len = m_iso_8859_str.size();
-
- for(size_t i = 0; i != rep_len; ++i)
- {
- if((rep[i] < 0x20) || ((rep[i] >= 0x7F) && (rep[i] < 0xA0)))
- return false;
- }
-
- return true;
- }
-
-bool operator==(const ASN1_EAC_String& lhs, const ASN1_EAC_String& rhs)
- {
- return (lhs.iso_8859() == rhs.iso_8859());
- }
-
-ASN1_Car::ASN1_Car(std::string const& str)
- : ASN1_EAC_String(str, ASN1_Tag(2))
- {}
-
-ASN1_Chr::ASN1_Chr(std::string const& str)
- : ASN1_EAC_String(str, ASN1_Tag(32))
- {}
-
-}
diff --git a/src/lib/cert/cvc/asn1_eac_tm.cpp b/src/lib/cert/cvc/asn1_eac_tm.cpp
deleted file mode 100644
index 9c65fcf6a..000000000
--- a/src/lib/cert/cvc/asn1_eac_tm.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
-* EAC Time Types
-* (C) 2007 FlexSecure GmbH
-* 2008-2009 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/eac_asn_obj.h>
-#include <botan/der_enc.h>
-#include <botan/ber_dec.h>
-#include <botan/charset.h>
-#include <botan/parsing.h>
-#include <botan/internal/rounding.h>
-#include <botan/calendar.h>
-#include <sstream>
-#include <iomanip>
-
-namespace Botan {
-
-namespace {
-
-std::vector<byte> enc_two_digit(u32bit in)
- {
- std::vector<byte> result;
- in %= 100;
- if(in < 10)
- result.push_back(0x00);
- else
- {
- u32bit y_first_pos = round_down<u32bit>(in, 10) / 10;
- result.push_back(static_cast<byte>(y_first_pos));
- }
-
- u32bit y_sec_pos = in % 10;
- result.push_back(static_cast<byte>(y_sec_pos));
- return result;
- }
-
-u32bit dec_two_digit(byte b1, byte b2)
- {
- u32bit upper = b1;
- u32bit lower = b2;
-
- if(upper > 9 || lower > 9)
- throw Invalid_Argument("CVC dec_two_digit value too large");
-
- return upper*10 + lower;
- }
-
-}
-
-/*
-* Create an EAC_Time
-*/
-EAC_Time::EAC_Time(const std::chrono::system_clock::time_point& time,
- ASN1_Tag t) : m_tag(t)
- {
- calendar_point cal = calendar_value(time);
-
- m_year = cal.year;
- m_month = cal.month;
- m_day = cal.day;
- }
-
-/*
-* Create an EAC_Time
-*/
-EAC_Time::EAC_Time(const std::string& t_spec, ASN1_Tag t) : m_tag(t)
- {
- set_to(t_spec);
- }
-
-/*
-* Create an EAC_Time
-*/
-EAC_Time::EAC_Time(u32bit y, u32bit m, u32bit d, ASN1_Tag t) :
- m_year(y), m_month(m), m_day(d), m_tag(t)
- {
- }
-
-/*
-* Set the time with a human readable string
-*/
-void EAC_Time::set_to(const std::string& time_str)
- {
- if(time_str == "")
- {
- m_year = m_month = m_day = 0;
- return;
- }
-
- std::vector<std::string> params;
- std::string current;
-
- for(u32bit j = 0; j != time_str.size(); ++j)
- {
- if(Charset::is_digit(time_str[j]))
- current += time_str[j];
- else
- {
- if(current != "")
- params.push_back(current);
- current.clear();
- }
- }
- if(current != "")
- params.push_back(current);
-
- if(params.size() != 3)
- throw Invalid_Argument("Invalid time specification " + time_str);
-
- m_year = to_u32bit(params[0]);
- m_month = to_u32bit(params[1]);
- m_day = to_u32bit(params[2]);
-
- if(!passes_sanity_check())
- throw Invalid_Argument("Invalid time specification " + time_str);
- }
-
-
-/*
-* DER encode a EAC_Time
-*/
-void EAC_Time::encode_into(DER_Encoder& der) const
- {
- der.add_object(m_tag, APPLICATION,
- encoded_eac_time());
- }
-
-/*
-* Return a string representation of the time
-*/
-std::string EAC_Time::as_string() const
- {
- if(time_is_set() == false)
- throw Invalid_State("EAC_Time::as_string: No time set");
-
- return std::to_string(m_year * 10000 + m_month * 100 + m_day);
- }
-
-/*
-* Return if the time has been set somehow
-*/
-bool EAC_Time::time_is_set() const
- {
- return (m_year != 0);
- }
-
-/*
-* Return a human readable string representation
-*/
-std::string EAC_Time::readable_string() const
- {
- if(time_is_set() == false)
- throw Invalid_State("EAC_Time::readable_string: No time set");
-
- // desired format: "%04d/%02d/%02d"
- std::stringstream output;
- output << std::setfill('0')
- << std::setw(4) << m_year << "/"
- << std::setw(2) << m_month << "/"
- << std::setw(2) << m_day;
- return output.str();
- }
-
-/*
-* Do a general sanity check on the time
-*/
-bool EAC_Time::passes_sanity_check() const
- {
- if(m_year < 2000 || m_year > 2099)
- return false;
- if(m_month == 0 || m_month > 12)
- return false;
- if(m_day == 0 || m_day > 31)
- return false;
-
- return true;
- }
-
-/*
-* modification functions
-*/
-void EAC_Time::add_years(u32bit years)
- {
- m_year += years;
- }
-
-void EAC_Time::add_months(u32bit months)
- {
- m_year += months/12;
- m_month += months % 12;
- if(m_month > 12)
- {
- m_year += 1;
- m_month -= 12;
- }
- }
-
-/*
-* Compare this time against another
-*/
-s32bit EAC_Time::cmp(const EAC_Time& other) const
- {
- if(time_is_set() == false)
- throw Invalid_State("EAC_Time::cmp: No time set");
-
- const s32bit EARLIER = -1, LATER = 1, SAME_TIME = 0;
-
- if(m_year < other.m_year) return EARLIER;
- if(m_year > other.m_year) return LATER;
- if(m_month < other.m_month) return EARLIER;
- if(m_month > other.m_month) return LATER;
- if(m_day < other.m_day) return EARLIER;
- if(m_day > other.m_day) return LATER;
-
- return SAME_TIME;
- }
-
-/*
-* Compare two EAC_Times for in various ways
-*/
-bool operator==(const EAC_Time& t1, const EAC_Time& t2)
- {
- return (t1.cmp(t2) == 0);
- }
-
-bool operator!=(const EAC_Time& t1, const EAC_Time& t2)
- {
- return (t1.cmp(t2) != 0);
- }
-
-bool operator<=(const EAC_Time& t1, const EAC_Time& t2)
- {
- return (t1.cmp(t2) <= 0);
- }
-
-bool operator>=(const EAC_Time& t1, const EAC_Time& t2)
- {
- return (t1.cmp(t2) >= 0);
- }
-
-bool operator>(const EAC_Time& t1, const EAC_Time& t2)
- {
- return (t1.cmp(t2) > 0);
- }
-
-bool operator<(const EAC_Time& t1, const EAC_Time& t2)
- {
- return (t1.cmp(t2) < 0);
- }
-
-/*
-* Decode a BER encoded EAC_Time
-*/
-void EAC_Time::decode_from(BER_Decoder& source)
- {
- BER_Object obj = source.get_next_object();
-
- if(obj.type_tag != m_tag)
- throw BER_Decoding_Error("Tag mismatch when decoding");
-
- if(obj.value.size() != 6)
- {
- throw Decoding_Error("EAC_Time decoding failed");
- }
-
- try
- {
- u32bit tmp_year = dec_two_digit(obj.value[0], obj.value[1]);
- u32bit tmp_mon = dec_two_digit(obj.value[2], obj.value[3]);
- u32bit tmp_day = dec_two_digit(obj.value[4], obj.value[5]);
- m_year = tmp_year + 2000;
- m_month = tmp_mon;
- m_day = tmp_day;
- }
- catch (Invalid_Argument)
- {
- throw Decoding_Error("EAC_Time decoding failed");
- }
-
- }
-
-/*
-* make the value an octet string for encoding
-*/
-std::vector<byte> EAC_Time::encoded_eac_time() const
- {
- std::vector<byte> result;
- result += enc_two_digit(m_year);
- result += enc_two_digit(m_month);
- result += enc_two_digit(m_day);
- return result;
- }
-
-}
diff --git a/src/lib/cert/cvc/cvc_ado.cpp b/src/lib/cert/cvc/cvc_ado.cpp
deleted file mode 100644
index f803c6bf3..000000000
--- a/src/lib/cert/cvc/cvc_ado.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
-* CVC Certificate Constructor
-* (C) 2007 FlexSecure GmbH
-* 2008 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/cvc_ado.h>
-#include <fstream>
-
-namespace Botan {
-
-EAC1_1_ADO::EAC1_1_ADO(DataSource& in)
- {
- init(in);
- do_decode();
- }
-
-EAC1_1_ADO::EAC1_1_ADO(const std::string& in)
- {
- DataSource_Stream stream(in, true);
- init(stream);
- do_decode();
- }
-
-void EAC1_1_ADO::force_decode()
- {
- std::vector<byte> inner_cert;
- BER_Decoder(m_tbs_bits)
- .start_cons(ASN1_Tag(33))
- .raw_bytes(inner_cert)
- .end_cons()
- .decode(m_car)
- .verify_end();
-
- std::vector<byte> req_bits = DER_Encoder()
- .start_cons(ASN1_Tag(33), APPLICATION)
- .raw_bytes(inner_cert)
- .end_cons()
- .get_contents_unlocked();
-
- DataSource_Memory req_source(req_bits);
- m_req = EAC1_1_Req(req_source);
- m_sig_algo = m_req.m_sig_algo;
- }
-
-std::vector<byte> EAC1_1_ADO::make_signed(PK_Signer& signer,
- const std::vector<byte>& tbs_bits,
- RandomNumberGenerator& rng)
- {
- const std::vector<byte> concat_sig = signer.sign_message(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_unlocked();
- }
-
-ASN1_Car EAC1_1_ADO::get_car() const
- {
- return m_car;
- }
-
-void EAC1_1_ADO::decode_info(DataSource& source,
- std::vector<byte> & res_tbs_bits,
- ECDSA_Signature & res_sig)
- {
- std::vector<byte> concat_sig;
- std::vector<byte> cert_inner_bits;
- ASN1_Car car;
-
- BER_Decoder(source)
- .start_cons(ASN1_Tag(7))
- .start_cons(ASN1_Tag(33))
- .raw_bytes(cert_inner_bits)
- .end_cons()
- .decode(car)
- .decode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION)
- .end_cons();
-
- std::vector<byte> enc_cert = DER_Encoder()
- .start_cons(ASN1_Tag(33), APPLICATION)
- .raw_bytes(cert_inner_bits)
- .end_cons()
- .get_contents_unlocked();
-
- res_tbs_bits = enc_cert;
- res_tbs_bits += DER_Encoder().encode(car).get_contents();
- res_sig = decode_concatenation(concat_sig);
- }
-
-void EAC1_1_ADO::encode(Pipe& out, X509_Encoding encoding) const
- {
- if(encoding == PEM)
- throw Invalid_Argument("EAC1_1_ADO::encode() cannot PEM encode an EAC object");
-
- auto concat_sig = EAC1_1_obj<EAC1_1_ADO>::m_sig.get_concatenation();
-
- out.write(DER_Encoder()
- .start_cons(ASN1_Tag(7), APPLICATION)
- .raw_bytes(m_tbs_bits)
- .encode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION)
- .end_cons()
- .get_contents());
- }
-
-std::vector<byte> EAC1_1_ADO::tbs_data() const
- {
- return m_tbs_bits;
- }
-
-bool EAC1_1_ADO::operator==(EAC1_1_ADO const& rhs) const
- {
- return (this->get_concat_sig() == rhs.get_concat_sig()
- && this->tbs_data() == rhs.tbs_data()
- && this->get_car() == rhs.get_car());
- }
-
-EAC1_1_Req EAC1_1_ADO::get_request() const
- {
- return m_req;
- }
-
-}
diff --git a/src/lib/cert/cvc/cvc_ado.h b/src/lib/cert/cvc/cvc_ado.h
deleted file mode 100644
index 4b861ec81..000000000
--- a/src/lib/cert/cvc/cvc_ado.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
-* EAC1_1 CVC ADO
-* (C) 2008 Falko Strenzke
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_EAC_CVC_ADO_H__
-#define BOTAN_EAC_CVC_ADO_H__
-
-#include <botan/eac_obj.h>
-#include <botan/eac_asn_obj.h>
-#include <botan/cvc_req.h>
-#include <string>
-
-namespace Botan {
-
-/**
-* This class represents a TR03110 (EAC) v1.1 CVC ADO request
-*/
-
- // CRTP continuation from EAC1_1_obj
-class BOTAN_DLL EAC1_1_ADO : public EAC1_1_obj<EAC1_1_ADO>
- {
- public:
- friend class EAC1_1_obj<EAC1_1_ADO>;
-
- /**
- * Construct a CVC ADO request from a DER encoded CVC ADO request file.
- * @param str the path to the DER encoded file
- */
- EAC1_1_ADO(const std::string& str);
-
- /**
- * Construct a CVC ADO request from a data source
- * @param source the data source
- */
- EAC1_1_ADO(DataSource& source);
-
- /**
- * Create a signed CVC ADO request from to be signed (TBS) data
- * @param signer the signer used to sign the CVC ADO request
- * @param tbs_bits the TBS data to sign
- * @param rng a random number generator
- */
- static std::vector<byte> make_signed(
- PK_Signer& signer,
- const std::vector<byte>& tbs_bits,
- RandomNumberGenerator& rng);
-
- /**
- * Get the CAR of this CVC ADO request
- * @result the CAR of this CVC ADO request
- */
- ASN1_Car get_car() const;
-
- /**
- * Get the CVC request contained in this object.
- * @result the CVC request inside this CVC ADO request
- */
- EAC1_1_Req get_request() const;
-
- /**
- * Encode this object into a pipe. Only DER is supported.
- * @param out the pipe to encode this object into
- * @param encoding the encoding type to use, must be DER
- */
- void encode(Pipe& out, X509_Encoding encoding) const;
-
- bool operator==(EAC1_1_ADO const& rhs) const;
-
- /**
- * Get the TBS data of this CVC ADO request.
- * @result the TBS data
- */
- std::vector<byte> tbs_data() const;
-
- virtual ~EAC1_1_ADO() {}
- private:
- ASN1_Car m_car;
- EAC1_1_Req m_req;
-
- void force_decode();
- static void decode_info(DataSource& source,
- std::vector<byte> & res_tbs_bits,
- ECDSA_Signature & res_sig);
- };
-
-inline bool operator!=(EAC1_1_ADO const& lhs, EAC1_1_ADO const& rhs)
- {
- return (!(lhs == rhs));
- }
-
-}
-
-#endif
-
-
diff --git a/src/lib/cert/cvc/cvc_cert.cpp b/src/lib/cert/cvc/cvc_cert.cpp
deleted file mode 100644
index 280a8acda..000000000
--- a/src/lib/cert/cvc/cvc_cert.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
-* (C) 2007 FlexSecure GmbH
-* 2008-2010 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/cvc_cert.h>
-#include <botan/oids.h>
-
-namespace Botan {
-
-ASN1_Car EAC1_1_CVC::get_car() const
- {
- return m_car;
- }
-
-ASN1_Ced EAC1_1_CVC::get_ced() const
- {
- return m_ced;
- }
-ASN1_Cex EAC1_1_CVC::get_cex() const
- {
- return m_cex;
- }
-u32bit EAC1_1_CVC::get_chat_value() const
- {
- return m_chat_val;
- }
-
-/*
-* Decode the TBSCertificate data
-*/
-void EAC1_1_CVC::force_decode()
- {
- std::vector<byte> enc_pk;
- std::vector<byte> enc_chat_val;
- size_t cpi;
- BER_Decoder tbs_cert(m_tbs_bits);
- tbs_cert.decode(cpi, ASN1_Tag(41), APPLICATION)
- .decode(m_car)
- .start_cons(ASN1_Tag(73))
- .raw_bytes(enc_pk)
- .end_cons()
- .decode(m_chr)
- .start_cons(ASN1_Tag(76))
- .decode(m_chat_oid)
- .decode(enc_chat_val, OCTET_STRING, ASN1_Tag(19), APPLICATION)
- .end_cons()
- .decode(m_ced)
- .decode(m_cex)
- .verify_end();
-
- if(enc_chat_val.size() != 1)
- throw Decoding_Error("CertificateHolderAuthorizationValue was not of length 1");
-
- if(cpi != 0)
- throw Decoding_Error("EAC1_1 certificate's cpi was not 0");
-
- m_pk = decode_eac1_1_key(enc_pk, m_sig_algo);
-
- m_chat_val = enc_chat_val[0];
-
- m_self_signed = (m_car.iso_8859() == m_chr.iso_8859());
- }
-
-/*
-* CVC Certificate Constructor
-*/
-EAC1_1_CVC::EAC1_1_CVC(DataSource& in)
- {
- init(in);
- m_self_signed = false;
- do_decode();
- }
-
-EAC1_1_CVC::EAC1_1_CVC(const std::string& in)
- {
- DataSource_Stream stream(in, true);
- init(stream);
- m_self_signed = false;
- do_decode();
- }
-
-bool EAC1_1_CVC::operator==(EAC1_1_CVC const& rhs) const
- {
- return (tbs_data() == rhs.tbs_data()
- && get_concat_sig() == rhs.get_concat_sig());
- }
-
-ECDSA_PublicKey* decode_eac1_1_key(const std::vector<byte>&,
- AlgorithmIdentifier&)
- {
- throw Internal_Error("decode_eac1_1_key: Unimplemented");
- return 0;
- }
-
-EAC1_1_CVC make_cvc_cert(PK_Signer& signer,
- const std::vector<byte>& public_key,
- ASN1_Car const& car,
- ASN1_Chr const& chr,
- byte holder_auth_templ,
- ASN1_Ced ced,
- ASN1_Cex cex,
- RandomNumberGenerator& rng)
- {
- OID chat_oid(OIDS::lookup("CertificateHolderAuthorizationTemplate"));
- std::vector<byte> enc_chat_val;
- enc_chat_val.push_back(holder_auth_templ);
-
- std::vector<byte> enc_cpi;
- enc_cpi.push_back(0x00);
- std::vector<byte> tbs = DER_Encoder()
- .encode(enc_cpi, OCTET_STRING, ASN1_Tag(41), APPLICATION) // cpi
- .encode(car)
- .raw_bytes(public_key)
- .encode(chr)
- .start_cons(ASN1_Tag(76), APPLICATION)
- .encode(chat_oid)
- .encode(enc_chat_val, OCTET_STRING, ASN1_Tag(19), APPLICATION)
- .end_cons()
- .encode(ced)
- .encode(cex)
- .get_contents_unlocked();
-
- std::vector<byte> signed_cert =
- EAC1_1_CVC::make_signed(signer,
- EAC1_1_CVC::build_cert_body(tbs),
- rng);
-
- DataSource_Memory source(signed_cert);
- return EAC1_1_CVC(source);
- }
-
-}
diff --git a/src/lib/cert/cvc/cvc_cert.h b/src/lib/cert/cvc/cvc_cert.h
deleted file mode 100644
index a45388550..000000000
--- a/src/lib/cert/cvc/cvc_cert.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
-* EAC1_1 CVC
-* (C) 2008 Falko Strenzke
-* 2008 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_CVC_EAC_H__
-#define BOTAN_CVC_EAC_H__
-
-#include <botan/cvc_gen_cert.h>
-#include <botan/ecdsa.h>
-#include <string>
-
-namespace Botan {
-
-/**
-* This class represents TR03110 (EAC) v1.1 CV Certificates
-*/
-class BOTAN_DLL EAC1_1_CVC : public EAC1_1_gen_CVC<EAC1_1_CVC>//Signed_Object
- {
- public:
- friend class EAC1_1_obj<EAC1_1_CVC>;
-
- /**
- * Get the CAR of the certificate.
- * @result the CAR of the certificate
- */
- ASN1_Car get_car() const;
-
- /**
- * Get the CED of this certificate.
- * @result the CED this certificate
- */
- ASN1_Ced get_ced() const;
-
- /**
- * Get the CEX of this certificate.
- * @result the CEX this certificate
- */
- ASN1_Cex get_cex() const;
-
- /**
- * Get the CHAT value.
- * @result the CHAT value
- */
- u32bit get_chat_value() const;
-
- bool operator==(const EAC1_1_CVC&) const;
-
- /**
- * Construct a CVC from a data source
- * @param source the data source
- */
- EAC1_1_CVC(DataSource& source);
-
- /**
- * Construct a CVC from a file
- * @param str the path to the certificate file
- */
- EAC1_1_CVC(const std::string& str);
-
- virtual ~EAC1_1_CVC() {}
- private:
- void force_decode();
- EAC1_1_CVC() {}
-
- ASN1_Car m_car;
- ASN1_Ced m_ced;
- ASN1_Cex m_cex;
- byte m_chat_val;
- OID m_chat_oid;
- };
-
-/*
-* Comparison
-*/
-inline bool operator!=(EAC1_1_CVC const& lhs, EAC1_1_CVC const& rhs)
- {
- return !(lhs == rhs);
- }
-
-/**
-* Create an arbitrary EAC 1.1 CVC.
-* The desired key encoding must be set within the key (if applicable).
-* @param signer the signer used to sign the certificate
-* @param public_key the DER encoded public key to appear in
-* the certificate
-* @param car the CAR of the certificate
-* @param chr the CHR of the certificate
-* @param holder_auth_templ the holder authorization value byte to
-* appear in the CHAT of the certificate
-* @param ced the CED to appear in the certificate
-* @param cex the CEX to appear in the certificate
-* @param rng a random number generator
-*/
-EAC1_1_CVC BOTAN_DLL make_cvc_cert(PK_Signer& signer,
- const std::vector<byte>& public_key,
- ASN1_Car const& car,
- ASN1_Chr const& chr,
- byte holder_auth_templ,
- ASN1_Ced ced,
- ASN1_Cex cex,
- RandomNumberGenerator& rng);
-
-/**
-* Decode an EAC encoding ECDSA key
-*/
-BOTAN_DLL ECDSA_PublicKey* decode_eac1_1_key(const std::vector<byte>& enc_key,
- AlgorithmIdentifier& sig_algo);
-
-}
-
-#endif
-
diff --git a/src/lib/cert/cvc/cvc_gen_cert.h b/src/lib/cert/cvc/cvc_gen_cert.h
deleted file mode 100644
index 2c3bca73d..000000000
--- a/src/lib/cert/cvc/cvc_gen_cert.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
-* EAC1_1 general CVC
-* (C) 2008 Falko Strenzke
-* 2008-2010 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_EAC_CVC_GEN_CERT_H__
-#define BOTAN_EAC_CVC_GEN_CERT_H__
-
-#include <botan/eac_obj.h>
-#include <botan/eac_asn_obj.h>
-#include <botan/ecdsa.h>
-#include <botan/pubkey.h>
-
-namespace Botan {
-
-/**
-* This class represents TR03110 (EAC) v1.1 generalized CV Certificates
-*/
-template<typename Derived>
-class EAC1_1_gen_CVC : public EAC1_1_obj<Derived> // CRTP continuation from EAC1_1_obj
- {
- friend class EAC1_1_obj<EAC1_1_gen_CVC>;
-
- public:
-
- /**
- * Get this certificates public key.
- * @result this certificates public key
- */
- Public_Key* subject_public_key() const;
-
- /**
- * Find out whether this object is self signed.
- * @result true if this object is self signed
- */
- bool is_self_signed() const;
-
- /**
- * Get the CHR of the certificate.
- * @result the CHR of the certificate
- */
- ASN1_Chr get_chr() const;
-
- /**
- * Put the DER encoded version of this object into a pipe. PEM
- * is not supported.
- * @param out the pipe to push the DER encoded version into
- * @param encoding the encoding to use. Must be DER.
- */
- void encode(Pipe& out, X509_Encoding encoding) const;
-
- /**
- * Get the to-be-signed (TBS) data of this object.
- * @result the TBS data of this object
- */
- std::vector<byte> tbs_data() const;
-
- /**
- * Build the DER encoded certifcate body of an object
- * @param tbs the data to be signed
- * @result the correctly encoded body of the object
- */
- static std::vector<byte> build_cert_body(const std::vector<byte>& tbs);
-
- /**
- * Create a signed generalized CVC object.
- * @param signer the signer used to sign this object
- * @param tbs_bits the body the generalized CVC object to be signed
- * @param rng a random number generator
- * @result the DER encoded signed generalized CVC object
- */
- static std::vector<byte> make_signed(
- PK_Signer& signer,
- const std::vector<byte>& tbs_bits,
- RandomNumberGenerator& rng);
-
- EAC1_1_gen_CVC() { m_pk = nullptr; }
-
- virtual ~EAC1_1_gen_CVC<Derived>()
- { delete m_pk; }
-
- protected:
- ECDSA_PublicKey* m_pk;
- ASN1_Chr m_chr;
- bool m_self_signed;
-
- static void decode_info(DataSource& source,
- std::vector<byte> & res_tbs_bits,
- ECDSA_Signature & res_sig);
-
- };
-
-template<typename Derived> ASN1_Chr EAC1_1_gen_CVC<Derived>::get_chr() const
- {
- return m_chr;
- }
-
-template<typename Derived> bool EAC1_1_gen_CVC<Derived>::is_self_signed() const
- {
- return m_self_signed;
- }
-
-template<typename Derived>
-std::vector<byte> EAC1_1_gen_CVC<Derived>::make_signed(
- PK_Signer& signer,
- const std::vector<byte>& tbs_bits,
- RandomNumberGenerator& rng) // static
- {
- const auto concat_sig = signer.sign_message(tbs_bits, rng);
-
- return DER_Encoder()
- .start_cons(ASN1_Tag(33), APPLICATION)
- .raw_bytes(tbs_bits)
- .encode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION)
- .end_cons()
- .get_contents_unlocked();
- }
-
-template<typename Derived>
-Public_Key* EAC1_1_gen_CVC<Derived>::subject_public_key() const
- {
- return new ECDSA_PublicKey(*m_pk);
- }
-
-template<typename Derived> std::vector<byte> EAC1_1_gen_CVC<Derived>::build_cert_body(const std::vector<byte>& tbs)
- {
- return DER_Encoder()
- .start_cons(ASN1_Tag(78), APPLICATION)
- .raw_bytes(tbs)
- .end_cons().get_contents_unlocked();
- }
-
-template<typename Derived> std::vector<byte> EAC1_1_gen_CVC<Derived>::tbs_data() const
- {
- return build_cert_body(EAC1_1_obj<Derived>::m_tbs_bits);
- }
-
-template<typename Derived> void EAC1_1_gen_CVC<Derived>::encode(Pipe& out, X509_Encoding encoding) const
- {
- std::vector<byte> concat_sig(EAC1_1_obj<Derived>::m_sig.get_concatenation());
- std::vector<byte> der = DER_Encoder()
- .start_cons(ASN1_Tag(33), APPLICATION)
- .start_cons(ASN1_Tag(78), APPLICATION)
- .raw_bytes(EAC1_1_obj<Derived>::m_tbs_bits)
- .end_cons()
- .encode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION)
- .end_cons()
- .get_contents_unlocked();
-
- if (encoding == PEM)
- throw Invalid_Argument("EAC1_1_gen_CVC::encode() cannot PEM encode an EAC object");
- else
- out.write(der);
- }
-
-template<typename Derived>
-void EAC1_1_gen_CVC<Derived>::decode_info(
- DataSource& source,
- std::vector<byte> & res_tbs_bits,
- ECDSA_Signature & res_sig)
- {
- std::vector<byte> concat_sig;
- BER_Decoder(source)
- .start_cons(ASN1_Tag(33))
- .start_cons(ASN1_Tag(78))
- .raw_bytes(res_tbs_bits)
- .end_cons()
- .decode(concat_sig, OCTET_STRING, ASN1_Tag(55), APPLICATION)
- .end_cons();
- res_sig = decode_concatenation(concat_sig);
- }
-
-}
-
-#endif
-
-
diff --git a/src/lib/cert/cvc/cvc_req.cpp b/src/lib/cert/cvc/cvc_req.cpp
deleted file mode 100644
index 1cb6b50ac..000000000
--- a/src/lib/cert/cvc/cvc_req.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-* (C) 2007 FlexSecure GmbH
-* 2008-2010 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/cvc_req.h>
-#include <botan/cvc_cert.h>
-#include <botan/ber_dec.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());
- }
-
-void EAC1_1_Req::force_decode()
- {
- std::vector<byte> enc_pk;
- BER_Decoder tbs_cert(m_tbs_bits);
- size_t cpi;
- tbs_cert.decode(cpi, ASN1_Tag(41), APPLICATION)
- .start_cons(ASN1_Tag(73))
- .raw_bytes(enc_pk)
- .end_cons()
- .decode(m_chr)
- .verify_end();
-
- if(cpi != 0)
- throw Decoding_Error("EAC1_1 requests cpi was not 0");
-
- m_pk = decode_eac1_1_key(enc_pk, m_sig_algo);
- }
-
-EAC1_1_Req::EAC1_1_Req(DataSource& in)
- {
- init(in);
- m_self_signed = true;
- do_decode();
- }
-
-EAC1_1_Req::EAC1_1_Req(const std::string& in)
- {
- DataSource_Stream stream(in, true);
- init(stream);
- m_self_signed = true;
- do_decode();
- }
-
-}
diff --git a/src/lib/cert/cvc/cvc_req.h b/src/lib/cert/cvc/cvc_req.h
deleted file mode 100644
index b71a8e764..000000000
--- a/src/lib/cert/cvc/cvc_req.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-* EAC1_1 CVC Request
-* (C) 2008 Falko Strenzke
-* 2010 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_EAC_CVC_REQ_H__
-#define BOTAN_EAC_CVC_REQ_H__
-
-#include <botan/cvc_gen_cert.h>
-
-namespace Botan {
-
-/**
-* This class represents TR03110 v1.1 EAC CV Certificate Requests.
-*/
-class BOTAN_DLL EAC1_1_Req : public EAC1_1_gen_CVC<EAC1_1_Req>
- {
- public:
- friend class EAC1_1_ADO;
- friend class EAC1_1_obj<EAC1_1_Req>;
-
- /**
- * Compare for equality with other
- * @param other compare for equality with this object
- */
- bool operator==(const EAC1_1_Req& other) const;
-
- /**
- * Construct a CVC request from a data source.
- * @param source the data source
- */
- EAC1_1_Req(DataSource& source);
-
- /**
- * Construct a CVC request from a DER encoded CVC request file.
- * @param str the path to the DER encoded file
- */
- EAC1_1_Req(const std::string& str);
-
- virtual ~EAC1_1_Req(){}
- private:
- void force_decode();
- EAC1_1_Req() {}
- };
-
-/*
-* Comparison Operator
-*/
-inline bool operator!=(EAC1_1_Req const& lhs, EAC1_1_Req const& rhs)
- {
- return !(lhs == rhs);
- }
-
-}
-
-#endif
diff --git a/src/lib/cert/cvc/cvc_self.cpp b/src/lib/cert/cvc/cvc_self.cpp
deleted file mode 100644
index fdc66bbfd..000000000
--- a/src/lib/cert/cvc/cvc_self.cpp
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
-* (C) 2007 FlexSecure GmbH
-* 2008-2010 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/cvc_self.h>
-#include <botan/ecc_key.h>
-#include <botan/point_gfp.h>
-#include <botan/oids.h>
-#include <sstream>
-
-namespace Botan {
-
-namespace {
-
-/*
-* cvc CHAT values
-*/
-enum CHAT_values{
- CVCA = 0xC0,
- DVCA_domestic = 0x80,
- DVCA_foreign = 0x40,
- IS = 0x00,
-
- IRIS = 0x02,
- FINGERPRINT = 0x01
-};
-
-void encode_eac_bigint(DER_Encoder& der, const BigInt& x, ASN1_Tag tag)
- {
- der.encode(BigInt::encode_1363(x, x.bytes()), OCTET_STRING, tag);
- }
-
-std::vector<byte> eac_1_1_encoding(const EC_PublicKey* key,
- const OID& sig_algo)
- {
- if(key->domain_format() == EC_DOMPAR_ENC_OID)
- throw Encoding_Error("CVC encoder: cannot encode parameters by OID");
-
- const EC_Group& domain = key->domain();
-
- // This is why we can't have nice things
-
- DER_Encoder enc;
- enc.start_cons(ASN1_Tag(73), APPLICATION)
- .encode(sig_algo);
-
- if(key->domain_format() == EC_DOMPAR_ENC_EXPLICIT)
- {
- encode_eac_bigint(enc, domain.get_curve().get_p(), ASN1_Tag(1));
- encode_eac_bigint(enc, domain.get_curve().get_a(), ASN1_Tag(2));
- encode_eac_bigint(enc, domain.get_curve().get_b(), ASN1_Tag(3));
-
- enc.encode(EC2OSP(domain.get_base_point(), PointGFp::UNCOMPRESSED),
- OCTET_STRING, ASN1_Tag(4));
-
- encode_eac_bigint(enc, domain.get_order(), ASN1_Tag(4));
- }
-
- enc.encode(EC2OSP(key->public_point(), PointGFp::UNCOMPRESSED),
- OCTET_STRING, ASN1_Tag(6));
-
- if(key->domain_format() == EC_DOMPAR_ENC_EXPLICIT)
- encode_eac_bigint(enc, domain.get_cofactor(), ASN1_Tag(7));
-
- enc.end_cons();
-
- return enc.get_contents_unlocked();
- }
-
-std::string padding_and_hash_from_oid(OID const& oid)
- {
- std::string padding_and_hash = OIDS::lookup(oid); // use the hash
-
- if(padding_and_hash.substr(0,6) != "ECDSA/")
- throw Invalid_State("CVC: Can only use ECDSA, not " + padding_and_hash);
-
- padding_and_hash.erase(0, padding_and_hash.find("/") + 1);
- return padding_and_hash;
- }
-
-}
-
-namespace CVC_EAC {
-
-EAC1_1_CVC create_self_signed_cert(Private_Key const& key,
- EAC1_1_CVC_Options const& opt,
- RandomNumberGenerator& rng)
- {
- // NOTE: we ignore the value of opt.chr
-
- const ECDSA_PrivateKey* priv_key = dynamic_cast<const ECDSA_PrivateKey*>(&key);
-
- if(priv_key == 0)
- throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
-
- ASN1_Chr chr(opt.car.value());
-
- AlgorithmIdentifier sig_algo;
- std::string padding_and_hash("EMSA1_BSI(" + opt.hash_alg + ")");
- sig_algo.oid = OIDS::lookup(priv_key->algo_name() + "/" + padding_and_hash);
- sig_algo = AlgorithmIdentifier(sig_algo.oid, AlgorithmIdentifier::USE_NULL_PARAM);
-
- PK_Signer signer(*priv_key, padding_and_hash);
-
- std::vector<byte> enc_public_key = eac_1_1_encoding(priv_key, sig_algo.oid);
-
- return make_cvc_cert(signer,
- enc_public_key,
- opt.car, chr,
- opt.holder_auth_templ,
- opt.ced, opt.cex, rng);
- }
-
-EAC1_1_Req create_cvc_req(Private_Key const& key,
- ASN1_Chr const& chr,
- std::string const& hash_alg,
- RandomNumberGenerator& rng)
- {
-
- ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
- if (priv_key == 0)
- {
- throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
- }
- AlgorithmIdentifier sig_algo;
- std::string padding_and_hash("EMSA1_BSI(" + hash_alg + ")");
- sig_algo.oid = OIDS::lookup(priv_key->algo_name() + "/" + padding_and_hash);
- sig_algo = AlgorithmIdentifier(sig_algo.oid, AlgorithmIdentifier::USE_NULL_PARAM);
-
- PK_Signer signer(*priv_key, padding_and_hash);
-
- std::vector<byte> enc_public_key = eac_1_1_encoding(priv_key, sig_algo.oid);
-
- std::vector<byte> enc_cpi;
- enc_cpi.push_back(0x00);
- std::vector<byte> tbs = DER_Encoder()
- .encode(enc_cpi, OCTET_STRING, ASN1_Tag(41), APPLICATION)
- .raw_bytes(enc_public_key)
- .encode(chr)
- .get_contents_unlocked();
-
- std::vector<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);
-
- DataSource_Memory source(signed_cert);
- return EAC1_1_Req(source);
- }
-
-EAC1_1_ADO create_ado_req(Private_Key const& key,
- EAC1_1_Req const& req,
- ASN1_Car const& car,
- RandomNumberGenerator& rng)
- {
-
- ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
- if (priv_key == 0)
- {
- throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
- }
-
- std::string padding_and_hash = padding_and_hash_from_oid(req.signature_algorithm().oid);
- PK_Signer signer(*priv_key, padding_and_hash);
- std::vector<byte> tbs_bits = req.BER_encode();
- tbs_bits += DER_Encoder().encode(car).get_contents();
-
- std::vector<byte> signed_cert =
- EAC1_1_ADO::make_signed(signer, tbs_bits, rng);
-
- DataSource_Memory source(signed_cert);
- return EAC1_1_ADO(source);
- }
-
-} // namespace CVC_EAC
-namespace DE_EAC
-{
-
-EAC1_1_CVC create_cvca(Private_Key const& key,
- std::string const& hash,
- ASN1_Car const& car, bool iris, bool fingerpr,
- u32bit cvca_validity_months,
- RandomNumberGenerator& rng)
- {
- ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
- if (priv_key == 0)
- {
- throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
- }
- EAC1_1_CVC_Options opts;
- opts.car = car;
-
- opts.ced = ASN1_Ced(std::chrono::system_clock::now());
- opts.cex = ASN1_Cex(opts.ced);
- opts.cex.add_months(cvca_validity_months);
- opts.holder_auth_templ = (CVCA | (iris * IRIS) | (fingerpr * FINGERPRINT));
- opts.hash_alg = hash;
- return CVC_EAC::create_self_signed_cert(*priv_key, opts, rng);
- }
-
-
-
-EAC1_1_CVC link_cvca(EAC1_1_CVC const& signer,
- Private_Key const& key,
- EAC1_1_CVC const& signee,
- RandomNumberGenerator& rng)
- {
- const ECDSA_PrivateKey* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
-
- if (priv_key == 0)
- throw Invalid_Argument("link_cvca(): unsupported key type");
-
- ASN1_Ced ced(std::chrono::system_clock::now());
- ASN1_Cex cex(signee.get_cex());
- if (*static_cast<EAC_Time*>(&ced) > *static_cast<EAC_Time*>(&cex))
- {
- std::string detail("link_cvca(): validity periods of provided certificates don't overlap: currend time = ced = ");
- detail += ced.as_string();
- detail += ", signee.cex = ";
- detail += cex.as_string();
- throw Invalid_Argument(detail);
- }
- if (signer.signature_algorithm() != signee.signature_algorithm())
- {
- 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);
- PK_Signer pk_signer(*priv_key, padding_and_hash);
- std::unique_ptr<Public_Key> pk(signee.subject_public_key());
- ECDSA_PublicKey* subj_pk = dynamic_cast<ECDSA_PublicKey*>(pk.get());
- subj_pk->set_parameter_encoding(EC_DOMPAR_ENC_EXPLICIT);
-
- std::vector<byte> enc_public_key = eac_1_1_encoding(priv_key, sig_algo.oid);
-
- return make_cvc_cert(pk_signer, enc_public_key,
- signer.get_car(),
- signee.get_chr(),
- signer.get_chat_value(),
- ced, cex,
- rng);
- }
-
-EAC1_1_CVC sign_request(EAC1_1_CVC const& signer_cert,
- Private_Key const& key,
- EAC1_1_Req const& signee,
- u32bit seqnr,
- u32bit seqnr_len,
- bool domestic,
- u32bit dvca_validity_months,
- u32bit ca_is_validity_months,
- RandomNumberGenerator& rng)
- {
- ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&key);
- if (priv_key == 0)
- {
- throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
- }
- std::string chr_str = signee.get_chr().value();
-
- std::string seqnr_string = std::to_string(seqnr);
-
- while(seqnr_string.size() < seqnr_len)
- seqnr_string = '0' + seqnr_string;
-
- chr_str += seqnr_string;
- ASN1_Chr chr(chr_str);
- std::string padding_and_hash = padding_and_hash_from_oid(signee.signature_algorithm().oid);
- PK_Signer pk_signer(*priv_key, padding_and_hash);
- std::unique_ptr<Public_Key> pk(signee.subject_public_key());
- ECDSA_PublicKey* subj_pk = dynamic_cast<ECDSA_PublicKey*>(pk.get());
- std::unique_ptr<Public_Key> signer_pk(signer_cert.subject_public_key());
-
- // for the case that the domain parameters are not set...
- // (we use those from the signer because they must fit)
- //subj_pk->set_domain_parameters(priv_key->domain_parameters());
-
- subj_pk->set_parameter_encoding(EC_DOMPAR_ENC_IMPLICITCA);
-
- AlgorithmIdentifier sig_algo(signer_cert.signature_algorithm());
-
- ASN1_Ced ced(std::chrono::system_clock::now());
-
- u32bit chat_val;
- u32bit chat_low = signer_cert.get_chat_value() & 0x3; // take the chat rights from signer
- ASN1_Cex cex(ced);
- if ((signer_cert.get_chat_value() & CVCA) == CVCA)
- {
- // we sign a dvca
- cex.add_months(dvca_validity_months);
- if (domestic)
- chat_val = DVCA_domestic | chat_low;
- else
- chat_val = DVCA_foreign | chat_low;
- }
- else if ((signer_cert.get_chat_value() & DVCA_domestic) == DVCA_domestic ||
- (signer_cert.get_chat_value() & DVCA_foreign) == DVCA_foreign)
- {
- cex.add_months(ca_is_validity_months);
- chat_val = IS | chat_low;
- }
- else
- {
- throw Invalid_Argument("sign_request(): encountered illegal value for CHAT");
- // (IS cannot sign certificates)
- }
-
- std::vector<byte> enc_public_key = eac_1_1_encoding(priv_key, sig_algo.oid);
-
- return make_cvc_cert(pk_signer, enc_public_key,
- ASN1_Car(signer_cert.get_chr().iso_8859()),
- chr,
- chat_val,
- ced,
- cex,
- rng);
- }
-
-EAC1_1_Req create_cvc_req(Private_Key const& prkey,
- ASN1_Chr const& chr,
- std::string const& hash_alg,
- RandomNumberGenerator& rng)
- {
- ECDSA_PrivateKey const* priv_key = dynamic_cast<ECDSA_PrivateKey const*>(&prkey);
- if (priv_key == 0)
- {
- throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type");
- }
- ECDSA_PrivateKey key(*priv_key);
- key.set_parameter_encoding(EC_DOMPAR_ENC_IMPLICITCA);
- return CVC_EAC::create_cvc_req(key, chr, hash_alg, rng);
- }
-
-} // namespace DE_EAC
-
-}
diff --git a/src/lib/cert/cvc/cvc_self.h b/src/lib/cert/cvc/cvc_self.h
deleted file mode 100644
index d56e96c40..000000000
--- a/src/lib/cert/cvc/cvc_self.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
-* CVC Self-Signed Certificate
-* (C) 2007 FlexSecure GmbH
-* 2008 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_CVC_EAC_SELF_H__
-#define BOTAN_CVC_EAC_SELF_H__
-
-#include <botan/cvc_cert.h>
-#include <botan/ecdsa.h>
-#include <botan/asn1_obj.h>
-#include <botan/cvc_req.h>
-#include <botan/cvc_ado.h>
-
-namespace Botan {
-
-/**
-* This class represents a set of options used for the creation of CVC certificates
-*/
-class BOTAN_DLL EAC1_1_CVC_Options
- {
- public:
-
- // public member variable:
- ASN1_Car car;
-
- // public member variable:
- ASN1_Chr chr;
-
- // public member variable:
- byte holder_auth_templ;
-
- // public member variable:
- ASN1_Ced ced;
-
- // public member variable:
- ASN1_Cex cex;
-
- // public member variable:
- std::string hash_alg;
- };
-
-/**
-* This namespace represents general EAC 1.1 convenience functions.
-*/
-namespace CVC_EAC {
-
-/**
-* Create a selfsigned CVCA
-* @param rng the rng to use
-* @param key the ECDSA private key to be used to sign the certificate
-* @param opts used to set several parameters. Necessary are:
-* car, holder_auth_templ, hash_alg, ced, cex and hash_alg
-* @result the self signed certificate
-*/
-
-EAC1_1_CVC BOTAN_DLL create_self_signed_cert(Private_Key const& key,
- EAC1_1_CVC_Options const& opts,
- RandomNumberGenerator& rng);
-/**
-* Create a CVC request. The key encoding will be according to the provided private key.
-* @param priv_key the private key associated with the requesting entity
-* @param chr the chr to appear in the certificate (to be provided without
-* sequence number)
-* @param hash_alg the string defining the hash algorithm to be used for the creation
-* of the signature
-* @param rng the rng to use
-* @result the new request
-*/
-EAC1_1_Req BOTAN_DLL create_cvc_req(Private_Key const& priv_key,
- ASN1_Chr const& chr,
- std::string const& hash_alg,
- RandomNumberGenerator& rng);
-
-/**
-* Create an ADO from a request object.
-* @param priv_key the private key used to sign the ADO
-* @param req the request forming the body of the ADO
-* @param car the CAR forming the body of the ADO, i.e. the
-* CHR of the entity associated with the provided private key
-* @param rng the rng to use
-*/
-EAC1_1_ADO BOTAN_DLL create_ado_req(Private_Key const& priv_key,
- EAC1_1_Req const& req,
- ASN1_Car const& car,
- RandomNumberGenerator& rng);
-}
-/**
-* This namespace represents EAC 1.1 CVC convenience functions
-* following the specific german requirements.
-*/
-
-namespace DE_EAC {
-
-/**
-* Create a CVCA certificate.
-* @param priv_key the private key associated with the CVCA certificate
-* to be created
-* @param hash the string identifying the hash algorithm to be used
-* for signing the certificate to be created
-* @param car the CAR of the certificate to be created
-* @param iris indicates whether the entity associated with the certificate
-* shall be entitled to read the biometrical iris image
-* @param fingerpr indicates whether the entity associated with the certificate
-* shall be entitled to read the biometrical fingerprint image
-* @param cvca_validity_months length of time in months this will be valid
-* @param rng a random number generator
-* @result the CVCA certificate created
-*/
-EAC1_1_CVC BOTAN_DLL create_cvca(Private_Key const& priv_key,
- std::string const& hash,
- ASN1_Car const& car,
- bool iris,
- bool fingerpr,
- u32bit cvca_validity_months,
- RandomNumberGenerator& rng);
-
-/**
-* Create a link certificate between two CVCA certificates. The key
-* encoding will be implicitCA.
-* @param signer the cvca certificate associated with the signing
-* entity
-* @param priv_key the private key associated with the signer
-* @param to_be_signed the certificate which whose CAR/CHR will be
-* the holder of the link certificate
-* @param rng a random number generator
-*/
-EAC1_1_CVC BOTAN_DLL link_cvca(EAC1_1_CVC const& signer,
- Private_Key const& priv_key,
- EAC1_1_CVC const& to_be_signed,
- RandomNumberGenerator& rng);
-
-/**
-* Create a CVC request. The key encoding will be implicitCA.
-* @param priv_key the private key associated with the requesting entity
-* @param chr the chr to appear in the certificate (to be provided without
-* sequence number)
-* @param hash_alg the string defining the hash algorithm to be used for the creation
-* of the signature
-* @param rng a random number generator
-* @result the new request
-*/
-EAC1_1_Req BOTAN_DLL create_cvc_req(Private_Key const& priv_key,
- ASN1_Chr const& chr,
- std::string const& hash_alg,
- RandomNumberGenerator& rng);
-
-/**
-* Sign a CVC request.
-* @param signer_cert the certificate of the signing entity
-* @param priv_key the private key of the signing entity
-* @param req the request to be signed
-* @param seqnr the sequence number of the certificate to be created
-* @param seqnr_len the number of digits the sequence number will be
-* encoded in
-* @param domestic indicates whether to sign a domestic or a foreign
-* certificate: set to true for domestic
-* @param dvca_validity_months validity period in months
-* @param ca_is_validity_months validity period in months
-* @param rng a random number generator
-* @result the new certificate
-*
-**/
-EAC1_1_CVC BOTAN_DLL sign_request(EAC1_1_CVC const& signer_cert,
- Private_Key const& priv_key,
- EAC1_1_Req const& req,
- u32bit seqnr,
- u32bit seqnr_len,
- bool domestic,
- u32bit dvca_validity_months,
- u32bit ca_is_validity_months,
- RandomNumberGenerator& rng);
-}
-
-}
-
-#endif
diff --git a/src/lib/cert/cvc/eac_asn_obj.h b/src/lib/cert/cvc/eac_asn_obj.h
deleted file mode 100644
index b4dcb6342..000000000
--- a/src/lib/cert/cvc/eac_asn_obj.h
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
-* EAC ASN.1 Objects
-* (C) 2007-2008 FlexSecure GmbH
-* 2008-2010 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_EAC_ASN1_OBJ_H__
-#define BOTAN_EAC_ASN1_OBJ_H__
-
-#include <botan/asn1_obj.h>
-#include <chrono>
-
-namespace Botan {
-
-/**
-* This class represents CVC EAC Time objects.
-* It only models year, month and day. Only limited sanity checks of
-* the inputted date value are performed.
-*/
-class BOTAN_DLL EAC_Time : public ASN1_Object
- {
- public:
- void encode_into(class DER_Encoder&) const;
- void decode_from(class BER_Decoder&);
-
- /**
- * Get a this objects value as a string.
- * @return date string
- */
- std::string as_string() const;
-
- /**
- * Get a this objects value as a readable formatted string.
- * @return date string
- */
- std::string readable_string() const;
-
- /**
- * Find out whether this object's values have been set.
- * @return true if this object's internal values are set
- */
- bool time_is_set() const;
-
- /**
- * Compare this to another EAC_Time object.
- * @return -1 if this object's date is earlier than
- * other, +1 in the opposite case, and 0 if both dates are
- * equal.
- */
- s32bit cmp(const EAC_Time& other) const;
-
- /**
- * Set this' value by a string value.
- * @param str a string in the format "yyyy mm dd",
- * e.g. "2007 08 01"
- */
- void set_to(const std::string& str);
-
- /**
- * Add the specified number of years to this.
- * @param years the number of years to add
- */
- void add_years(u32bit years);
-
- /**
- * Add the specified number of months to this.
- * @param months the number of months to add
- */
- void add_months(u32bit months);
-
- /**
- * Get the year value of this objects.
- * @return year value
- */
- u32bit get_year() const { return m_year; }
-
- /**
- * Get the month value of this objects.
- * @return month value
- */
- u32bit get_month() const { return m_month; }
-
- /**
- * Get the day value of this objects.
- * @return day value
- */
- u32bit get_day() const { return m_day; }
-
- EAC_Time(const std::chrono::system_clock::time_point& time,
- ASN1_Tag tag = ASN1_Tag(0));
-
- EAC_Time(const std::string& yyyy_mm_dd,
- ASN1_Tag tag = ASN1_Tag(0));
-
- EAC_Time(u32bit year, u32bit month, u32bit day,
- ASN1_Tag tag = ASN1_Tag(0));
-
- virtual ~EAC_Time() {}
- private:
- std::vector<byte> encoded_eac_time() const;
- bool passes_sanity_check() const;
- u32bit m_year, m_month, m_day;
- ASN1_Tag m_tag;
- };
-
-/**
-* This class represents CVC CEDs. Only limited sanity checks of
-* the inputted date value are performed.
-*/
-class BOTAN_DLL ASN1_Ced : public EAC_Time
- {
- public:
- /**
- * Construct a CED from a string value.
- * @param str a string in the format "yyyy mm dd",
- * e.g. "2007 08 01"
- */
- ASN1_Ced(const std::string& str = "") :
- EAC_Time(str, ASN1_Tag(37)) {}
-
- /**
- * Construct a CED from a time point
- */
- ASN1_Ced(const std::chrono::system_clock::time_point& time) :
- EAC_Time(time, ASN1_Tag(37)) {}
-
- /**
- * Copy constructor (for general EAC_Time objects).
- * @param other the object to copy from
- */
- ASN1_Ced(const EAC_Time& other) :
- EAC_Time(other.get_year(), other.get_month(), other.get_day(),
- ASN1_Tag(37))
- {}
- };
-
-/**
-* This class represents CVC CEXs. Only limited sanity checks of
-* the inputted date value are performed.
-*/
-class BOTAN_DLL ASN1_Cex : public EAC_Time
- {
- public:
- /**
- * Construct a CEX from a string value.
- * @param str a string in the format "yyyy mm dd",
- * e.g. "2007 08 01"
- */
- ASN1_Cex(const std::string& str = "") :
- EAC_Time(str, ASN1_Tag(36)) {}
-
- ASN1_Cex(const std::chrono::system_clock::time_point& time) :
- EAC_Time(time, ASN1_Tag(36)) {}
-
- ASN1_Cex(const EAC_Time& other) :
- EAC_Time(other.get_year(), other.get_month(), other.get_day(),
- ASN1_Tag(36))
- {}
- };
-
-/**
-* Base class for car/chr of cv certificates.
-*/
-class BOTAN_DLL ASN1_EAC_String: public ASN1_Object
- {
- public:
- void encode_into(class DER_Encoder&) const;
- void decode_from(class BER_Decoder&);
-
- /**
- * Get this objects string value.
- * @return string value
- */
- std::string value() const;
-
- /**
- * Get this objects string value.
- * @return string value in iso8859 encoding
- */
- std::string iso_8859() const;
-
- ASN1_Tag tagging() const;
- ASN1_EAC_String(const std::string& str, ASN1_Tag the_tag);
-
- virtual ~ASN1_EAC_String() {}
- protected:
- bool sanity_check() const;
- private:
- std::string m_iso_8859_str;
- ASN1_Tag m_tag;
- };
-
-/**
-* This class represents CARs of CVCs. (String tagged with 2)
-*/
-class BOTAN_DLL ASN1_Car : public ASN1_EAC_String
- {
- public:
- /**
- * Create a CAR with the specified content.
- * @param str the CAR value
- */
- ASN1_Car(std::string const& str = "");
- };
-
-/**
-* This class represents CHRs of CVCs (tag 32)
-*/
-class BOTAN_DLL ASN1_Chr : public ASN1_EAC_String
- {
- public:
- /**
- * Create a CHR with the specified content.
- * @param str the CHR value
- */
- ASN1_Chr(std::string const& str = "");
- };
-
-/*
-* Comparison Operations
-*/
-bool BOTAN_DLL operator==(const EAC_Time&, const EAC_Time&);
-bool BOTAN_DLL operator!=(const EAC_Time&, const EAC_Time&);
-bool BOTAN_DLL operator<=(const EAC_Time&, const EAC_Time&);
-bool BOTAN_DLL operator>=(const EAC_Time&, const EAC_Time&);
-bool BOTAN_DLL operator>(const EAC_Time&, const EAC_Time&);
-bool BOTAN_DLL operator<(const EAC_Time&, const EAC_Time&);
-
-bool BOTAN_DLL operator==(const ASN1_EAC_String&, const ASN1_EAC_String&);
-inline bool operator!=(const ASN1_EAC_String& lhs, const ASN1_EAC_String& rhs)
- {
- return !(lhs == rhs);
- }
-
-}
-
-#endif
diff --git a/src/lib/cert/cvc/eac_obj.h b/src/lib/cert/cvc/eac_obj.h
deleted file mode 100644
index a6e676076..000000000
--- a/src/lib/cert/cvc/eac_obj.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-* EAC1_1 objects
-* (C) 2008 Falko Strenzke
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_EAC_OBJ_H__
-#define BOTAN_EAC_OBJ_H__
-
-#include <botan/signed_obj.h>
-#include <botan/ecdsa_sig.h>
-
-namespace Botan {
-
-/**
-* TR03110 v1.1 EAC CV Certificate
-*/
-template<typename Derived> // CRTP is used enable the call sequence:
-class EAC1_1_obj : public EAC_Signed_Object
- {
- public:
- /**
- * Return the signature as a concatenation of the encoded parts.
- * @result the concatenated signature
- */
- std::vector<byte> get_concat_sig() const
- { return m_sig.get_concatenation(); }
-
- bool check_signature(class Public_Key& key) const
- {
- return EAC_Signed_Object::check_signature(key, m_sig.DER_encode());
- }
-
- protected:
- ECDSA_Signature m_sig;
-
- void init(DataSource& in)
- {
- try
- {
- Derived::decode_info(in, m_tbs_bits, m_sig);
- }
- catch(Decoding_Error)
- {
- throw Decoding_Error(m_PEM_label_pref + " decoding failed");
- }
- }
-
- virtual ~EAC1_1_obj<Derived>(){}
- };
-
-}
-
-#endif
diff --git a/src/lib/cert/cvc/ecdsa_sig.cpp b/src/lib/cert/cvc/ecdsa_sig.cpp
deleted file mode 100644
index 5e85d7932..000000000
--- a/src/lib/cert/cvc/ecdsa_sig.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-* ECDSA Signature
-* (C) 2007 Falko Strenzke, FlexSecure GmbH
-* (C) 2008-2010 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/ecdsa_sig.h>
-
-namespace Botan {
-
-ECDSA_Signature::ECDSA_Signature(const std::vector<byte>& ber)
- {
- BER_Decoder(ber)
- .start_cons(SEQUENCE)
- .decode(m_r)
- .decode(m_s)
- .end_cons()
- .verify_end();
- }
-
-std::vector<byte> ECDSA_Signature::DER_encode() const
- {
- return DER_Encoder()
- .start_cons(SEQUENCE)
- .encode(get_r())
- .encode(get_s())
- .end_cons()
- .get_contents_unlocked();
- }
-
-std::vector<byte> ECDSA_Signature::get_concatenation() const
- {
- // use the larger
- const size_t enc_len = m_r > m_s ? m_r.bytes() : m_s.bytes();
-
- const auto sv_r = BigInt::encode_1363(m_r, enc_len);
- const auto sv_s = BigInt::encode_1363(m_s, enc_len);
-
- secure_vector<byte> result(sv_r);
- result += sv_s;
- return unlock(result);
- }
-
-ECDSA_Signature decode_concatenation(const std::vector<byte>& concat)
- {
- if(concat.size() % 2 != 0)
- throw Invalid_Argument("Erroneous length of signature");
-
- const size_t rs_len = concat.size() / 2;
-
- BigInt r = BigInt::decode(&concat[0], rs_len);
- BigInt s = BigInt::decode(&concat[rs_len], rs_len);
-
- return ECDSA_Signature(r, s);
- }
-
-}
diff --git a/src/lib/cert/cvc/ecdsa_sig.h b/src/lib/cert/cvc/ecdsa_sig.h
deleted file mode 100644
index 2845cbec9..000000000
--- a/src/lib/cert/cvc/ecdsa_sig.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-* ECDSA Signature
-* (C) 2007 Falko Strenzke, FlexSecure GmbH
-* (C) 2008-2010 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_ECDSA_SIGNATURE_H__
-#define BOTAN_ECDSA_SIGNATURE_H__
-
-#include <botan/bigint.h>
-#include <botan/der_enc.h>
-#include <botan/ber_dec.h>
-
-namespace Botan {
-
-/**
-* Class representing an ECDSA signature
-*/
-class BOTAN_DLL ECDSA_Signature
- {
- public:
- friend class ECDSA_Signature_Decoder;
-
- ECDSA_Signature() {}
- ECDSA_Signature(const BigInt& r, const BigInt& s) :
- m_r(r), m_s(s) {}
-
- ECDSA_Signature(const std::vector<byte>& ber);
-
- const BigInt& get_r() const { return m_r; }
- const BigInt& get_s() const { return m_s; }
-
- /**
- * return the r||s
- */
- std::vector<byte> get_concatenation() const;
-
- std::vector<byte> DER_encode() const;
-
- bool operator==(const ECDSA_Signature& other) const
- {
- return (get_r() == other.get_r() && get_s() == other.get_s());
- }
-
- private:
- BigInt m_r;
- BigInt m_s;
- };
-
-inline bool operator!=(const ECDSA_Signature& lhs, const ECDSA_Signature& rhs)
- {
- return !(lhs == rhs);
- }
-
-ECDSA_Signature decode_concatenation(const std::vector<byte>& concatenation);
-
-}
-
-#endif
diff --git a/src/lib/cert/cvc/info.txt b/src/lib/cert/cvc/info.txt
deleted file mode 100644
index e3da5435e..000000000
--- a/src/lib/cert/cvc/info.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-define CARD_VERIFIABLE_CERTIFICATES 20131128
-load_on request
-
-<header:public>
-cvc_ado.h
-cvc_cert.h
-cvc_gen_cert.h
-cvc_req.h
-cvc_self.h
-eac_asn_obj.h
-eac_obj.h
-ecdsa_sig.h
-signed_obj.h
-</header:public>
-
-<source>
-asn1_eac_str.cpp
-asn1_eac_tm.cpp
-ecdsa_sig.cpp
-cvc_ado.cpp
-cvc_cert.cpp
-cvc_req.cpp
-cvc_self.cpp
-signed_obj.cpp
-</source>
-
-<requires>
-asn1
-bigint
-ecdsa
-filters
-oid_lookup
-pem
-pubkey
-</requires>
diff --git a/src/lib/cert/cvc/signed_obj.cpp b/src/lib/cert/cvc/signed_obj.cpp
deleted file mode 100644
index 1e3849663..000000000
--- a/src/lib/cert/cvc/signed_obj.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
-* EAC SIGNED Object
-* (C) 1999-2010 Jack Lloyd
-* 2007 FlexSecure GmbH
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/signed_obj.h>
-#include <botan/pubkey.h>
-#include <botan/oids.h>
-
-namespace Botan {
-
-/*
-* Return a BER encoded X.509 object
-*/
-std::vector<byte> EAC_Signed_Object::BER_encode() const
- {
- Pipe ber;
- ber.start_msg();
- encode(ber, RAW_BER);
- ber.end_msg();
- return unlock(ber.read_all());
- }
-
-/*
-* Return a PEM encoded X.509 object
-*/
-std::string EAC_Signed_Object::PEM_encode() const
- {
- Pipe pem;
- pem.start_msg();
- encode(pem, PEM);
- pem.end_msg();
- return pem.read_all_as_string();
- }
-
-/*
-* Return the algorithm used to sign this object
-*/
-AlgorithmIdentifier EAC_Signed_Object::signature_algorithm() const
- {
- return m_sig_algo;
- }
-
-bool EAC_Signed_Object::check_signature(Public_Key& pub_key,
- const std::vector<byte>& sig) const
- {
- try
- {
- std::vector<std::string> sig_info =
- split_on(OIDS::lookup(m_sig_algo.oid), '/');
-
- if(sig_info.size() != 2 || sig_info[0] != pub_key.algo_name())
- {
- return false;
- }
-
- std::string padding = sig_info[1];
- Signature_Format format =
- (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363;
-
- std::vector<byte> to_sign = tbs_data();
-
- PK_Verifier verifier(pub_key, padding, format);
- return verifier.verify_message(to_sign, sig);
- }
- catch(...)
- {
- return false;
- }
- }
-
-/*
-* Try to decode the actual information
-*/
-void EAC_Signed_Object::do_decode()
- {
- try {
- force_decode();
- }
- catch(Decoding_Error& e)
- {
- const std::string what = e.what();
- throw Decoding_Error(m_PEM_label_pref + " decoding failed (" + what + ")");
- }
- catch(Invalid_Argument& e)
- {
- const std::string what = e.what();
- throw Decoding_Error(m_PEM_label_pref + " decoding failed (" + what + ")");
- }
- }
-
-}
diff --git a/src/lib/cert/cvc/signed_obj.h b/src/lib/cert/cvc/signed_obj.h
deleted file mode 100644
index b3fe20f31..000000000
--- a/src/lib/cert/cvc/signed_obj.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
-* EAC SIGNED Object
-* (C) 2007 FlexSecure GmbH
-* 2008 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_EAC_SIGNED_OBJECT_H__
-#define BOTAN_EAC_SIGNED_OBJECT_H__
-
-#include <botan/asn1_obj.h>
-#include <botan/x509_key.h>
-#include <botan/pipe.h>
-#include <vector>
-
-namespace Botan {
-
-/**
-* This class represents abstract signed EAC object
-*/
-class BOTAN_DLL EAC_Signed_Object
- {
- public:
- /**
- * Get the TBS (to-be-signed) data in this object.
- * @return DER encoded TBS data of this object
- */
- virtual std::vector<byte> tbs_data() const = 0;
-
- /**
- * Get the signature of this object as a concatenation, i.e. if the
- * signature consists of multiple parts (like in the case of ECDSA)
- * these will be concatenated.
- * @return signature as a concatenation of its parts
- */
-
- /*
- NOTE: this is here only because abstract signature objects have
- not yet been introduced
- */
- virtual std::vector<byte> get_concat_sig() const = 0;
-
- /**
- * Get the signature algorithm identifier used to sign this object.
- * @result the signature algorithm identifier
- */
- AlgorithmIdentifier signature_algorithm() const;
-
- /**
- * Check the signature of this object.
- * @param key the public key associated with this signed object
- * @param sig the signature we are checking
- * @return true if the signature was created by the private key
- * associated with this public key
- */
- bool check_signature(class Public_Key& key,
- const std::vector<byte>& sig) const;
-
- /**
- * Write this object DER encoded into a specified pipe.
- * @param pipe the pipe to write the encoded object to
- * @param encoding the encoding type to use
- */
- virtual void encode(Pipe& pipe,
- X509_Encoding encoding = PEM) const = 0;
-
- /**
- * BER encode this object.
- * @return result containing the BER representation of this object.
- */
- std::vector<byte> BER_encode() const;
-
- /**
- * PEM encode this object.
- * @return result containing the PEM representation of this object.
- */
- std::string PEM_encode() const;
-
- virtual ~EAC_Signed_Object() {}
- protected:
- void do_decode();
- EAC_Signed_Object() {}
-
- AlgorithmIdentifier m_sig_algo;
- std::vector<byte> m_tbs_bits;
- std::string m_PEM_label_pref;
- std::vector<std::string> m_PEM_labels_allowed;
- private:
- virtual void force_decode() = 0;
- };
-
-}
-
-#endif
diff --git a/src/lib/cert/x509/key_constraint.cpp b/src/lib/cert/x509/key_constraint.cpp
index 24791b34a..a90af013c 100644
--- a/src/lib/cert/x509/key_constraint.cpp
+++ b/src/lib/cert/x509/key_constraint.cpp
@@ -1,69 +1,46 @@
/*
* KeyUsage
* (C) 1999-2007 Jack Lloyd
+* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/key_constraint.h>
#include <botan/x509_key.h>
-#include <botan/ber_dec.h>
namespace Botan {
-namespace BER {
-
-/*
-* Decode a BER encoded KeyUsage
-*/
-void decode(BER_Decoder& source, Key_Constraints& key_usage)
- {
- BER_Object obj = source.get_next_object();
-
- if(obj.type_tag != BIT_STRING || obj.class_tag != UNIVERSAL)
- throw BER_Bad_Tag("Bad tag for usage constraint",
- obj.type_tag, obj.class_tag);
- if(obj.value.size() != 2 && obj.value.size() != 3)
- throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint");
- if(obj.value[0] >= 8)
- throw BER_Decoding_Error("Invalid unused bits in usage constraint");
-
- const byte mask = (0xFF << obj.value[0]);
- obj.value[obj.value.size()-1] &= mask;
-
- u16bit usage = 0;
- for(size_t j = 1; j != obj.value.size(); ++j)
- usage = (obj.value[j] << 8) | usage;
-
- key_usage = Key_Constraints(usage);
- }
-
-}
-
/*
-* Find the allowable key constraints
+* Make sure the given key constraints are permitted for the given key type
*/
-Key_Constraints find_constraints(const Public_Key& pub_key,
- Key_Constraints limits)
+void verify_cert_constraints_valid_for_key_type(const Public_Key& pub_key,
+ Key_Constraints constraints)
{
const std::string name = pub_key.algo_name();
- size_t constraints = 0;
+ size_t permitted = 0;
if(name == "DH" || name == "ECDH")
- constraints |= KEY_AGREEMENT;
+ {
+ permitted |= KEY_AGREEMENT | ENCIPHER_ONLY | DECIPHER_ONLY;
+ }
if(name == "RSA" || name == "ElGamal")
- constraints |= KEY_ENCIPHERMENT | DATA_ENCIPHERMENT;
+ {
+ permitted |= KEY_ENCIPHERMENT | DATA_ENCIPHERMENT;
+ }
if(name == "RSA" || name == "RW" || name == "NR" ||
- name == "DSA" || name == "ECDSA")
- constraints |= DIGITAL_SIGNATURE | NON_REPUDIATION;
-
- if(limits)
- constraints &= limits;
-
- return Key_Constraints(constraints);
+ name == "DSA" || name == "ECDSA" || name == "ECGDSA" || name == "ECKCDSA")
+ {
+ permitted |= DIGITAL_SIGNATURE | NON_REPUDIATION | KEY_CERT_SIGN | CRL_SIGN;
+ }
+
+ if ( ( constraints & permitted ) != constraints )
+ {
+ throw Exception("Constraint not permitted for key type " + name);
+ }
}
}
diff --git a/src/lib/cert/x509/key_constraint.h b/src/lib/cert/x509/key_constraint.h
index 179e413b5..b67eb7010 100644
--- a/src/lib/cert/x509/key_constraint.h
+++ b/src/lib/cert/x509/key_constraint.h
@@ -1,6 +1,7 @@
/*
* Enumerations
* (C) 1999-2007 Jack Lloyd
+* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -8,7 +9,7 @@
#ifndef BOTAN_ENUMS_H__
#define BOTAN_ENUMS_H__
-#include <botan/ber_dec.h>
+#include <botan/build.h>
namespace Botan {
@@ -32,26 +33,13 @@ enum Key_Constraints {
class Public_Key;
/**
-* Create the key constraints for a specific public key.
-* @param pub_key the public key from which the basic set of
-* constraints to be placed in the return value is derived
-* @param limits additional limits that will be incorporated into the
-* return value
-* @return combination of key type specific constraints and
-* additional limits
+* Check that key constraints are permitted for a specific public key.
+* @param pub_key the public key on which the constraints shall be enforced on
+* @param constrains the constraints that shall be enforced on the key
+* @throw Exception if the given constraints are not permitted for this key
*/
-
-BOTAN_DLL Key_Constraints find_constraints(const Public_Key& pub_key,
- Key_Constraints limits);
-
-/**
-* BER Decoding Function for key constraints
-*/
-namespace BER {
-
-void BOTAN_DLL decode(BER_Decoder&, Key_Constraints&);
-
-}
+BOTAN_DLL void verify_cert_constraints_valid_for_key_type(const Public_Key& pub_key,
+ Key_Constraints constraints);
}
diff --git a/src/lib/cert/x509/name_constraint.cpp b/src/lib/cert/x509/name_constraint.cpp
index a1ed19856..83f6386ba 100644
--- a/src/lib/cert/x509/name_constraint.cpp
+++ b/src/lib/cert/x509/name_constraint.cpp
@@ -33,7 +33,7 @@ GeneralName::GeneralName(const std::string& v) : GeneralName()
void GeneralName::encode_into(class DER_Encoder&) const
{
- throw Exception("General Name encoding not implemented");
+ throw Not_Implemented("GeneralName encoding");
}
void GeneralName::decode_from(class BER_Decoder& ber)
@@ -249,7 +249,7 @@ GeneralSubtree::GeneralSubtree(const std::string& v) : GeneralSubtree()
void GeneralSubtree::encode_into(class DER_Encoder&) const
{
- throw std::runtime_error("General Subtree encoding not implemented");
+ throw Not_Implemented("General Subtree encoding");
}
void GeneralSubtree::decode_from(class BER_Decoder& ber)
diff --git a/src/lib/cert/x509/ocsp.cpp b/src/lib/cert/x509/ocsp.cpp
index 4f4a3aece..df8df3b39 100644
--- a/src/lib/cert/x509/ocsp.cpp
+++ b/src/lib/cert/x509/ocsp.cpp
@@ -81,7 +81,7 @@ void check_signature(const std::vector<byte>& tbs_response,
// Otherwise attempt to chain the signing cert to a trust root
- if(!certs[0].allowed_usage("PKIX.OCSPSigning"))
+ if(!certs[0].allowed_extended_usage("PKIX.OCSPSigning"))
throw Exception("OCSP response cert does not allow OCSP signing");
auto result = x509_path_validate(certs, Path_Validation_Restrictions(), trusted_roots);
diff --git a/src/lib/cert/x509/ocsp_types.cpp b/src/lib/cert/x509/ocsp_types.cpp
index ba5b825f7..d470c2fa1 100644
--- a/src/lib/cert/x509/ocsp_types.cpp
+++ b/src/lib/cert/x509/ocsp_types.cpp
@@ -92,7 +92,7 @@ void CertID::decode_from(class BER_Decoder& from)
void SingleResponse::encode_into(class DER_Encoder&) const
{
- throw Exception("Not implemented (SingleResponse::encode_into)");
+ throw Not_Implemented("SingleResponse::encode_into");
}
void SingleResponse::decode_from(class BER_Decoder& from)
diff --git a/src/lib/cert/x509/x509_ca.cpp b/src/lib/cert/x509/x509_ca.cpp
index 46c8c65f2..58c6676f4 100644
--- a/src/lib/cert/x509/x509_ca.cpp
+++ b/src/lib/cert/x509/x509_ca.cpp
@@ -52,11 +52,14 @@ X509_Certificate X509_CA::sign_request(const PKCS10_Request& req,
{
Key_Constraints constraints;
if(req.is_CA())
+ {
constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN);
+ }
else
{
std::unique_ptr<Public_Key> key(req.subject_public_key());
- constraints = find_constraints(*key, req.constraints());
+ verify_cert_constraints_valid_for_key_type(*key, req.constraints());
+ constraints = req.constraints();
}
Extensions extensions;
@@ -65,7 +68,10 @@ X509_Certificate X509_CA::sign_request(const PKCS10_Request& req,
new Cert_Extension::Basic_Constraints(req.is_CA(), req.path_limit()),
true);
- extensions.add(new Cert_Extension::Key_Usage(constraints), true);
+ if(constraints != NO_CONSTRAINTS)
+ {
+ extensions.add(new Cert_Extension::Key_Usage(constraints), true);
+ }
extensions.add(new Cert_Extension::Authority_Key_ID(m_cert.subject_key_id()));
extensions.add(new Cert_Extension::Subject_Key_ID(req.raw_public_key()));
@@ -233,13 +239,17 @@ PK_Signer* choose_sig_format(const Private_Key& key,
std::string padding;
if(algo_name == "RSA")
+ {
padding = "EMSA3";
- else if(algo_name == "DSA")
+ }
+ else if(algo_name == "DSA" || algo_name == "ECDSA" || algo_name == "ECGDSA" || algo_name == "ECKCDSA")
+ {
padding = "EMSA1";
- else if(algo_name == "ECDSA")
- padding = "EMSA1_BSI";
+ }
else
+ {
throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name);
+ }
const Signature_Format format = (key.message_parts() > 1) ? DER_SEQUENCE : IEEE_1363;
diff --git a/src/lib/cert/x509/x509_ca.h b/src/lib/cert/x509/x509_ca.h
index 6ea51cd06..ba3724f5e 100644
--- a/src/lib/cert/x509/x509_ca.h
+++ b/src/lib/cert/x509/x509_ca.h
@@ -22,7 +22,6 @@ namespace Botan {
class BOTAN_DLL X509_CA
{
public:
-
/**
* Sign a PKCS#10 Request.
* @param req the request to sign
diff --git a/src/lib/cert/x509/x509_ext.cpp b/src/lib/cert/x509/x509_ext.cpp
index 85d40bf21..650c20d53 100644
--- a/src/lib/cert/x509/x509_ext.cpp
+++ b/src/lib/cert/x509/x509_ext.cpp
@@ -1,6 +1,7 @@
/*
* X.509 Certificate Extensions
* (C) 1999-2010,2012 Jack Lloyd
+* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -293,7 +294,9 @@ void Key_Usage::decode_inner(const std::vector<byte>& in)
u16bit usage = 0;
for(size_t i = 1; i != obj.value.size(); ++i)
- usage = (obj.value[i] << 8) | usage;
+ {
+ usage = (obj.value[i] << 8*(sizeof(usage)-i)) | usage;
+ }
m_constraints = Key_Constraints(usage);
}
@@ -461,7 +464,7 @@ void Extended_Key_Usage::contents_to(Data_Store& subject, Data_Store&) const
*/
std::vector<byte> Name_Constraints::encode_inner() const
{
- throw std::runtime_error("Name_Constraints encoding not implemented");
+ throw Not_Implemented("Name_Constraints encoding");
}
@@ -777,7 +780,7 @@ void CRL_ReasonCode::contents_to(Data_Store& info, Data_Store&) const
std::vector<byte> CRL_Distribution_Points::encode_inner() const
{
- throw Exception("CRL_Distribution_Points encoding not implemented");
+ throw Not_Implemented("CRL_Distribution_Points encoding");
}
void CRL_Distribution_Points::decode_inner(const std::vector<byte>& buf)
@@ -800,7 +803,7 @@ void CRL_Distribution_Points::contents_to(Data_Store& info, Data_Store&) const
void CRL_Distribution_Points::Distribution_Point::encode_into(class DER_Encoder&) const
{
- throw Exception("CRL_Distribution_Points encoding not implemented");
+ throw Not_Implemented("CRL_Distribution_Points encoding");
}
void CRL_Distribution_Points::Distribution_Point::decode_from(class BER_Decoder& ber)
@@ -815,16 +818,15 @@ void CRL_Distribution_Points::Distribution_Point::decode_from(class BER_Decoder&
std::vector<byte> Unknown_Critical_Extension::encode_inner() const
{
- throw Exception("Unknown_Critical_Extension encoding not implemented");
+ throw Not_Implemented("Unknown_Critical_Extension encoding");
}
-void Unknown_Critical_Extension::decode_inner(const std::vector<byte>& buf)
+void Unknown_Critical_Extension::decode_inner(const std::vector<byte>&)
{
}
-void Unknown_Critical_Extension::contents_to(Data_Store& info, Data_Store&) const
+void Unknown_Critical_Extension::contents_to(Data_Store&, Data_Store&) const
{
- // TODO: textual representation?
}
}
diff --git a/src/lib/cert/x509/x509cert.cpp b/src/lib/cert/x509/x509cert.cpp
index d7da00af0..ffedf43f0 100644
--- a/src/lib/cert/x509/x509cert.cpp
+++ b/src/lib/cert/x509/x509cert.cpp
@@ -1,6 +1,7 @@
/*
* X.509 Certificates
* (C) 1999-2010,2015 Jack Lloyd
+* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -257,10 +258,10 @@ bool X509_Certificate::allowed_usage(Key_Constraints usage) const
{
if(constraints() == NO_CONSTRAINTS)
return true;
- return ((constraints() & usage) != 0);
+ return ((constraints() & usage) == usage);
}
-bool X509_Certificate::allowed_usage(const std::string& usage) const
+bool X509_Certificate::allowed_extended_usage(const std::string& usage) const
{
const std::vector<std::string> ex = ex_constraints();
@@ -275,19 +276,21 @@ bool X509_Certificate::allowed_usage(const std::string& usage) const
bool X509_Certificate::allowed_usage(Usage_Type usage) const
{
+ // These follow suggestions in RFC 5280 4.2.1.12
+
switch(usage)
{
case Usage_Type::UNSPECIFIED:
return true;
case Usage_Type::TLS_SERVER_AUTH:
- return allowed_usage(Key_Constraints(DATA_ENCIPHERMENT | KEY_ENCIPHERMENT | DIGITAL_SIGNATURE)) && allowed_usage("PKIX.ServerAuth");
+ return (allowed_usage(KEY_AGREEMENT) || allowed_usage(KEY_ENCIPHERMENT) || allowed_usage(DIGITAL_SIGNATURE)) && allowed_extended_usage("PKIX.ServerAuth");
case Usage_Type::TLS_CLIENT_AUTH:
- return allowed_usage(Key_Constraints(DIGITAL_SIGNATURE | NON_REPUDIATION)) && allowed_usage("PKIX.ClientAuth");
+ return (allowed_usage(DIGITAL_SIGNATURE) || allowed_usage(KEY_AGREEMENT)) && allowed_extended_usage("PKIX.ClientAuth");
case Usage_Type::OCSP_RESPONDER:
- return allowed_usage(Key_Constraints(DIGITAL_SIGNATURE | NON_REPUDIATION)) && allowed_usage("PKIX.OCSPSigning");
+ return (allowed_usage(DIGITAL_SIGNATURE) || allowed_usage(NON_REPUDIATION)) && allowed_extended_usage("PKIX.OCSPSigning");
case Usage_Type::CERTIFICATE_AUTHORITY:
return is_CA_cert();
@@ -296,6 +299,33 @@ bool X509_Certificate::allowed_usage(Usage_Type usage) const
return false;
}
+bool X509_Certificate::has_constraints(Key_Constraints constraints) const
+ {
+ if(this->constraints() == NO_CONSTRAINTS)
+ {
+ return false;
+ }
+
+ return ((this->constraints() & constraints) != 0);
+ }
+
+bool X509_Certificate::has_ex_constraint(const std::string& ex_constraint) const
+ {
+ const std::vector<std::string> ex = ex_constraints();
+
+ if(ex.empty())
+ {
+ return false;
+ }
+
+ if(std::find(ex.begin(), ex.end(), ex_constraint) != ex.end())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
/*
* Return the path length constraint
*/
@@ -538,7 +568,7 @@ std::string X509_Certificate::to_string() const
if(constraints & DIGITAL_SIGNATURE)
out << " Digital Signature\n";
if(constraints & NON_REPUDIATION)
- out << " Non-Repuidation\n";
+ out << " Non-Repudiation\n";
if(constraints & KEY_ENCIPHERMENT)
out << " Key Encipherment\n";
if(constraints & DATA_ENCIPHERMENT)
@@ -549,6 +579,10 @@ std::string X509_Certificate::to_string() const
out << " Cert Sign\n";
if(constraints & CRL_SIGN)
out << " CRL Sign\n";
+ if(constraints & ENCIPHER_ONLY)
+ out << " Encipher Only\n";
+ if(constraints & DECIPHER_ONLY)
+ out << " Decipher Only\n";
}
std::vector<std::string> policies = this->policies();
diff --git a/src/lib/cert/x509/x509cert.h b/src/lib/cert/x509/x509cert.h
index c521cf7ca..eb98f9c3d 100644
--- a/src/lib/cert/x509/x509cert.h
+++ b/src/lib/cert/x509/x509cert.h
@@ -33,7 +33,7 @@ enum class Usage_Type
/**
* This class represents X.509 Certificate
*/
-class BOTAN_DLL X509_Certificate final : public X509_Object
+class BOTAN_DLL X509_Certificate : public X509_Object
{
public:
/**
@@ -140,17 +140,39 @@ class BOTAN_DLL X509_Certificate final : public X509_Object
*/
bool is_CA_cert() const;
+ /**
+ * Returns true if the specified @param usage is set in the key usage extension
+ * or if no key usage constraints are set at all.
+ * To check if a certain key constraint is set in the certificate
+ * use @see X509_Certificate#has_constraints.
+ */
bool allowed_usage(Key_Constraints usage) const;
/**
- * Returns true if and only if name (referring to an extended key
- * constraint, eg "PKIX.ServerAuth") is included in the extended
- * key extension.
+ * Returns true if the specified @param usage is set in the extended key usage extension
+ * or if no extended key usage constraints are set at all.
+ * To check if a certain extended key constraint is set in the certificate
+ * use @see X509_Certificate#has_ex_constraint.
*/
- bool allowed_usage(const std::string& usage) const;
+ bool allowed_extended_usage(const std::string& usage) const;
+ /**
+ * Returns true if the required key and extended key constraints are set in the certificate
+ * for the specified @param usage or if no key constraints are set in both the key usage
+ * and extended key usage extension.
+ */
bool allowed_usage(Usage_Type usage) const;
+ /// Returns true if the specified @param constraints are included in the key usage extension.
+ bool has_constraints(Key_Constraints constraints) const;
+
+ /**
+ * Returns true if and only if @param ex_constraint (referring to an extended key
+ * constraint, eg "PKIX.ServerAuth") is included in the extended
+ * key extension.
+ */
+ bool has_ex_constraint(const std::string& ex_constraint) const;
+
/**
* Get the path limit as defined in the BasicConstraints extension of
* this certificate.
diff --git a/src/lib/cert/x509/x509opt.cpp b/src/lib/cert/x509/x509opt.cpp
index 158f4c779..2dd2098fe 100644
--- a/src/lib/cert/x509/x509opt.cpp
+++ b/src/lib/cert/x509/x509opt.cpp
@@ -62,19 +62,6 @@ void X509_Cert_Options::CA_key(size_t limit)
}
/*
-* Do basic sanity checks
-*/
-void X509_Cert_Options::sanity_check() const
- {
- if(common_name.empty() || country.empty())
- throw Encoding_Error("X.509 certificate: name and country MUST be set");
- if(country.size() != 2)
- throw Encoding_Error("Invalid ISO country code: " + country);
- if(start >= end)
- throw Encoding_Error("X509_Cert_Options: invalid time constraints");
- }
-
-/*
* Initialize the certificate options
*/
X509_Cert_Options::X509_Cert_Options(const std::string& initial_opts,
diff --git a/src/lib/cert/x509/x509self.cpp b/src/lib/cert/x509/x509self.cpp
index 7d1c01c37..102e24f77 100644
--- a/src/lib/cert/x509/x509self.cpp
+++ b/src/lib/cert/x509/x509self.cpp
@@ -49,17 +49,20 @@ X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts,
X509_DN subject_dn;
AlternativeName subject_alt;
- opts.sanity_check();
-
std::vector<byte> pub_key = X509::BER_encode(key);
std::unique_ptr<PK_Signer> signer(choose_sig_format(key, hash_fn, sig_algo));
load_info(opts, subject_dn, subject_alt);
Key_Constraints constraints;
if(opts.is_CA)
+ {
constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN);
+ }
else
- constraints = find_constraints(key, opts.constraints);
+ {
+ verify_cert_constraints_valid_for_key_type(key, opts.constraints);
+ constraints = opts.constraints;
+ }
Extensions extensions;
@@ -67,7 +70,10 @@ X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts,
new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit),
true);
- extensions.add(new Cert_Extension::Key_Usage(constraints), true);
+ if(constraints != NO_CONSTRAINTS)
+ {
+ extensions.add(new Cert_Extension::Key_Usage(constraints), true);
+ }
extensions.add(new Cert_Extension::Subject_Key_ID(pub_key));
@@ -95,24 +101,33 @@ PKCS10_Request create_cert_req(const X509_Cert_Options& opts,
X509_DN subject_dn;
AlternativeName subject_alt;
- opts.sanity_check();
-
std::vector<byte> pub_key = X509::BER_encode(key);
std::unique_ptr<PK_Signer> signer(choose_sig_format(key, hash_fn, sig_algo));
load_info(opts, subject_dn, subject_alt);
const size_t PKCS10_VERSION = 0;
+ Key_Constraints constraints;
+ if(opts.is_CA)
+ {
+ constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN);
+ }
+ else
+ {
+ verify_cert_constraints_valid_for_key_type(key, opts.constraints);
+ constraints = opts.constraints;
+ }
+
Extensions extensions;
extensions.add(
new Cert_Extension::Basic_Constraints(opts.is_CA, opts.path_limit));
- extensions.add(
- new Cert_Extension::Key_Usage(
- opts.is_CA ? Key_Constraints(KEY_CERT_SIGN | CRL_SIGN) :
- find_constraints(key, opts.constraints)
- )
- );
+
+ if(constraints != NO_CONSTRAINTS)
+ {
+ extensions.add(
+ new Cert_Extension::Key_Usage(constraints));
+ }
extensions.add(
new Cert_Extension::Extended_Key_Usage(opts.ex_constraints));
extensions.add(
diff --git a/src/lib/cert/x509/x509self.h b/src/lib/cert/x509/x509self.h
index a4bbad214..401b2eb2f 100644
--- a/src/lib/cert/x509/x509self.h
+++ b/src/lib/cert/x509/x509self.h
@@ -115,11 +115,6 @@ class BOTAN_DLL X509_Cert_Options
std::vector<OID> ex_constraints;
/**
- * Check the options set in this object for validity.
- */
- void sanity_check() const;
-
- /**
* Mark the certificate as a CA certificate and set the path limit.
* @param limit the path limit to be set in the BasicConstraints extension.
*/
diff --git a/src/lib/entropy/beos_stats/es_beos.cpp b/src/lib/entropy/beos_stats/es_beos.cpp
index aa0e257a9..907ca37bb 100644
--- a/src/lib/entropy/beos_stats/es_beos.cpp
+++ b/src/lib/entropy/beos_stats/es_beos.cpp
@@ -16,48 +16,51 @@ namespace Botan {
/**
* BeOS entropy poll
*/
-void BeOS_EntropySource::poll(Entropy_Accumulator& accum)
+size_t BeOS_EntropySource::poll(RandomNumberGenerator& rng)
{
+ size_t bits = 0;
+
system_info info_sys;
get_system_info(&info_sys);
- accum.add(info_sys, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ rng.add_entropy_T(info_sys);
key_info info_key; // current state of the keyboard
get_key_info(&info_key);
- accum.add(info_key, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ rng.add_entropy_T(info_key);
team_info info_team;
int32 cookie_team = 0;
while(get_next_team_info(&cookie_team, &info_team) == B_OK)
{
- accum.add(info_team, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ rng.add_entropy_T(info_team);
team_id id = info_team.team;
int32 cookie = 0;
thread_info info_thr;
while(get_next_thread_info(id, &cookie, &info_thr) == B_OK)
- accum.add(info_thr, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ rng.add_entropy_T(info_thr);
cookie = 0;
image_info info_img;
while(get_next_image_info(id, &cookie, &info_img) == B_OK)
- accum.add(info_img, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ rng.add_entropy_T(info_img);
cookie = 0;
sem_info info_sem;
while(get_next_sem_info(id, &cookie, &info_sem) == B_OK)
- accum.add(info_sem, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ rng.add_entropy_T(info_sem);
cookie = 0;
area_info info_area;
while(get_next_area_info(id, &cookie, &info_area) == B_OK)
- accum.add(info_area, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ rng.add_entropy_T(info_area);
- if(accum.polling_finished())
- break;
+ bits += 32;
}
+
+ return bits;
}
}
diff --git a/src/lib/entropy/beos_stats/es_beos.h b/src/lib/entropy/beos_stats/es_beos.h
index a5b90a607..e40433b6c 100644
--- a/src/lib/entropy/beos_stats/es_beos.h
+++ b/src/lib/entropy/beos_stats/es_beos.h
@@ -20,7 +20,7 @@ class BeOS_EntropySource final : public Entropy_Source
private:
std::string name() const override { return "system_stats"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
};
}
diff --git a/src/lib/entropy/cryptoapi_rng/es_capi.cpp b/src/lib/entropy/cryptoapi_rng/es_capi.cpp
index c9d8fb7c4..a1d809d0d 100644
--- a/src/lib/entropy/cryptoapi_rng/es_capi.cpp
+++ b/src/lib/entropy/cryptoapi_rng/es_capi.cpp
@@ -1,6 +1,6 @@
/*
* Win32 CryptoAPI EntropySource
-* (C) 1999-2009 Jack Lloyd
+* (C) 1999-2009,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -16,38 +16,34 @@ namespace Botan {
namespace {
-class CSP_Handle
+class CSP_Handle_Impl : public Win32_CAPI_EntropySource::CSP_Handle
{
public:
- explicit CSP_Handle(u64bit capi_provider)
+ explicit CSP_Handle_Impl(u64bit capi_provider)
{
- m_valid = false;
- DWORD prov_type = (DWORD)capi_provider;
-
- if(CryptAcquireContext(&m_handle, 0, 0,
- prov_type, CRYPT_VERIFYCONTEXT))
- m_valid = true;
+ m_valid = ::CryptAcquireContext(&m_handle,
+ 0,
+ 0,
+ static_cast<DWORD>(capi_provider),
+ CRYPT_VERIFYCONTEXT);
}
- ~CSP_Handle()
+ ~CSP_Handle_Impl()
{
- if(is_valid())
- CryptReleaseContext(m_handle, 0);
+ if(m_valid)
+ ::CryptReleaseContext(m_handle, 0);
}
size_t gen_random(byte out[], size_t n) const
{
- if(is_valid() && CryptGenRandom(m_handle, static_cast<DWORD>(n), out))
+ if(m_valid && ::CryptGenRandom(m_handle, static_cast<DWORD>(n), out))
return n;
return 0;
}
- bool is_valid() const { return m_valid; }
-
- HCRYPTPROV get_handle() const { return m_handle; }
private:
- HCRYPTPROV m_handle;
bool m_valid;
+ HCRYPTPROV m_handle;
};
}
@@ -55,20 +51,23 @@ class CSP_Handle
/*
* Gather Entropy from Win32 CAPI
*/
-void Win32_CAPI_EntropySource::poll(Entropy_Accumulator& accum)
+size_t Win32_CAPI_EntropySource::poll(RandomNumberGenerator& rng)
{
- secure_vector<byte>& buf = accum.get_io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
+ secure_vector<uint8_t> buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
+ size_t bits = 0;
- for(size_t i = 0; i != m_prov_types.size(); ++i)
+ for(size_t i = 0; i != m_csp_provs.size(); ++i)
{
- CSP_Handle csp(m_prov_types[i]);
+ size_t got = m_csp_provs[i]->gen_random(buf.data(), buf.size());
- if(size_t got = csp.gen_random(buf.data(), buf.size()))
+ if(got > 0)
{
- accum.add(buf.data(), got, BOTAN_ENTROPY_ESTIMATE_STRONG_RNG);
- break;
+ rng.add_entropy(buf.data(), got);
+ bits += got * 8;
}
}
+
+ return bits;
}
/*
@@ -76,18 +75,21 @@ void Win32_CAPI_EntropySource::poll(Entropy_Accumulator& accum)
*/
Win32_CAPI_EntropySource::Win32_CAPI_EntropySource(const std::string& provs)
{
- std::vector<std::string> capi_provs = split_on(provs, ':');
-
- for(size_t i = 0; i != capi_provs.size(); ++i)
+ for(std::string prov_name : split_on(provs, ':'))
{
- if(capi_provs[i] == "RSA_FULL") m_prov_types.push_back(PROV_RSA_FULL);
- if(capi_provs[i] == "INTEL_SEC") m_prov_types.push_back(PROV_INTEL_SEC);
- if(capi_provs[i] == "FORTEZZA") m_prov_types.push_back(PROV_FORTEZZA);
- if(capi_provs[i] == "RNG") m_prov_types.push_back(PROV_RNG);
+ DWORD prov_type;
+
+ if(prov_name == "RSA_FULL")
+ prov_type = PROV_RSA_FULL;
+ else if(prov_name == "INTEL_SEC")
+ prov_type = PROV_INTEL_SEC;
+ else if(prov_name == "RNG")
+ prov_type = PROV_RNG;
+ else
+ continue;
+
+ m_csp_provs.push_back(std::unique_ptr<CSP_Handle>(new CSP_Handle_Impl(prov_type)));
}
-
- if(m_prov_types.size() == 0)
- m_prov_types.push_back(PROV_RSA_FULL);
}
}
diff --git a/src/lib/entropy/cryptoapi_rng/es_capi.h b/src/lib/entropy/cryptoapi_rng/es_capi.h
index b1c60bfa1..82a779672 100644
--- a/src/lib/entropy/cryptoapi_rng/es_capi.h
+++ b/src/lib/entropy/cryptoapi_rng/es_capi.h
@@ -21,15 +21,21 @@ class Win32_CAPI_EntropySource final : public Entropy_Source
public:
std::string name() const override { return "win32_cryptoapi"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
- /**
- * Win32_Capi_Entropysource Constructor
- * @param provs list of providers, separated by ':'
- */
+ /**
+ * Win32_Capi_Entropysource Constructor
+ * @param provs list of providers, separated by ':'
+ */
explicit Win32_CAPI_EntropySource(const std::string& provs = "");
+
+ class CSP_Handle
+ {
+ public:
+ virtual size_t gen_random(byte out[], size_t n) const = 0;
+ };
private:
- std::vector<u64bit> m_prov_types;
+ std::vector<std::unique_ptr<CSP_Handle>> m_csp_provs;
};
}
diff --git a/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp b/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp
index 4f1ed87bd..b53e4061e 100644
--- a/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp
+++ b/src/lib/entropy/darwin_secrandom/darwin_secrandom.cpp
@@ -7,19 +7,21 @@
#include <botan/internal/darwin_secrandom.h>
#include <Security/Security.h>
+#include <Security/SecRandom.h>
namespace Botan {
/**
* Gather entropy from SecRandomCopyBytes
*/
-void Darwin_SecRandom::poll(Entropy_Accumulator& accum)
+size_t Darwin_SecRandom::poll(RandomNumberGenerator& rng)
{
- secure_vector<byte>& buf = accum.get_io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
+ secure_vector<uint8_t> buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
if(0 == SecRandomCopyBytes(kSecRandomDefault, buf.size(), buf.data()))
{
- accum.add(buf.data(), buf.size(), BOTAN_ENTROPY_ESTIMATE_STRONG_RNG);
+ rng.add_entropy(buf.data(), buf.size());
+ return buf.size() * 8;
}
}
diff --git a/src/lib/entropy/darwin_secrandom/darwin_secrandom.h b/src/lib/entropy/darwin_secrandom/darwin_secrandom.h
index 09cdc208d..e1c012459 100644
--- a/src/lib/entropy/darwin_secrandom/darwin_secrandom.h
+++ b/src/lib/entropy/darwin_secrandom/darwin_secrandom.h
@@ -20,7 +20,7 @@ class Darwin_SecRandom final : public Entropy_Source
public:
std::string name() const override { return "darwin_secrandom"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
};
}
diff --git a/src/lib/entropy/dev_random/dev_random.cpp b/src/lib/entropy/dev_random/dev_random.cpp
index aca161d64..b51f19ecb 100644
--- a/src/lib/entropy/dev_random/dev_random.cpp
+++ b/src/lib/entropy/dev_random/dev_random.cpp
@@ -6,6 +6,7 @@
*/
#include <botan/internal/dev_random.h>
+#include <botan/exceptn.h>
#include <sys/types.h>
#include <sys/select.h>
@@ -31,14 +32,36 @@ Device_EntropySource::Device_EntropySource(const std::vector<std::string>& fsnam
const int flags = O_RDONLY | O_NONBLOCK | O_NOCTTY;
+ m_max_fd = 0;
+
for(auto fsname : fsnames)
{
- fd_type fd = ::open(fsname.c_str(), flags);
+ int fd = ::open(fsname.c_str(), flags);
- if(fd >= 0 && fd < FD_SETSIZE)
- m_devices.push_back(fd);
- else if(fd >= 0)
- ::close(fd);
+ if(fd > 0)
+ {
+ if(fd > FD_SETSIZE)
+ {
+ ::close(fd);
+ throw Exception("Open of OS RNG succeeded but fd is too large for fd_set");
+ }
+
+ m_dev_fds.push_back(fd);
+ m_max_fd = std::max(m_max_fd, fd);
+ }
+ else
+ {
+ /*
+ ENOENT or EACCES is normal as some of the named devices may not exist
+ on this system. But any other errno value probably indicates
+ either a bug in the application or file descriptor exhaustion.
+ */
+ if(errno != ENOENT && errno != EACCES)
+ {
+ throw Exception("Opening OS RNG device failed with errno " +
+ std::to_string(errno));
+ }
+ }
}
}
@@ -47,46 +70,55 @@ Device_EntropySource destructor: close all open devices
*/
Device_EntropySource::~Device_EntropySource()
{
- for(size_t i = 0; i != m_devices.size(); ++i)
- ::close(m_devices[i]);
+ for(int fd : m_dev_fds)
+ {
+ // ignoring return value here, can't throw in destructor anyway
+ ::close(fd);
+ }
}
/**
* Gather entropy from a RNG device
*/
-void Device_EntropySource::poll(Entropy_Accumulator& accum)
+size_t Device_EntropySource::poll(RandomNumberGenerator& rng)
{
- if(m_devices.empty())
- return;
+ size_t bits = 0;
- fd_type max_fd = m_devices[0];
- fd_set read_set;
- FD_ZERO(&read_set);
- for(size_t i = 0; i != m_devices.size(); ++i)
+ if(m_dev_fds.size() > 0)
{
- FD_SET(m_devices[i], &read_set);
- max_fd = std::max(m_devices[i], max_fd);
- }
-
- struct ::timeval timeout;
+ fd_set read_set;
+ FD_ZERO(&read_set);
- timeout.tv_sec = (BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS / 1000);
- timeout.tv_usec = (BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS % 1000) * 1000;
+ for(int dev_fd : m_dev_fds)
+ {
+ FD_SET(dev_fd, &read_set);
+ }
- if(::select(max_fd + 1, &read_set, nullptr, nullptr, &timeout) < 0)
- return;
+ secure_vector<uint8_t> io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
- secure_vector<byte>& buf = accum.get_io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
+ struct ::timeval timeout;
+ timeout.tv_sec = (BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS / 1000);
+ timeout.tv_usec = (BOTAN_SYSTEM_RNG_POLL_TIMEOUT_MS % 1000) * 1000;
- for(size_t i = 0; i != m_devices.size(); ++i)
- {
- if(FD_ISSET(m_devices[i], &read_set))
+ if(::select(m_max_fd + 1, &read_set, nullptr, nullptr, &timeout) > 0)
{
- const ssize_t got = ::read(m_devices[i], buf.data(), buf.size());
- if(got > 0)
- accum.add(buf.data(), got, BOTAN_ENTROPY_ESTIMATE_STRONG_RNG);
+ for(int dev_fd : m_dev_fds)
+ {
+ if(FD_ISSET(dev_fd, &read_set))
+ {
+ const ssize_t got = ::read(dev_fd, io_buf.data(), io_buf.size());
+
+ if(got > 0)
+ {
+ rng.add_entropy(io_buf.data(), static_cast<size_t>(got));
+ bits += got * 8;
+ }
+ }
+ }
}
}
+
+ return bits;
}
}
diff --git a/src/lib/entropy/dev_random/dev_random.h b/src/lib/entropy/dev_random/dev_random.h
index 1f29b2f64..7c8df0553 100644
--- a/src/lib/entropy/dev_random/dev_random.h
+++ b/src/lib/entropy/dev_random/dev_random.h
@@ -22,13 +22,14 @@ class Device_EntropySource final : public Entropy_Source
public:
std::string name() const override { return "dev_random"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
Device_EntropySource(const std::vector<std::string>& fsnames);
+
~Device_EntropySource();
private:
- typedef int fd_type;
- std::vector<fd_type> m_devices;
+ std::vector<int> m_dev_fds;
+ int m_max_fd;
};
}
diff --git a/src/lib/entropy/egd/es_egd.cpp b/src/lib/entropy/egd/es_egd.cpp
index 9bc6de6fe..384516aa8 100644
--- a/src/lib/entropy/egd/es_egd.cpp
+++ b/src/lib/entropy/egd/es_egd.cpp
@@ -134,22 +134,24 @@ EGD_EntropySource::~EGD_EntropySource()
/**
* Gather Entropy from EGD
*/
-void EGD_EntropySource::poll(Entropy_Accumulator& accum)
+size_t EGD_EntropySource::poll(RandomNumberGenerator& rng)
{
std::lock_guard<std::mutex> lock(m_mutex);
- secure_vector<byte>& buf = accum.get_io_buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
+ secure_vector<byte> buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
for(size_t i = 0; i != m_sockets.size(); ++i)
{
- size_t got = m_sockets[i].read(buf.data(), buf.size());
+ size_t got = m_sockets[i].read(m_io_buf.data(), m_io_buf.size());
if(got)
{
- accum.add(buf.data(), got, BOTAN_ENTROPY_ESTIMATE_STRONG_RNG);
- break;
+ rng.add_entropy(m_io_buf.data(), got);
+ return got * 8;
}
}
+
+ return 0;
}
}
diff --git a/src/lib/entropy/egd/es_egd.h b/src/lib/entropy/egd/es_egd.h
index 1a624713a..04b4591e3 100644
--- a/src/lib/entropy/egd/es_egd.h
+++ b/src/lib/entropy/egd/es_egd.h
@@ -23,7 +23,7 @@ class EGD_EntropySource final : public Entropy_Source
public:
std::string name() const override { return "egd"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
EGD_EntropySource(const std::vector<std::string>&);
~EGD_EntropySource();
@@ -44,6 +44,7 @@ class EGD_EntropySource final : public Entropy_Source
std::mutex m_mutex;
std::vector<EGD_Socket> m_sockets;
+ secure_vector<uint8_t> m_io_buf;
};
}
diff --git a/src/lib/entropy/entropy_src.h b/src/lib/entropy/entropy_src.h
index 539df809a..94c67a18e 100644
--- a/src/lib/entropy/entropy_src.h
+++ b/src/lib/entropy/entropy_src.h
@@ -1,6 +1,6 @@
/*
* EntropySource
-* (C) 2008,2009,2014,2015 Jack Lloyd
+* (C) 2008,2009,2014,2015,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -9,68 +9,15 @@
#define BOTAN_ENTROPY_H__
#include <botan/secmem.h>
+#include <botan/rng.h>
#include <string>
-#include <functional>
+#include <chrono>
+#include <memory>
+#include <vector>
namespace Botan {
-/**
-* Class used to accumulate the poll results of EntropySources
-*/
-class BOTAN_DLL Entropy_Accumulator final
- {
- public:
- /**
- * Initialize an Entropy_Accumulator
- *
- * @param accum will be called with poll results, first params the data and
- * length, the second a best estimate of min-entropy for the entire buffer;
- * out of an abundance of caution this will be zero for many sources.
- * accum should return true if it wants the polling to stop, though it may
- * still be called again a few more times, and should be careful to return
- * true then as well.
- */
- explicit Entropy_Accumulator(std::function<bool (const byte[], size_t, double)> accum) :
- m_accum_fn(accum) {}
-
- /**
- * @return if our polling goal has been achieved
- */
- bool polling_goal_achieved() const { return m_done; }
-
- bool polling_finished() const { return m_done; }
-
- /**
- * Add entropy to the accumulator
- * @param bytes the input bytes
- * @param length specifies how many bytes the input is
- * @param entropy_bits_per_byte is a best guess at how much
- * entropy per byte is in this input
- */
- void add(const void* bytes, size_t length, double entropy_bits_per_byte)
- {
- m_done = m_accum_fn(reinterpret_cast<const byte*>(bytes),
- length, entropy_bits_per_byte * length) || m_done;
- }
-
- /**
- * Add entropy to the accumulator
- * @param v is some value
- * @param entropy_bits_per_byte is a best guess at how much
- * entropy per byte is in this input
- */
- template<typename T>
- void add(const T& v, double entropy_bits_per_byte)
- {
- add(&v, sizeof(T), entropy_bits_per_byte);
- }
-
- secure_vector<byte>& get_io_buf(size_t sz) { m_io_buf.resize(sz); return m_io_buf; }
- private:
- std::function<bool (const byte[], size_t, double)> m_accum_fn;
- secure_vector<byte> m_io_buf;
- bool m_done = false;
- };
+class RandomNumberGenerator;
/**
* Abstract interface to a source of entropy
@@ -93,9 +40,10 @@ class BOTAN_DLL Entropy_Source
/**
* Perform an entropy gathering poll
- * @param accum is an accumulator object that will be given entropy
+ * @param rng will be provided with entropy via calls to add_entropy
+ @ @return conservative estimate of actual entropy added to rng during poll
*/
- virtual void poll(Entropy_Accumulator& accum) = 0;
+ virtual size_t poll(RandomNumberGenerator& rng) = 0;
virtual ~Entropy_Source() {}
};
@@ -109,8 +57,14 @@ class BOTAN_DLL Entropy_Sources final
std::vector<std::string> enabled_sources() const;
- void poll(Entropy_Accumulator& accum);
- bool poll_just(Entropy_Accumulator& accum, const std::string& src);
+ size_t poll(RandomNumberGenerator& rng,
+ size_t bits,
+ std::chrono::milliseconds timeout);
+
+ /**
+ * Poll just a single named source. Ordinally only used for testing
+ */
+ size_t poll_just(RandomNumberGenerator& rng, const std::string& src);
Entropy_Sources() {}
explicit Entropy_Sources(const std::vector<std::string>& sources);
diff --git a/src/lib/entropy/entropy_srcs.cpp b/src/lib/entropy/entropy_srcs.cpp
index a5dc0a819..22d2e5e4b 100644
--- a/src/lib/entropy/entropy_srcs.cpp
+++ b/src/lib/entropy/entropy_srcs.cpp
@@ -6,6 +6,7 @@
*/
#include <botan/entropy_src.h>
+#include <botan/rng.h>
#if defined(BOTAN_HAS_ENTROPY_SRC_HIGH_RESOLUTION_TIMER)
#include <botan/internal/hres_timer.h>
@@ -68,7 +69,7 @@ std::unique_ptr<Entropy_Source> Entropy_Source::create(const std::string& name)
return std::unique_ptr<Entropy_Source>(new Intel_Rdrand);
#endif
}
-
+
if(name == "rdseed")
{
#if defined(BOTAN_HAS_ENTROPY_SRC_RDSEED)
@@ -154,28 +155,38 @@ std::vector<std::string> Entropy_Sources::enabled_sources() const
return sources;
}
-void Entropy_Sources::poll(Entropy_Accumulator& accum)
+size_t Entropy_Sources::poll(RandomNumberGenerator& rng,
+ size_t poll_bits,
+ std::chrono::milliseconds timeout)
{
- for(size_t i = 0; i != m_srcs.size(); ++i)
+ typedef std::chrono::system_clock clock;
+
+ auto deadline = clock::now() + timeout;
+
+ size_t bits_collected = 0;
+
+ for(Entropy_Source* src : m_srcs)
{
- m_srcs[i]->poll(accum);
- if(accum.polling_goal_achieved())
+ bits_collected += src->poll(rng);
+
+ if (bits_collected >= poll_bits || clock::now() > deadline)
break;
}
+
+ return bits_collected;
}
-bool Entropy_Sources::poll_just(Entropy_Accumulator& accum, const std::string& the_src)
+size_t Entropy_Sources::poll_just(RandomNumberGenerator& rng, const std::string& the_src)
{
for(size_t i = 0; i != m_srcs.size(); ++i)
{
if(m_srcs[i]->name() == the_src)
{
- m_srcs[i]->poll(accum);
- return true;
+ return m_srcs[i]->poll(rng);
}
}
- return false;
+ return 0;
}
Entropy_Sources::Entropy_Sources(const std::vector<std::string>& sources)
diff --git a/src/lib/entropy/hres_timer/hres_timer.cpp b/src/lib/entropy/hres_timer/hres_timer.cpp
deleted file mode 100644
index e2a5ddbef..000000000
--- a/src/lib/entropy/hres_timer/hres_timer.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-* High Resolution Timestamp Entropy Source
-* (C) 1999-2009,2011,2014,2016 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/internal/hres_timer.h>
-#include <botan/internal/os_utils.h>
-
-#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
- #include <time.h>
-#endif
-
-namespace Botan {
-
-/*
-* Get the timestamp
-*/
-void High_Resolution_Timestamp::poll(Entropy_Accumulator& accum)
- {
- accum.add(OS::get_processor_timestamp(), BOTAN_ENTROPY_ESTIMATE_TIMESTAMPS);
-
- accum.add(OS::get_system_timestamp_ns(), BOTAN_ENTROPY_ESTIMATE_TIMESTAMPS);
-
-#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
-
-#define CLOCK_GETTIME_POLL(src) \
- do { \
- struct timespec ts; \
- ::clock_gettime(src, &ts); \
- accum.add(&ts, sizeof(ts), BOTAN_ENTROPY_ESTIMATE_TIMESTAMPS); \
- } while(0)
-
-#if defined(CLOCK_REALTIME)
- CLOCK_GETTIME_POLL(CLOCK_REALTIME);
-#endif
-
-#if defined(CLOCK_MONOTONIC)
- CLOCK_GETTIME_POLL(CLOCK_MONOTONIC);
-#endif
-
-#if defined(CLOCK_MONOTONIC_RAW)
- CLOCK_GETTIME_POLL(CLOCK_MONOTONIC_RAW);
-#endif
-
-#if defined(CLOCK_PROCESS_CPUTIME_ID)
- CLOCK_GETTIME_POLL(CLOCK_PROCESS_CPUTIME_ID);
-#endif
-
-#if defined(CLOCK_THREAD_CPUTIME_ID)
- CLOCK_GETTIME_POLL(CLOCK_THREAD_CPUTIME_ID);
-#endif
-
-#undef CLOCK_GETTIME_POLL
-
-#endif
- }
-
-}
diff --git a/src/lib/entropy/hres_timer/hres_timer.h b/src/lib/entropy/hres_timer/hres_timer.h
deleted file mode 100644
index d297a87b1..000000000
--- a/src/lib/entropy/hres_timer/hres_timer.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-* High Resolution Timestamp Entropy Source
-* (C) 1999-2009 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_ENTROPY_SRC_HRES_TIMER_H__
-#define BOTAN_ENTROPY_SRC_HRES_TIMER_H__
-
-#include <botan/entropy_src.h>
-
-namespace Botan {
-
-/**
-* Entropy source using high resolution timers
-*
-* @note Any results from timers are marked as not contributing entropy
-* to the poll, as a local attacker could observe them directly.
-*/
-class High_Resolution_Timestamp final : public Entropy_Source
- {
- public:
- std::string name() const override { return "timestamp"; }
- void poll(Entropy_Accumulator& accum) override;
- };
-
-}
-
-#endif
diff --git a/src/lib/entropy/hres_timer/info.txt b/src/lib/entropy/hres_timer/info.txt
deleted file mode 100644
index dfe8fab0b..000000000
--- a/src/lib/entropy/hres_timer/info.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-define ENTROPY_SRC_HIGH_RESOLUTION_TIMER 20131128
-
-<source>
-hres_timer.cpp
-</source>
-
-<header:internal>
-hres_timer.h
-</header:internal>
-
-<libs>
-linux -> rt
-</libs>
diff --git a/src/lib/entropy/info.txt b/src/lib/entropy/info.txt
index ba5a4044d..d80176113 100644
--- a/src/lib/entropy/info.txt
+++ b/src/lib/entropy/info.txt
@@ -1 +1,5 @@
define ENTROPY_SOURCE 20151120
+
+<requires>
+rng
+</requires>
diff --git a/src/lib/entropy/proc_walk/proc_walk.cpp b/src/lib/entropy/proc_walk/proc_walk.cpp
index c59a8227b..beaa57308 100644
--- a/src/lib/entropy/proc_walk/proc_walk.cpp
+++ b/src/lib/entropy/proc_walk/proc_walk.cpp
@@ -110,7 +110,7 @@ int Directory_Walker::next_fd()
}
-void ProcWalking_EntropySource::poll(Entropy_Accumulator& accum)
+size_t ProcWalking_EntropySource::poll(RandomNumberGenerator& rng)
{
const size_t MAX_FILES_READ_PER_POLL = 2048;
@@ -121,6 +121,8 @@ void ProcWalking_EntropySource::poll(Entropy_Accumulator& accum)
m_buf.resize(4096);
+ size_t bits = 0;
+
for(size_t i = 0; i != MAX_FILES_READ_PER_POLL; ++i)
{
int fd = m_dir->next_fd();
@@ -136,11 +138,18 @@ void ProcWalking_EntropySource::poll(Entropy_Accumulator& accum)
::close(fd);
if(got > 0)
- accum.add(m_buf.data(), got, BOTAN_ENTROPY_ESTIMATE_SYSTEM_TEXT);
+ {
+ rng.add_entropy(m_buf.data(), static_cast<size_t>(got));
- if(accum.polling_finished())
+ // Conservative estimate of 4 bits per file
+ bits += 4;
+ }
+
+ if(bits > 128)
break;
}
+
+ return bits;
}
}
diff --git a/src/lib/entropy/proc_walk/proc_walk.h b/src/lib/entropy/proc_walk/proc_walk.h
index f6db8185a..369b52699 100644
--- a/src/lib/entropy/proc_walk/proc_walk.h
+++ b/src/lib/entropy/proc_walk/proc_walk.h
@@ -28,7 +28,7 @@ class ProcWalking_EntropySource final : public Entropy_Source
public:
std::string name() const override { return "proc_walk"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
ProcWalking_EntropySource(const std::string& root_dir) :
m_path(root_dir), m_dir(nullptr) {}
diff --git a/src/lib/entropy/rdrand/info.txt b/src/lib/entropy/rdrand/info.txt
index e3e1a2a50..ebc7fb747 100644
--- a/src/lib/entropy/rdrand/info.txt
+++ b/src/lib/entropy/rdrand/info.txt
@@ -1,6 +1,8 @@
define ENTROPY_SRC_RDRAND 20131128
-need_isa rdrand
+<requires>
+rdrand_rng
+</requires>
<source>
rdrand.cpp
@@ -9,15 +11,3 @@ rdrand.cpp
<header:internal>
rdrand.h
</header:internal>
-
-<arch>
-x86_32
-x86_64
-</arch>
-
-<cc>
-gcc
-clang
-icc
-msvc
-</cc>
diff --git a/src/lib/entropy/rdrand/rdrand.cpp b/src/lib/entropy/rdrand/rdrand.cpp
index 89234b460..7fa05c605 100644
--- a/src/lib/entropy/rdrand/rdrand.cpp
+++ b/src/lib/entropy/rdrand/rdrand.cpp
@@ -7,41 +7,24 @@
*/
#include <botan/internal/rdrand.h>
+#include <botan/rdrand_rng.h>
#include <botan/cpuid.h>
#include <botan/build.h>
-#if !defined(BOTAN_USE_GCC_INLINE_ASM)
- #include <immintrin.h>
-#endif
-
namespace Botan {
-void Intel_Rdrand::poll(Entropy_Accumulator& accum) {
- if(!CPUID::has_rdrand())
- return;
-
- for(size_t p = 0; p != BOTAN_ENTROPY_INTEL_RNG_POLLS; ++p)
+size_t Intel_Rdrand::poll(RandomNumberGenerator& rng) {
+ if(CPUID::has_rdrand() && BOTAN_ENTROPY_INTEL_RNG_POLLS > 0)
{
- for(size_t i = 0; i != BOTAN_ENTROPY_RDRAND_RETRIES; ++i)
- {
- uint32_t r = 0;
+ RDRAND_RNG rdrand_rng;
+ secure_vector<uint8_t> buf(4 * BOTAN_ENTROPY_INTEL_RNG_POLLS);
-#if defined(BOTAN_USE_GCC_INLINE_ASM)
- int cf = 0;
-
- // Encoding of rdrand %eax
- asm(".byte 0x0F, 0xC7, 0xF0; adcl $0,%1" :
- "=a" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc");
-#else
- int cf = _rdrand32_step(&r);
-#endif
- if(1 == cf)
- {
- accum.add(r, BOTAN_ENTROPY_ESTIMATE_HARDWARE_RNG);
- break;
- }
- }
+ rdrand_rng.randomize(buf.data(), buf.size());
+ rng.add_entropy(buf.data(), buf.size());
}
+
+ // RDRAND is used but not trusted
+ return 0;
}
}
diff --git a/src/lib/entropy/rdrand/rdrand.h b/src/lib/entropy/rdrand/rdrand.h
index 48d090775..db9de39b6 100644
--- a/src/lib/entropy/rdrand/rdrand.h
+++ b/src/lib/entropy/rdrand/rdrand.h
@@ -20,7 +20,7 @@ class Intel_Rdrand final : public Entropy_Source
{
public:
std::string name() const override { return "rdrand"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
};
}
diff --git a/src/lib/entropy/rdseed/rdseed.cpp b/src/lib/entropy/rdseed/rdseed.cpp
index 2ba2075cc..325edfd41 100644
--- a/src/lib/entropy/rdseed/rdseed.cpp
+++ b/src/lib/entropy/rdseed/rdseed.cpp
@@ -15,32 +15,34 @@
namespace Botan {
-void Intel_Rdseed::poll(Entropy_Accumulator& accum) {
- if(!CPUID::has_rdseed())
- return;
-
- for(size_t p = 0; p != BOTAN_ENTROPY_INTEL_RNG_POLLS; ++p)
+size_t Intel_Rdseed::poll(RandomNumberGenerator& rng) {
+ if(CPUID::has_rdseed())
{
- for(size_t i = 0; i != BOTAN_ENTROPY_RDSEED_RETRIES; ++i)
+ for(size_t p = 0; p != BOTAN_ENTROPY_INTEL_RNG_POLLS; ++p)
{
- uint32_t r = 0;
+ for(size_t i = 0; i != BOTAN_ENTROPY_RDSEED_RETRIES; ++i)
+ {
+ uint32_t r = 0;
#if defined(BOTAN_USE_GCC_INLINE_ASM)
- int cf = 0;
+ int cf = 0;
- // Encoding of rdseed %eax
- asm(".byte 0x0F, 0xC7, 0xF8; adcl $0,%1" :
- "=a" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc");
+ // Encoding of rdseed %eax
+ asm(".byte 0x0F, 0xC7, 0xF8; adcl $0,%1" :
+ "=a" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc");
#else
- int cf = _rdseed32_step(&r);
+ int cf = _rdseed32_step(&r);
#endif
- if(1 == cf)
- {
- accum.add(r, BOTAN_ENTROPY_ESTIMATE_HARDWARE_RNG);
- break;
+ if(1 == cf)
+ {
+ rng.add_entropy_T(r);
+ break;
+ }
}
}
}
+
+ return 0;
}
}
diff --git a/src/lib/entropy/rdseed/rdseed.h b/src/lib/entropy/rdseed/rdseed.h
index f86c32768..4ea584354 100644
--- a/src/lib/entropy/rdseed/rdseed.h
+++ b/src/lib/entropy/rdseed/rdseed.h
@@ -20,7 +20,7 @@ class Intel_Rdseed final : public Entropy_Source
{
public:
std::string name() const override { return "rdseed"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
};
}
diff --git a/src/lib/entropy/unix_procs/unix_procs.cpp b/src/lib/entropy/unix_procs/unix_procs.cpp
index 55ad295cd..8f885cfcf 100644
--- a/src/lib/entropy/unix_procs/unix_procs.cpp
+++ b/src/lib/entropy/unix_procs/unix_procs.cpp
@@ -67,17 +67,52 @@ Unix_EntropySource::Unix_EntropySource(const std::vector<std::string>& trusted_p
{
}
-void UnixProcessInfo_EntropySource::poll(Entropy_Accumulator& accum)
+size_t UnixProcessInfo_EntropySource::poll(RandomNumberGenerator& rng)
{
- accum.add(::getpid(), BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
- accum.add(::getppid(), BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
- accum.add(::getuid(), BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
- accum.add(::getgid(), BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
- accum.add(::getpgrp(), BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
+ rng.add_entropy_T(::getpid());
+ rng.add_entropy_T(::getppid());
+ rng.add_entropy_T(::getuid());
+ rng.add_entropy_T(::getgid());
+ rng.add_entropy_T(::getpgrp());
struct ::rusage usage;
::getrusage(RUSAGE_SELF, &usage);
- accum.add(usage, BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
+ rng.add_entropy_T(usage);
+
+#if defined(BOTAN_TARGET_OS_HAS_CLOCK_GETTIME)
+
+#define CLOCK_GETTIME_POLL(src) \
+ do { \
+ struct timespec ts; \
+ ::clock_gettime(src, &ts); \
+ rng.add_entropy_T(ts); \
+ } while(0)
+
+#if defined(CLOCK_REALTIME)
+ CLOCK_GETTIME_POLL(CLOCK_REALTIME);
+#endif
+
+#if defined(CLOCK_MONOTONIC)
+ CLOCK_GETTIME_POLL(CLOCK_MONOTONIC);
+#endif
+
+#if defined(CLOCK_MONOTONIC_RAW)
+ CLOCK_GETTIME_POLL(CLOCK_MONOTONIC_RAW);
+#endif
+
+#if defined(CLOCK_PROCESS_CPUTIME_ID)
+ CLOCK_GETTIME_POLL(CLOCK_PROCESS_CPUTIME_ID);
+#endif
+
+#if defined(CLOCK_THREAD_CPUTIME_ID)
+ CLOCK_GETTIME_POLL(CLOCK_THREAD_CPUTIME_ID);
+#endif
+
+#undef CLOCK_GETTIME_POLL
+
+#endif
+
+ return 0;
}
void Unix_EntropySource::Unix_Process::spawn(const std::vector<std::string>& args)
@@ -168,11 +203,11 @@ const std::vector<std::string>& Unix_EntropySource::next_source()
return src;
}
-void Unix_EntropySource::poll(Entropy_Accumulator& accum)
+size_t Unix_EntropySource::poll(RandomNumberGenerator& rng)
{
// refuse to run setuid or setgid, or as root
if((getuid() != geteuid()) || (getgid() != getegid()) || (geteuid() == 0))
- return;
+ return 0;
std::lock_guard<std::mutex> lock(m_mutex);
@@ -192,13 +227,15 @@ void Unix_EntropySource::poll(Entropy_Accumulator& accum)
}
if(m_sources.empty())
- return; // still empty, really nothing to try
+ return 0; // still empty, really nothing to try
const size_t MS_WAIT_TIME = 32;
m_buf.resize(4096);
- while(!accum.polling_finished())
+ size_t bytes = 0;
+
+ while(bytes < 128 * 1024) // arbitrary limit...
{
while(m_procs.size() < m_concurrent)
m_procs.emplace_back(Unix_Process(next_source()));
@@ -228,7 +265,7 @@ void Unix_EntropySource::poll(Entropy_Accumulator& accum)
timeout.tv_usec = (MS_WAIT_TIME % 1000) * 1000;
if(::select(max_fd + 1, &read_set, nullptr, nullptr, &timeout) < 0)
- return; // or continue?
+ break; // or continue?
for(auto& proc : m_procs)
{
@@ -237,13 +274,19 @@ void Unix_EntropySource::poll(Entropy_Accumulator& accum)
if(FD_ISSET(fd, &read_set))
{
const ssize_t got = ::read(fd, m_buf.data(), m_buf.size());
+
if(got > 0)
- accum.add(m_buf.data(), got, BOTAN_ENTROPY_ESTIMATE_SYSTEM_TEXT);
+ {
+ rng.add_entropy(m_buf.data(), got);
+ bytes += got;
+ }
else
proc.spawn(next_source());
}
}
}
+
+ return bytes / 1024;
}
}
diff --git a/src/lib/entropy/unix_procs/unix_procs.h b/src/lib/entropy/unix_procs/unix_procs.h
index e1749af5f..27f7ab5bb 100644
--- a/src/lib/entropy/unix_procs/unix_procs.h
+++ b/src/lib/entropy/unix_procs/unix_procs.h
@@ -25,7 +25,7 @@ class Unix_EntropySource final : public Entropy_Source
public:
std::string name() const override { return "unix_procs"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
/**
* @param trusted_paths is a list of directories that are assumed
@@ -83,7 +83,7 @@ class UnixProcessInfo_EntropySource final : public Entropy_Source
public:
std::string name() const override { return "proc_info"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
};
}
diff --git a/src/lib/entropy/win32_stats/es_win32.cpp b/src/lib/entropy/win32_stats/es_win32.cpp
index ce0edea83..bbc64eaab 100644
--- a/src/lib/entropy/win32_stats/es_win32.cpp
+++ b/src/lib/entropy/win32_stats/es_win32.cpp
@@ -1,6 +1,6 @@
/*
* Win32 EntropySource
-* (C) 1999-2009 Jack Lloyd
+* (C) 1999-2009,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -14,44 +14,44 @@ namespace Botan {
/**
* Win32 poll using stats functions including Tooltip32
*/
-void Win32_EntropySource::poll(Entropy_Accumulator& accum)
+size_t Win32_EntropySource::poll(RandomNumberGenerator& rng)
{
/*
- First query a bunch of basic statistical stuff, though
- don't count it for much in terms of contributed entropy.
+ First query a bunch of basic statistical stuff
*/
- accum.add(GetTickCount(), BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
- accum.add(GetMessagePos(), BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
- accum.add(GetMessageTime(), BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
- accum.add(GetInputState(), BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ rng.add_entropy_T(::GetTickCount());
+ rng.add_entropy_T(::GetMessagePos());
+ rng.add_entropy_T(::GetMessageTime());
+ rng.add_entropy_T(::GetInputState());
- accum.add(GetCurrentProcessId(), BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
- accum.add(GetCurrentThreadId(), BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
+ rng.add_entropy_T(::GetCurrentProcessId());
+ rng.add_entropy_T(::GetCurrentThreadId());
SYSTEM_INFO sys_info;
- GetSystemInfo(&sys_info);
- accum.add(sys_info, BOTAN_ENTROPY_ESTIMATE_STATIC_SYSTEM_DATA);
+ ::GetSystemInfo(&sys_info);
+ rng.add_entropy_T(sys_info);
MEMORYSTATUSEX mem_info;
- GlobalMemoryStatusEx(&mem_info);
- accum.add(mem_info, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ ::GlobalMemoryStatusEx(&mem_info);
+ rng.add_entropy_T(mem_info);
POINT point;
- GetCursorPos(&point);
- accum.add(point, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ ::GetCursorPos(&point);
+ rng.add_entropy_T(point);
- GetCaretPos(&point);
- accum.add(point, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
+ ::GetCaretPos(&point);
+ rng.add_entropy_T(point);
/*
- Now use the Tooltip library to iterate throug various objects on
+ Now use the Tooltip library to iterate through various objects on
the system, including processes, threads, and heap objects.
*/
- HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
+ HANDLE snapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
+ size_t bits = 0;
#define TOOLHELP32_ITER(DATA_TYPE, FUNC_FIRST, FUNC_NEXT) \
- if(!accum.polling_finished()) \
+ if(bits < 256) \
{ \
DATA_TYPE info; \
info.dwSize = sizeof(DATA_TYPE); \
@@ -59,57 +59,52 @@ void Win32_EntropySource::poll(Entropy_Accumulator& accum)
{ \
do \
{ \
- accum.add(info, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA); \
+ rng.add_entropy_T(info); \
+ bits += 4; \
} while(FUNC_NEXT(snapshot, &info)); \
} \
}
- TOOLHELP32_ITER(MODULEENTRY32, Module32First, Module32Next);
- TOOLHELP32_ITER(PROCESSENTRY32, Process32First, Process32Next);
- TOOLHELP32_ITER(THREADENTRY32, Thread32First, Thread32Next);
+ TOOLHELP32_ITER(MODULEENTRY32, ::Module32First, ::Module32Next);
+ TOOLHELP32_ITER(PROCESSENTRY32, ::Process32First, ::Process32Next);
+ TOOLHELP32_ITER(THREADENTRY32, ::Thread32First, ::Thread32Next);
#undef TOOLHELP32_ITER
- if(!accum.polling_finished())
+ if(bits <= 256)
{
HEAPLIST32 heap_list;
heap_list.dwSize = sizeof(HEAPLIST32);
- const size_t HEAP_LISTS_MAX = 32;
- const size_t HEAP_OBJS_PER_LIST = 128;
-
- if(Heap32ListFirst(snapshot, &heap_list))
+ if(::Heap32ListFirst(snapshot, &heap_list))
{
- size_t heap_lists_found = 0;
do
{
- accum.add(heap_list, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
-
- if(++heap_lists_found > HEAP_LISTS_MAX)
- break;
+ rng.add_entropy_T(heap_list);
HEAPENTRY32 heap_entry;
heap_entry.dwSize = sizeof(HEAPENTRY32);
- if(Heap32First(&heap_entry, heap_list.th32ProcessID,
- heap_list.th32HeapID))
+ if(::Heap32First(&heap_entry,
+ heap_list.th32ProcessID,
+ heap_list.th32HeapID))
{
- size_t heap_objs_found = 0;
do
{
- if(heap_objs_found++ > HEAP_OBJS_PER_LIST)
- break;
- accum.add(heap_entry, BOTAN_ENTROPY_ESTIMATE_SYSTEM_DATA);
- } while(Heap32Next(&heap_entry));
+ rng.add_entropy_T(heap_entry);
+ bits += 4;
+ } while(::Heap32Next(&heap_entry));
}
- if(accum.polling_finished())
+ if(bits >= 256)
break;
- } while(Heap32ListNext(snapshot, &heap_list));
+ } while(::Heap32ListNext(snapshot, &heap_list));
}
}
- CloseHandle(snapshot);
+ ::CloseHandle(snapshot);
+
+ return bits;
}
}
diff --git a/src/lib/entropy/win32_stats/es_win32.h b/src/lib/entropy/win32_stats/es_win32.h
index 5dc3f7f17..26b904bbb 100644
--- a/src/lib/entropy/win32_stats/es_win32.h
+++ b/src/lib/entropy/win32_stats/es_win32.h
@@ -19,7 +19,7 @@ class Win32_EntropySource final : public Entropy_Source
{
public:
std::string name() const override { return "system_stats"; }
- void poll(Entropy_Accumulator& accum) override;
+ size_t poll(RandomNumberGenerator& rng) override;
};
}
diff --git a/src/lib/ffi/ffi.cpp b/src/lib/ffi/ffi.cpp
index 11084ae50..e42f32234 100644
--- a/src/lib/ffi/ffi.cpp
+++ b/src/lib/ffi/ffi.cpp
@@ -287,7 +287,7 @@ int botan_rng_get(botan_rng_t rng, uint8_t* out, size_t out_len)
int botan_rng_reseed(botan_rng_t rng, size_t bits)
{
- return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { r.reseed(bits); });
+ return BOTAN_FFI_DO(Botan::RandomNumberGenerator, rng, r, { r.reseed_from_rng(Botan::system_rng(), bits); });
}
int botan_hash_init(botan_hash_t* hash, const char* hash_name, uint32_t flags)
@@ -653,12 +653,13 @@ int botan_pbkdf_timed(const char* pbkdf_algo,
int botan_kdf(const char* kdf_algo,
uint8_t out[], size_t out_len,
const uint8_t secret[], size_t secret_len,
- const uint8_t salt[], size_t salt_len)
+ const uint8_t salt[], size_t salt_len,
+ const uint8_t label[], size_t label_len)
{
try
{
std::unique_ptr<Botan::KDF> kdf(Botan::get_kdf(kdf_algo));
- kdf->kdf(out, out_len, secret, secret_len, salt, salt_len);
+ kdf->kdf(out, out_len, secret, secret_len, salt, salt_len, label, label_len);
return 0;
}
catch(std::exception& e)
diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h
index 6cbe56743..165554105 100644
--- a/src/lib/ffi/ffi.h
+++ b/src/lib/ffi/ffi.h
@@ -269,7 +269,8 @@ BOTAN_DLL int botan_pbkdf_timed(const char* pbkdf_algo,
BOTAN_DLL int botan_kdf(const char* kdf_algo,
uint8_t out[], size_t out_len,
const uint8_t secret[], size_t secret_len,
- const uint8_t salt[], size_t salt_len);
+ const uint8_t salt[], size_t salt_len,
+ const uint8_t label[], size_t label_len);
/*
* Bcrypt
diff --git a/src/lib/ffi/info.txt b/src/lib/ffi/info.txt
index 7c8968ff0..057bbd012 100644
--- a/src/lib/ffi/info.txt
+++ b/src/lib/ffi/info.txt
@@ -7,7 +7,6 @@ pbkdf
pubkey
x509
#tls
-auto_rng
system_rng
</requires>
diff --git a/src/lib/hash/par_hash/par_hash.cpp b/src/lib/hash/par_hash/par_hash.cpp
index 5645a99c7..f6bed96ee 100644
--- a/src/lib/hash/par_hash/par_hash.cpp
+++ b/src/lib/hash/par_hash/par_hash.cpp
@@ -68,7 +68,7 @@ HashFunction* Parallel::clone() const
std::vector<HashFunction*> hash_copies;
for(auto&& hash : m_hashes)
- hash_copies.push_back(hash->clone());
+ hash_copies.push_back(hash.get());
return new Parallel(hash_copies);
}
diff --git a/src/lib/kdf/hkdf/hkdf.cpp b/src/lib/kdf/hkdf/hkdf.cpp
index 6f83853f9..56dc72f09 100644
--- a/src/lib/kdf/hkdf/hkdf.cpp
+++ b/src/lib/kdf/hkdf/hkdf.cpp
@@ -22,7 +22,8 @@ HKDF* HKDF::make(const Spec& spec)
size_t HKDF::kdf(byte out[], size_t out_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const
{
m_prf->set_key(secret, secret_len);
@@ -33,6 +34,7 @@ size_t HKDF::kdf(byte out[], size_t out_len,
while(offset != out_len && counter != 0)
{
m_prf->update(h);
+ m_prf->update(label, label_len);
m_prf->update(salt, salt_len);
m_prf->update(counter++);
m_prf->final(h);
diff --git a/src/lib/kdf/hkdf/hkdf.h b/src/lib/kdf/hkdf/hkdf.h
index 3e3e2b73a..1dba82ee2 100644
--- a/src/lib/kdf/hkdf/hkdf.h
+++ b/src/lib/kdf/hkdf/hkdf.h
@@ -31,7 +31,8 @@ class BOTAN_DLL HKDF final : public KDF
size_t kdf(byte out[], size_t out_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const override;
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const override;
private:
std::unique_ptr<MessageAuthenticationCode> m_prf;
diff --git a/src/lib/kdf/kdf.cpp b/src/lib/kdf/kdf.cpp
index 7f4488d32..66296bf96 100644
--- a/src/lib/kdf/kdf.cpp
+++ b/src/lib/kdf/kdf.cpp
@@ -21,6 +21,10 @@
#include <botan/kdf2.h>
#endif
+#if defined(BOTAN_HAS_KDF1_18033)
+#include <botan/kdf1_iso18033.h>
+#endif
+
#if defined(BOTAN_HAS_TLS_V10_PRF)
#include <botan/prf_tls.h>
#endif
@@ -89,6 +93,10 @@ BOTAN_REGISTER_KDF_1HASH(KDF1, "KDF1");
BOTAN_REGISTER_KDF_1HASH(KDF2, "KDF2");
#endif
+#if defined(BOTAN_HAS_KDF1_18033)
+BOTAN_REGISTER_KDF_1HASH( KDF1_18033, "KDF1-18033" );
+#endif
+
#if defined(BOTAN_HAS_TLS_V10_PRF)
BOTAN_REGISTER_KDF_NOARGS(TLS_PRF, "TLS-PRF");
#endif
diff --git a/src/lib/kdf/kdf.h b/src/lib/kdf/kdf.h
index 88b50c8b8..3c8a7a013 100644
--- a/src/lib/kdf/kdf.h
+++ b/src/lib/kdf/kdf.h
@@ -40,7 +40,8 @@ class BOTAN_DLL KDF
virtual size_t kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const = 0;
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const = 0;
/**
@@ -50,15 +51,19 @@ class BOTAN_DLL KDF
* @param secret_len size of secret in bytes
* @param salt a diversifier
* @param salt_len size of salt in bytes
+ * @param label purpose for the derived keying material
+ * @param label_len size of label in bytes
*/
secure_vector<byte> derive_key(size_t key_len,
const byte secret[],
size_t secret_len,
const byte salt[],
- size_t salt_len) const
+ size_t salt_len,
+ const byte label[] = nullptr,
+ size_t label_len = 0) const
{
secure_vector<byte> key(key_len);
- key.resize(kdf(key.data(), key.size(), secret, secret_len, salt, salt_len));
+ key.resize(kdf(key.data(), key.size(), secret, secret_len, salt, salt_len, label, label_len));
return key;
}
@@ -67,14 +72,19 @@ class BOTAN_DLL KDF
* @param key_len the desired output length in bytes
* @param secret the secret input
* @param salt a diversifier
+ * @param label purpose for the derived keying material
*/
secure_vector<byte> derive_key(size_t key_len,
const secure_vector<byte>& secret,
- const std::string& salt = "") const
+ const std::string& salt = "",
+ const std::string& label = "") const
{
return derive_key(key_len, secret.data(), secret.size(),
reinterpret_cast<const byte*>(salt.data()),
- salt.length());
+ salt.length(),
+ reinterpret_cast<const byte*>(label.data()),
+ label.length());
+
}
/**
@@ -82,15 +92,18 @@ class BOTAN_DLL KDF
* @param key_len the desired output length in bytes
* @param secret the secret input
* @param salt a diversifier
+ * @param label purpose for the derived keying material
*/
- template<typename Alloc, typename Alloc2>
+ template<typename Alloc, typename Alloc2, typename Alloc3>
secure_vector<byte> derive_key(size_t key_len,
const std::vector<byte, Alloc>& secret,
- const std::vector<byte, Alloc2>& salt) const
+ const std::vector<byte, Alloc2>& salt,
+ const std::vector<byte, Alloc3>& label) const
{
return derive_key(key_len,
secret.data(), secret.size(),
- salt.data(), salt.size());
+ salt.data(), salt.size(),
+ label.data(), label.size());
}
/**
@@ -99,15 +112,19 @@ class BOTAN_DLL KDF
* @param secret the secret input
* @param salt a diversifier
* @param salt_len size of salt in bytes
+ * @param label purpose for the derived keying material
*/
secure_vector<byte> derive_key(size_t key_len,
const secure_vector<byte>& secret,
const byte salt[],
- size_t salt_len) const
+ size_t salt_len,
+ const std::string& label = "") const
{
return derive_key(key_len,
secret.data(), secret.size(),
- salt, salt_len);
+ salt, salt_len,
+ reinterpret_cast<const byte*>(label.data()),
+ label.size());
}
/**
@@ -116,15 +133,19 @@ class BOTAN_DLL KDF
* @param secret the secret input
* @param secret_len size of secret in bytes
* @param salt a diversifier
+ * @param label purpose for the derived keying material
*/
secure_vector<byte> derive_key(size_t key_len,
const byte secret[],
size_t secret_len,
- const std::string& salt = "") const
+ const std::string& salt = "",
+ const std::string& label = "") const
{
return derive_key(key_len, secret, secret_len,
reinterpret_cast<const byte*>(salt.data()),
- salt.length());
+ salt.length(),
+ reinterpret_cast<const byte*>(label.data()),
+ label.length());
}
virtual KDF* clone() const = 0;
diff --git a/src/lib/kdf/kdf1/kdf1.cpp b/src/lib/kdf/kdf1/kdf1.cpp
index c7ea3c37e..14dddc5f4 100644
--- a/src/lib/kdf/kdf1/kdf1.cpp
+++ b/src/lib/kdf/kdf1/kdf1.cpp
@@ -11,9 +11,11 @@ namespace Botan {
size_t KDF1::kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const
{
m_hash->update(secret, secret_len);
+ m_hash->update(label, label_len);
m_hash->update(salt, salt_len);
if(key_len < m_hash->output_length())
diff --git a/src/lib/kdf/kdf1/kdf1.h b/src/lib/kdf/kdf1/kdf1.h
index adaa84894..59bff4d8d 100644
--- a/src/lib/kdf/kdf1/kdf1.h
+++ b/src/lib/kdf/kdf1/kdf1.h
@@ -25,7 +25,8 @@ class BOTAN_DLL KDF1 final : public KDF
size_t kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const override;
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const override;
explicit KDF1(HashFunction* h) : m_hash(h) {}
private:
diff --git a/src/lib/kdf/kdf1_iso18033/info.txt b/src/lib/kdf/kdf1_iso18033/info.txt
new file mode 100644
index 000000000..507a04561
--- /dev/null
+++ b/src/lib/kdf/kdf1_iso18033/info.txt
@@ -0,0 +1 @@
+define KDF1_18033 20160128
diff --git a/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.cpp b/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.cpp
new file mode 100644
index 000000000..7beca0862
--- /dev/null
+++ b/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.cpp
@@ -0,0 +1,37 @@
+/*
+* KDF1 from ISO 18033-2
+* (C) 2016 Philipp Weber
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/kdf1_iso18033.h>
+
+namespace Botan {
+
+size_t KDF1_18033::kdf(byte key[], size_t key_len,
+ const byte secret[], size_t secret_len,
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const
+ {
+ u32bit counter = 0;
+ secure_vector<byte> h;
+
+ size_t offset = 0;
+ while(offset != key_len && counter != 0xFFFFFFFF)
+ {
+ m_hash->update(secret, secret_len);
+ m_hash->update_be(counter++);
+ m_hash->update(label, label_len);
+ m_hash->update(salt, salt_len);
+ m_hash->final(h);
+
+ const size_t added = std::min(h.size(), key_len - offset);
+ copy_mem(&key[offset], h.data(), added);
+ offset += added;
+ }
+
+ return offset;
+ }
+
+}
diff --git a/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.h b/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.h
new file mode 100644
index 000000000..f61864d1f
--- /dev/null
+++ b/src/lib/kdf/kdf1_iso18033/kdf1_iso18033.h
@@ -0,0 +1,38 @@
+/*
+* KDF1 from ISO 18033-2
+* (C) 2016 Philipp Weber
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_KDF1_18033_H__
+#define BOTAN_KDF1_18033_H__
+
+#include <botan/kdf.h>
+#include <botan/hash.h>
+
+namespace Botan {
+
+/**
+* KDF1, from ISO 18033-2
+*/
+class BOTAN_DLL KDF1_18033 : public KDF
+ {
+ public:
+ std::string name() const override { return "KDF1-18033(" + m_hash->name() + ")"; }
+
+ KDF* clone() const override { return new KDF1_18033(m_hash->clone()); }
+
+ size_t kdf(byte key[], size_t key_len,
+ const byte secret[], size_t secret_len,
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const override;
+
+ KDF1_18033(HashFunction* h) : m_hash(h) {}
+ private:
+ std::unique_ptr<HashFunction> m_hash;
+ };
+
+}
+
+#endif
diff --git a/src/lib/kdf/kdf2/kdf2.cpp b/src/lib/kdf/kdf2/kdf2.cpp
index df2b7a91c..760ebfc83 100644
--- a/src/lib/kdf/kdf2/kdf2.cpp
+++ b/src/lib/kdf/kdf2/kdf2.cpp
@@ -11,7 +11,8 @@ namespace Botan {
size_t KDF2::kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const
{
u32bit counter = 1;
secure_vector<byte> h;
@@ -21,6 +22,7 @@ size_t KDF2::kdf(byte key[], size_t key_len,
{
m_hash->update(secret, secret_len);
m_hash->update_be(counter++);
+ m_hash->update(label, label_len);
m_hash->update(salt, salt_len);
m_hash->final(h);
diff --git a/src/lib/kdf/kdf2/kdf2.h b/src/lib/kdf/kdf2/kdf2.h
index 7403df21c..600f7c91c 100644
--- a/src/lib/kdf/kdf2/kdf2.h
+++ b/src/lib/kdf/kdf2/kdf2.h
@@ -25,7 +25,8 @@ class BOTAN_DLL KDF2 final : public KDF
size_t kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const override;
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const override;
explicit KDF2(HashFunction* h) : m_hash(h) {}
private:
diff --git a/src/lib/kdf/prf_tls/prf_tls.cpp b/src/lib/kdf/prf_tls/prf_tls.cpp
index 547b0c9c8..14b330901 100644
--- a/src/lib/kdf/prf_tls/prf_tls.cpp
+++ b/src/lib/kdf/prf_tls/prf_tls.cpp
@@ -73,23 +73,36 @@ void P_hash(byte out[], size_t out_len,
size_t TLS_PRF::kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const
{
const size_t S1_len = (secret_len + 1) / 2,
S2_len = (secret_len + 1) / 2;
const byte* S1 = secret;
const byte* S2 = secret + (secret_len - S2_len);
+ secure_vector<byte> msg;
- P_hash(key, key_len, *m_hmac_md5, S1, S1_len, salt, salt_len);
- P_hash(key, key_len, *m_hmac_sha1, S2, S2_len, salt, salt_len);
+ msg.reserve(label_len + salt_len);
+ msg += std::make_pair(label, label_len);
+ msg += std::make_pair(salt, salt_len);
+
+ P_hash(key, key_len, *m_hmac_md5, S1, S1_len, msg.data(), msg.size());
+ P_hash(key, key_len, *m_hmac_sha1, S2, S2_len, msg.data(), msg.size());
return key_len;
}
size_t TLS_12_PRF::kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const
{
- P_hash(key, key_len, *m_mac, secret, secret_len, salt, salt_len);
+ secure_vector<byte> msg;
+
+ msg.reserve(label_len + salt_len);
+ msg += std::make_pair(label, label_len);
+ msg += std::make_pair(salt, salt_len);
+
+ P_hash(key, key_len, *m_mac, secret, secret_len, msg.data(), msg.size());
return key_len;
}
diff --git a/src/lib/kdf/prf_tls/prf_tls.h b/src/lib/kdf/prf_tls/prf_tls.h
index a51006d88..37a517125 100644
--- a/src/lib/kdf/prf_tls/prf_tls.h
+++ b/src/lib/kdf/prf_tls/prf_tls.h
@@ -25,7 +25,8 @@ class BOTAN_DLL TLS_PRF final : public KDF
size_t kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const override;
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const override;
TLS_PRF();
private:
@@ -45,7 +46,8 @@ class BOTAN_DLL TLS_12_PRF final : public KDF
size_t kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const override;
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const override;
explicit TLS_12_PRF(MessageAuthenticationCode* mac) : m_mac(mac) {}
diff --git a/src/lib/kdf/prf_x942/prf_x942.cpp b/src/lib/kdf/prf_x942/prf_x942.cpp
index fb8de1e85..206cf6ce6 100644
--- a/src/lib/kdf/prf_x942/prf_x942.cpp
+++ b/src/lib/kdf/prf_x942/prf_x942.cpp
@@ -30,15 +30,21 @@ std::vector<byte> encode_x942_int(u32bit n)
size_t X942_PRF::kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const
{
std::unique_ptr<HashFunction> hash(HashFunction::create("SHA-160"));
const OID kek_algo(m_key_wrap_oid);
secure_vector<byte> h;
+ secure_vector<byte> in;
size_t offset = 0;
u32bit counter = 1;
+ in.reserve(salt_len + label_len);
+ in += std::make_pair(label,label_len);
+ in += std::make_pair(salt,salt_len);
+
while(offset != key_len && counter)
{
hash->update(secret, secret_len);
@@ -54,7 +60,7 @@ size_t X942_PRF::kdf(byte key[], size_t key_len,
.encode_if(salt_len != 0,
DER_Encoder()
.start_explicit(0)
- .encode(salt, salt_len, OCTET_STRING)
+ .encode(in, OCTET_STRING)
.end_explicit()
)
diff --git a/src/lib/kdf/prf_x942/prf_x942.h b/src/lib/kdf/prf_x942/prf_x942.h
index c15be9845..afe56de80 100644
--- a/src/lib/kdf/prf_x942/prf_x942.h
+++ b/src/lib/kdf/prf_x942/prf_x942.h
@@ -24,7 +24,8 @@ class BOTAN_DLL X942_PRF final : public KDF
size_t kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const override;
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const override;
explicit X942_PRF(const std::string& oid);
private:
diff --git a/src/lib/kdf/sp800_108/sp800_108.cpp b/src/lib/kdf/sp800_108/sp800_108.cpp
index 873db814c..aafb349b2 100644
--- a/src/lib/kdf/sp800_108/sp800_108.cpp
+++ b/src/lib/kdf/sp800_108/sp800_108.cpp
@@ -8,6 +8,8 @@
#include <botan/sp800_108.h>
#include <botan/hmac.h>
+#include <iterator>
+
namespace Botan {
SP800_108_Counter* SP800_108_Counter::make(const Spec& spec)
@@ -23,13 +25,18 @@ SP800_108_Counter* SP800_108_Counter::make(const Spec& spec)
size_t SP800_108_Counter::kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const
{
const std::size_t prf_len = m_prf->output_length();
+ const byte delim = 0;
byte *p = key;
uint32_t counter = 1;
+ uint32_t length = key_len * 8;
+ byte be_len[4] = { 0 };
secure_vector<byte> tmp;
+ store_be(length, be_len);
m_prf->set_key(secret, secret_len);
while(p < key + key_len && counter != 0)
@@ -40,7 +47,10 @@ size_t SP800_108_Counter::kdf(byte key[], size_t key_len,
store_be(counter, be_cnt);
m_prf->update(be_cnt,4);
- m_prf->update(salt, salt_len);
+ m_prf->update(label,label_len);
+ m_prf->update(delim);
+ m_prf->update(salt,salt_len);
+ m_prf->update(be_len,4);
m_prf->final(tmp);
std::move(tmp.begin(), tmp.begin() + to_copy, p);
@@ -68,16 +78,21 @@ SP800_108_Feedback* SP800_108_Feedback::make(const Spec& spec)
size_t SP800_108_Feedback::kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const
{
const std::size_t prf_len = m_prf->output_length();
const std::size_t iv_len = (salt_len >= prf_len ? prf_len : 0);
+ const byte delim = 0;
byte *p = key;
uint32_t counter = 1;
+ uint32_t length = key_len * 8;
+ byte be_len[4] = { 0 };
secure_vector< byte > prev(salt, salt + iv_len);
secure_vector< byte > ctx(salt + iv_len, salt + salt_len);
+ store_be(length, be_len);
m_prf->set_key(secret, secret_len);
while(p < key + key_len && counter != 0)
@@ -89,7 +104,10 @@ size_t SP800_108_Feedback::kdf(byte key[], size_t key_len,
m_prf->update(prev);
m_prf->update(be_cnt,4);
+ m_prf->update(label,label_len);
+ m_prf->update(delim);
m_prf->update(ctx);
+ m_prf->update(be_len,4);
m_prf->final(prev);
std::copy(prev.begin(), prev.begin() + to_copy, p);
@@ -117,15 +135,27 @@ SP800_108_Pipeline* SP800_108_Pipeline::make(const Spec& spec)
size_t SP800_108_Pipeline::kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const
{
const std::size_t prf_len = m_prf->output_length();
+ const byte delim = 0;
+
byte *p = key;
uint32_t counter = 1;
- secure_vector<byte> ai(salt, salt + salt_len), ki;
+ uint32_t length = key_len * 8;
+ byte be_len[4] = { 0 };
+ secure_vector<byte> ai, ki;
+ store_be(length, be_len);
m_prf->set_key(secret,secret_len);
+ // A(0)
+ std::copy(label,label + label_len,std::back_inserter(ai));
+ ai.emplace_back(delim);
+ std::copy(salt,salt + salt_len,std::back_inserter(ai));
+ std::copy(be_len,be_len + 4,std::back_inserter(ai));
+
while(p < key + key_len && counter != 0)
{
// A(i)
@@ -140,7 +170,10 @@ size_t SP800_108_Pipeline::kdf(byte key[], size_t key_len,
m_prf->update(ai);
m_prf->update(be_cnt,4);
+ m_prf->update(label, label_len);
+ m_prf->update(delim);
m_prf->update(salt, salt_len);
+ m_prf->update(be_len,4);
m_prf->final(ki);
std::copy(ki.begin(), ki.begin() + to_copy, p);
diff --git a/src/lib/kdf/sp800_108/sp800_108.h b/src/lib/kdf/sp800_108/sp800_108.h
index 0acdfacf9..71a918c15 100644
--- a/src/lib/kdf/sp800_108/sp800_108.h
+++ b/src/lib/kdf/sp800_108/sp800_108.h
@@ -23,9 +23,27 @@ class BOTAN_DLL SP800_108_Counter : public KDF
KDF* clone() const override { return new SP800_108_Counter(m_prf->clone()); }
+ /**
+ * Derive a key using the SP800-108 KDF in Counter mode.
+ *
+ * The implementation hard codes the length of [L]_2
+ * and [i]_2 (the value r) to 32 bits.
+ *
+ * @param key resulting keying material
+ * @param key_len the desired output length in bytes
+ * @param secret K_I
+ * @param secret_len size of K_I in bytes
+ * @param salt Context
+ * @param salt_len size of Context in bytes
+ * @param label Label
+ * @param label_len size of Label in bytes
+ *
+ * @throws Invalid_Argument key_len > 2^32
+ */
size_t kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const override;
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const override;
SP800_108_Counter(MessageAuthenticationCode* mac) : m_prf(mac) {}
@@ -44,9 +62,27 @@ class BOTAN_DLL SP800_108_Feedback : public KDF
KDF* clone() const override { return new SP800_108_Feedback(m_prf->clone()); }
+ /**
+ * Derive a key using the SP800-108 KDF in Feedback mode.
+ *
+ * The implementation uses the optional counter i and hard
+ * codes the length of [L]_2 and [i]_2 (the value r) to 32 bits.
+ *
+ * @param key resulting keying material
+ * @param key_len the desired output length in bytes
+ * @param secret K_I
+ * @param secret_len size of K_I in bytes
+ * @param salt IV || Context
+ * @param salt_len size of Context plus IV in bytes
+ * @param label Label
+ * @param label_len size of Label in bytes
+ *
+ * @throws Invalid_Argument key_len > 2^32
+ */
size_t kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const override;
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const override;
SP800_108_Feedback(MessageAuthenticationCode* mac) : m_prf(mac) {}
@@ -65,9 +101,27 @@ class BOTAN_DLL SP800_108_Pipeline : public KDF
KDF* clone() const override { return new SP800_108_Pipeline(m_prf->clone()); }
+ /**
+ * Derive a key using the SP800-108 KDF in Double Pipeline mode.
+ *
+ * The implementation uses the optional counter i and hard
+ * codes the length of [L]_2 and [i]_2 (the value r) to 32 bits.
+ *
+ * @param key resulting keying material
+ * @param key_len the desired output length in bytes
+ * @param secret K_I
+ * @param secret_len size of K_I in bytes
+ * @param salt Context
+ * @param salt_len size of Context in bytes
+ * @param label Label
+ * @param label_len size of Label in bytes
+ *
+ * @throws Invalid_Argument key_len > 2^32
+ */
size_t kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const override;
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const override;
SP800_108_Pipeline(MessageAuthenticationCode* mac) : m_prf(mac) {}
diff --git a/src/lib/kdf/sp800_56c/sp800_56c.cpp b/src/lib/kdf/sp800_56c/sp800_56c.cpp
index 664d32b30..338feba2a 100644
--- a/src/lib/kdf/sp800_56c/sp800_56c.cpp
+++ b/src/lib/kdf/sp800_56c/sp800_56c.cpp
@@ -27,17 +27,18 @@ SP800_56C* SP800_56C::make(const Spec& spec)
size_t SP800_56C::kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const
{
// Randomness Extraction
- secure_vector< byte > k_dk, context;
+ secure_vector< byte > k_dk;
m_prf->set_key(salt, salt_len);
m_prf->update(secret, secret_len);
m_prf->final(k_dk);
// Key Expansion
- m_exp->kdf(key, key_len, k_dk.data(), k_dk.size(), context.data(), context.size());
+ m_exp->kdf(key, key_len, k_dk.data(), k_dk.size(), nullptr, 0, label, label_len);
return key_len;
}
diff --git a/src/lib/kdf/sp800_56c/sp800_56c.h b/src/lib/kdf/sp800_56c/sp800_56c.h
index d1b6f39b5..1281ed314 100644
--- a/src/lib/kdf/sp800_56c/sp800_56c.h
+++ b/src/lib/kdf/sp800_56c/sp800_56c.h
@@ -23,9 +23,27 @@ class BOTAN_DLL SP800_56C : public KDF
KDF* clone() const override { return new SP800_56C(m_prf->clone(), m_exp->clone()); }
+ /**
+ * Derive a key using the SP800-56C KDF.
+ *
+ * The implementation hard codes the context value for the
+ * expansion step to the empty string.
+ *
+ * @param key derived keying material K_M
+ * @param key_len the desired output length in bytes
+ * @param secret shared secret Z
+ * @param secret_len size of Z in bytes
+ * @param salt salt s of the extraction step
+ * @param salt_len size of s in bytes
+ * @param label label for the expansion step
+ * @param label_len size of label in bytes
+ *
+ * @throws Invalid_Argument key_len > 2^32
+ */
size_t kdf(byte key[], size_t key_len,
const byte secret[], size_t secret_len,
- const byte salt[], size_t salt_len) const override;
+ const byte salt[], size_t salt_len,
+ const byte label[], size_t label_len) const override;
SP800_56C(MessageAuthenticationCode* mac, KDF* exp) : m_prf(mac), m_exp(exp) {}
diff --git a/src/lib/mac/siphash/siphash.cpp b/src/lib/mac/siphash/siphash.cpp
index 4a9ffe8ea..cb72f771c 100644
--- a/src/lib/mac/siphash/siphash.cpp
+++ b/src/lib/mac/siphash/siphash.cpp
@@ -85,9 +85,7 @@ void SipHash::final_result(byte mac[])
store_le(X, mac);
- m_mbuf = 0;
- m_mbuf_pos = 0;
- m_words = 0;
+ clear();
}
void SipHash::key_schedule(const byte key[], size_t)
@@ -105,6 +103,9 @@ void SipHash::key_schedule(const byte key[], size_t)
void SipHash::clear()
{
m_V.clear();
+ m_mbuf = 0;
+ m_mbuf_pos = 0;
+ m_words = 0;
}
std::string SipHash::name() const
diff --git a/src/lib/math/bigint/big_code.cpp b/src/lib/math/bigint/big_code.cpp
index 299fdc246..c8687715d 100644
--- a/src/lib/math/bigint/big_code.cpp
+++ b/src/lib/math/bigint/big_code.cpp
@@ -98,6 +98,17 @@ void BigInt::encode_1363(byte output[], size_t bytes, const BigInt& n)
}
/*
+* Encode two BigInt, with leading 0s if needed, and concatenate
+*/
+secure_vector<byte> BigInt::encode_fixed_length_int_pair(const BigInt& n1, const BigInt& n2, size_t bytes)
+ {
+ secure_vector<byte> output(2 * bytes);
+ BigInt::encode_1363(output.data(), bytes, n1);
+ BigInt::encode_1363(output.data() + bytes, bytes, n2);
+ return output;
+ }
+
+/*
* Decode a BigInt
*/
BigInt BigInt::decode(const byte buf[], size_t length, Base base)
diff --git a/src/lib/math/bigint/big_ops2.cpp b/src/lib/math/bigint/big_ops2.cpp
index 9a3408247..6e234f036 100644
--- a/src/lib/math/bigint/big_ops2.cpp
+++ b/src/lib/math/bigint/big_ops2.cpp
@@ -1,6 +1,7 @@
/*
* BigInt Assignment Operators
* (C) 1999-2007 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -118,10 +119,7 @@ BigInt& BigInt::operator*=(const BigInt& y)
secure_vector<word> z(data(), data() + x_sw);
secure_vector<word> workspace(size());
-
- bigint_mul(mutable_data(), size(), workspace.data(),
- z.data(), z.size(), x_sw,
- y.data(), y.size(), y_sw);
+ bigint_mul(*this, BigInt(*this), y, workspace.data());
}
return (*this);
diff --git a/src/lib/math/bigint/big_ops3.cpp b/src/lib/math/bigint/big_ops3.cpp
index 6cf837020..24927b4fc 100644
--- a/src/lib/math/bigint/big_ops3.cpp
+++ b/src/lib/math/bigint/big_ops3.cpp
@@ -1,6 +1,7 @@
/*
* BigInt Binary Operators
* (C) 1999-2007 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -93,9 +94,7 @@ BigInt operator*(const BigInt& x, const BigInt& y)
else if(x_sw && y_sw)
{
secure_vector<word> workspace(z.size());
- bigint_mul(z.mutable_data(), z.size(), workspace.data(),
- x.data(), x.size(), x_sw,
- y.data(), y.size(), y_sw);
+ bigint_mul(z, x, y, workspace.data());
}
if(x_sw && y_sw && x.sign() != y.sign())
diff --git a/src/lib/math/bigint/bigint.h b/src/lib/math/bigint/bigint.h
index 2963ba35d..a61bee39c 100644
--- a/src/lib/math/bigint/bigint.h
+++ b/src/lib/math/bigint/bigint.h
@@ -566,6 +566,15 @@ class BOTAN_DLL BigInt
static void encode_1363(byte out[], size_t bytes, const BigInt& n);
+ /**
+ * Encode two BigInt to a byte array according to IEEE 1363
+ * @param n1 the first BigInt to encode
+ * @param n2 the second BigInt to encode
+ * @param bytes the length of the encoding of each single BigInt
+ * @result a secure_vector<byte> containing the concatenation of the two encoded BigInt
+ */
+ static secure_vector<byte> encode_fixed_length_int_pair(const BigInt& n1, const BigInt& n2, size_t bytes);
+
private:
secure_vector<word> m_reg;
Sign m_signedness = Positive;
diff --git a/src/lib/math/ec_gfp/curve_gfp.cpp b/src/lib/math/ec_gfp/curve_gfp.cpp
index 9bf2191c6..96593e601 100644
--- a/src/lib/math/ec_gfp/curve_gfp.cpp
+++ b/src/lib/math/ec_gfp/curve_gfp.cpp
@@ -1,6 +1,7 @@
/*
* Elliptic curves over GF(p) Montgomery Representation
* (C) 2014,2015 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -80,20 +81,14 @@ void CurveGFp_Montgomery::curve_mul(BigInt& z, const BigInt& x, const BigInt& y,
return;
}
- const size_t x_sw = x.sig_words();
- const size_t y_sw = y.sig_words();
-
const size_t output_size = 2*m_p_words + 1;
ws.resize(2*(m_p_words+2));
z.grow_to(output_size);
z.clear();
- bigint_monty_mul(z.mutable_data(), output_size,
- x.data(), x.size(), x_sw,
- y.data(), y.size(), y_sw,
- m_p.data(), m_p_words, m_p_dash,
- ws.data());
+ bigint_monty_mul(z, x, y, m_p.data(), m_p_words, m_p_dash, ws.data());
+
}
void CurveGFp_Montgomery::curve_sqr(BigInt& z, const BigInt& x,
@@ -115,9 +110,7 @@ void CurveGFp_Montgomery::curve_sqr(BigInt& z, const BigInt& x,
z.grow_to(output_size);
z.clear();
- bigint_monty_sqr(z.mutable_data(), output_size,
- x.data(), x.size(), x_sw,
- m_p.data(), m_p_words, m_p_dash,
+ bigint_monty_sqr(z, x, m_p.data(), m_p_words, m_p_dash,
ws.data());
}
@@ -174,9 +167,7 @@ void CurveGFp_NIST::curve_mul(BigInt& z, const BigInt& x, const BigInt& y,
z.grow_to(output_size);
z.clear();
- bigint_mul(z.mutable_data(), output_size, ws.data(),
- x.data(), x.size(), x.sig_words(),
- y.data(), y.size(), y.sig_words());
+ bigint_mul(z, x, y, ws.data());
this->redc(z, ws);
}
diff --git a/src/lib/math/mp/info.txt b/src/lib/math/mp/info.txt
index 6aa0142f3..b5db12648 100644
--- a/src/lib/math/mp/info.txt
+++ b/src/lib/math/mp/info.txt
@@ -1,12 +1,10 @@
define BIGINT_MP 20151225
<source>
-mp_asm.cpp
+mp_core.cpp
mp_comba.cpp
mp_karat.cpp
mp_monty.cpp
-mp_misc.cpp
-mp_shift.cpp
</source>
<header:public>
@@ -15,8 +13,6 @@ mp_types.h
<header:internal>
mp_core.h
+mp_madd.h
+mp_asmi.h
</header:internal>
-
-<requires>
-mp_x86_64|mp_x86_32|mp_x86_32_msvc|mp_generic
-</requires>
diff --git a/src/lib/math/mp/mp_asmi.h b/src/lib/math/mp/mp_asmi.h
new file mode 100644
index 000000000..afb4d1407
--- /dev/null
+++ b/src/lib/math/mp/mp_asmi.h
@@ -0,0 +1,820 @@
+/*
+* Lowest Level MPI Algorithms
+* (C) 1999-2010 Jack Lloyd
+* 2006 Luca Piccarreta
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_MP_ASM_INTERNAL_H__
+#define BOTAN_MP_ASM_INTERNAL_H__
+
+#include <botan/internal/mp_madd.h>
+
+namespace Botan {
+
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+
+#define ADDSUB2_OP(OPERATION, INDEX) \
+ ASM("movl 4*" #INDEX "(%[y]), %[carry]") \
+ ASM(OPERATION " %[carry], 4*" #INDEX "(%[x])") \
+
+#define ADDSUB3_OP(OPERATION, INDEX) \
+ ASM("movl 4*" #INDEX "(%[x]), %[carry]") \
+ ASM(OPERATION " 4*" #INDEX "(%[y]), %[carry]") \
+ ASM("movl %[carry], 4*" #INDEX "(%[z])") \
+
+#define LINMUL_OP(WRITE_TO, INDEX) \
+ ASM("movl 4*" #INDEX "(%[x]),%%eax") \
+ ASM("mull %[y]") \
+ ASM("addl %[carry],%%eax") \
+ ASM("adcl $0,%%edx") \
+ ASM("movl %%edx,%[carry]") \
+ ASM("movl %%eax, 4*" #INDEX "(%[" WRITE_TO "])")
+
+#define MULADD_OP(IGNORED, INDEX) \
+ ASM("movl 4*" #INDEX "(%[x]),%%eax") \
+ ASM("mull %[y]") \
+ ASM("addl %[carry],%%eax") \
+ ASM("adcl $0,%%edx") \
+ ASM("addl 4*" #INDEX "(%[z]),%%eax") \
+ ASM("adcl $0,%%edx") \
+ ASM("movl %%edx,%[carry]") \
+ ASM("movl %%eax, 4*" #INDEX " (%[z])")
+
+#define ADD_OR_SUBTRACT(CORE_CODE) \
+ ASM("rorl %[carry]") \
+ CORE_CODE \
+ ASM("sbbl %[carry],%[carry]") \
+ ASM("negl %[carry]")
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
+
+#define ADDSUB2_OP(OPERATION, INDEX) \
+ ASM("movq 8*" #INDEX "(%[y]), %[carry]") \
+ ASM(OPERATION " %[carry], 8*" #INDEX "(%[x])") \
+
+#define ADDSUB3_OP(OPERATION, INDEX) \
+ ASM("movq 8*" #INDEX "(%[x]), %[carry]") \
+ ASM(OPERATION " 8*" #INDEX "(%[y]), %[carry]") \
+ ASM("movq %[carry], 8*" #INDEX "(%[z])") \
+
+#define LINMUL_OP(WRITE_TO, INDEX) \
+ ASM("movq 8*" #INDEX "(%[x]),%%rax") \
+ ASM("mulq %[y]") \
+ ASM("addq %[carry],%%rax") \
+ ASM("adcq $0,%%rdx") \
+ ASM("movq %%rdx,%[carry]") \
+ ASM("movq %%rax, 8*" #INDEX "(%[" WRITE_TO "])")
+
+#define MULADD_OP(IGNORED, INDEX) \
+ ASM("movq 8*" #INDEX "(%[x]),%%rax") \
+ ASM("mulq %[y]") \
+ ASM("addq %[carry],%%rax") \
+ ASM("adcq $0,%%rdx") \
+ ASM("addq 8*" #INDEX "(%[z]),%%rax") \
+ ASM("adcq $0,%%rdx") \
+ ASM("movq %%rdx,%[carry]") \
+ ASM("movq %%rax, 8*" #INDEX " (%[z])")
+
+#define ADD_OR_SUBTRACT(CORE_CODE) \
+ ASM("rorq %[carry]") \
+ CORE_CODE \
+ ASM("sbbq %[carry],%[carry]") \
+ ASM("negq %[carry]")
+
+#endif
+
+#if defined(ADD_OR_SUBTRACT)
+
+#define ASM(x) x "\n\t"
+
+#define DO_8_TIMES(MACRO, ARG) \
+ MACRO(ARG, 0) \
+ MACRO(ARG, 1) \
+ MACRO(ARG, 2) \
+ MACRO(ARG, 3) \
+ MACRO(ARG, 4) \
+ MACRO(ARG, 5) \
+ MACRO(ARG, 6) \
+ MACRO(ARG, 7)
+
+#endif
+
+/*
+* Word Addition
+*/
+inline word word_add(word x, word y, word* carry)
+ {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+ asm(
+ ADD_OR_SUBTRACT(ASM("adcl %[y],%[x]"))
+ : [x]"=r"(x), [carry]"=r"(*carry)
+ : "0"(x), [y]"rm"(y), "1"(*carry)
+ : "cc");
+ return x;
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
+
+ asm(
+ ADD_OR_SUBTRACT(ASM("adcq %[y],%[x]"))
+ : [x]"=r"(x), [carry]"=r"(*carry)
+ : "0"(x), [y]"rm"(y), "1"(*carry)
+ : "cc");
+ return x;
+
+#else
+ word z = x + y;
+ word c1 = (z < x);
+ z += *carry;
+ *carry = c1 | (z < *carry);
+ return z;
+#endif
+ }
+
+/*
+* Eight Word Block Addition, Two Argument
+*/
+inline word word8_add2(word x[8], const word y[8], word carry)
+ {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+ asm(
+ ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcl"))
+ : [carry]"=r"(carry)
+ : [x]"r"(x), [y]"r"(y), "0"(carry)
+ : "cc", "memory");
+ return carry;
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
+
+ asm(
+ ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcq"))
+ : [carry]"=r"(carry)
+ : [x]"r"(x), [y]"r"(y), "0"(carry)
+ : "cc", "memory");
+ return carry;
+
+#elif defined(BOTAN_MP_USE_X86_32_MSVC_ASM)
+
+ __asm {
+ mov edx,[x]
+ mov esi,[y]
+ xor eax,eax
+ sub eax,[carry] //force CF=1 iff *carry==1
+ mov eax,[esi]
+ adc [edx],eax
+ mov eax,[esi+4]
+ adc [edx+4],eax
+ mov eax,[esi+8]
+ adc [edx+8],eax
+ mov eax,[esi+12]
+ adc [edx+12],eax
+ mov eax,[esi+16]
+ adc [edx+16],eax
+ mov eax,[esi+20]
+ adc [edx+20],eax
+ mov eax,[esi+24]
+ adc [edx+24],eax
+ mov eax,[esi+28]
+ adc [edx+28],eax
+ sbb eax,eax
+ neg eax
+ }
+
+#else
+ x[0] = word_add(x[0], y[0], &carry);
+ x[1] = word_add(x[1], y[1], &carry);
+ x[2] = word_add(x[2], y[2], &carry);
+ x[3] = word_add(x[3], y[3], &carry);
+ x[4] = word_add(x[4], y[4], &carry);
+ x[5] = word_add(x[5], y[5], &carry);
+ x[6] = word_add(x[6], y[6], &carry);
+ x[7] = word_add(x[7], y[7], &carry);
+ return carry;
+#endif
+ }
+
+/*
+* Eight Word Block Addition, Three Argument
+*/
+inline word word8_add3(word z[8], const word x[8],
+ const word y[8], word carry)
+ {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+ asm(
+ ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcl"))
+ : [carry]"=r"(carry)
+ : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry)
+ : "cc", "memory");
+ return carry;
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
+
+ asm(
+ ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcq"))
+ : [carry]"=r"(carry)
+ : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry)
+ : "cc", "memory");
+ return carry;
+
+#elif defined(BOTAN_MP_USE_X86_32_MSVC_ASM)
+
+ __asm {
+ mov edi,[x]
+ mov esi,[y]
+ mov ebx,[z]
+ xor eax,eax
+ sub eax,[carry] //force CF=1 iff *carry==1
+ mov eax,[edi]
+ adc eax,[esi]
+ mov [ebx],eax
+
+ mov eax,[edi+4]
+ adc eax,[esi+4]
+ mov [ebx+4],eax
+
+ mov eax,[edi+8]
+ adc eax,[esi+8]
+ mov [ebx+8],eax
+
+ mov eax,[edi+12]
+ adc eax,[esi+12]
+ mov [ebx+12],eax
+
+ mov eax,[edi+16]
+ adc eax,[esi+16]
+ mov [ebx+16],eax
+
+ mov eax,[edi+20]
+ adc eax,[esi+20]
+ mov [ebx+20],eax
+
+ mov eax,[edi+24]
+ adc eax,[esi+24]
+ mov [ebx+24],eax
+
+ mov eax,[edi+28]
+ adc eax,[esi+28]
+ mov [ebx+28],eax
+
+ sbb eax,eax
+ neg eax
+ }
+
+#else
+ z[0] = word_add(x[0], y[0], &carry);
+ z[1] = word_add(x[1], y[1], &carry);
+ z[2] = word_add(x[2], y[2], &carry);
+ z[3] = word_add(x[3], y[3], &carry);
+ z[4] = word_add(x[4], y[4], &carry);
+ z[5] = word_add(x[5], y[5], &carry);
+ z[6] = word_add(x[6], y[6], &carry);
+ z[7] = word_add(x[7], y[7], &carry);
+ return carry;
+#endif
+ }
+
+/*
+* Word Subtraction
+*/
+inline word word_sub(word x, word y, word* carry)
+ {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+ asm(
+ ADD_OR_SUBTRACT(ASM("sbbl %[y],%[x]"))
+ : [x]"=r"(x), [carry]"=r"(*carry)
+ : "0"(x), [y]"rm"(y), "1"(*carry)
+ : "cc");
+ return x;
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
+
+ asm(
+ ADD_OR_SUBTRACT(ASM("sbbq %[y],%[x]"))
+ : [x]"=r"(x), [carry]"=r"(*carry)
+ : "0"(x), [y]"rm"(y), "1"(*carry)
+ : "cc");
+ return x;
+
+#else
+ word t0 = x - y;
+ word c1 = (t0 > x);
+ word z = t0 - *carry;
+ *carry = c1 | (z > t0);
+ return z;
+#endif
+ }
+
+/*
+* Eight Word Block Subtraction, Two Argument
+*/
+inline word word8_sub2(word x[8], const word y[8], word carry)
+ {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+ asm(
+ ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbl"))
+ : [carry]"=r"(carry)
+ : [x]"r"(x), [y]"r"(y), "0"(carry)
+ : "cc", "memory");
+ return carry;
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
+
+ asm(
+ ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbq"))
+ : [carry]"=r"(carry)
+ : [x]"r"(x), [y]"r"(y), "0"(carry)
+ : "cc", "memory");
+ return carry;
+
+#elif defined(BOTAN_MP_USE_X86_32_MSVC_ASM)
+
+ __asm {
+ mov edi,[x]
+ mov esi,[y]
+ xor eax,eax
+ sub eax,[carry] //force CF=1 iff *carry==1
+ mov eax,[edi]
+ sbb eax,[esi]
+ mov [edi],eax
+ mov eax,[edi+4]
+ sbb eax,[esi+4]
+ mov [edi+4],eax
+ mov eax,[edi+8]
+ sbb eax,[esi+8]
+ mov [edi+8],eax
+ mov eax,[edi+12]
+ sbb eax,[esi+12]
+ mov [edi+12],eax
+ mov eax,[edi+16]
+ sbb eax,[esi+16]
+ mov [edi+16],eax
+ mov eax,[edi+20]
+ sbb eax,[esi+20]
+ mov [edi+20],eax
+ mov eax,[edi+24]
+ sbb eax,[esi+24]
+ mov [edi+24],eax
+ mov eax,[edi+28]
+ sbb eax,[esi+28]
+ mov [edi+28],eax
+ sbb eax,eax
+ neg eax
+ }
+
+#else
+ x[0] = word_sub(x[0], y[0], &carry);
+ x[1] = word_sub(x[1], y[1], &carry);
+ x[2] = word_sub(x[2], y[2], &carry);
+ x[3] = word_sub(x[3], y[3], &carry);
+ x[4] = word_sub(x[4], y[4], &carry);
+ x[5] = word_sub(x[5], y[5], &carry);
+ x[6] = word_sub(x[6], y[6], &carry);
+ x[7] = word_sub(x[7], y[7], &carry);
+ return carry;
+#endif
+ }
+
+/*
+* Eight Word Block Subtraction, Two Argument
+*/
+inline word word8_sub2_rev(word x[8], const word y[8], word carry)
+ {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+ asm(
+ ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl"))
+ : [carry]"=r"(carry)
+ : [x]"r"(y), [y]"r"(x), [z]"r"(x), "0"(carry)
+ : "cc", "memory");
+ return carry;
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
+
+ asm(
+ ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbq"))
+ : [carry]"=r"(carry)
+ : [x]"r"(y), [y]"r"(x), [z]"r"(x), "0"(carry)
+ : "cc", "memory");
+ return carry;
+
+#else
+ x[0] = word_sub(y[0], x[0], &carry);
+ x[1] = word_sub(y[1], x[1], &carry);
+ x[2] = word_sub(y[2], x[2], &carry);
+ x[3] = word_sub(y[3], x[3], &carry);
+ x[4] = word_sub(y[4], x[4], &carry);
+ x[5] = word_sub(y[5], x[5], &carry);
+ x[6] = word_sub(y[6], x[6], &carry);
+ x[7] = word_sub(y[7], x[7], &carry);
+ return carry;
+#endif
+ }
+
+/*
+* Eight Word Block Subtraction, Three Argument
+*/
+inline word word8_sub3(word z[8], const word x[8],
+ const word y[8], word carry)
+ {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+ asm(
+ ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl"))
+ : [carry]"=r"(carry)
+ : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry)
+ : "cc", "memory");
+ return carry;
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
+
+ asm(
+ ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbq"))
+ : [carry]"=r"(carry)
+ : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry)
+ : "cc", "memory");
+ return carry;
+
+#elif defined(BOTAN_MP_USE_X86_32_MSVC_ASM)
+
+ __asm {
+ mov edi,[x]
+ mov esi,[y]
+ xor eax,eax
+ sub eax,[carry] //force CF=1 iff *carry==1
+ mov ebx,[z]
+ mov eax,[edi]
+ sbb eax,[esi]
+ mov [ebx],eax
+ mov eax,[edi+4]
+ sbb eax,[esi+4]
+ mov [ebx+4],eax
+ mov eax,[edi+8]
+ sbb eax,[esi+8]
+ mov [ebx+8],eax
+ mov eax,[edi+12]
+ sbb eax,[esi+12]
+ mov [ebx+12],eax
+ mov eax,[edi+16]
+ sbb eax,[esi+16]
+ mov [ebx+16],eax
+ mov eax,[edi+20]
+ sbb eax,[esi+20]
+ mov [ebx+20],eax
+ mov eax,[edi+24]
+ sbb eax,[esi+24]
+ mov [ebx+24],eax
+ mov eax,[edi+28]
+ sbb eax,[esi+28]
+ mov [ebx+28],eax
+ sbb eax,eax
+ neg eax
+ }
+
+#else
+ z[0] = word_sub(x[0], y[0], &carry);
+ z[1] = word_sub(x[1], y[1], &carry);
+ z[2] = word_sub(x[2], y[2], &carry);
+ z[3] = word_sub(x[3], y[3], &carry);
+ z[4] = word_sub(x[4], y[4], &carry);
+ z[5] = word_sub(x[5], y[5], &carry);
+ z[6] = word_sub(x[6], y[6], &carry);
+ z[7] = word_sub(x[7], y[7], &carry);
+ return carry;
+#endif
+ }
+
+/*
+* Eight Word Block Linear Multiplication
+*/
+inline word word8_linmul2(word x[8], word y, word carry)
+ {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+ asm(
+ DO_8_TIMES(LINMUL_OP, "x")
+ : [carry]"=r"(carry)
+ : [x]"r"(x), [y]"rm"(y), "0"(carry)
+ : "cc", "%eax", "%edx");
+ return carry;
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
+
+ asm(
+ DO_8_TIMES(LINMUL_OP, "x")
+ : [carry]"=r"(carry)
+ : [x]"r"(x), [y]"rm"(y), "0"(carry)
+ : "cc", "%rax", "%rdx");
+ return carry;
+
+#elif defined(BOTAN_MP_USE_X86_32_MSVC_ASM)
+
+ __asm {
+ mov esi,[x]
+ mov eax,[esi] //load a
+ mul [y] //edx(hi):eax(lo)=a*b
+ add eax,[carry] //sum lo carry
+ adc edx,0 //sum hi carry
+ mov ecx,edx //store carry
+ mov [esi],eax //load a
+
+ mov eax,[esi+4] //load a
+ mul [y] //edx(hi):eax(lo)=a*b
+ add eax,ecx //sum lo carry
+ adc edx,0 //sum hi carry
+ mov ecx,edx //store carry
+ mov [esi+4],eax //load a
+
+ mov eax,[esi+8] //load a
+ mul [y] //edx(hi):eax(lo)=a*b
+ add eax,ecx //sum lo carry
+ adc edx,0 //sum hi carry
+ mov ecx,edx //store carry
+ mov [esi+8],eax //load a
+
+ mov eax,[esi+12] //load a
+ mul [y] //edx(hi):eax(lo)=a*b
+ add eax,ecx //sum lo carry
+ adc edx,0 //sum hi carry
+ mov ecx,edx //store carry
+ mov [esi+12],eax //load a
+
+ mov eax,[esi+16] //load a
+ mul [y] //edx(hi):eax(lo)=a*b
+ add eax,ecx //sum lo carry
+ adc edx,0 //sum hi carry
+ mov ecx,edx //store carry
+ mov [esi+16],eax //load a
+
+ mov eax,[esi+20] //load a
+ mul [y] //edx(hi):eax(lo)=a*b
+ add eax,ecx //sum lo carry
+ adc edx,0 //sum hi carry
+ mov ecx,edx //store carry
+ mov [esi+20],eax //load a
+
+ mov eax,[esi+24] //load a
+ mul [y] //edx(hi):eax(lo)=a*b
+ add eax,ecx //sum lo carry
+ adc edx,0 //sum hi carry
+ mov ecx,edx //store carry
+ mov [esi+24],eax //load a
+
+ mov eax,[esi+28] //load a
+ mul [y] //edx(hi):eax(lo)=a*b
+ add eax,ecx //sum lo carry
+ adc edx,0 //sum hi carry
+ mov [esi+28],eax //load a
+
+ mov eax,edx //store carry
+ }
+
+#else
+ x[0] = word_madd2(x[0], y, &carry);
+ x[1] = word_madd2(x[1], y, &carry);
+ x[2] = word_madd2(x[2], y, &carry);
+ x[3] = word_madd2(x[3], y, &carry);
+ x[4] = word_madd2(x[4], y, &carry);
+ x[5] = word_madd2(x[5], y, &carry);
+ x[6] = word_madd2(x[6], y, &carry);
+ x[7] = word_madd2(x[7], y, &carry);
+ return carry;
+#endif
+ }
+
+/*
+* Eight Word Block Linear Multiplication
+*/
+inline word word8_linmul3(word z[8], const word x[8], word y, word carry)
+ {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+ asm(
+ DO_8_TIMES(LINMUL_OP, "z")
+ : [carry]"=r"(carry)
+ : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry)
+ : "cc", "%eax", "%edx");
+ return carry;
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
+ asm(
+ DO_8_TIMES(LINMUL_OP, "z")
+ : [carry]"=r"(carry)
+ : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry)
+ : "cc", "%rax", "%rdx");
+ return carry;
+
+#elif defined(BOTAN_MP_USE_X86_32_MSVC_ASM)
+
+ __asm {
+ mov edi,[z]
+ mov esi,[x]
+ mov eax,[esi] //load a
+ mul [y] //edx(hi):eax(lo)=a*b
+ add eax,[carry] //sum lo carry
+ adc edx,0 //sum hi carry
+ mov ecx,edx //store carry
+ mov [edi],eax //load a
+
+ mov eax,[esi+4] //load a
+ mul [y] //edx(hi):eax(lo)=a*b
+ add eax,ecx //sum lo carry
+ adc edx,0 //sum hi carry
+ mov ecx,edx //store carry
+ mov [edi+4],eax //load a
+
+ mov eax,[esi+8] //load a
+ mul [y] //edx(hi):eax(lo)=a*b
+ add eax,ecx //sum lo carry
+ adc edx,0 //sum hi carry
+ mov ecx,edx //store carry
+ mov [edi+8],eax //load a
+
+ mov eax,[esi+12] //load a
+ mul [y] //edx(hi):eax(lo)=a*b
+ add eax,ecx //sum lo carry
+ adc edx,0 //sum hi carry
+ mov ecx,edx //store carry
+ mov [edi+12],eax //load a
+
+ mov eax,[esi+16] //load a
+ mul [y] //edx(hi):eax(lo)=a*b
+ add eax,ecx //sum lo carry
+ adc edx,0 //sum hi carry
+ mov ecx,edx //store carry
+ mov [edi+16],eax //load a
+
+ mov eax,[esi+20] //load a
+ mul [y] //edx(hi):eax(lo)=a*b
+ add eax,ecx //sum lo carry
+ adc edx,0 //sum hi carry
+ mov ecx,edx //store carry
+ mov [edi+20],eax //load a
+
+ mov eax,[esi+24] //load a
+ mul [y] //edx(hi):eax(lo)=a*b
+ add eax,ecx //sum lo carry
+ adc edx,0 //sum hi carry
+ mov ecx,edx //store carry
+ mov [edi+24],eax //load a
+
+ mov eax,[esi+28] //load a
+ mul [y] //edx(hi):eax(lo)=a*b
+ add eax,ecx //sum lo carry
+ adc edx,0 //sum hi carry
+ mov [edi+28],eax //load a
+ mov eax,edx //store carry
+ }
+
+#else
+ z[0] = word_madd2(x[0], y, &carry);
+ z[1] = word_madd2(x[1], y, &carry);
+ z[2] = word_madd2(x[2], y, &carry);
+ z[3] = word_madd2(x[3], y, &carry);
+ z[4] = word_madd2(x[4], y, &carry);
+ z[5] = word_madd2(x[5], y, &carry);
+ z[6] = word_madd2(x[6], y, &carry);
+ z[7] = word_madd2(x[7], y, &carry);
+ return carry;
+#endif
+ }
+
+/*
+* Eight Word Block Multiply/Add
+*/
+inline word word8_madd3(word z[8], const word x[8], word y, word carry)
+ {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+ asm(
+ DO_8_TIMES(MULADD_OP, "")
+ : [carry]"=r"(carry)
+ : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry)
+ : "cc", "%eax", "%edx");
+ return carry;
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
+
+ asm(
+ DO_8_TIMES(MULADD_OP, "")
+ : [carry]"=r"(carry)
+ : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry)
+ : "cc", "%rax", "%rdx");
+ return carry;
+
+#else
+ z[0] = word_madd3(x[0], y, z[0], &carry);
+ z[1] = word_madd3(x[1], y, z[1], &carry);
+ z[2] = word_madd3(x[2], y, z[2], &carry);
+ z[3] = word_madd3(x[3], y, z[3], &carry);
+ z[4] = word_madd3(x[4], y, z[4], &carry);
+ z[5] = word_madd3(x[5], y, z[5], &carry);
+ z[6] = word_madd3(x[6], y, z[6], &carry);
+ z[7] = word_madd3(x[7], y, z[7], &carry);
+ return carry;
+#endif
+ }
+
+/*
+* Multiply-Add Accumulator
+* (w2,w1,w0) += x * y
+*/
+inline void word3_muladd(word* w2, word* w1, word* w0, word x, word y)
+ {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+ asm(
+ ASM("mull %[y]")
+
+ ASM("addl %[x],%[w0]")
+ ASM("adcl %[y],%[w1]")
+ ASM("adcl $0,%[w2]")
+
+ : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2)
+ : [x]"a"(x), [y]"d"(y), "0"(*w0), "1"(*w1), "2"(*w2)
+ : "cc");
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
+
+ asm(
+ ASM("mulq %[y]")
+
+ ASM("addq %[x],%[w0]")
+ ASM("adcq %[y],%[w1]")
+ ASM("adcq $0,%[w2]")
+
+ : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2)
+ : [x]"a"(x), [y]"d"(y), "0"(*w0), "1"(*w1), "2"(*w2)
+ : "cc");
+
+#else
+ word carry = *w0;
+ *w0 = word_madd2(x, y, &carry);
+ *w1 += carry;
+ *w2 += (*w1 < carry) ? 1 : 0;
+#endif
+ }
+
+/*
+* Multiply-Add Accumulator
+* (w2,w1,w0) += 2 * x * y
+*/
+inline void word3_muladd_2(word* w2, word* w1, word* w0, word x, word y)
+ {
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+ asm(
+ ASM("mull %[y]")
+
+ ASM("addl %[x],%[w0]")
+ ASM("adcl %[y],%[w1]")
+ ASM("adcl $0,%[w2]")
+
+ ASM("addl %[x],%[w0]")
+ ASM("adcl %[y],%[w1]")
+ ASM("adcl $0,%[w2]")
+
+ : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2)
+ : [x]"a"(x), [y]"d"(y), "0"(*w0), "1"(*w1), "2"(*w2)
+ : "cc");
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
+
+ asm(
+ ASM("mulq %[y]")
+
+ ASM("addq %[x],%[w0]")
+ ASM("adcq %[y],%[w1]")
+ ASM("adcq $0,%[w2]")
+
+ ASM("addq %[x],%[w0]")
+ ASM("adcq %[y],%[w1]")
+ ASM("adcq $0,%[w2]")
+
+ : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2)
+ : [x]"a"(x), [y]"d"(y), "0"(*w0), "1"(*w1), "2"(*w2)
+ : "cc");
+
+#else
+ word carry = 0;
+ x = word_madd2(x, y, &carry);
+ y = carry;
+
+ word top = (y >> (BOTAN_MP_WORD_BITS-1));
+ y <<= 1;
+ y |= (x >> (BOTAN_MP_WORD_BITS-1));
+ x <<= 1;
+
+ carry = 0;
+ *w0 = word_add(*w0, x, &carry);
+ *w1 = word_add(*w1, y, &carry);
+ *w2 = word_add(*w2, top, &carry);
+#endif
+ }
+
+#if defined(ASM)
+ #undef ASM
+ #undef DO_8_TIMES
+ #undef ADD_OR_SUBTRACT
+ #undef ADDSUB2_OP
+ #undef ADDSUB3_OP
+ #undef LINMUL_OP
+ #undef MULADD_OP
+#endif
+
+}
+
+#endif
diff --git a/src/lib/math/mp/mp_asm.cpp b/src/lib/math/mp/mp_core.cpp
index cfbb027d7..2a0b08f67 100644
--- a/src/lib/math/mp/mp_asm.cpp
+++ b/src/lib/math/mp/mp_core.cpp
@@ -8,7 +8,6 @@
#include <botan/internal/mp_core.h>
#include <botan/internal/mp_asmi.h>
-#include <botan/internal/mp_core.h>
#include <botan/internal/ct_utils.h>
#include <botan/exceptn.h>
#include <botan/mem_ops.h>
@@ -253,4 +252,189 @@ void bigint_linmul3(word z[], const word x[], size_t x_size, word y)
z[x_size] = carry;
}
+/*
+* Single Operand Left Shift
+*/
+void bigint_shl1(word x[], size_t x_size, size_t word_shift, size_t bit_shift)
+ {
+ if(word_shift)
+ {
+ copy_mem(x + word_shift, x, x_size);
+ clear_mem(x, word_shift);
+ }
+
+ if(bit_shift)
+ {
+ word carry = 0;
+ for(size_t j = word_shift; j != x_size + word_shift + 1; ++j)
+ {
+ word temp = x[j];
+ x[j] = (temp << bit_shift) | carry;
+ carry = (temp >> (MP_WORD_BITS - bit_shift));
+ }
+ }
+ }
+
+/*
+* Single Operand Right Shift
+*/
+void bigint_shr1(word x[], size_t x_size, size_t word_shift, size_t bit_shift)
+ {
+ if(x_size < word_shift)
+ {
+ clear_mem(x, x_size);
+ return;
+ }
+
+ if(word_shift)
+ {
+ copy_mem(x, x + word_shift, x_size - word_shift);
+ clear_mem(x + x_size - word_shift, word_shift);
+ }
+
+ if(bit_shift)
+ {
+ word carry = 0;
+
+ size_t top = x_size - word_shift;
+
+ while(top >= 4)
+ {
+ word w = x[top-1];
+ x[top-1] = (w >> bit_shift) | carry;
+ carry = (w << (MP_WORD_BITS - bit_shift));
+
+ w = x[top-2];
+ x[top-2] = (w >> bit_shift) | carry;
+ carry = (w << (MP_WORD_BITS - bit_shift));
+
+ w = x[top-3];
+ x[top-3] = (w >> bit_shift) | carry;
+ carry = (w << (MP_WORD_BITS - bit_shift));
+
+ w = x[top-4];
+ x[top-4] = (w >> bit_shift) | carry;
+ carry = (w << (MP_WORD_BITS - bit_shift));
+
+ top -= 4;
+ }
+
+ while(top)
+ {
+ word w = x[top-1];
+ x[top-1] = (w >> bit_shift) | carry;
+ carry = (w << (MP_WORD_BITS - bit_shift));
+
+ top--;
+ }
+ }
+ }
+
+/*
+* Two Operand Left Shift
+*/
+void bigint_shl2(word y[], const word x[], size_t x_size,
+ size_t word_shift, size_t bit_shift)
+ {
+ for(size_t j = 0; j != x_size; ++j)
+ y[j + word_shift] = x[j];
+ if(bit_shift)
+ {
+ word carry = 0;
+ for(size_t j = word_shift; j != x_size + word_shift + 1; ++j)
+ {
+ word w = y[j];
+ y[j] = (w << bit_shift) | carry;
+ carry = (w >> (MP_WORD_BITS - bit_shift));
+ }
+ }
+ }
+
+/*
+* Two Operand Right Shift
+*/
+void bigint_shr2(word y[], const word x[], size_t x_size,
+ size_t word_shift, size_t bit_shift)
+ {
+ if(x_size < word_shift) return;
+
+ for(size_t j = 0; j != x_size - word_shift; ++j)
+ y[j] = x[j + word_shift];
+ if(bit_shift)
+ {
+ word carry = 0;
+ for(size_t j = x_size - word_shift; j > 0; --j)
+ {
+ word w = y[j-1];
+ y[j-1] = (w >> bit_shift) | carry;
+ carry = (w << (MP_WORD_BITS - bit_shift));
+ }
+ }
+ }
+
+/*
+* Compare two MP integers
+*/
+s32bit bigint_cmp(const word x[], size_t x_size,
+ const word y[], size_t y_size)
+ {
+ if(x_size < y_size) { return (-bigint_cmp(y, y_size, x, x_size)); }
+
+ while(x_size > y_size)
+ {
+ if(x[x_size-1])
+ return 1;
+ x_size--;
+ }
+
+ for(size_t i = x_size; i > 0; --i)
+ {
+ if(x[i-1] > y[i-1])
+ return 1;
+ if(x[i-1] < y[i-1])
+ return -1;
+ }
+
+ return 0;
+ }
+
+/*
+* Do a 2-word/1-word Division
+*/
+word bigint_divop(word n1, word n0, word d)
+ {
+ if(d == 0)
+ throw Invalid_Argument("bigint_divop divide by zero");
+
+ word high = n1 % d, quotient = 0;
+
+ for(size_t i = 0; i != MP_WORD_BITS; ++i)
+ {
+ word high_top_bit = (high & MP_WORD_TOP_BIT);
+
+ high <<= 1;
+ high |= (n0 >> (MP_WORD_BITS-1-i)) & 1;
+ quotient <<= 1;
+
+ if(high_top_bit || high >= d)
+ {
+ high -= d;
+ quotient |= 1;
+ }
+ }
+
+ return quotient;
+ }
+
+/*
+* Do a 2-word/1-word Modulo
+*/
+word bigint_modop(word n1, word n0, word d)
+ {
+ word z = bigint_divop(n1, n0, d);
+ word dummy = 0;
+ z = word_madd2(z, d, &dummy);
+ return (n0-z);
+ }
+
}
diff --git a/src/lib/math/mp/mp_core.h b/src/lib/math/mp/mp_core.h
index 73f13742c..c4ce005ba 100644
--- a/src/lib/math/mp/mp_core.h
+++ b/src/lib/math/mp/mp_core.h
@@ -2,6 +2,7 @@
* MPI Algorithms
* (C) 1999-2010 Jack Lloyd
* 2006 Luca Piccarreta
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -9,6 +10,7 @@
#ifndef BOTAN_MP_CORE_OPS_H__
#define BOTAN_MP_CORE_OPS_H__
+#include <botan/bigint.h>
#include <botan/mp_types.h>
namespace Botan {
@@ -134,17 +136,14 @@ void bigint_monty_redc(word z[],
/*
* Montgomery Multiplication
*/
-void bigint_monty_mul(word z[], size_t z_size,
- const word x[], size_t x_size, size_t x_sw,
- const word y[], size_t y_size, size_t y_sw,
+void bigint_monty_mul(BigInt& z, const BigInt& x, const BigInt& y,
const word p[], size_t p_size, word p_dash,
word workspace[]);
/*
* Montgomery Squaring
*/
-void bigint_monty_sqr(word z[], size_t z_size,
- const word x[], size_t x_size, size_t x_sw,
+void bigint_monty_sqr(BigInt& z, const BigInt& x,
const word p[], size_t p_size, word p_dash,
word workspace[]);
@@ -182,9 +181,7 @@ void bigint_comba_sqr16(word out[32], const word in[16]);
/*
* High Level Multiplication/Squaring Interfaces
*/
-void bigint_mul(word z[], size_t z_size, word workspace[],
- const word x[], size_t x_size, size_t x_sw,
- const word y[], size_t y_size, size_t y_sw);
+void bigint_mul(BigInt& z, const BigInt& x, const BigInt& y, word workspace[]);
void bigint_sqr(word z[], size_t z_size, word workspace[],
const word x[], size_t x_size, size_t x_sw);
diff --git a/src/lib/math/mp/mp_generic/info.txt b/src/lib/math/mp/mp_generic/info.txt
deleted file mode 100644
index c87dd00ca..000000000
--- a/src/lib/math/mp/mp_generic/info.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-load_on dep
-
-<header:internal>
-mp_madd.h
-mp_asmi.h
-</header:internal>
diff --git a/src/lib/math/mp/mp_generic/mp_asmi.h b/src/lib/math/mp/mp_generic/mp_asmi.h
deleted file mode 100644
index 708afdfa0..000000000
--- a/src/lib/math/mp/mp_generic/mp_asmi.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
-* Lowest Level MPI Algorithms
-* (C) 1999-2010 Jack Lloyd
-* 2006 Luca Piccarreta
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_MP_ASM_INTERNAL_H__
-#define BOTAN_MP_ASM_INTERNAL_H__
-
-#include <botan/internal/mp_madd.h>
-
-namespace Botan {
-
-/*
-* Word Addition
-*/
-inline word word_add(word x, word y, word* carry)
- {
- word z = x + y;
- word c1 = (z < x);
- z += *carry;
- *carry = c1 | (z < *carry);
- return z;
- }
-
-/*
-* Eight Word Block Addition, Two Argument
-*/
-inline word word8_add2(word x[8], const word y[8], word carry)
- {
- x[0] = word_add(x[0], y[0], &carry);
- x[1] = word_add(x[1], y[1], &carry);
- x[2] = word_add(x[2], y[2], &carry);
- x[3] = word_add(x[3], y[3], &carry);
- x[4] = word_add(x[4], y[4], &carry);
- x[5] = word_add(x[5], y[5], &carry);
- x[6] = word_add(x[6], y[6], &carry);
- x[7] = word_add(x[7], y[7], &carry);
- return carry;
- }
-
-/*
-* Eight Word Block Addition, Three Argument
-*/
-inline word word8_add3(word z[8], const word x[8],
- const word y[8], word carry)
- {
- z[0] = word_add(x[0], y[0], &carry);
- z[1] = word_add(x[1], y[1], &carry);
- z[2] = word_add(x[2], y[2], &carry);
- z[3] = word_add(x[3], y[3], &carry);
- z[4] = word_add(x[4], y[4], &carry);
- z[5] = word_add(x[5], y[5], &carry);
- z[6] = word_add(x[6], y[6], &carry);
- z[7] = word_add(x[7], y[7], &carry);
- return carry;
- }
-
-/*
-* Word Subtraction
-*/
-inline word word_sub(word x, word y, word* carry)
- {
- word t0 = x - y;
- word c1 = (t0 > x);
- word z = t0 - *carry;
- *carry = c1 | (z > t0);
- return z;
- }
-
-/*
-* Eight Word Block Subtraction, Two Argument
-*/
-inline word word8_sub2(word x[8], const word y[8], word carry)
- {
- x[0] = word_sub(x[0], y[0], &carry);
- x[1] = word_sub(x[1], y[1], &carry);
- x[2] = word_sub(x[2], y[2], &carry);
- x[3] = word_sub(x[3], y[3], &carry);
- x[4] = word_sub(x[4], y[4], &carry);
- x[5] = word_sub(x[5], y[5], &carry);
- x[6] = word_sub(x[6], y[6], &carry);
- x[7] = word_sub(x[7], y[7], &carry);
- return carry;
- }
-
-/*
-* Eight Word Block Subtraction, Two Argument
-*/
-inline word word8_sub2_rev(word x[8], const word y[8], word carry)
- {
- x[0] = word_sub(y[0], x[0], &carry);
- x[1] = word_sub(y[1], x[1], &carry);
- x[2] = word_sub(y[2], x[2], &carry);
- x[3] = word_sub(y[3], x[3], &carry);
- x[4] = word_sub(y[4], x[4], &carry);
- x[5] = word_sub(y[5], x[5], &carry);
- x[6] = word_sub(y[6], x[6], &carry);
- x[7] = word_sub(y[7], x[7], &carry);
- return carry;
- }
-
-/*
-* Eight Word Block Subtraction, Three Argument
-*/
-inline word word8_sub3(word z[8], const word x[8],
- const word y[8], word carry)
- {
- z[0] = word_sub(x[0], y[0], &carry);
- z[1] = word_sub(x[1], y[1], &carry);
- z[2] = word_sub(x[2], y[2], &carry);
- z[3] = word_sub(x[3], y[3], &carry);
- z[4] = word_sub(x[4], y[4], &carry);
- z[5] = word_sub(x[5], y[5], &carry);
- z[6] = word_sub(x[6], y[6], &carry);
- z[7] = word_sub(x[7], y[7], &carry);
- return carry;
- }
-
-/*
-* Eight Word Block Linear Multiplication
-*/
-inline word word8_linmul2(word x[8], word y, word carry)
- {
- x[0] = word_madd2(x[0], y, &carry);
- x[1] = word_madd2(x[1], y, &carry);
- x[2] = word_madd2(x[2], y, &carry);
- x[3] = word_madd2(x[3], y, &carry);
- x[4] = word_madd2(x[4], y, &carry);
- x[5] = word_madd2(x[5], y, &carry);
- x[6] = word_madd2(x[6], y, &carry);
- x[7] = word_madd2(x[7], y, &carry);
- return carry;
- }
-
-/*
-* Eight Word Block Linear Multiplication
-*/
-inline word word8_linmul3(word z[8], const word x[8], word y, word carry)
- {
- z[0] = word_madd2(x[0], y, &carry);
- z[1] = word_madd2(x[1], y, &carry);
- z[2] = word_madd2(x[2], y, &carry);
- z[3] = word_madd2(x[3], y, &carry);
- z[4] = word_madd2(x[4], y, &carry);
- z[5] = word_madd2(x[5], y, &carry);
- z[6] = word_madd2(x[6], y, &carry);
- z[7] = word_madd2(x[7], y, &carry);
- return carry;
- }
-
-/*
-* Eight Word Block Multiply/Add
-*/
-inline word word8_madd3(word z[8], const word x[8], word y, word carry)
- {
- z[0] = word_madd3(x[0], y, z[0], &carry);
- z[1] = word_madd3(x[1], y, z[1], &carry);
- z[2] = word_madd3(x[2], y, z[2], &carry);
- z[3] = word_madd3(x[3], y, z[3], &carry);
- z[4] = word_madd3(x[4], y, z[4], &carry);
- z[5] = word_madd3(x[5], y, z[5], &carry);
- z[6] = word_madd3(x[6], y, z[6], &carry);
- z[7] = word_madd3(x[7], y, z[7], &carry);
- return carry;
- }
-
-/*
-* Multiply-Add Accumulator
-*/
-inline void word3_muladd(word* w2, word* w1, word* w0, word a, word b)
- {
- word carry = *w0;
- *w0 = word_madd2(a, b, &carry);
- *w1 += carry;
- *w2 += (*w1 < carry) ? 1 : 0;
- }
-
-/*
-* Multiply-Add Accumulator
-*/
-inline void word3_muladd_2(word* w2, word* w1, word* w0, word a, word b)
- {
- word carry = 0;
- a = word_madd2(a, b, &carry);
- b = carry;
-
- word top = (b >> (BOTAN_MP_WORD_BITS-1));
- b <<= 1;
- b |= (a >> (BOTAN_MP_WORD_BITS-1));
- a <<= 1;
-
- carry = 0;
- *w0 = word_add(*w0, a, &carry);
- *w1 = word_add(*w1, b, &carry);
- *w2 = word_add(*w2, top, &carry);
- }
-
-}
-
-#endif
diff --git a/src/lib/math/mp/mp_karat.cpp b/src/lib/math/mp/mp_karat.cpp
index 9135fdd6a..7a763e2a9 100644
--- a/src/lib/math/mp/mp_karat.cpp
+++ b/src/lib/math/mp/mp_karat.cpp
@@ -1,6 +1,7 @@
/*
* Multiplication and Squaring
* (C) 1999-2010 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -252,60 +253,55 @@ size_t karatsuba_size(size_t z_size, size_t x_size, size_t x_sw)
/*
* Multiplication Algorithm Dispatcher
*/
-void bigint_mul(word z[], size_t z_size, word workspace[],
- const word x[], size_t x_size, size_t x_sw,
- const word y[], size_t y_size, size_t y_sw)
+void bigint_mul(BigInt& z, const BigInt& x, const BigInt& y, word workspace[])
{
- // checking that z_size >= x_sw + y_sw without overflow
- BOTAN_ASSERT(z_size > x_sw && z_size > y_sw && z_size-x_sw >= y_sw, "Output size is sufficient");
-
- if(x_sw == 1)
+ if(x.sig_words() == 1)
{
- bigint_linmul3(z, y, y_sw, x[0]);
+ bigint_linmul3(z.mutable_data(), y.data(), y.sig_words(), x.data()[0]);
}
- else if(y_sw == 1)
+ else if(y.sig_words() == 1)
{
- bigint_linmul3(z, x, x_sw, y[0]);
+ bigint_linmul3(z.mutable_data(), x.data(), x.sig_words(), y.data()[0]);
}
- else if(x_sw <= 4 && x_size >= 4 &&
- y_sw <= 4 && y_size >= 4 && z_size >= 8)
+ else if(x.sig_words() <= 4 && x.size() >= 4 &&
+ y.sig_words() <= 4 && y.size() >= 4 && z.size() >= 8)
{
- bigint_comba_mul4(z, x, y);
+ bigint_comba_mul4(z.mutable_data(), x.data(), y.data());
}
- else if(x_sw <= 6 && x_size >= 6 &&
- y_sw <= 6 && y_size >= 6 && z_size >= 12)
+ else if(x.sig_words() <= 6 && x.size() >= 6 &&
+ y.sig_words() <= 6 && y.size() >= 6 && z.size() >= 12)
{
- bigint_comba_mul6(z, x, y);
+ bigint_comba_mul6(z.mutable_data(), x.data(), y.data());
}
- else if(x_sw <= 8 && x_size >= 8 &&
- y_sw <= 8 && y_size >= 8 && z_size >= 16)
+ else if(x.sig_words() <= 8 && x.size() >= 8 &&
+ y.sig_words() <= 8 && y.size() >= 8 && z.size() >= 16)
{
- bigint_comba_mul8(z, x, y);
+ bigint_comba_mul8(z.mutable_data(), x.data(), y.data());
}
- else if(x_sw <= 9 && x_size >= 9 &&
- y_sw <= 9 && y_size >= 9 && z_size >= 18)
+ else if(x.sig_words() <= 9 && x.size() >= 9 &&
+ y.sig_words() <= 9 && y.size() >= 9 && z.size() >= 18)
{
- bigint_comba_mul9(z, x, y);
+ bigint_comba_mul9(z.mutable_data(), x.data(), y.data());
}
- else if(x_sw <= 16 && x_size >= 16 &&
- y_sw <= 16 && y_size >= 16 && z_size >= 32)
+ else if(x.sig_words() <= 16 && x.size() >= 16 &&
+ y.sig_words() <= 16 && y.size() >= 16 && z.size() >= 32)
{
- bigint_comba_mul16(z, x, y);
+ bigint_comba_mul16(z.mutable_data(), x.data(), y.data());
}
- else if(x_sw < KARATSUBA_MULTIPLY_THRESHOLD ||
- y_sw < KARATSUBA_MULTIPLY_THRESHOLD ||
+ else if(x.sig_words() < KARATSUBA_MULTIPLY_THRESHOLD ||
+ y.sig_words() < KARATSUBA_MULTIPLY_THRESHOLD ||
!workspace)
{
- basecase_mul(z, x, x_sw, y, y_sw);
+ basecase_mul(z.mutable_data(), x.data(), x.sig_words(), y.data(), y.sig_words());
}
else
{
- const size_t N = karatsuba_size(z_size, x_size, x_sw, y_size, y_sw);
+ const size_t N = karatsuba_size(z.size(), x.size(), x.sig_words(), y.size(), y.sig_words());
if(N)
- karatsuba_mul(z, x, y, N, workspace);
+ karatsuba_mul(z.mutable_data(), x.data(), y.data(), N, workspace);
else
- basecase_mul(z, x, x_sw, y, y_sw);
+ basecase_mul(z.mutable_data(), x.data(), x.sig_words(), y.data(), y.sig_words());
}
}
diff --git a/src/lib/math/mp/mp_generic/mp_madd.h b/src/lib/math/mp/mp_madd.h
index 95a1069a4..0567622d9 100644
--- a/src/lib/math/mp/mp_generic/mp_madd.h
+++ b/src/lib/math/mp/mp_madd.h
@@ -35,12 +35,52 @@ namespace Botan {
#error BOTAN_MP_WORD_BITS must be 8, 16, 32, or 64
#endif
+#if defined(BOTAN_TARGET_ARCH_IS_X86_32) && (BOTAN_MP_WORD_BITS == 32)
+
+ #if defined(BOTAN_USE_GCC_INLINE_ASM)
+ #define BOTAN_MP_USE_X86_32_ASM
+ #define ASM(x) x "\n\t"
+ #elif defined(BOTAN_TARGET_COMPILER_IS_MSVC)
+ #define BOTAN_MP_USE_X86_32_MSVC_ASM
+ #endif
+
+#elif defined(BOTAN_TARGET_ARCH_IS_X86_64) && (BOTAN_MP_WORD_BITS == 64) && (BOTAN_USE_GCC_INLINE_ASM)
+ #define BOTAN_MP_USE_X86_64_ASM
+ #define ASM(x) x "\n\t"
+#endif
+
+#if defined(BOTAN_MP_USE_X86_32_ASM) || defined(BOTAN_MP_USE_X86_64_ASM)
+ #define ASM(x) x "\n\t"
+#endif
+
/*
* Word Multiply/Add
*/
inline word word_madd2(word a, word b, word* c)
{
-#if defined(BOTAN_HAS_MP_DWORD)
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+ asm(
+ ASM("mull %[b]")
+ ASM("addl %[c],%[a]")
+ ASM("adcl $0,%[carry]")
+
+ : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*c)
+ : "0"(a), "1"(b), [c]"g"(*c) : "cc");
+
+ return a;
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
+ asm(
+ ASM("mulq %[b]")
+ ASM("addq %[c],%[a]")
+ ASM("adcq $0,%[carry]")
+
+ : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*c)
+ : "0"(a), "1"(b), [c]"g"(*c) : "cc");
+
+ return a;
+
+#elif defined(BOTAN_HAS_MP_DWORD)
const dword s = static_cast<dword>(a) * b + *c;
*c = static_cast<word>(s >> BOTAN_MP_WORD_BITS);
return static_cast<word>(s);
@@ -64,7 +104,37 @@ inline word word_madd2(word a, word b, word* c)
*/
inline word word_madd3(word a, word b, word c, word* d)
{
-#if defined(BOTAN_HAS_MP_DWORD)
+#if defined(BOTAN_MP_USE_X86_32_ASM)
+ asm(
+ ASM("mull %[b]")
+
+ ASM("addl %[c],%[a]")
+ ASM("adcl $0,%[carry]")
+
+ ASM("addl %[d],%[a]")
+ ASM("adcl $0,%[carry]")
+
+ : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*d)
+ : "0"(a), "1"(b), [c]"g"(c), [d]"g"(*d) : "cc");
+
+ return a;
+
+#elif defined(BOTAN_MP_USE_X86_64_ASM)
+ asm(
+ ASM("mulq %[b]")
+
+ ASM("addq %[c],%[a]")
+ ASM("adcq $0,%[carry]")
+
+ ASM("addq %[d],%[a]")
+ ASM("adcq $0,%[carry]")
+
+ : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*d)
+ : "0"(a), "1"(b), [c]"g"(c), [d]"g"(*d) : "cc");
+
+ return a;
+
+#elif defined(BOTAN_HAS_MP_DWORD)
const dword s = static_cast<dword>(a) * b + c + *d;
*d = static_cast<word>(s >> BOTAN_MP_WORD_BITS);
return static_cast<word>(s);
@@ -86,6 +156,10 @@ inline word word_madd3(word a, word b, word c, word* d)
#endif
}
+#if defined(ASM)
+ #undef ASM
+#endif
+
}
#endif
diff --git a/src/lib/math/mp/mp_misc.cpp b/src/lib/math/mp/mp_misc.cpp
deleted file mode 100644
index 768543a64..000000000
--- a/src/lib/math/mp/mp_misc.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
-* MP Misc Functions
-* (C) 1999-2008 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/internal/mp_core.h>
-#include <botan/internal/mp_madd.h>
-#include <botan/exceptn.h>
-
-namespace Botan {
-
-/*
-* Compare two MP integers
-*/
-s32bit bigint_cmp(const word x[], size_t x_size,
- const word y[], size_t y_size)
- {
- if(x_size < y_size) { return (-bigint_cmp(y, y_size, x, x_size)); }
-
- while(x_size > y_size)
- {
- if(x[x_size-1])
- return 1;
- x_size--;
- }
-
- for(size_t i = x_size; i > 0; --i)
- {
- if(x[i-1] > y[i-1])
- return 1;
- if(x[i-1] < y[i-1])
- return -1;
- }
-
- return 0;
- }
-
-/*
-* Do a 2-word/1-word Division
-*/
-word bigint_divop(word n1, word n0, word d)
- {
- if(d == 0)
- throw Invalid_Argument("bigint_divop divide by zero");
-
- word high = n1 % d, quotient = 0;
-
- for(size_t i = 0; i != MP_WORD_BITS; ++i)
- {
- word high_top_bit = (high & MP_WORD_TOP_BIT);
-
- high <<= 1;
- high |= (n0 >> (MP_WORD_BITS-1-i)) & 1;
- quotient <<= 1;
-
- if(high_top_bit || high >= d)
- {
- high -= d;
- quotient |= 1;
- }
- }
-
- return quotient;
- }
-
-/*
-* Do a 2-word/1-word Modulo
-*/
-word bigint_modop(word n1, word n0, word d)
- {
- word z = bigint_divop(n1, n0, d);
- word dummy = 0;
- z = word_madd2(z, d, &dummy);
- return (n0-z);
- }
-
-}
diff --git a/src/lib/math/mp/mp_monty.cpp b/src/lib/math/mp/mp_monty.cpp
index 7e427b540..88b5de715 100644
--- a/src/lib/math/mp/mp_monty.cpp
+++ b/src/lib/math/mp/mp_monty.cpp
@@ -2,10 +2,12 @@
* Montgomery Reduction
* (C) 1999-2011 Jack Lloyd
* 2006 Luca Piccarreta
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
+#include <botan/bigint.h>
#include <botan/internal/mp_core.h>
#include <botan/internal/mp_madd.h>
#include <botan/internal/mp_asmi.h>
@@ -92,30 +94,25 @@ void bigint_monty_redc(word z[],
BOTAN_ASSERT(borrow == 0 || borrow == 1, "Expected borrow");
}
-void bigint_monty_mul(word z[], size_t z_size,
- const word x[], size_t x_size, size_t x_sw,
- const word y[], size_t y_size, size_t y_sw,
+void bigint_monty_mul(BigInt& z, const BigInt& x, const BigInt& y,
const word p[], size_t p_size, word p_dash,
word ws[])
{
- bigint_mul(&z[0], z_size, &ws[0],
- &x[0], x_size, x_sw,
- &y[0], y_size, y_sw);
+ bigint_mul(z, x, y, &ws[0]);
- bigint_monty_redc(&z[0],
+ bigint_monty_redc(z.mutable_data(),
&p[0], p_size, p_dash,
&ws[0]);
+
}
-void bigint_monty_sqr(word z[], size_t z_size,
- const word x[], size_t x_size, size_t x_sw,
- const word p[], size_t p_size, word p_dash,
- word ws[])
+void bigint_monty_sqr(BigInt& z, const BigInt& x, const word p[],
+ size_t p_size, word p_dash, word ws[])
{
- bigint_sqr(&z[0], z_size, &ws[0],
- &x[0], x_size, x_sw);
+ bigint_sqr(z.mutable_data(), z.size(), &ws[0],
+ x.data(), x.size(), x.sig_words());
- bigint_monty_redc(&z[0],
+ bigint_monty_redc(z.mutable_data(),
&p[0], p_size, p_dash,
&ws[0]);
}
diff --git a/src/lib/math/mp/mp_shift.cpp b/src/lib/math/mp/mp_shift.cpp
deleted file mode 100644
index 1850888a0..000000000
--- a/src/lib/math/mp/mp_shift.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
-* MP Shift Algorithms
-* (C) 1999-2007,2014 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/internal/mp_core.h>
-#include <botan/mem_ops.h>
-
-namespace Botan {
-
-/*
-* Single Operand Left Shift
-*/
-void bigint_shl1(word x[], size_t x_size, size_t word_shift, size_t bit_shift)
- {
- if(word_shift)
- {
- copy_mem(x + word_shift, x, x_size);
- clear_mem(x, word_shift);
- }
-
- if(bit_shift)
- {
- word carry = 0;
- for(size_t j = word_shift; j != x_size + word_shift + 1; ++j)
- {
- word temp = x[j];
- x[j] = (temp << bit_shift) | carry;
- carry = (temp >> (MP_WORD_BITS - bit_shift));
- }
- }
- }
-
-/*
-* Single Operand Right Shift
-*/
-void bigint_shr1(word x[], size_t x_size, size_t word_shift, size_t bit_shift)
- {
- if(x_size < word_shift)
- {
- clear_mem(x, x_size);
- return;
- }
-
- if(word_shift)
- {
- copy_mem(x, x + word_shift, x_size - word_shift);
- clear_mem(x + x_size - word_shift, word_shift);
- }
-
- if(bit_shift)
- {
- word carry = 0;
-
- size_t top = x_size - word_shift;
-
- while(top >= 4)
- {
- word w = x[top-1];
- x[top-1] = (w >> bit_shift) | carry;
- carry = (w << (MP_WORD_BITS - bit_shift));
-
- w = x[top-2];
- x[top-2] = (w >> bit_shift) | carry;
- carry = (w << (MP_WORD_BITS - bit_shift));
-
- w = x[top-3];
- x[top-3] = (w >> bit_shift) | carry;
- carry = (w << (MP_WORD_BITS - bit_shift));
-
- w = x[top-4];
- x[top-4] = (w >> bit_shift) | carry;
- carry = (w << (MP_WORD_BITS - bit_shift));
-
- top -= 4;
- }
-
- while(top)
- {
- word w = x[top-1];
- x[top-1] = (w >> bit_shift) | carry;
- carry = (w << (MP_WORD_BITS - bit_shift));
-
- top--;
- }
- }
- }
-
-/*
-* Two Operand Left Shift
-*/
-void bigint_shl2(word y[], const word x[], size_t x_size,
- size_t word_shift, size_t bit_shift)
- {
- for(size_t j = 0; j != x_size; ++j)
- y[j + word_shift] = x[j];
- if(bit_shift)
- {
- word carry = 0;
- for(size_t j = word_shift; j != x_size + word_shift + 1; ++j)
- {
- word w = y[j];
- y[j] = (w << bit_shift) | carry;
- carry = (w >> (MP_WORD_BITS - bit_shift));
- }
- }
- }
-
-/*
-* Two Operand Right Shift
-*/
-void bigint_shr2(word y[], const word x[], size_t x_size,
- size_t word_shift, size_t bit_shift)
- {
- if(x_size < word_shift) return;
-
- for(size_t j = 0; j != x_size - word_shift; ++j)
- y[j] = x[j + word_shift];
- if(bit_shift)
- {
- word carry = 0;
- for(size_t j = x_size - word_shift; j > 0; --j)
- {
- word w = y[j-1];
- y[j-1] = (w >> bit_shift) | carry;
- carry = (w << (MP_WORD_BITS - bit_shift));
- }
- }
- }
-
-}
diff --git a/src/lib/math/mp/mp_x86_32/info.txt b/src/lib/math/mp/mp_x86_32/info.txt
deleted file mode 100644
index f36abaf62..000000000
--- a/src/lib/math/mp/mp_x86_32/info.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-load_on dep
-
-mp_bits 32
-
-<header:internal>
-mp_madd.h
-mp_asmi.h
-</header:internal>
-
-<arch>
-x86_32
-</arch>
-
-<cc>
-clang
-gcc
-icc
-</cc>
diff --git a/src/lib/math/mp/mp_x86_32/mp_asmi.h b/src/lib/math/mp/mp_x86_32/mp_asmi.h
deleted file mode 100644
index 95af89fc0..000000000
--- a/src/lib/math/mp/mp_x86_32/mp_asmi.h
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
-* Lowest Level MPI Algorithms
-* (C) 1999-2010 Jack Lloyd
-* 2006 Luca Piccarreta
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_MP_ASM_INTERNAL_H__
-#define BOTAN_MP_ASM_INTERNAL_H__
-
-#include <botan/internal/mp_madd.h>
-
-namespace Botan {
-
-/*
-* Helper Macros for x86 Assembly
-*/
-#ifndef ASM
- #define ASM(x) x "\n\t"
-#endif
-
-#define ADDSUB2_OP(OPERATION, INDEX) \
- ASM("movl 4*" #INDEX "(%[y]), %[carry]") \
- ASM(OPERATION " %[carry], 4*" #INDEX "(%[x])") \
-
-#define ADDSUB3_OP(OPERATION, INDEX) \
- ASM("movl 4*" #INDEX "(%[x]), %[carry]") \
- ASM(OPERATION " 4*" #INDEX "(%[y]), %[carry]") \
- ASM("movl %[carry], 4*" #INDEX "(%[z])") \
-
-#define LINMUL_OP(WRITE_TO, INDEX) \
- ASM("movl 4*" #INDEX "(%[x]),%%eax") \
- ASM("mull %[y]") \
- ASM("addl %[carry],%%eax") \
- ASM("adcl $0,%%edx") \
- ASM("movl %%edx,%[carry]") \
- ASM("movl %%eax, 4*" #INDEX "(%[" WRITE_TO "])")
-
-#define MULADD_OP(IGNORED, INDEX) \
- ASM("movl 4*" #INDEX "(%[x]),%%eax") \
- ASM("mull %[y]") \
- ASM("addl %[carry],%%eax") \
- ASM("adcl $0,%%edx") \
- ASM("addl 4*" #INDEX "(%[z]),%%eax") \
- ASM("adcl $0,%%edx") \
- ASM("movl %%edx,%[carry]") \
- ASM("movl %%eax, 4*" #INDEX " (%[z])")
-
-#define DO_8_TIMES(MACRO, ARG) \
- MACRO(ARG, 0) \
- MACRO(ARG, 1) \
- MACRO(ARG, 2) \
- MACRO(ARG, 3) \
- MACRO(ARG, 4) \
- MACRO(ARG, 5) \
- MACRO(ARG, 6) \
- MACRO(ARG, 7)
-
-#define ADD_OR_SUBTRACT(CORE_CODE) \
- ASM("rorl %[carry]") \
- CORE_CODE \
- ASM("sbbl %[carry],%[carry]") \
- ASM("negl %[carry]")
-
-/*
-* Word Addition
-*/
-inline word word_add(word x, word y, word* carry)
- {
- asm(
- ADD_OR_SUBTRACT(ASM("adcl %[y],%[x]"))
- : [x]"=r"(x), [carry]"=r"(*carry)
- : "0"(x), [y]"rm"(y), "1"(*carry)
- : "cc");
- return x;
- }
-
-/*
-* Eight Word Block Addition, Two Argument
-*/
-inline word word8_add2(word x[8], const word y[8], word carry)
- {
- asm(
- ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcl"))
- : [carry]"=r"(carry)
- : [x]"r"(x), [y]"r"(y), "0"(carry)
- : "cc", "memory");
- return carry;
- }
-
-/*
-* Eight Word Block Addition, Three Argument
-*/
-inline word word8_add3(word z[8], const word x[8], const word y[8], word carry)
- {
- asm(
- ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcl"))
- : [carry]"=r"(carry)
- : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry)
- : "cc", "memory");
- return carry;
- }
-
-/*
-* Word Subtraction
-*/
-inline word word_sub(word x, word y, word* carry)
- {
- asm(
- ADD_OR_SUBTRACT(ASM("sbbl %[y],%[x]"))
- : [x]"=r"(x), [carry]"=r"(*carry)
- : "0"(x), [y]"rm"(y), "1"(*carry)
- : "cc");
- return x;
- }
-
-/*
-* Eight Word Block Subtraction, Two Argument
-*/
-inline word word8_sub2(word x[8], const word y[8], word carry)
- {
- asm(
- ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbl"))
- : [carry]"=r"(carry)
- : [x]"r"(x), [y]"r"(y), "0"(carry)
- : "cc", "memory");
- return carry;
- }
-
-/*
-* Eight Word Block Subtraction, Two Argument
-*/
-inline word word8_sub2_rev(word x[8], const word y[8], word carry)
- {
- asm(
- ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl"))
- : [carry]"=r"(carry)
- : [x]"r"(y), [y]"r"(x), [z]"r"(x), "0"(carry)
- : "cc", "memory");
- return carry;
- }
-
-/*
-* Eight Word Block Subtraction, Three Argument
-*/
-inline word word8_sub3(word z[8], const word x[8], const word y[8], word carry)
- {
- asm(
- ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbl"))
- : [carry]"=r"(carry)
- : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry)
- : "cc", "memory");
- return carry;
- }
-
-/*
-* Eight Word Block Linear Multiplication
-*/
-inline word word8_linmul2(word x[8], word y, word carry)
- {
- asm(
- DO_8_TIMES(LINMUL_OP, "x")
- : [carry]"=r"(carry)
- : [x]"r"(x), [y]"rm"(y), "0"(carry)
- : "cc", "%eax", "%edx");
- return carry;
- }
-
-/*
-* Eight Word Block Linear Multiplication
-*/
-inline word word8_linmul3(word z[8], const word x[8], word y, word carry)
- {
- asm(
- DO_8_TIMES(LINMUL_OP, "z")
- : [carry]"=r"(carry)
- : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry)
- : "cc", "%eax", "%edx");
- return carry;
- }
-
-/*
-* Eight Word Block Multiply/Add
-*/
-inline word word8_madd3(word z[8], const word x[8], word y, word carry)
- {
- asm(
- DO_8_TIMES(MULADD_OP, "")
- : [carry]"=r"(carry)
- : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry)
- : "cc", "%eax", "%edx");
- return carry;
- }
-
-/*
-* Multiply-Add Accumulator
-*/
-inline void word3_muladd(word* w2, word* w1, word* w0, word x, word y)
- {
- asm(
- ASM("mull %[y]")
-
- ASM("addl %[x],%[w0]")
- ASM("adcl %[y],%[w1]")
- ASM("adcl $0,%[w2]")
-
- : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2)
- : [x]"a"(x), [y]"d"(y), "0"(*w0), "1"(*w1), "2"(*w2)
- : "cc");
- }
-
-/*
-* Multiply-Add Accumulator
-*/
-inline void word3_muladd_2(word* w2, word* w1, word* w0, word x, word y)
- {
- asm(
- ASM("mull %[y]")
-
- ASM("addl %[x],%[w0]")
- ASM("adcl %[y],%[w1]")
- ASM("adcl $0,%[w2]")
-
- ASM("addl %[x],%[w0]")
- ASM("adcl %[y],%[w1]")
- ASM("adcl $0,%[w2]")
-
- : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2)
- : [x]"a"(x), [y]"d"(y), "0"(*w0), "1"(*w1), "2"(*w2)
- : "cc");
- }
-
-}
-
-#endif
diff --git a/src/lib/math/mp/mp_x86_32/mp_madd.h b/src/lib/math/mp/mp_x86_32/mp_madd.h
deleted file mode 100644
index 9c0990398..000000000
--- a/src/lib/math/mp/mp_x86_32/mp_madd.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
-* Lowest Level MPI Algorithms
-* (C) 1999-2008 Jack Lloyd
-* 2006 Luca Piccarreta
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_MP_WORD_MULADD_H__
-#define BOTAN_MP_WORD_MULADD_H__
-
-#include <botan/mp_types.h>
-
-#if (BOTAN_MP_WORD_BITS != 32)
- #error The mp_x86_32 module requires that BOTAN_MP_WORD_BITS == 32
-#endif
-
-namespace Botan {
-
-/*
-* Helper Macros for x86 Assembly
-*/
-#define ASM(x) x "\n\t"
-
-/*
-* Word Multiply
-*/
-inline word word_madd2(word a, word b, word* c)
- {
- asm(
- ASM("mull %[b]")
- ASM("addl %[c],%[a]")
- ASM("adcl $0,%[carry]")
-
- : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*c)
- : "0"(a), "1"(b), [c]"g"(*c) : "cc");
-
- return a;
- }
-
-/*
-* Word Multiply/Add
-*/
-inline word word_madd3(word a, word b, word c, word* d)
- {
- asm(
- ASM("mull %[b]")
-
- ASM("addl %[c],%[a]")
- ASM("adcl $0,%[carry]")
-
- ASM("addl %[d],%[a]")
- ASM("adcl $0,%[carry]")
-
- : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*d)
- : "0"(a), "1"(b), [c]"g"(c), [d]"g"(*d) : "cc");
-
- return a;
- }
-
-}
-
-#endif
diff --git a/src/lib/math/mp/mp_x86_32_msvc/info.txt b/src/lib/math/mp/mp_x86_32_msvc/info.txt
deleted file mode 100644
index 3029d6a61..000000000
--- a/src/lib/math/mp/mp_x86_32_msvc/info.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-mp_bits 32
-
-load_on dep
-
-<header:internal>
-mp_generic:mp_madd.h
-mp_asmi.h
-</header:internal>
-
-<arch>
-x86_32
-</arch>
-
-<cc>
-msvc
-</cc>
diff --git a/src/lib/math/mp/mp_x86_32_msvc/mp_asmi.h b/src/lib/math/mp/mp_x86_32_msvc/mp_asmi.h
deleted file mode 100644
index 92bf7980d..000000000
--- a/src/lib/math/mp/mp_x86_32_msvc/mp_asmi.h
+++ /dev/null
@@ -1,454 +0,0 @@
-/*
-* Lowest Level MPI Algorithms
-* (C) 1999-2010 Jack Lloyd
-* 2006 Luca Piccarreta
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_MP_ASM_INTERNAL_H__
-#define BOTAN_MP_ASM_INTERNAL_H__
-
-#include <botan/internal/mp_madd.h>
-
-namespace Botan {
-
-/*
-* Word Addition
-*/
-inline word word_add(word x, word y, word* carry)
- {
- word z = x + y;
- word c1 = (z < x);
- z += *carry;
- *carry = c1 | (z < *carry);
- return z;
- }
-
-/*
-* Eight Word Block Addition, Two Argument
-*/
-inline word word8_add2(word x[8], const word y[8], word carry)
- {
- __asm {
- mov edx,[x]
- mov esi,[y]
- xor eax,eax
- sub eax,[carry] //force CF=1 iff *carry==1
- mov eax,[esi]
- adc [edx],eax
- mov eax,[esi+4]
- adc [edx+4],eax
- mov eax,[esi+8]
- adc [edx+8],eax
- mov eax,[esi+12]
- adc [edx+12],eax
- mov eax,[esi+16]
- adc [edx+16],eax
- mov eax,[esi+20]
- adc [edx+20],eax
- mov eax,[esi+24]
- adc [edx+24],eax
- mov eax,[esi+28]
- adc [edx+28],eax
- sbb eax,eax
- neg eax
- }
- }
-
-/*
-* Eight Word Block Addition, Three Argument
-*/
-inline word word8_add3(word z[8], const word x[8], const word y[8], word carry)
- {
- __asm {
- mov edi,[x]
- mov esi,[y]
- mov ebx,[z]
- xor eax,eax
- sub eax,[carry] //force CF=1 iff *carry==1
- mov eax,[edi]
- adc eax,[esi]
- mov [ebx],eax
-
- mov eax,[edi+4]
- adc eax,[esi+4]
- mov [ebx+4],eax
-
- mov eax,[edi+8]
- adc eax,[esi+8]
- mov [ebx+8],eax
-
- mov eax,[edi+12]
- adc eax,[esi+12]
- mov [ebx+12],eax
-
- mov eax,[edi+16]
- adc eax,[esi+16]
- mov [ebx+16],eax
-
- mov eax,[edi+20]
- adc eax,[esi+20]
- mov [ebx+20],eax
-
- mov eax,[edi+24]
- adc eax,[esi+24]
- mov [ebx+24],eax
-
- mov eax,[edi+28]
- adc eax,[esi+28]
- mov [ebx+28],eax
-
- sbb eax,eax
- neg eax
- }
- }
-
-/*
-* Word Subtraction
-*/
-inline word word_sub(word x, word y, word* carry)
- {
- word t0 = x - y;
- word c1 = (t0 > x);
- word z = t0 - *carry;
- *carry = c1 | (z > t0);
- return z;
- }
-
-/*
-* Eight Word Block Subtraction, Two Argument
-*/
-inline word word8_sub2(word x[8], const word y[8], word carry)
- {
- __asm {
- mov edi,[x]
- mov esi,[y]
- xor eax,eax
- sub eax,[carry] //force CF=1 iff *carry==1
- mov eax,[edi]
- sbb eax,[esi]
- mov [edi],eax
- mov eax,[edi+4]
- sbb eax,[esi+4]
- mov [edi+4],eax
- mov eax,[edi+8]
- sbb eax,[esi+8]
- mov [edi+8],eax
- mov eax,[edi+12]
- sbb eax,[esi+12]
- mov [edi+12],eax
- mov eax,[edi+16]
- sbb eax,[esi+16]
- mov [edi+16],eax
- mov eax,[edi+20]
- sbb eax,[esi+20]
- mov [edi+20],eax
- mov eax,[edi+24]
- sbb eax,[esi+24]
- mov [edi+24],eax
- mov eax,[edi+28]
- sbb eax,[esi+28]
- mov [edi+28],eax
- sbb eax,eax
- neg eax
- }
- }
-
-/*
-* Eight Word Block Subtraction, Two Argument
-*/
-inline word word8_sub2_rev(word x[8], const word y[8], word carry)
- {
- x[0] = word_sub(y[0], x[0], &carry);
- x[1] = word_sub(y[1], x[1], &carry);
- x[2] = word_sub(y[2], x[2], &carry);
- x[3] = word_sub(y[3], x[3], &carry);
- x[4] = word_sub(y[4], x[4], &carry);
- x[5] = word_sub(y[5], x[5], &carry);
- x[6] = word_sub(y[6], x[6], &carry);
- x[7] = word_sub(y[7], x[7], &carry);
- return carry;
- }
-
-
-/*
-* Eight Word Block Subtraction, Three Argument
-*/
-inline word word8_sub3(word z[8], const word x[8],
- const word y[8], word carry)
- {
- __asm {
- mov edi,[x]
- mov esi,[y]
- xor eax,eax
- sub eax,[carry] //force CF=1 iff *carry==1
- mov ebx,[z]
- mov eax,[edi]
- sbb eax,[esi]
- mov [ebx],eax
- mov eax,[edi+4]
- sbb eax,[esi+4]
- mov [ebx+4],eax
- mov eax,[edi+8]
- sbb eax,[esi+8]
- mov [ebx+8],eax
- mov eax,[edi+12]
- sbb eax,[esi+12]
- mov [ebx+12],eax
- mov eax,[edi+16]
- sbb eax,[esi+16]
- mov [ebx+16],eax
- mov eax,[edi+20]
- sbb eax,[esi+20]
- mov [ebx+20],eax
- mov eax,[edi+24]
- sbb eax,[esi+24]
- mov [ebx+24],eax
- mov eax,[edi+28]
- sbb eax,[esi+28]
- mov [ebx+28],eax
- sbb eax,eax
- neg eax
- }
- }
-
-/*
-* Eight Word Block Linear Multiplication
-*/
-inline word word8_linmul2(word x[8], word y, word carry)
- {
- __asm {
- mov esi,[x]
- mov eax,[esi] //load a
- mul [y] //edx(hi):eax(lo)=a*b
- add eax,[carry] //sum lo carry
- adc edx,0 //sum hi carry
- mov ecx,edx //store carry
- mov [esi],eax //load a
-
- mov eax,[esi+4] //load a
- mul [y] //edx(hi):eax(lo)=a*b
- add eax,ecx //sum lo carry
- adc edx,0 //sum hi carry
- mov ecx,edx //store carry
- mov [esi+4],eax //load a
-
- mov eax,[esi+8] //load a
- mul [y] //edx(hi):eax(lo)=a*b
- add eax,ecx //sum lo carry
- adc edx,0 //sum hi carry
- mov ecx,edx //store carry
- mov [esi+8],eax //load a
-
- mov eax,[esi+12] //load a
- mul [y] //edx(hi):eax(lo)=a*b
- add eax,ecx //sum lo carry
- adc edx,0 //sum hi carry
- mov ecx,edx //store carry
- mov [esi+12],eax //load a
-
- mov eax,[esi+16] //load a
- mul [y] //edx(hi):eax(lo)=a*b
- add eax,ecx //sum lo carry
- adc edx,0 //sum hi carry
- mov ecx,edx //store carry
- mov [esi+16],eax //load a
-
- mov eax,[esi+20] //load a
- mul [y] //edx(hi):eax(lo)=a*b
- add eax,ecx //sum lo carry
- adc edx,0 //sum hi carry
- mov ecx,edx //store carry
- mov [esi+20],eax //load a
-
- mov eax,[esi+24] //load a
- mul [y] //edx(hi):eax(lo)=a*b
- add eax,ecx //sum lo carry
- adc edx,0 //sum hi carry
- mov ecx,edx //store carry
- mov [esi+24],eax //load a
-
- mov eax,[esi+28] //load a
- mul [y] //edx(hi):eax(lo)=a*b
- add eax,ecx //sum lo carry
- adc edx,0 //sum hi carry
- mov [esi+28],eax //load a
-
- mov eax,edx //store carry
- }
- }
-
-inline word word8_linmul3(word z[4], const word x[4], word y, word carry)
- {
- __asm {
-#if 0
- //it's slower!!!
- mov edx,[z]
- mov eax,[x]
- movd mm7,[y]
-
- movd mm0,[eax]
- movd mm1,[eax+4]
- movd mm2,[eax+8]
- pmuludq mm0,mm7
- pmuludq mm1,mm7
- pmuludq mm2,mm7
-
- movd mm6,[carry]
- paddq mm0,mm6
- movd [edx],mm0
-
- psrlq mm0,32
- paddq mm1,mm0
- movd [edx+4],mm1
-
- movd mm3,[eax+12]
- psrlq mm1,32
- paddq mm2,mm1
- movd [edx+8],mm2
-
- pmuludq mm3,mm7
- movd mm4,[eax+16]
- psrlq mm2,32
- paddq mm3,mm2
- movd [edx+12],mm3
-
- pmuludq mm4,mm7
- movd mm5,[eax+20]
- psrlq mm3,32
- paddq mm4,mm3
- movd [edx+16],mm4
-
- pmuludq mm5,mm7
- movd mm0,[eax+24]
- psrlq mm4,32
- paddq mm5,mm4
- movd [edx+20],mm5
-
- pmuludq mm0,mm7
- movd mm1,[eax+28]
- psrlq mm5,32
- paddq mm0,mm5
- movd [edx+24],mm0
-
- pmuludq mm1,mm7
- psrlq mm0,32
- paddq mm1,mm0
- movd [edx+28],mm1
- psrlq mm1,32
-
- movd eax,mm1
- emms
-#else
- mov edi,[z]
- mov esi,[x]
- mov eax,[esi] //load a
- mul [y] //edx(hi):eax(lo)=a*b
- add eax,[carry] //sum lo carry
- adc edx,0 //sum hi carry
- mov ecx,edx //store carry
- mov [edi],eax //load a
-
- mov eax,[esi+4] //load a
- mul [y] //edx(hi):eax(lo)=a*b
- add eax,ecx //sum lo carry
- adc edx,0 //sum hi carry
- mov ecx,edx //store carry
- mov [edi+4],eax //load a
-
- mov eax,[esi+8] //load a
- mul [y] //edx(hi):eax(lo)=a*b
- add eax,ecx //sum lo carry
- adc edx,0 //sum hi carry
- mov ecx,edx //store carry
- mov [edi+8],eax //load a
-
- mov eax,[esi+12] //load a
- mul [y] //edx(hi):eax(lo)=a*b
- add eax,ecx //sum lo carry
- adc edx,0 //sum hi carry
- mov ecx,edx //store carry
- mov [edi+12],eax //load a
-
- mov eax,[esi+16] //load a
- mul [y] //edx(hi):eax(lo)=a*b
- add eax,ecx //sum lo carry
- adc edx,0 //sum hi carry
- mov ecx,edx //store carry
- mov [edi+16],eax //load a
-
- mov eax,[esi+20] //load a
- mul [y] //edx(hi):eax(lo)=a*b
- add eax,ecx //sum lo carry
- adc edx,0 //sum hi carry
- mov ecx,edx //store carry
- mov [edi+20],eax //load a
-
- mov eax,[esi+24] //load a
- mul [y] //edx(hi):eax(lo)=a*b
- add eax,ecx //sum lo carry
- adc edx,0 //sum hi carry
- mov ecx,edx //store carry
- mov [edi+24],eax //load a
-
- mov eax,[esi+28] //load a
- mul [y] //edx(hi):eax(lo)=a*b
- add eax,ecx //sum lo carry
- adc edx,0 //sum hi carry
- mov [edi+28],eax //load a
- mov eax,edx //store carry
-#endif
- }
- }
-
-/*
-* Eight Word Block Multiply/Add
-*/
-inline word word8_madd3(word z[8], const word x[8], word y, word carry)
- {
- z[0] = word_madd3(x[0], y, z[0], &carry);
- z[1] = word_madd3(x[1], y, z[1], &carry);
- z[2] = word_madd3(x[2], y, z[2], &carry);
- z[3] = word_madd3(x[3], y, z[3], &carry);
- z[4] = word_madd3(x[4], y, z[4], &carry);
- z[5] = word_madd3(x[5], y, z[5], &carry);
- z[6] = word_madd3(x[6], y, z[6], &carry);
- z[7] = word_madd3(x[7], y, z[7], &carry);
- return carry;
- }
-
-/*
-* Multiply-Add Accumulator
-*/
-inline void word3_muladd(word* w2, word* w1, word* w0, word a, word b)
- {
- word carry = *w0;
- *w0 = word_madd2(a, b, &carry);
- *w1 += carry;
- *w2 += (*w1 < carry) ? 1 : 0;
- }
-
-/*
-* Multiply-Add Accumulator
-*/
-inline void word3_muladd_2(word* w2, word* w1, word* w0, word a, word b)
- {
- word carry = 0;
- a = word_madd2(a, b, &carry);
- b = carry;
-
- word top = (b >> (BOTAN_MP_WORD_BITS-1));
- b <<= 1;
- b |= (a >> (BOTAN_MP_WORD_BITS-1));
- a <<= 1;
-
- carry = 0;
- *w0 = word_add(*w0, a, &carry);
- *w1 = word_add(*w1, b, &carry);
- *w2 = word_add(*w2, top, &carry);
- }
-
-}
-
-#endif
diff --git a/src/lib/math/mp/mp_x86_64/info.txt b/src/lib/math/mp/mp_x86_64/info.txt
deleted file mode 100644
index 75c42ddc1..000000000
--- a/src/lib/math/mp/mp_x86_64/info.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-load_on dep
-
-mp_bits 64
-
-<header:internal>
-mp_madd.h
-mp_asmi.h
-</header:internal>
-
-<arch>
-x86_64
-</arch>
-
-<cc>
-clang
-gcc
-icc
-</cc>
diff --git a/src/lib/math/mp/mp_x86_64/mp_asmi.h b/src/lib/math/mp/mp_x86_64/mp_asmi.h
deleted file mode 100644
index cd5884867..000000000
--- a/src/lib/math/mp/mp_x86_64/mp_asmi.h
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
-* Lowest Level MPI Algorithms
-* (C) 1999-2010 Jack Lloyd
-* 2006 Luca Piccarreta
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_MP_ASM_INTERNAL_H__
-#define BOTAN_MP_ASM_INTERNAL_H__
-
-#include <botan/internal/mp_madd.h>
-
-namespace Botan {
-
-/*
-* Helper Macros for x86-64 Assembly
-*/
-#ifndef ASM
- #define ASM(x) x "\n\t"
-#endif
-
-#define ADDSUB2_OP(OPERATION, INDEX) \
- ASM("movq 8*" #INDEX "(%[y]), %[carry]") \
- ASM(OPERATION " %[carry], 8*" #INDEX "(%[x])") \
-
-#define ADDSUB3_OP(OPERATION, INDEX) \
- ASM("movq 8*" #INDEX "(%[x]), %[carry]") \
- ASM(OPERATION " 8*" #INDEX "(%[y]), %[carry]") \
- ASM("movq %[carry], 8*" #INDEX "(%[z])") \
-
-#define LINMUL_OP(WRITE_TO, INDEX) \
- ASM("movq 8*" #INDEX "(%[x]),%%rax") \
- ASM("mulq %[y]") \
- ASM("addq %[carry],%%rax") \
- ASM("adcq $0,%%rdx") \
- ASM("movq %%rdx,%[carry]") \
- ASM("movq %%rax, 8*" #INDEX "(%[" WRITE_TO "])")
-
-#define MULADD_OP(IGNORED, INDEX) \
- ASM("movq 8*" #INDEX "(%[x]),%%rax") \
- ASM("mulq %[y]") \
- ASM("addq %[carry],%%rax") \
- ASM("adcq $0,%%rdx") \
- ASM("addq 8*" #INDEX "(%[z]),%%rax") \
- ASM("adcq $0,%%rdx") \
- ASM("movq %%rdx,%[carry]") \
- ASM("movq %%rax, 8*" #INDEX " (%[z])")
-
-#define DO_8_TIMES(MACRO, ARG) \
- MACRO(ARG, 0) \
- MACRO(ARG, 1) \
- MACRO(ARG, 2) \
- MACRO(ARG, 3) \
- MACRO(ARG, 4) \
- MACRO(ARG, 5) \
- MACRO(ARG, 6) \
- MACRO(ARG, 7)
-
-#define ADD_OR_SUBTRACT(CORE_CODE) \
- ASM("rorq %[carry]") \
- CORE_CODE \
- ASM("sbbq %[carry],%[carry]") \
- ASM("negq %[carry]")
-
-/*
-* Word Addition
-*/
-inline word word_add(word x, word y, word* carry)
- {
- asm(
- ADD_OR_SUBTRACT(ASM("adcq %[y],%[x]"))
- : [x]"=r"(x), [carry]"=r"(*carry)
- : "0"(x), [y]"rm"(y), "1"(*carry)
- : "cc");
- return x;
- }
-
-/*
-* Eight Word Block Addition, Two Argument
-*/
-inline word word8_add2(word x[8], const word y[8], word carry)
- {
- asm(
- ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "adcq"))
- : [carry]"=r"(carry)
- : [x]"r"(x), [y]"r"(y), "0"(carry)
- : "cc", "memory");
- return carry;
- }
-
-/*
-* Eight Word Block Addition, Three Argument
-*/
-inline word word8_add3(word z[8], const word x[8], const word y[8], word carry)
- {
- asm(
- ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "adcq"))
- : [carry]"=r"(carry)
- : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry)
- : "cc", "memory");
- return carry;
- }
-
-/*
-* Word Subtraction
-*/
-inline word word_sub(word x, word y, word* carry)
- {
- asm(
- ADD_OR_SUBTRACT(ASM("sbbq %[y],%[x]"))
- : [x]"=r"(x), [carry]"=r"(*carry)
- : "0"(x), [y]"rm"(y), "1"(*carry)
- : "cc");
- return x;
- }
-
-/*
-* Eight Word Block Subtraction, Two Argument
-*/
-inline word word8_sub2(word x[8], const word y[8], word carry)
- {
- asm(
- ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB2_OP, "sbbq"))
- : [carry]"=r"(carry)
- : [x]"r"(x), [y]"r"(y), "0"(carry)
- : "cc", "memory");
- return carry;
- }
-
-/*
-* Eight Word Block Subtraction, Two Argument
-*/
-inline word word8_sub2_rev(word x[8], const word y[8], word carry)
- {
- asm(
- ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbq"))
- : [carry]"=r"(carry)
- : [x]"r"(y), [y]"r"(x), [z]"r"(x), "0"(carry)
- : "cc", "memory");
- return carry;
- }
-
-/*
-* Eight Word Block Subtraction, Three Argument
-*/
-inline word word8_sub3(word z[8], const word x[8], const word y[8], word carry)
- {
- asm(
- ADD_OR_SUBTRACT(DO_8_TIMES(ADDSUB3_OP, "sbbq"))
- : [carry]"=r"(carry)
- : [x]"r"(x), [y]"r"(y), [z]"r"(z), "0"(carry)
- : "cc", "memory");
- return carry;
- }
-
-/*
-* Eight Word Block Linear Multiplication
-*/
-inline word word8_linmul2(word x[8], word y, word carry)
- {
- asm(
- DO_8_TIMES(LINMUL_OP, "x")
- : [carry]"=r"(carry)
- : [x]"r"(x), [y]"rm"(y), "0"(carry)
- : "cc", "%rax", "%rdx");
- return carry;
- }
-
-/*
-* Eight Word Block Linear Multiplication
-*/
-inline word word8_linmul3(word z[8], const word x[8], word y, word carry)
- {
- asm(
- DO_8_TIMES(LINMUL_OP, "z")
- : [carry]"=r"(carry)
- : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry)
- : "cc", "%rax", "%rdx");
- return carry;
- }
-
-/*
-* Eight Word Block Multiply/Add
-*/
-inline word word8_madd3(word z[8], const word x[8], word y, word carry)
- {
- asm(
- DO_8_TIMES(MULADD_OP, "")
- : [carry]"=r"(carry)
- : [z]"r"(z), [x]"r"(x), [y]"rm"(y), "0"(carry)
- : "cc", "%rax", "%rdx");
- return carry;
- }
-
-/*
-* Multiply-Add Accumulator
-*/
-inline void word3_muladd(word* w2, word* w1, word* w0, word x, word y)
- {
- asm(
- ASM("mulq %[y]")
-
- ASM("addq %[x],%[w0]")
- ASM("adcq %[y],%[w1]")
- ASM("adcq $0,%[w2]")
-
- : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2)
- : [x]"a"(x), [y]"d"(y), "0"(*w0), "1"(*w1), "2"(*w2)
- : "cc");
- }
-
-/*
-* Multiply-Add Accumulator
-*/
-inline void word3_muladd_2(word* w2, word* w1, word* w0, word x, word y)
- {
- asm(
- ASM("mulq %[y]")
-
- ASM("addq %[x],%[w0]")
- ASM("adcq %[y],%[w1]")
- ASM("adcq $0,%[w2]")
-
- ASM("addq %[x],%[w0]")
- ASM("adcq %[y],%[w1]")
- ASM("adcq $0,%[w2]")
-
- : [w0]"=r"(*w0), [w1]"=r"(*w1), [w2]"=r"(*w2)
- : [x]"a"(x), [y]"d"(y), "0"(*w0), "1"(*w1), "2"(*w2)
- : "cc");
- }
-
-#undef ASM
-#undef DO_8_TIMES
-#undef ADD_OR_SUBTRACT
-#undef ADDSUB2_OP
-#undef ADDSUB3_OP
-#undef LINMUL_OP
-#undef MULADD_OP
-
-}
-
-#endif
diff --git a/src/lib/math/mp/mp_x86_64/mp_madd.h b/src/lib/math/mp/mp_x86_64/mp_madd.h
deleted file mode 100644
index 6f9185dc0..000000000
--- a/src/lib/math/mp/mp_x86_64/mp_madd.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-* Lowest Level MPI Algorithms
-* (C) 1999-2008 Jack Lloyd
-* 2006 Luca Piccarreta
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_MP_WORD_MULADD_H__
-#define BOTAN_MP_WORD_MULADD_H__
-
-#include <botan/mp_types.h>
-
-#if (BOTAN_MP_WORD_BITS != 64)
- #error The mp_x86_64 module requires that BOTAN_MP_WORD_BITS == 64
-#endif
-
-namespace Botan {
-
-/*
-* Helper Macros for x86-64 Assembly
-*/
-#define ASM(x) x "\n\t"
-
-/*
-* Word Multiply
-*/
-inline word word_madd2(word a, word b, word* c)
- {
- asm(
- ASM("mulq %[b]")
- ASM("addq %[c],%[a]")
- ASM("adcq $0,%[carry]")
-
- : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*c)
- : "0"(a), "1"(b), [c]"g"(*c) : "cc");
-
- return a;
- }
-
-/*
-* Word Multiply/Add
-*/
-inline word word_madd3(word a, word b, word c, word* d)
- {
- asm(
- ASM("mulq %[b]")
-
- ASM("addq %[c],%[a]")
- ASM("adcq $0,%[carry]")
-
- ASM("addq %[d],%[a]")
- ASM("adcq $0,%[carry]")
-
- : [a]"=a"(a), [b]"=rm"(b), [carry]"=&d"(*d)
- : "0"(a), "1"(b), [c]"g"(c), [d]"g"(*d) : "cc");
-
- return a;
- }
-
-#undef ASM
-
-}
-
-#endif
diff --git a/src/lib/math/numbertheory/mp_numth.cpp b/src/lib/math/numbertheory/mp_numth.cpp
index 3373b9ee7..d78d21128 100644
--- a/src/lib/math/numbertheory/mp_numth.cpp
+++ b/src/lib/math/numbertheory/mp_numth.cpp
@@ -1,6 +1,7 @@
/*
* Fused and Important MP Algorithms
* (C) 1999-2007 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -40,20 +41,13 @@ BigInt mul_add(const BigInt& a, const BigInt& b, const BigInt& c)
if(a.sign() != b.sign())
sign = BigInt::Negative;
- const size_t a_sw = a.sig_words();
- const size_t b_sw = b.sig_words();
- const size_t c_sw = c.sig_words();
-
- BigInt r(sign, std::max(a.size() + b.size(), c_sw) + 1);
+ BigInt r(sign, std::max(a.size() + b.size(), c.sig_words()) + 1);
secure_vector<word> workspace(r.size());
- bigint_mul(r.mutable_data(), r.size(),
- workspace.data(),
- a.data(), a.size(), a_sw,
- b.data(), b.size(), b_sw);
+ bigint_mul(r, a, b, workspace.data());
- const size_t r_size = std::max(r.sig_words(), c_sw);
- bigint_add2(r.mutable_data(), r_size, c.data(), c_sw);
+ const size_t r_size = std::max(r.sig_words(), c.sig_words());
+ bigint_add2(r.mutable_data(), r_size, c.data(), c.sig_words());
return r;
}
diff --git a/src/lib/math/numbertheory/powm_mnt.cpp b/src/lib/math/numbertheory/powm_mnt.cpp
index 5c441db3a..572f0de98 100644
--- a/src/lib/math/numbertheory/powm_mnt.cpp
+++ b/src/lib/math/numbertheory/powm_mnt.cpp
@@ -1,6 +1,7 @@
/*
* Montgomery Exponentiation
* (C) 1999-2010,2012 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -8,6 +9,7 @@
#include <botan/internal/def_powm.h>
#include <botan/numthry.h>
#include <botan/internal/mp_core.h>
+#include <iostream>
namespace Botan {
@@ -34,36 +36,26 @@ void Montgomery_Exponentiator::set_base(const BigInt& base)
m_g[0] = 1;
- bigint_monty_mul(z.mutable_data(), z.size(),
- m_g[0].data(), m_g[0].size(), m_g[0].sig_words(),
- m_R2_mod.data(), m_R2_mod.size(), m_R2_mod.sig_words(),
+ bigint_monty_mul(z, m_g[0], m_R2_mod,
m_modulus.data(), m_mod_words, m_mod_prime,
workspace.data());
-
m_g[0] = z;
m_g[1] = (base >= m_modulus) ? (base % m_modulus) : base;
- bigint_monty_mul(z.mutable_data(), z.size(),
- m_g[1].data(), m_g[1].size(), m_g[1].sig_words(),
- m_R2_mod.data(), m_R2_mod.size(), m_R2_mod.sig_words(),
+ bigint_monty_mul(z, m_g[1], m_R2_mod,
m_modulus.data(), m_mod_words, m_mod_prime,
workspace.data());
m_g[1] = z;
const BigInt& x = m_g[1];
- const size_t x_sig = x.sig_words();
for(size_t i = 2; i != m_g.size(); ++i)
{
const BigInt& y = m_g[i-1];
- const size_t y_sig = y.sig_words();
- bigint_monty_mul(z.mutable_data(), z.size(),
- x.data(), x.size(), x_sig,
- y.data(), y.size(), y_sig,
- m_modulus.data(), m_mod_words, m_mod_prime,
+ bigint_monty_mul(z, x, y, m_modulus.data(), m_mod_words, m_mod_prime,
workspace.data());
m_g[i] = z;
@@ -82,15 +74,13 @@ BigInt Montgomery_Exponentiator::execute() const
const size_t z_size = 2*(m_mod_words + 1);
BigInt z(BigInt::Positive, z_size);
- secure_vector<word> workspace(z_size);
+ secure_vector<word> workspace(z.size());
for(size_t i = exp_nibbles; i > 0; --i)
{
for(size_t k = 0; k != m_window_bits; ++k)
{
- bigint_monty_sqr(z.mutable_data(), z_size,
- x.data(), x.size(), x.sig_words(),
- m_modulus.data(), m_mod_words, m_mod_prime,
+ bigint_monty_sqr(z, x, m_modulus.data(), m_mod_words, m_mod_prime,
workspace.data());
x = z;
@@ -100,9 +90,7 @@ BigInt Montgomery_Exponentiator::execute() const
const BigInt& y = m_g[nibble];
- bigint_monty_mul(z.mutable_data(), z_size,
- x.data(), x.size(), x.sig_words(),
- y.data(), y.size(), y.sig_words(),
+ bigint_monty_mul(z, x, y,
m_modulus.data(), m_mod_words, m_mod_prime,
workspace.data());
diff --git a/src/lib/modes/aead/gcm/gcm.cpp b/src/lib/modes/aead/gcm/gcm.cpp
index 1dc5efe4f..e23551cb4 100644
--- a/src/lib/modes/aead/gcm/gcm.cpp
+++ b/src/lib/modes/aead/gcm/gcm.cpp
@@ -168,7 +168,7 @@ GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size) :
m_ghash.reset(new GHASH);
- m_ctr.reset(new CTR_BE(cipher)); // CTR_BE takes ownership of cipher
+ m_ctr.reset(new CTR_BE(cipher, 4)); // CTR_BE takes ownership of cipher
if(m_tag_size != 8 && m_tag_size != 16)
throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(m_tag_size));
diff --git a/src/lib/modes/mode_pad/mode_pad.cpp b/src/lib/modes/mode_pad/mode_pad.cpp
index 0f1df9e8a..7b4546c86 100644
--- a/src/lib/modes/mode_pad/mode_pad.cpp
+++ b/src/lib/modes/mode_pad/mode_pad.cpp
@@ -69,8 +69,10 @@ void ANSI_X923_Padding::add_padding(secure_vector<byte>& buffer,
{
const byte pad_value = static_cast<byte>(block_size - last_byte_pos);
- for(size_t i = last_byte_pos; i < block_size; ++i)
+ for(size_t i = last_byte_pos; i < block_size-1; ++i)
+ {
buffer.push_back(0);
+ }
buffer.push_back(pad_value);
}
diff --git a/src/lib/modes/mode_pad/mode_pad.h b/src/lib/modes/mode_pad/mode_pad.h
index 0a775b1ea..bc2b7c132 100644
--- a/src/lib/modes/mode_pad/mode_pad.h
+++ b/src/lib/modes/mode_pad/mode_pad.h
@@ -32,6 +32,7 @@ class BOTAN_DLL BlockCipherModePaddingMethod
/**
* @param block the last block
* @param size the of the block
+ * @return number of padding bytes
*/
virtual size_t unpad(const byte block[],
size_t size) const = 0;
@@ -119,7 +120,7 @@ class BOTAN_DLL Null_Padding final : public BlockCipherModePaddingMethod
std::string name() const override { return "NoPadding"; }
};
-BlockCipherModePaddingMethod* get_bc_pad(const std::string& algo_spec);
+BOTAN_DLL BlockCipherModePaddingMethod* get_bc_pad(const std::string& algo_spec);
}
diff --git a/src/lib/pk_pad/eme_oaep/oaep.cpp b/src/lib/pk_pad/eme_oaep/oaep.cpp
index 0ae0d8554..1ae1068a7 100644
--- a/src/lib/pk_pad/eme_oaep/oaep.cpp
+++ b/src/lib/pk_pad/eme_oaep/oaep.cpp
@@ -35,8 +35,10 @@ secure_vector<byte> OAEP::pad(const byte in[], size_t in_length,
{
key_length /= 8;
- if(key_length < in_length + 2*m_Phash.size() + 1)
+ if(in_length > maximum_input_size(key_length * 8))
+ {
throw Invalid_Argument("OAEP: Input is too large");
+ }
secure_vector<byte> out(key_length);
diff --git a/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp b/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp
index 8148b7bc9..9bab8eb95 100644
--- a/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp
+++ b/src/lib/pk_pad/eme_pkcs1/eme_pkcs.cpp
@@ -14,22 +14,22 @@ namespace Botan {
* PKCS1 Pad Operation
*/
secure_vector<byte> EME_PKCS1v15::pad(const byte in[], size_t inlen,
- size_t olen,
+ size_t key_length,
RandomNumberGenerator& rng) const
{
- olen /= 8;
+ key_length /= 8;
- if(olen < 10)
- throw Encoding_Error("PKCS1: Output space too small");
- if(inlen > olen - 10)
- throw Encoding_Error("PKCS1: Input is too large");
+ if(inlen > maximum_input_size(key_length * 8))
+ {
+ throw Invalid_Argument("PKCS1: Input is too large");
+ }
- secure_vector<byte> out(olen);
+ secure_vector<byte> out(key_length);
out[0] = 0x02;
- rng.randomize(out.data() + 1, (olen - inlen - 2));
+ rng.randomize(out.data() + 1, (key_length - inlen - 2));
- for(size_t j = 1; j != olen - inlen - 1; ++j)
+ for(size_t j = 1; j != key_length - inlen - 1; ++j)
{
if(out[j] == 0)
{
@@ -37,7 +37,7 @@ secure_vector<byte> EME_PKCS1v15::pad(const byte in[], size_t inlen,
}
}
- buffer_insert(out, olen - inlen, in, inlen);
+ buffer_insert(out, key_length - inlen, in, inlen);
return out;
}
diff --git a/src/lib/pk_pad/emsa.cpp b/src/lib/pk_pad/emsa.cpp
index 3b8641357..4d4b96ad1 100644
--- a/src/lib/pk_pad/emsa.cpp
+++ b/src/lib/pk_pad/emsa.cpp
@@ -11,10 +11,6 @@
#include <botan/emsa1.h>
#endif
-#if defined(BOTAN_HAS_EMSA1_BSI)
- #include <botan/emsa1_bsi.h>
-#endif
-
#if defined(BOTAN_HAS_EMSA_X931)
#include <botan/emsa_x931.h>
#endif
@@ -45,6 +41,19 @@ EMSA* get_emsa(const std::string& algo_spec)
throw Algorithm_Not_Found(algo_spec);
}
+std::string hash_for_emsa(const std::string& algo_spec)
+ {
+ SCAN_Name emsa_name(algo_spec);
+
+ if(emsa_name.arg_count() > 0)
+ {
+ const std::string pos_hash = emsa_name.arg(0);
+ return pos_hash;
+ }
+
+ return "SHA-512"; // safe default if nothing we understand
+ }
+
#define BOTAN_REGISTER_EMSA_NAMED_NOARGS(type, name) \
BOTAN_REGISTER_NAMED_T(EMSA, name, type, make_new_T<type>)
@@ -58,10 +67,6 @@ EMSA* get_emsa(const std::string& algo_spec)
BOTAN_REGISTER_EMSA_1HASH(EMSA1, "EMSA1");
#endif
-#if defined(BOTAN_HAS_EMSA1_BSI)
-BOTAN_REGISTER_EMSA_1HASH(EMSA1_BSI, "EMSA1_BSI");
-#endif
-
#if defined(BOTAN_HAS_EMSA_PKCS1)
BOTAN_REGISTER_NAMED_T(EMSA, "EMSA_PKCS1", EMSA_PCS1v15, EMSA_PKCS1v15::make);
#endif
diff --git a/src/lib/pk_pad/emsa.h b/src/lib/pk_pad/emsa.h
index d4fd146da..f4697d100 100644
--- a/src/lib/pk_pad/emsa.h
+++ b/src/lib/pk_pad/emsa.h
@@ -59,16 +59,27 @@ class BOTAN_DLL EMSA
size_t key_bits) = 0;
virtual ~EMSA();
+
+ virtual EMSA* clone() = 0;
};
/**
* Factory method for EMSA (message-encoding methods for signatures
* with appendix) objects
-* @param algo_spec the name of the EME to create
+* @param algo_spec the name of the EMSA to create
* @return pointer to newly allocated object of that type
*/
BOTAN_DLL EMSA* get_emsa(const std::string& algo_spec);
+/**
+* Returns the hash function used in the given EMSA scheme
+* If the hash function is not specified or not understood,
+* returns "SHA-512"
+* @param algo_spec the name of the EMSA
+* @return hash function used in the given EMSA scheme
+*/
+BOTAN_DLL std::string hash_for_emsa(const std::string& algo_spec);
+
}
#endif
diff --git a/src/lib/pk_pad/emsa1/emsa1.cpp b/src/lib/pk_pad/emsa1/emsa1.cpp
index 0031bf263..67f8ab21f 100644
--- a/src/lib/pk_pad/emsa1/emsa1.cpp
+++ b/src/lib/pk_pad/emsa1/emsa1.cpp
@@ -40,6 +40,11 @@ secure_vector<byte> emsa1_encoding(const secure_vector<byte>& msg,
}
+EMSA* EMSA1::clone()
+ {
+ return new EMSA1(m_hash->clone());
+ }
+
void EMSA1::update(const byte input[], size_t length)
{
m_hash->update(input, length);
diff --git a/src/lib/pk_pad/emsa1/emsa1.h b/src/lib/pk_pad/emsa1/emsa1.h
index e346167da..5a4b4b372 100644
--- a/src/lib/pk_pad/emsa1/emsa1.h
+++ b/src/lib/pk_pad/emsa1/emsa1.h
@@ -25,8 +25,13 @@ class BOTAN_DLL EMSA1 : public EMSA
*/
explicit EMSA1(HashFunction* hash) : m_hash(hash) {}
+ EMSA* clone() override;
+
protected:
size_t hash_output_length() const { return m_hash->output_length(); }
+
+ std::unique_ptr<HashFunction> m_hash;
+
private:
void update(const byte[], size_t) override;
secure_vector<byte> raw_data() override;
@@ -39,7 +44,6 @@ class BOTAN_DLL EMSA1 : public EMSA
const secure_vector<byte>& raw,
size_t key_bits) override;
- std::unique_ptr<HashFunction> m_hash;
};
}
diff --git a/src/lib/pk_pad/emsa1_bsi/emsa1_bsi.cpp b/src/lib/pk_pad/emsa1_bsi/emsa1_bsi.cpp
deleted file mode 100644
index 5fc96da8d..000000000
--- a/src/lib/pk_pad/emsa1_bsi/emsa1_bsi.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
-* EMSA1 BSI
-* (C) 1999-2008 Jack Lloyd
-* 2008 Falko Strenzke, FlexSecure GmbH
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/emsa1_bsi.h>
-
-namespace Botan {
-
-/*
-* EMSA1 BSI Encode Operation
-*/
-secure_vector<byte> EMSA1_BSI::encoding_of(const secure_vector<byte>& msg,
- size_t output_bits,
- RandomNumberGenerator&)
- {
- if(msg.size() != hash_output_length())
- throw Encoding_Error("EMSA1_BSI::encoding_of: Invalid size for input");
-
- if(8*msg.size() <= output_bits)
- return msg;
-
- throw Encoding_Error("EMSA1_BSI::encoding_of: max key input size exceeded");
- }
-
-}
diff --git a/src/lib/pk_pad/emsa1_bsi/emsa1_bsi.h b/src/lib/pk_pad/emsa1_bsi/emsa1_bsi.h
deleted file mode 100644
index a7fae6c23..000000000
--- a/src/lib/pk_pad/emsa1_bsi/emsa1_bsi.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-* EMSA1 BSI Variant
-* (C) 1999-2008 Jack Lloyd
-* 2007 FlexSecure GmbH
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_EMSA1_BSI_H__
-#define BOTAN_EMSA1_BSI_H__
-
-#include <botan/emsa1.h>
-
-namespace Botan {
-
-/**
-* EMSA1_BSI is a variant of EMSA1 specified by the BSI. It accepts
-* only hash values which are less or equal than the maximum key
-* length. The implementation comes from InSiTo
-*/
-class BOTAN_DLL EMSA1_BSI final : public EMSA1
- {
- public:
- /**
- * @param hash the hash object to use
- */
- explicit EMSA1_BSI(HashFunction* hash) : EMSA1(hash) {}
- private:
- secure_vector<byte> encoding_of(const secure_vector<byte>&, size_t,
- RandomNumberGenerator& rng) override;
- };
-
-}
-
-#endif
diff --git a/src/lib/pk_pad/emsa1_bsi/info.txt b/src/lib/pk_pad/emsa1_bsi/info.txt
deleted file mode 100644
index 021c99720..000000000
--- a/src/lib/pk_pad/emsa1_bsi/info.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-define EMSA1_BSI 20131128
-
-<requires>
-emsa1
-</requires>
diff --git a/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.h b/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.h
index 9d5bc7829..0773ed2c4 100644
--- a/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.h
+++ b/src/lib/pk_pad/emsa_pkcs1/emsa_pkcs1.h
@@ -28,6 +28,8 @@ class BOTAN_DLL EMSA_PKCS1v15 final : public EMSA
*/
explicit EMSA_PKCS1v15(HashFunction* hash);
+ EMSA* clone() override { return new EMSA_PKCS1v15(m_hash->clone()); }
+
void update(const byte[], size_t) override;
secure_vector<byte> raw_data() override;
@@ -50,6 +52,8 @@ class BOTAN_DLL EMSA_PKCS1v15 final : public EMSA
class BOTAN_DLL EMSA_PKCS1v15_Raw final : public EMSA
{
public:
+ EMSA* clone() override { return new EMSA_PKCS1v15_Raw(); }
+
void update(const byte[], size_t) override;
secure_vector<byte> raw_data() override;
diff --git a/src/lib/pk_pad/emsa_pssr/pssr.h b/src/lib/pk_pad/emsa_pssr/pssr.h
index ee234b0b6..9b39417a5 100644
--- a/src/lib/pk_pad/emsa_pssr/pssr.h
+++ b/src/lib/pk_pad/emsa_pssr/pssr.h
@@ -31,6 +31,8 @@ class BOTAN_DLL PSSR final : public EMSA
*/
PSSR(HashFunction* hash, size_t salt_size);
+ EMSA* clone() override { return new PSSR(m_hash->clone(), m_SALT_SIZE); }
+
static PSSR* make(const Spec& spec);
private:
void update(const byte input[], size_t length) override;
diff --git a/src/lib/pk_pad/emsa_raw/emsa_raw.h b/src/lib/pk_pad/emsa_raw/emsa_raw.h
index 272d34b0e..cc2d5d63a 100644
--- a/src/lib/pk_pad/emsa_raw/emsa_raw.h
+++ b/src/lib/pk_pad/emsa_raw/emsa_raw.h
@@ -18,6 +18,9 @@ namespace Botan {
*/
class BOTAN_DLL EMSA_Raw final : public EMSA
{
+ public:
+ EMSA* clone() override { return new EMSA_Raw(); }
+
private:
void update(const byte[], size_t) override;
secure_vector<byte> raw_data() override;
diff --git a/src/lib/pk_pad/emsa_x931/emsa_x931.h b/src/lib/pk_pad/emsa_x931/emsa_x931.h
index 400042a86..56754d3b1 100644
--- a/src/lib/pk_pad/emsa_x931/emsa_x931.h
+++ b/src/lib/pk_pad/emsa_x931/emsa_x931.h
@@ -25,6 +25,8 @@ class BOTAN_DLL EMSA_X931 final : public EMSA
* @param hash the hash object to use
*/
explicit EMSA_X931(HashFunction* hash);
+
+ EMSA* clone() override { return new EMSA_X931(m_hash->clone()); }
private:
void update(const byte[], size_t) override;
secure_vector<byte> raw_data() override;
diff --git a/src/lib/pk_pad/hash_id/hash_id.cpp b/src/lib/pk_pad/hash_id/hash_id.cpp
index 28bbea346..882c30a4c 100644
--- a/src/lib/pk_pad/hash_id/hash_id.cpp
+++ b/src/lib/pk_pad/hash_id/hash_id.cpp
@@ -48,6 +48,10 @@ const byte SHA_512_PKCS_ID[] = {
0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40 };
+const byte SHA_512_256_PKCS_ID[] = {
+0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
+0x65, 0x03, 0x04, 0x02, 0x06, 0x05, 0x00, 0x04, 0x20 };
+
const byte TIGER_PKCS_ID[] = {
0x30, 0x29, 0x30, 0x0D, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04,
0x01, 0xDA, 0x47, 0x0C, 0x02, 0x05, 0x00, 0x04, 0x18 };
@@ -99,6 +103,10 @@ std::vector<byte> pkcs_hash_id(const std::string& name)
return std::vector<byte>(SHA_512_PKCS_ID,
SHA_512_PKCS_ID + sizeof(SHA_512_PKCS_ID));
+ if(name == "SHA-512-256")
+ return std::vector<byte>(SHA_512_256_PKCS_ID,
+ SHA_512_256_PKCS_ID + sizeof(SHA_512_256_PKCS_ID));
+
if(name == "Tiger(24,3)")
return std::vector<byte>(TIGER_PKCS_ID,
TIGER_PKCS_ID + sizeof(TIGER_PKCS_ID));
diff --git a/src/lib/prov/openssl/openssl_rc4.cpp b/src/lib/prov/openssl/openssl_rc4.cpp
index e36535e08..d6246e4ab 100644
--- a/src/lib/prov/openssl/openssl_rc4.cpp
+++ b/src/lib/prov/openssl/openssl_rc4.cpp
@@ -12,6 +12,7 @@
#include <botan/internal/algo_registry.h>
#include <botan/internal/openssl.h>
#include <botan/parsing.h>
+#include <botan/exceptn.h>
#include <openssl/rc4.h>
namespace Botan {
@@ -45,6 +46,16 @@ class OpenSSL_RC4 : public StreamCipher
explicit OpenSSL_RC4(size_t skip = 0) : m_skip(skip) { clear(); }
~OpenSSL_RC4() { clear(); }
+
+ void set_iv(const byte*, size_t) override
+ {
+ throw Exception("RC4 does not support an IV");
+ }
+
+ void seek(u64bit) override
+ {
+ throw Exception("RC4 does not support seeking");
+ }
private:
void cipher(const byte in[], byte out[], size_t length) override
{
diff --git a/src/lib/prov/pkcs11/info.txt b/src/lib/prov/pkcs11/info.txt
new file mode 100644
index 000000000..2715c7cda
--- /dev/null
+++ b/src/lib/prov/pkcs11/info.txt
@@ -0,0 +1,48 @@
+define PKCS11 20160219
+
+load_on vendor
+
+<requires>
+dyn_load
+rng
+pk_pad
+</requires>
+
+<header:internal>
+p11_mechanism.h
+</header:internal>
+
+<header:external>
+pkcs11.h
+pkcs11f.h
+pkcs11t.h
+</header:external>
+
+<header:public>
+p11.h
+p11_ecc_key.h
+p11_ecdh.h
+p11_ecdsa.h
+p11_module.h
+p11_object.h
+p11_randomgenerator.h
+p11_rsa.h
+p11_session.h
+p11_slot.h
+p11_x509.h
+</header:public>
+
+<source>
+p11.cpp
+p11_ecc_key.cpp
+p11_ecdh.cpp
+p11_ecdsa.cpp
+p11_mechanism.cpp
+p11_module.cpp
+p11_object.cpp
+p11_randomgenerator.cpp
+p11_rsa.cpp
+p11_session.cpp
+p11_slot.cpp
+p11_x509.cpp
+</source> \ No newline at end of file
diff --git a/src/lib/prov/pkcs11/p11.cpp b/src/lib/prov/pkcs11/p11.cpp
new file mode 100644
index 000000000..d338438d3
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11.cpp
@@ -0,0 +1,769 @@
+/*
+* PKCS#11
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11.h>
+#include <botan/p11_session.h>
+
+#include <cstdint>
+#include <string>
+#include <functional>
+
+namespace Botan {
+namespace PKCS11 {
+
+ReturnValue* ThrowException = reinterpret_cast< ReturnValue* >(-1);
+
+namespace {
+/// @param function_result Return value of the PKCS11 module function
+/// @param returnValue if (`ThrowException`) is passed the function throws an exception, otherwise if a non-NULL pointer is passed:
+/// return_value receives the return value of the PKCS#11 function and no exception is thrown.
+/// @return true if function call was successful, false otherwise
+bool handle_return_value(const CK_RV function_result, ReturnValue* return_value)
+ {
+ if(return_value == ThrowException)
+ {
+ if(static_cast< ReturnValue >(function_result) != ReturnValue::OK)
+ {
+ // caller wants exception
+ throw PKCS11_ReturnError(static_cast< ReturnValue >(function_result));
+ }
+ }
+ else if(return_value != nullptr)
+ {
+ // caller wants return value
+ *return_value = static_cast< ReturnValue >(function_result);
+ }
+
+ return static_cast< ReturnValue >(function_result) == ReturnValue::OK;
+ }
+}
+
+void initialize_token(Slot& slot, const std::string& label, const secure_string& so_pin, const secure_string& pin)
+ {
+ slot.initialize(label, so_pin);
+ set_pin(slot, so_pin, pin);
+ }
+
+void change_pin(Slot& slot, const secure_string& old_pin, const secure_string& new_pin)
+ {
+ Session session(slot, false);
+ session.login(UserType::User, old_pin);
+ session.set_pin(old_pin, new_pin);
+ }
+
+void change_so_pin(Slot& slot, const secure_string& old_so_pin, const secure_string& new_so_pin)
+ {
+ Session session(slot, false);
+ session.login(UserType::SO, old_so_pin);
+ session.set_pin(old_so_pin, new_so_pin);
+ }
+
+void set_pin(Slot& slot, const secure_string& so_pin, const secure_string& pin)
+ {
+ Session session(slot, false);
+ session.login(UserType::SO, so_pin);
+ session.init_pin(pin);
+ }
+
+LowLevel::LowLevel(FunctionListPtr ptr) :
+ m_func_list_ptr(ptr)
+ {
+ if(m_func_list_ptr == nullptr)
+ {
+ throw Invalid_Argument("Invalid PKCS#11 function list ptr");
+ }
+ }
+
+LowLevel::~LowLevel() BOTAN_NOEXCEPT
+{}
+
+/****************************** General purpose functions ******************************/
+
+bool LowLevel::C_Initialize(VoidPtr init_args,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Initialize(init_args), return_value);
+ }
+
+bool LowLevel::C_Finalize(VoidPtr reserved,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Finalize(reserved), return_value);
+ }
+
+bool LowLevel::C_GetInfo(Info* info_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetInfo(info_ptr), return_value);
+ }
+
+bool LowLevel::C_GetFunctionList(Dynamically_Loaded_Library& pkcs11_module, FunctionListPtr* function_list_ptr_ptr,
+ ReturnValue* return_value)
+ {
+ using get_function_list = CK_RV(*)(FunctionListPtr*);
+
+ get_function_list get_function_list_ptr = pkcs11_module.resolve<get_function_list>("C_GetFunctionList");
+
+ return handle_return_value(get_function_list_ptr(function_list_ptr_ptr), return_value);
+ }
+
+/****************************** Slot and token management functions ******************************/
+
+bool LowLevel::C_GetSlotList(Bbool token_present,
+ SlotId* slot_list_ptr,
+ Ulong* count_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetSlotList(token_present, slot_list_ptr, count_ptr), return_value);
+ }
+
+bool LowLevel::C_GetSlotList(bool token_present,
+ std::vector<SlotId>& slot_ids,
+ ReturnValue* return_value) const
+ {
+ slot_ids.clear();
+
+ // first get available slots
+ Ulong number_slots = 0;
+
+ bool success = C_GetSlotList(token_present, nullptr, &number_slots, return_value);
+
+ if(!success || !number_slots)
+ {
+ return success;
+ }
+
+ // get actual slot ids
+ slot_ids.resize(number_slots);
+ return C_GetSlotList(token_present, slot_ids.data(), &number_slots, return_value);
+ }
+
+bool LowLevel::C_GetSlotInfo(SlotId slot_id,
+ SlotInfo* info_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetSlotInfo(slot_id, info_ptr), return_value);
+ }
+
+bool LowLevel::C_GetTokenInfo(SlotId slot_id,
+ TokenInfo* info_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetTokenInfo(slot_id, info_ptr), return_value);
+ }
+
+bool LowLevel::C_WaitForSlotEvent(Flags flags,
+ SlotId* slot_ptr,
+ VoidPtr reserved,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_WaitForSlotEvent(flags, slot_ptr, reserved), return_value);
+ }
+
+bool LowLevel::C_GetMechanismList(SlotId slot_id,
+ MechanismType* mechanism_list_ptr,
+ Ulong* count_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetMechanismList(slot_id,
+ reinterpret_cast< CK_MECHANISM_TYPE_PTR >(mechanism_list_ptr), count_ptr), return_value);
+ }
+
+bool LowLevel::C_GetMechanismList(SlotId slot_id,
+ std::vector<MechanismType>& mechanisms,
+ ReturnValue* return_value) const
+ {
+ mechanisms.clear();
+
+ // first get number of mechanisms
+ Ulong number_mechanisms = 0;
+
+ bool success = C_GetMechanismList(slot_id, nullptr, &number_mechanisms, return_value);
+
+ if(!success || !number_mechanisms)
+ {
+ return success;
+ }
+
+ // get actual mechanisms
+ mechanisms.resize(number_mechanisms);
+ return C_GetMechanismList(slot_id, reinterpret_cast< MechanismType* >(mechanisms.data()), &number_mechanisms,
+ return_value);
+ }
+
+bool LowLevel::C_GetMechanismInfo(SlotId slot_id,
+ MechanismType type,
+ MechanismInfo* info_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetMechanismInfo(slot_id, static_cast< CK_MECHANISM_TYPE >(type),
+ info_ptr), return_value);
+ }
+
+bool LowLevel::C_InitToken(SlotId slot_id,
+ Utf8Char* so_pin_ptr,
+ Ulong so_pin_len,
+ Utf8Char* label_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_InitToken(slot_id, so_pin_ptr, so_pin_len, label_ptr), return_value);
+ }
+
+bool LowLevel::C_InitPIN(SessionHandle session,
+ Utf8Char* pin_ptr,
+ Ulong pin_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_InitPIN(session, pin_ptr, pin_len), return_value);
+ }
+
+bool LowLevel::C_SetPIN(SessionHandle session,
+ Utf8Char* old_pin_ptr,
+ Ulong old_len,
+ Utf8Char* new_pin_ptr,
+ Ulong new_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SetPIN(session, old_pin_ptr, old_len, new_pin_ptr, new_len),
+ return_value);
+ }
+
+/****************************** Session management ******************************/
+
+bool LowLevel::C_OpenSession(SlotId slot_id,
+ Flags flags,
+ VoidPtr application,
+ Notify notify,
+ SessionHandle* session_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_OpenSession(slot_id, flags, application, notify, session_ptr),
+ return_value);
+ }
+
+bool LowLevel::C_CloseSession(SessionHandle session,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_CloseSession(session), return_value);
+ }
+
+bool LowLevel::C_CloseAllSessions(SlotId slot_id,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_CloseAllSessions(slot_id), return_value);
+ }
+
+bool LowLevel::C_GetSessionInfo(SessionHandle session,
+ SessionInfo* info_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetSessionInfo(session, info_ptr), return_value);
+ }
+
+bool LowLevel::C_GetOperationState(SessionHandle session,
+ Byte* operation_state_ptr,
+ Ulong* operation_state_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetOperationState(session, operation_state_ptr, operation_state_len_ptr),
+ return_value);
+ }
+
+bool LowLevel::C_SetOperationState(SessionHandle session,
+ Byte* operation_state_ptr,
+ Ulong operation_state_len,
+ ObjectHandle encryption_key,
+ ObjectHandle authentication_key,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SetOperationState(session, operation_state_ptr, operation_state_len,
+ encryption_key, authentication_key), return_value);
+ }
+
+bool LowLevel::C_Login(SessionHandle session,
+ UserType user_type,
+ Utf8Char* pin_ptr,
+ Ulong pin_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Login(session, static_cast< CK_USER_TYPE >(user_type), pin_ptr, pin_len),
+ return_value);
+ }
+
+bool LowLevel::C_Logout(SessionHandle session,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Logout(session), return_value);
+ }
+
+/****************************** Object management functions ******************************/
+
+bool LowLevel::C_CreateObject(SessionHandle session,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ObjectHandle* object_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_CreateObject(session, attribute_template_ptr, count, object_ptr),
+ return_value);
+ }
+
+bool LowLevel::C_CopyObject(SessionHandle session,
+ ObjectHandle object,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ObjectHandle* new_object_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_CopyObject(session, object, attribute_template_ptr, count,
+ new_object_ptr), return_value);
+ }
+
+bool LowLevel::C_DestroyObject(SessionHandle session,
+ ObjectHandle object,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DestroyObject(session, object), return_value);
+ }
+
+bool LowLevel::C_GetObjectSize(SessionHandle session,
+ ObjectHandle object,
+ Ulong* size_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetObjectSize(session, object, size_ptr), return_value);
+ }
+
+bool LowLevel::C_GetAttributeValue(SessionHandle session,
+ ObjectHandle object,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetAttributeValue(session, object, attribute_template_ptr, count),
+ return_value);
+ }
+
+bool LowLevel::C_SetAttributeValue(SessionHandle session,
+ ObjectHandle object,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SetAttributeValue(session, object, attribute_template_ptr, count),
+ return_value);
+ }
+
+bool LowLevel::C_FindObjectsInit(SessionHandle session,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_FindObjectsInit(session, attribute_template_ptr, count), return_value);
+ }
+
+bool LowLevel::C_FindObjects(SessionHandle session,
+ ObjectHandle* object_ptr,
+ Ulong max_object_count,
+ Ulong* object_count_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_FindObjects(session, object_ptr, max_object_count, object_count_ptr),
+ return_value);
+ }
+
+bool LowLevel::C_FindObjectsFinal(SessionHandle session,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_FindObjectsFinal(session), return_value);
+ }
+
+/****************************** Encryption functions ******************************/
+
+bool LowLevel::C_EncryptInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_EncryptInit(session, mechanism_ptr, key), return_value);
+ }
+
+bool LowLevel::C_Encrypt(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* encrypted_data_ptr,
+ Ulong* encrypted_data_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Encrypt(session, data_ptr, data_len, encrypted_data_ptr,
+ encrypted_data_len_ptr), return_value);
+ }
+
+bool LowLevel::C_EncryptUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ Byte* encrypted_part_ptr,
+ Ulong* encrypted_part_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_EncryptUpdate(session, part_ptr, part_len, encrypted_part_ptr,
+ encrypted_part_len_ptr), return_value);
+ }
+
+bool LowLevel::C_EncryptFinal(SessionHandle session,
+ Byte* last_encrypted_part_ptr,
+ Ulong* last_encrypted_part_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_EncryptFinal(session, last_encrypted_part_ptr,
+ last_encrypted_part_len_ptr), return_value);
+ }
+
+/****************************** Decryption functions ******************************/
+
+bool LowLevel::C_DecryptInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DecryptInit(session, mechanism_ptr, key), return_value);
+ }
+
+bool LowLevel::C_Decrypt(SessionHandle session,
+ Byte* encrypted_data_ptr,
+ Ulong encrypted_data_len,
+ Byte* data_ptr,
+ Ulong* data_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Decrypt(session, encrypted_data_ptr, encrypted_data_len, data_ptr,
+ data_len_ptr), return_value);
+ }
+
+bool LowLevel::C_DecryptUpdate(SessionHandle session,
+ Byte* encrypted_part_ptr,
+ Ulong encrypted_part_len,
+ Byte* part_ptr,
+ Ulong* part_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DecryptUpdate(session, encrypted_part_ptr, encrypted_part_len, part_ptr,
+ part_len_ptr), return_value);
+ }
+
+bool LowLevel::C_DecryptFinal(SessionHandle session,
+ Byte* last_part_ptr,
+ Ulong* last_part_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DecryptFinal(session, last_part_ptr, last_part_len_ptr), return_value);
+ }
+
+/****************************** Message digesting functions ******************************/
+
+bool LowLevel::C_DigestInit(SessionHandle session,
+ Mechanism* mechanism,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DigestInit(session, mechanism), return_value);
+ }
+
+bool LowLevel::C_Digest(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* digest_ptr,
+ Ulong* digest_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Digest(session, data_ptr, data_len, digest_ptr, digest_len_ptr),
+ return_value);
+ }
+
+bool LowLevel::C_DigestUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DigestUpdate(session, part_ptr, part_len), return_value);
+ }
+
+bool LowLevel::C_DigestKey(SessionHandle session,
+ ObjectHandle key,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DigestKey(session, key), return_value);
+ }
+
+bool LowLevel::C_DigestFinal(SessionHandle session,
+ Byte* digest_ptr,
+ Ulong* digest_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DigestFinal(session, digest_ptr, digest_len_ptr), return_value);
+ }
+
+/****************************** Signing and MACing functions ******************************/
+
+bool LowLevel::C_SignInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SignInit(session, mechanism_ptr, key), return_value);
+ }
+
+bool LowLevel::C_Sign(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* signature_ptr,
+ Ulong* signature_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Sign(session, data_ptr, data_len, signature_ptr, signature_len_ptr),
+ return_value);
+ }
+
+bool LowLevel::C_SignUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SignUpdate(session, part_ptr, part_len), return_value);
+ }
+
+bool LowLevel::C_SignFinal(SessionHandle session,
+ Byte* signature_ptr,
+ Ulong* signature_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SignFinal(session, signature_ptr, signature_len_ptr), return_value);
+ }
+
+bool LowLevel::C_SignRecoverInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SignRecoverInit(session, mechanism_ptr, key), return_value);
+ }
+
+bool LowLevel::C_SignRecover(SessionHandle session,
+ Byte* data,
+ Ulong data_len,
+ Byte* signature,
+ Ulong* signature_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SignRecover(session, data, data_len, signature, signature_len),
+ return_value);
+ }
+
+/****************************** Functions for verifying signatures and MACs ******************************/
+
+bool LowLevel::C_VerifyInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_VerifyInit(session, mechanism_ptr, key), return_value);
+ }
+
+bool LowLevel::C_Verify(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* signature_ptr,
+ Ulong signature_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_Verify(session, data_ptr, data_len, signature_ptr, signature_len),
+ return_value);
+ }
+
+bool LowLevel::C_VerifyUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_VerifyUpdate(session, part_ptr, part_len), return_value);
+ }
+
+bool LowLevel::C_VerifyFinal(SessionHandle session,
+ Byte* signature_ptr,
+ Ulong signature_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_VerifyFinal(session, signature_ptr, signature_len), return_value);
+ }
+
+bool LowLevel::C_VerifyRecoverInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_VerifyRecoverInit(session, mechanism_ptr, key), return_value);
+ }
+
+bool LowLevel::C_VerifyRecover(SessionHandle session,
+ Byte* signature_ptr,
+ Ulong signature_len,
+ Byte* data_ptr,
+ Ulong* data_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_VerifyRecover(session, signature_ptr, signature_len, data_ptr,
+ data_len_ptr), return_value);
+ }
+
+/****************************** Dual-purpose cryptographic functions ******************************/
+
+bool LowLevel::C_DigestEncryptUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ Byte* encrypted_part_ptr,
+ Ulong* encrypted_part_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DigestEncryptUpdate(session, part_ptr, part_len, encrypted_part_ptr,
+ encrypted_part_len_ptr), return_value);
+ }
+
+bool LowLevel::C_DecryptDigestUpdate(SessionHandle session,
+ Byte* encrypted_part_ptr,
+ Ulong encrypted_part_len,
+ Byte* part_ptr,
+ Ulong* part_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DecryptDigestUpdate(session, encrypted_part_ptr, encrypted_part_len,
+ part_ptr, part_len_ptr), return_value);
+ }
+
+bool LowLevel::C_SignEncryptUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ Byte* encrypted_part_ptr,
+ Ulong* encrypted_part_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SignEncryptUpdate(session, part_ptr, part_len, encrypted_part_ptr,
+ encrypted_part_len_ptr), return_value);
+ }
+
+bool LowLevel::C_DecryptVerifyUpdate(SessionHandle session,
+ Byte* encrypted_part_ptr,
+ Ulong encrypted_part_len,
+ Byte* part_ptr,
+ Ulong* part_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DecryptVerifyUpdate(session, encrypted_part_ptr, encrypted_part_len,
+ part_ptr, part_len_ptr), return_value);
+ }
+
+/****************************** Key management functions ******************************/
+
+bool LowLevel::C_GenerateKey(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ObjectHandle* key_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GenerateKey(session, mechanism_ptr, attribute_template_ptr, count,
+ key_ptr), return_value);
+ }
+
+bool LowLevel::C_GenerateKeyPair(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ Attribute* public_key_template_ptr,
+ Ulong public_key_attribute_count,
+ Attribute* private_key_template_ptr,
+ Ulong private_key_attribute_count,
+ ObjectHandle* public_key_ptr,
+ ObjectHandle* private_key_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GenerateKeyPair(session, mechanism_ptr, public_key_template_ptr,
+ public_key_attribute_count, private_key_template_ptr,
+ private_key_attribute_count, public_key_ptr, private_key_ptr), return_value);
+ }
+
+bool LowLevel::C_WrapKey(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle wrapping_key,
+ ObjectHandle key,
+ Byte* wrapped_key_ptr,
+ Ulong* wrapped_key_len_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_WrapKey(session, mechanism_ptr, wrapping_key, key, wrapped_key_ptr,
+ wrapped_key_len_ptr), return_value);
+ }
+
+bool LowLevel::C_UnwrapKey(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle unwrapping_key,
+ Byte* wrapped_key_ptr,
+ Ulong wrapped_key_len,
+ Attribute* attribute_template_ptr,
+ Ulong attribute_count,
+ ObjectHandle* key_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_UnwrapKey(session, mechanism_ptr, unwrapping_key, wrapped_key_ptr,
+ wrapped_key_len, attribute_template_ptr,
+ attribute_count, key_ptr), return_value);
+ }
+
+bool LowLevel::C_DeriveKey(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle base_key,
+ Attribute* attribute_template_ptr,
+ Ulong attribute_count,
+ ObjectHandle* key_ptr,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_DeriveKey(session, mechanism_ptr, base_key, attribute_template_ptr,
+ attribute_count, key_ptr), return_value);
+ }
+
+/****************************** Random number generation functions ******************************/
+
+bool LowLevel::C_SeedRandom(SessionHandle session,
+ Byte* seed_ptr,
+ Ulong seed_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_SeedRandom(session, seed_ptr, seed_len), return_value);
+ }
+
+bool LowLevel::C_GenerateRandom(SessionHandle session,
+ Byte* random_data_ptr,
+ Ulong random_len,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GenerateRandom(session, random_data_ptr, random_len), return_value);
+ }
+
+/****************************** Parallel function management functions ******************************/
+
+bool LowLevel::C_GetFunctionStatus(SessionHandle session,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_GetFunctionStatus(session), return_value);
+ }
+
+bool LowLevel::C_CancelFunction(SessionHandle session,
+ ReturnValue* return_value) const
+ {
+ return handle_return_value(m_func_list_ptr->C_CancelFunction(session), return_value);
+ }
+
+}
+
+}
diff --git a/src/lib/prov/pkcs11/p11.h b/src/lib/prov/pkcs11/p11.h
new file mode 100644
index 000000000..c18c07d59
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11.h
@@ -0,0 +1,2861 @@
+/*
+* PKCS#11
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_H__
+#define BOTAN_P11_H__
+
+#include <botan/secmem.h>
+#include <botan/exceptn.h>
+#include <botan/dyn_load.h>
+
+#include <vector>
+#include <string>
+#include <map>
+
+#define BOTAN_PKCS11_RSA_PRIO 90
+#define BOTAN_PKCS11_ECDSA_PRIO 90
+#define BOTAN_PKCS11_ECDH_PRIO 90
+
+#define CK_PTR *
+
+#if defined(_MSC_VER)
+#define CK_DECLARE_FUNCTION(returnType, name) \
+ returnType __declspec(dllimport) name
+#else
+#define CK_DECLARE_FUNCTION(returnType, name) \
+ returnType name
+#endif
+
+#if defined(_MSC_VER)
+#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ returnType __declspec(dllimport) (* name)
+#else
+#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ returnType (* name)
+#endif
+
+#define CK_CALLBACK_FUNCTION(returnType, name) \
+ returnType (* name)
+
+#ifndef NULL_PTR
+ #define NULL_PTR nullptr
+#endif
+
+#if defined(_MSC_VER)
+ #pragma pack(push, cryptoki, 1)
+#endif
+
+#include "pkcs11.h"
+
+#if defined(_MSC_VER)
+ #pragma pack(pop, cryptoki)
+#endif
+
+static_assert(CRYPTOKI_VERSION_MAJOR == 2 && CRYPTOKI_VERSION_MINOR == 40,
+ "The Botan PKCS#11 module was implemented against PKCS#11 v2.40. Please use the correct PKCS#11 headers.");
+
+namespace Botan {
+namespace PKCS11 {
+
+using secure_string = secure_vector<byte>;
+
+enum class AttributeType : CK_ATTRIBUTE_TYPE
+ {
+ Class = CKA_CLASS,
+ Token = CKA_TOKEN,
+ Private = CKA_PRIVATE,
+ Label = CKA_LABEL,
+ Application = CKA_APPLICATION,
+ Value = CKA_VALUE,
+ ObjectId = CKA_OBJECT_ID,
+ CertificateType = CKA_CERTIFICATE_TYPE,
+ Issuer = CKA_ISSUER,
+ SerialNumber = CKA_SERIAL_NUMBER,
+ AcIssuer = CKA_AC_ISSUER,
+ Owner = CKA_OWNER,
+ AttrTypes = CKA_ATTR_TYPES,
+ Trusted = CKA_TRUSTED,
+ CertificateCategory = CKA_CERTIFICATE_CATEGORY,
+ JavaMidpSecurityDomain = CKA_JAVA_MIDP_SECURITY_DOMAIN,
+ Url = CKA_URL,
+ HashOfSubjectPublicKey = CKA_HASH_OF_SUBJECT_PUBLIC_KEY,
+ HashOfIssuerPublicKey = CKA_HASH_OF_ISSUER_PUBLIC_KEY,
+ NameHashAlgorithm = CKA_NAME_HASH_ALGORITHM,
+ CheckValue = CKA_CHECK_VALUE,
+ KeyType = CKA_KEY_TYPE,
+ Subject = CKA_SUBJECT,
+ Id = CKA_ID,
+ Sensitive = CKA_SENSITIVE,
+ Encrypt = CKA_ENCRYPT,
+ Decrypt = CKA_DECRYPT,
+ Wrap = CKA_WRAP,
+ Unwrap = CKA_UNWRAP,
+ Sign = CKA_SIGN,
+ SignRecover = CKA_SIGN_RECOVER,
+ Verify = CKA_VERIFY,
+ VerifyRecover = CKA_VERIFY_RECOVER,
+ Derive = CKA_DERIVE,
+ StartDate = CKA_START_DATE,
+ EndDate = CKA_END_DATE,
+ Modulus = CKA_MODULUS,
+ ModulusBits = CKA_MODULUS_BITS,
+ PublicExponent = CKA_PUBLIC_EXPONENT,
+ PrivateExponent = CKA_PRIVATE_EXPONENT,
+ Prime1 = CKA_PRIME_1,
+ Prime2 = CKA_PRIME_2,
+ Exponent1 = CKA_EXPONENT_1,
+ Exponent2 = CKA_EXPONENT_2,
+ Coefficient = CKA_COEFFICIENT,
+ PublicKeyInfo = CKA_PUBLIC_KEY_INFO,
+ Prime = CKA_PRIME,
+ Subprime = CKA_SUBPRIME,
+ Base = CKA_BASE,
+ PrimeBits = CKA_PRIME_BITS,
+ SubprimeBits = CKA_SUBPRIME_BITS,
+ SubPrimeBits = CKA_SUB_PRIME_BITS,
+ ValueBits = CKA_VALUE_BITS,
+ ValueLen = CKA_VALUE_LEN,
+ Extractable = CKA_EXTRACTABLE,
+ Local = CKA_LOCAL,
+ NeverExtractable = CKA_NEVER_EXTRACTABLE,
+ AlwaysSensitive = CKA_ALWAYS_SENSITIVE,
+ KeyGenMechanism = CKA_KEY_GEN_MECHANISM,
+ Modifiable = CKA_MODIFIABLE,
+ Copyable = CKA_COPYABLE,
+ Destroyable = CKA_DESTROYABLE,
+ EcdsaParams = CKA_ECDSA_PARAMS,
+ EcParams = CKA_EC_PARAMS,
+ EcPoint = CKA_EC_POINT,
+ SecondaryAuth = CKA_SECONDARY_AUTH,
+ AuthPinFlags = CKA_AUTH_PIN_FLAGS,
+ AlwaysAuthenticate = CKA_ALWAYS_AUTHENTICATE,
+ WrapWithTrusted = CKA_WRAP_WITH_TRUSTED,
+ WrapTemplate = CKA_WRAP_TEMPLATE,
+ UnwrapTemplate = CKA_UNWRAP_TEMPLATE,
+ DeriveTemplate = CKA_DERIVE_TEMPLATE,
+ OtpFormat = CKA_OTP_FORMAT,
+ OtpLength = CKA_OTP_LENGTH,
+ OtpTimeInterval = CKA_OTP_TIME_INTERVAL,
+ OtpUserFriendlyMode = CKA_OTP_USER_FRIENDLY_MODE,
+ OtpChallengeRequirement = CKA_OTP_CHALLENGE_REQUIREMENT,
+ OtpTimeRequirement = CKA_OTP_TIME_REQUIREMENT,
+ OtpCounterRequirement = CKA_OTP_COUNTER_REQUIREMENT,
+ OtpPinRequirement = CKA_OTP_PIN_REQUIREMENT,
+ OtpCounter = CKA_OTP_COUNTER,
+ OtpTime = CKA_OTP_TIME,
+ OtpUserIdentifier = CKA_OTP_USER_IDENTIFIER,
+ OtpServiceIdentifier = CKA_OTP_SERVICE_IDENTIFIER,
+ OtpServiceLogo = CKA_OTP_SERVICE_LOGO,
+ OtpServiceLogoType = CKA_OTP_SERVICE_LOGO_TYPE,
+ Gostr3410Params = CKA_GOSTR3410_PARAMS,
+ Gostr3411Params = CKA_GOSTR3411_PARAMS,
+ Gost28147Params = CKA_GOST28147_PARAMS,
+ HwFeatureType = CKA_HW_FEATURE_TYPE,
+ ResetOnInit = CKA_RESET_ON_INIT,
+ HasReset = CKA_HAS_RESET,
+ PixelX = CKA_PIXEL_X,
+ PixelY = CKA_PIXEL_Y,
+ Resolution = CKA_RESOLUTION,
+ CharRows = CKA_CHAR_ROWS,
+ CharColumns = CKA_CHAR_COLUMNS,
+ Color = CKA_COLOR,
+ BitsPerPixel = CKA_BITS_PER_PIXEL,
+ CharSets = CKA_CHAR_SETS,
+ EncodingMethods = CKA_ENCODING_METHODS,
+ MimeTypes = CKA_MIME_TYPES,
+ MechanismType = CKA_MECHANISM_TYPE,
+ RequiredCmsAttributes = CKA_REQUIRED_CMS_ATTRIBUTES,
+ DefaultCmsAttributes = CKA_DEFAULT_CMS_ATTRIBUTES,
+ SupportedCmsAttributes = CKA_SUPPORTED_CMS_ATTRIBUTES,
+ AllowedMechanisms = CKA_ALLOWED_MECHANISMS,
+ VendorDefined = CKA_VENDOR_DEFINED,
+ };
+
+enum class CertificateType : CK_CERTIFICATE_TYPE
+ {
+ X509 = CKC_X_509,
+ X509AttrCert = CKC_X_509_ATTR_CERT,
+ Wtls = CKC_WTLS,
+ VendorDefined = CKC_VENDOR_DEFINED,
+ };
+
+/// Indicates if a stored certificate is a user certificate for which the corresponding private key is available
+/// on the token ("token user"), a CA certificate ("authority"), or another end-entity certificate ("other entity").
+enum class CertificateCategory : CK_ULONG
+ {
+ Unspecified = CK_CERTIFICATE_CATEGORY_UNSPECIFIED,
+ TokenUser = CK_CERTIFICATE_CATEGORY_TOKEN_USER,
+ Authority = CK_CERTIFICATE_CATEGORY_AUTHORITY,
+ OtherEntity = CK_CERTIFICATE_CATEGORY_OTHER_ENTITY
+ };
+
+enum class KeyDerivation : CK_ULONG
+ {
+ Null = CKD_NULL,
+ Sha1Kdf = CKD_SHA1_KDF,
+ Sha1KdfAsn1 = CKD_SHA1_KDF_ASN1,
+ Sha1KdfConcatenate = CKD_SHA1_KDF_CONCATENATE,
+ Sha224Kdf = CKD_SHA224_KDF,
+ Sha256Kdf = CKD_SHA256_KDF,
+ Sha384Kdf = CKD_SHA384_KDF,
+ Sha512Kdf = CKD_SHA512_KDF,
+ CpdiversifyKdf = CKD_CPDIVERSIFY_KDF,
+ };
+
+enum class Flag : CK_FLAGS
+ {
+ None = 0,
+ TokenPresent = CKF_TOKEN_PRESENT,
+ RemovableDevice = CKF_REMOVABLE_DEVICE,
+ HwSlot = CKF_HW_SLOT,
+ Rng = CKF_RNG,
+ WriteProtected = CKF_WRITE_PROTECTED,
+ LoginRequired = CKF_LOGIN_REQUIRED,
+ UserPinInitialized = CKF_USER_PIN_INITIALIZED,
+ RestoreKeyNotNeeded = CKF_RESTORE_KEY_NOT_NEEDED,
+ ClockOnToken = CKF_CLOCK_ON_TOKEN,
+ ProtectedAuthenticationPath = CKF_PROTECTED_AUTHENTICATION_PATH,
+ DualCryptoOperations = CKF_DUAL_CRYPTO_OPERATIONS,
+ TokenInitialized = CKF_TOKEN_INITIALIZED,
+ SecondaryAuthentication = CKF_SECONDARY_AUTHENTICATION,
+ UserPinCountLow = CKF_USER_PIN_COUNT_LOW,
+ UserPinFinalTry = CKF_USER_PIN_FINAL_TRY,
+ UserPinLocked = CKF_USER_PIN_LOCKED,
+ UserPinToBeChanged = CKF_USER_PIN_TO_BE_CHANGED,
+ SoPinCountLow = CKF_SO_PIN_COUNT_LOW,
+ SoPinFinalTry = CKF_SO_PIN_FINAL_TRY,
+ SoPinLocked = CKF_SO_PIN_LOCKED,
+ SoPinToBeChanged = CKF_SO_PIN_TO_BE_CHANGED,
+ ErrorState = CKF_ERROR_STATE,
+ RwSession = CKF_RW_SESSION,
+ SerialSession = CKF_SERIAL_SESSION,
+ ArrayAttribute = CKF_ARRAY_ATTRIBUTE,
+ Hw = CKF_HW,
+ Encrypt = CKF_ENCRYPT,
+ Decrypt = CKF_DECRYPT,
+ Digest = CKF_DIGEST,
+ Sign = CKF_SIGN,
+ SignRecover = CKF_SIGN_RECOVER,
+ Verify = CKF_VERIFY,
+ VerifyRecover = CKF_VERIFY_RECOVER,
+ Generate = CKF_GENERATE,
+ GenerateKeyPair = CKF_GENERATE_KEY_PAIR,
+ Wrap = CKF_WRAP,
+ Unwrap = CKF_UNWRAP,
+ Derive = CKF_DERIVE,
+ EcFP = CKF_EC_F_P,
+ EcF2m = CKF_EC_F_2M,
+ EcEcparameters = CKF_EC_ECPARAMETERS,
+ EcNamedcurve = CKF_EC_NAMEDCURVE,
+ EcUncompress = CKF_EC_UNCOMPRESS,
+ EcCompress = CKF_EC_COMPRESS,
+ Extension = CKF_EXTENSION,
+ LibraryCantCreateOsThreads = CKF_LIBRARY_CANT_CREATE_OS_THREADS,
+ OsLockingOk = CKF_OS_LOCKING_OK,
+ DontBlock = CKF_DONT_BLOCK,
+ NextOtp = CKF_NEXT_OTP,
+ ExcludeTime = CKF_EXCLUDE_TIME,
+ ExcludeCounter = CKF_EXCLUDE_COUNTER,
+ ExcludeChallenge = CKF_EXCLUDE_CHALLENGE,
+ ExcludePin = CKF_EXCLUDE_PIN,
+ UserFriendlyOtp = CKF_USER_FRIENDLY_OTP,
+ };
+
+inline Flag operator | (Flag a, Flag b)
+ {
+ return static_cast< Flag >(static_cast< CK_FLAGS >(a) | static_cast< CK_FLAGS >(b));
+ }
+
+enum class MGF : CK_RSA_PKCS_MGF_TYPE
+ {
+ Mgf1Sha1 = CKG_MGF1_SHA1,
+ Mgf1Sha256 = CKG_MGF1_SHA256,
+ Mgf1Sha384 = CKG_MGF1_SHA384,
+ Mgf1Sha512 = CKG_MGF1_SHA512,
+ Mgf1Sha224 = CKG_MGF1_SHA224,
+ };
+
+enum class HardwareType : CK_HW_FEATURE_TYPE
+ {
+ MonotonicCounter = CKH_MONOTONIC_COUNTER,
+ Clock = CKH_CLOCK,
+ UserInterface = CKH_USER_INTERFACE,
+ VendorDefined = CKH_VENDOR_DEFINED,
+ };
+
+enum class KeyType : CK_KEY_TYPE
+ {
+ Rsa = CKK_RSA,
+ Dsa = CKK_DSA,
+ Dh = CKK_DH,
+ Ecdsa = CKK_ECDSA,
+ Ec = CKK_EC,
+ X942Dh = CKK_X9_42_DH,
+ Kea = CKK_KEA,
+ GenericSecret = CKK_GENERIC_SECRET,
+ Rc2 = CKK_RC2,
+ Rc4 = CKK_RC4,
+ Des = CKK_DES,
+ Des2 = CKK_DES2,
+ Des3 = CKK_DES3,
+ Cast = CKK_CAST,
+ Cast3 = CKK_CAST3,
+ Cast5 = CKK_CAST5,
+ Cast128 = CKK_CAST128,
+ Rc5 = CKK_RC5,
+ Idea = CKK_IDEA,
+ Skipjack = CKK_SKIPJACK,
+ Baton = CKK_BATON,
+ Juniper = CKK_JUNIPER,
+ Cdmf = CKK_CDMF,
+ Aes = CKK_AES,
+ Blowfish = CKK_BLOWFISH,
+ Twofish = CKK_TWOFISH,
+ Securid = CKK_SECURID,
+ Hotp = CKK_HOTP,
+ Acti = CKK_ACTI,
+ Camellia = CKK_CAMELLIA,
+ Aria = CKK_ARIA,
+ Md5Hmac = CKK_MD5_HMAC,
+ Sha1Hmac = CKK_SHA_1_HMAC,
+ Ripemd128Hmac = CKK_RIPEMD128_HMAC,
+ Ripemd160Hmac = CKK_RIPEMD160_HMAC,
+ Sha256Hmac = CKK_SHA256_HMAC,
+ Sha384Hmac = CKK_SHA384_HMAC,
+ Sha512Hmac = CKK_SHA512_HMAC,
+ Sha224Hmac = CKK_SHA224_HMAC,
+ Seed = CKK_SEED,
+ Gostr3410 = CKK_GOSTR3410,
+ Gostr3411 = CKK_GOSTR3411,
+ Gost28147 = CKK_GOST28147,
+ VendorDefined = CKK_VENDOR_DEFINED,
+ };
+
+enum class MechanismType : CK_MECHANISM_TYPE
+ {
+ RsaPkcsKeyPairGen = CKM_RSA_PKCS_KEY_PAIR_GEN,
+ RsaPkcs = CKM_RSA_PKCS,
+ Rsa9796 = CKM_RSA_9796,
+ RsaX509 = CKM_RSA_X_509,
+ Md2RsaPkcs = CKM_MD2_RSA_PKCS,
+ Md5RsaPkcs = CKM_MD5_RSA_PKCS,
+ Sha1RsaPkcs = CKM_SHA1_RSA_PKCS,
+ Ripemd128RsaPkcs = CKM_RIPEMD128_RSA_PKCS,
+ Ripemd160RsaPkcs = CKM_RIPEMD160_RSA_PKCS,
+ RsaPkcsOaep = CKM_RSA_PKCS_OAEP,
+ RsaX931KeyPairGen = CKM_RSA_X9_31_KEY_PAIR_GEN,
+ RsaX931 = CKM_RSA_X9_31,
+ Sha1RsaX931 = CKM_SHA1_RSA_X9_31,
+ RsaPkcsPss = CKM_RSA_PKCS_PSS,
+ Sha1RsaPkcsPss = CKM_SHA1_RSA_PKCS_PSS,
+ DsaKeyPairGen = CKM_DSA_KEY_PAIR_GEN,
+ Dsa = CKM_DSA,
+ DsaSha1 = CKM_DSA_SHA1,
+ DsaSha224 = CKM_DSA_SHA224,
+ DsaSha256 = CKM_DSA_SHA256,
+ DsaSha384 = CKM_DSA_SHA384,
+ DsaSha512 = CKM_DSA_SHA512,
+ DhPkcsKeyPairGen = CKM_DH_PKCS_KEY_PAIR_GEN,
+ DhPkcsDerive = CKM_DH_PKCS_DERIVE,
+ X942DhKeyPairGen = CKM_X9_42_DH_KEY_PAIR_GEN,
+ X942DhDerive = CKM_X9_42_DH_DERIVE,
+ X942DhHybridDerive = CKM_X9_42_DH_HYBRID_DERIVE,
+ X942MqvDerive = CKM_X9_42_MQV_DERIVE,
+ Sha256RsaPkcs = CKM_SHA256_RSA_PKCS,
+ Sha384RsaPkcs = CKM_SHA384_RSA_PKCS,
+ Sha512RsaPkcs = CKM_SHA512_RSA_PKCS,
+ Sha256RsaPkcsPss = CKM_SHA256_RSA_PKCS_PSS,
+ Sha384RsaPkcsPss = CKM_SHA384_RSA_PKCS_PSS,
+ Sha512RsaPkcsPss = CKM_SHA512_RSA_PKCS_PSS,
+ Sha224RsaPkcs = CKM_SHA224_RSA_PKCS,
+ Sha224RsaPkcsPss = CKM_SHA224_RSA_PKCS_PSS,
+ Sha512224 = CKM_SHA512_224,
+ Sha512224Hmac = CKM_SHA512_224_HMAC,
+ Sha512224HmacGeneral = CKM_SHA512_224_HMAC_GENERAL,
+ Sha512224KeyDerivation = CKM_SHA512_224_KEY_DERIVATION,
+ Sha512256 = CKM_SHA512_256,
+ Sha512256Hmac = CKM_SHA512_256_HMAC,
+ Sha512256HmacGeneral = CKM_SHA512_256_HMAC_GENERAL,
+ Sha512256KeyDerivation = CKM_SHA512_256_KEY_DERIVATION,
+ Sha512T = CKM_SHA512_T,
+ Sha512THmac = CKM_SHA512_T_HMAC,
+ Sha512THmacGeneral = CKM_SHA512_T_HMAC_GENERAL,
+ Sha512TKeyDerivation = CKM_SHA512_T_KEY_DERIVATION,
+ Rc2KeyGen = CKM_RC2_KEY_GEN,
+ Rc2Ecb = CKM_RC2_ECB,
+ Rc2Cbc = CKM_RC2_CBC,
+ Rc2Mac = CKM_RC2_MAC,
+ Rc2MacGeneral = CKM_RC2_MAC_GENERAL,
+ Rc2CbcPad = CKM_RC2_CBC_PAD,
+ Rc4KeyGen = CKM_RC4_KEY_GEN,
+ Rc4 = CKM_RC4,
+ DesKeyGen = CKM_DES_KEY_GEN,
+ DesEcb = CKM_DES_ECB,
+ DesCbc = CKM_DES_CBC,
+ DesMac = CKM_DES_MAC,
+ DesMacGeneral = CKM_DES_MAC_GENERAL,
+ DesCbcPad = CKM_DES_CBC_PAD,
+ Des2KeyGen = CKM_DES2_KEY_GEN,
+ Des3KeyGen = CKM_DES3_KEY_GEN,
+ Des3Ecb = CKM_DES3_ECB,
+ Des3Cbc = CKM_DES3_CBC,
+ Des3Mac = CKM_DES3_MAC,
+ Des3MacGeneral = CKM_DES3_MAC_GENERAL,
+ Des3CbcPad = CKM_DES3_CBC_PAD,
+ Des3CmacGeneral = CKM_DES3_CMAC_GENERAL,
+ Des3Cmac = CKM_DES3_CMAC,
+ CdmfKeyGen = CKM_CDMF_KEY_GEN,
+ CdmfEcb = CKM_CDMF_ECB,
+ CdmfCbc = CKM_CDMF_CBC,
+ CdmfMac = CKM_CDMF_MAC,
+ CdmfMacGeneral = CKM_CDMF_MAC_GENERAL,
+ CdmfCbcPad = CKM_CDMF_CBC_PAD,
+ DesOfb64 = CKM_DES_OFB64,
+ DesOfb8 = CKM_DES_OFB8,
+ DesCfb64 = CKM_DES_CFB64,
+ DesCfb8 = CKM_DES_CFB8,
+ Md2 = CKM_MD2,
+ Md2Hmac = CKM_MD2_HMAC,
+ Md2HmacGeneral = CKM_MD2_HMAC_GENERAL,
+ Md5 = CKM_MD5,
+ Md5Hmac = CKM_MD5_HMAC,
+ Md5HmacGeneral = CKM_MD5_HMAC_GENERAL,
+ Sha1 = CKM_SHA_1,
+ Sha1Hmac = CKM_SHA_1_HMAC,
+ Sha1HmacGeneral = CKM_SHA_1_HMAC_GENERAL,
+ Ripemd128 = CKM_RIPEMD128,
+ Ripemd128Hmac = CKM_RIPEMD128_HMAC,
+ Ripemd128HmacGeneral = CKM_RIPEMD128_HMAC_GENERAL,
+ Ripemd160 = CKM_RIPEMD160,
+ Ripemd160Hmac = CKM_RIPEMD160_HMAC,
+ Ripemd160HmacGeneral = CKM_RIPEMD160_HMAC_GENERAL,
+ Sha256 = CKM_SHA256,
+ Sha256Hmac = CKM_SHA256_HMAC,
+ Sha256HmacGeneral = CKM_SHA256_HMAC_GENERAL,
+ Sha224 = CKM_SHA224,
+ Sha224Hmac = CKM_SHA224_HMAC,
+ Sha224HmacGeneral = CKM_SHA224_HMAC_GENERAL,
+ Sha384 = CKM_SHA384,
+ Sha384Hmac = CKM_SHA384_HMAC,
+ Sha384HmacGeneral = CKM_SHA384_HMAC_GENERAL,
+ Sha512 = CKM_SHA512,
+ Sha512Hmac = CKM_SHA512_HMAC,
+ Sha512HmacGeneral = CKM_SHA512_HMAC_GENERAL,
+ SecuridKeyGen = CKM_SECURID_KEY_GEN,
+ Securid = CKM_SECURID,
+ HotpKeyGen = CKM_HOTP_KEY_GEN,
+ Hotp = CKM_HOTP,
+ Acti = CKM_ACTI,
+ ActiKeyGen = CKM_ACTI_KEY_GEN,
+ CastKeyGen = CKM_CAST_KEY_GEN,
+ CastEcb = CKM_CAST_ECB,
+ CastCbc = CKM_CAST_CBC,
+ CastMac = CKM_CAST_MAC,
+ CastMacGeneral = CKM_CAST_MAC_GENERAL,
+ CastCbcPad = CKM_CAST_CBC_PAD,
+ Cast3KeyGen = CKM_CAST3_KEY_GEN,
+ Cast3Ecb = CKM_CAST3_ECB,
+ Cast3Cbc = CKM_CAST3_CBC,
+ Cast3Mac = CKM_CAST3_MAC,
+ Cast3MacGeneral = CKM_CAST3_MAC_GENERAL,
+ Cast3CbcPad = CKM_CAST3_CBC_PAD,
+ Cast5KeyGen = CKM_CAST5_KEY_GEN,
+ Cast128KeyGen = CKM_CAST128_KEY_GEN,
+ Cast5Ecb = CKM_CAST5_ECB,
+ Cast128Ecb = CKM_CAST128_ECB,
+ Cast5Cbc = CKM_CAST5_CBC,
+ Cast128Cbc = CKM_CAST128_CBC,
+ Cast5Mac = CKM_CAST5_MAC,
+ Cast128Mac = CKM_CAST128_MAC,
+ Cast5MacGeneral = CKM_CAST5_MAC_GENERAL,
+ Cast128MacGeneral = CKM_CAST128_MAC_GENERAL,
+ Cast5CbcPad = CKM_CAST5_CBC_PAD,
+ Cast128CbcPad = CKM_CAST128_CBC_PAD,
+ Rc5KeyGen = CKM_RC5_KEY_GEN,
+ Rc5Ecb = CKM_RC5_ECB,
+ Rc5Cbc = CKM_RC5_CBC,
+ Rc5Mac = CKM_RC5_MAC,
+ Rc5MacGeneral = CKM_RC5_MAC_GENERAL,
+ Rc5CbcPad = CKM_RC5_CBC_PAD,
+ IdeaKeyGen = CKM_IDEA_KEY_GEN,
+ IdeaEcb = CKM_IDEA_ECB,
+ IdeaCbc = CKM_IDEA_CBC,
+ IdeaMac = CKM_IDEA_MAC,
+ IdeaMacGeneral = CKM_IDEA_MAC_GENERAL,
+ IdeaCbcPad = CKM_IDEA_CBC_PAD,
+ GenericSecretKeyGen = CKM_GENERIC_SECRET_KEY_GEN,
+ ConcatenateBaseAndKey = CKM_CONCATENATE_BASE_AND_KEY,
+ ConcatenateBaseAndData = CKM_CONCATENATE_BASE_AND_DATA,
+ ConcatenateDataAndBase = CKM_CONCATENATE_DATA_AND_BASE,
+ XorBaseAndData = CKM_XOR_BASE_AND_DATA,
+ ExtractKeyFromKey = CKM_EXTRACT_KEY_FROM_KEY,
+ Ssl3PreMasterKeyGen = CKM_SSL3_PRE_MASTER_KEY_GEN,
+ Ssl3MasterKeyDerive = CKM_SSL3_MASTER_KEY_DERIVE,
+ Ssl3KeyAndMacDerive = CKM_SSL3_KEY_AND_MAC_DERIVE,
+ Ssl3MasterKeyDeriveDh = CKM_SSL3_MASTER_KEY_DERIVE_DH,
+ TlsPreMasterKeyGen = CKM_TLS_PRE_MASTER_KEY_GEN,
+ TlsMasterKeyDerive = CKM_TLS_MASTER_KEY_DERIVE,
+ TlsKeyAndMacDerive = CKM_TLS_KEY_AND_MAC_DERIVE,
+ TlsMasterKeyDeriveDh = CKM_TLS_MASTER_KEY_DERIVE_DH,
+ TlsPrf = CKM_TLS_PRF,
+ Ssl3Md5Mac = CKM_SSL3_MD5_MAC,
+ Ssl3Sha1Mac = CKM_SSL3_SHA1_MAC,
+ Md5KeyDerivation = CKM_MD5_KEY_DERIVATION,
+ Md2KeyDerivation = CKM_MD2_KEY_DERIVATION,
+ Sha1KeyDerivation = CKM_SHA1_KEY_DERIVATION,
+ Sha256KeyDerivation = CKM_SHA256_KEY_DERIVATION,
+ Sha384KeyDerivation = CKM_SHA384_KEY_DERIVATION,
+ Sha512KeyDerivation = CKM_SHA512_KEY_DERIVATION,
+ Sha224KeyDerivation = CKM_SHA224_KEY_DERIVATION,
+ PbeMd2DesCbc = CKM_PBE_MD2_DES_CBC,
+ PbeMd5DesCbc = CKM_PBE_MD5_DES_CBC,
+ PbeMd5CastCbc = CKM_PBE_MD5_CAST_CBC,
+ PbeMd5Cast3Cbc = CKM_PBE_MD5_CAST3_CBC,
+ PbeMd5Cast5Cbc = CKM_PBE_MD5_CAST5_CBC,
+ PbeMd5Cast128Cbc = CKM_PBE_MD5_CAST128_CBC,
+ PbeSha1Cast5Cbc = CKM_PBE_SHA1_CAST5_CBC,
+ PbeSha1Cast128Cbc = CKM_PBE_SHA1_CAST128_CBC,
+ PbeSha1Rc4128 = CKM_PBE_SHA1_RC4_128,
+ PbeSha1Rc440 = CKM_PBE_SHA1_RC4_40,
+ PbeSha1Des3EdeCbc = CKM_PBE_SHA1_DES3_EDE_CBC,
+ PbeSha1Des2EdeCbc = CKM_PBE_SHA1_DES2_EDE_CBC,
+ PbeSha1Rc2128Cbc = CKM_PBE_SHA1_RC2_128_CBC,
+ PbeSha1Rc240Cbc = CKM_PBE_SHA1_RC2_40_CBC,
+ Pkcs5Pbkd2 = CKM_PKCS5_PBKD2,
+ PbaSha1WithSha1Hmac = CKM_PBA_SHA1_WITH_SHA1_HMAC,
+ WtlsPreMasterKeyGen = CKM_WTLS_PRE_MASTER_KEY_GEN,
+ WtlsMasterKeyDerive = CKM_WTLS_MASTER_KEY_DERIVE,
+ WtlsMasterKeyDeriveDhEcc = CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC,
+ WtlsPrf = CKM_WTLS_PRF,
+ WtlsServerKeyAndMacDerive = CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE,
+ WtlsClientKeyAndMacDerive = CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE,
+ Tls10MacServer = CKM_TLS10_MAC_SERVER,
+ Tls10MacClient = CKM_TLS10_MAC_CLIENT,
+ Tls12Mac = CKM_TLS12_MAC,
+ Tls12Kdf = CKM_TLS12_KDF,
+ Tls12MasterKeyDerive = CKM_TLS12_MASTER_KEY_DERIVE,
+ Tls12KeyAndMacDerive = CKM_TLS12_KEY_AND_MAC_DERIVE,
+ Tls12MasterKeyDeriveDh = CKM_TLS12_MASTER_KEY_DERIVE_DH,
+ Tls12KeySafeDerive = CKM_TLS12_KEY_SAFE_DERIVE,
+ TlsMac = CKM_TLS_MAC,
+ TlsKdf = CKM_TLS_KDF,
+ KeyWrapLynks = CKM_KEY_WRAP_LYNKS,
+ KeyWrapSetOaep = CKM_KEY_WRAP_SET_OAEP,
+ CmsSig = CKM_CMS_SIG,
+ KipDerive = CKM_KIP_DERIVE,
+ KipWrap = CKM_KIP_WRAP,
+ KipMac = CKM_KIP_MAC,
+ CamelliaKeyGen = CKM_CAMELLIA_KEY_GEN,
+ CamelliaEcb = CKM_CAMELLIA_ECB,
+ CamelliaCbc = CKM_CAMELLIA_CBC,
+ CamelliaMac = CKM_CAMELLIA_MAC,
+ CamelliaMacGeneral = CKM_CAMELLIA_MAC_GENERAL,
+ CamelliaCbcPad = CKM_CAMELLIA_CBC_PAD,
+ CamelliaEcbEncryptData = CKM_CAMELLIA_ECB_ENCRYPT_DATA,
+ CamelliaCbcEncryptData = CKM_CAMELLIA_CBC_ENCRYPT_DATA,
+ CamelliaCtr = CKM_CAMELLIA_CTR,
+ AriaKeyGen = CKM_ARIA_KEY_GEN,
+ AriaEcb = CKM_ARIA_ECB,
+ AriaCbc = CKM_ARIA_CBC,
+ AriaMac = CKM_ARIA_MAC,
+ AriaMacGeneral = CKM_ARIA_MAC_GENERAL,
+ AriaCbcPad = CKM_ARIA_CBC_PAD,
+ AriaEcbEncryptData = CKM_ARIA_ECB_ENCRYPT_DATA,
+ AriaCbcEncryptData = CKM_ARIA_CBC_ENCRYPT_DATA,
+ SeedKeyGen = CKM_SEED_KEY_GEN,
+ SeedEcb = CKM_SEED_ECB,
+ SeedCbc = CKM_SEED_CBC,
+ SeedMac = CKM_SEED_MAC,
+ SeedMacGeneral = CKM_SEED_MAC_GENERAL,
+ SeedCbcPad = CKM_SEED_CBC_PAD,
+ SeedEcbEncryptData = CKM_SEED_ECB_ENCRYPT_DATA,
+ SeedCbcEncryptData = CKM_SEED_CBC_ENCRYPT_DATA,
+ SkipjackKeyGen = CKM_SKIPJACK_KEY_GEN,
+ SkipjackEcb64 = CKM_SKIPJACK_ECB64,
+ SkipjackCbc64 = CKM_SKIPJACK_CBC64,
+ SkipjackOfb64 = CKM_SKIPJACK_OFB64,
+ SkipjackCfb64 = CKM_SKIPJACK_CFB64,
+ SkipjackCfb32 = CKM_SKIPJACK_CFB32,
+ SkipjackCfb16 = CKM_SKIPJACK_CFB16,
+ SkipjackCfb8 = CKM_SKIPJACK_CFB8,
+ SkipjackWrap = CKM_SKIPJACK_WRAP,
+ SkipjackPrivateWrap = CKM_SKIPJACK_PRIVATE_WRAP,
+ SkipjackRelayx = CKM_SKIPJACK_RELAYX,
+ KeaKeyPairGen = CKM_KEA_KEY_PAIR_GEN,
+ KeaKeyDerive = CKM_KEA_KEY_DERIVE,
+ KeaDerive = CKM_KEA_DERIVE,
+ FortezzaTimestamp = CKM_FORTEZZA_TIMESTAMP,
+ BatonKeyGen = CKM_BATON_KEY_GEN,
+ BatonEcb128 = CKM_BATON_ECB128,
+ BatonEcb96 = CKM_BATON_ECB96,
+ BatonCbc128 = CKM_BATON_CBC128,
+ BatonCounter = CKM_BATON_COUNTER,
+ BatonShuffle = CKM_BATON_SHUFFLE,
+ BatonWrap = CKM_BATON_WRAP,
+ EcdsaKeyPairGen = CKM_ECDSA_KEY_PAIR_GEN,
+ EcKeyPairGen = CKM_EC_KEY_PAIR_GEN,
+ Ecdsa = CKM_ECDSA,
+ EcdsaSha1 = CKM_ECDSA_SHA1,
+ EcdsaSha224 = CKM_ECDSA_SHA224,
+ EcdsaSha256 = CKM_ECDSA_SHA256,
+ EcdsaSha384 = CKM_ECDSA_SHA384,
+ EcdsaSha512 = CKM_ECDSA_SHA512,
+ Ecdh1Derive = CKM_ECDH1_DERIVE,
+ Ecdh1CofactorDerive = CKM_ECDH1_COFACTOR_DERIVE,
+ EcmqvDerive = CKM_ECMQV_DERIVE,
+ EcdhAesKeyWrap = CKM_ECDH_AES_KEY_WRAP,
+ RsaAesKeyWrap = CKM_RSA_AES_KEY_WRAP,
+ JuniperKeyGen = CKM_JUNIPER_KEY_GEN,
+ JuniperEcb128 = CKM_JUNIPER_ECB128,
+ JuniperCbc128 = CKM_JUNIPER_CBC128,
+ JuniperCounter = CKM_JUNIPER_COUNTER,
+ JuniperShuffle = CKM_JUNIPER_SHUFFLE,
+ JuniperWrap = CKM_JUNIPER_WRAP,
+ Fasthash = CKM_FASTHASH,
+ AesKeyGen = CKM_AES_KEY_GEN,
+ AesEcb = CKM_AES_ECB,
+ AesCbc = CKM_AES_CBC,
+ AesMac = CKM_AES_MAC,
+ AesMacGeneral = CKM_AES_MAC_GENERAL,
+ AesCbcPad = CKM_AES_CBC_PAD,
+ AesCtr = CKM_AES_CTR,
+ AesGcm = CKM_AES_GCM,
+ AesCcm = CKM_AES_CCM,
+ AesCts = CKM_AES_CTS,
+ AesCmac = CKM_AES_CMAC,
+ AesCmacGeneral = CKM_AES_CMAC_GENERAL,
+ AesXcbcMac = CKM_AES_XCBC_MAC,
+ AesXcbcMac96 = CKM_AES_XCBC_MAC_96,
+ AesGmac = CKM_AES_GMAC,
+ BlowfishKeyGen = CKM_BLOWFISH_KEY_GEN,
+ BlowfishCbc = CKM_BLOWFISH_CBC,
+ TwofishKeyGen = CKM_TWOFISH_KEY_GEN,
+ TwofishCbc = CKM_TWOFISH_CBC,
+ BlowfishCbcPad = CKM_BLOWFISH_CBC_PAD,
+ TwofishCbcPad = CKM_TWOFISH_CBC_PAD,
+ DesEcbEncryptData = CKM_DES_ECB_ENCRYPT_DATA,
+ DesCbcEncryptData = CKM_DES_CBC_ENCRYPT_DATA,
+ Des3EcbEncryptData = CKM_DES3_ECB_ENCRYPT_DATA,
+ Des3CbcEncryptData = CKM_DES3_CBC_ENCRYPT_DATA,
+ AesEcbEncryptData = CKM_AES_ECB_ENCRYPT_DATA,
+ AesCbcEncryptData = CKM_AES_CBC_ENCRYPT_DATA,
+ Gostr3410KeyPairGen = CKM_GOSTR3410_KEY_PAIR_GEN,
+ Gostr3410 = CKM_GOSTR3410,
+ Gostr3410WithGostr3411 = CKM_GOSTR3410_WITH_GOSTR3411,
+ Gostr3410KeyWrap = CKM_GOSTR3410_KEY_WRAP,
+ Gostr3410Derive = CKM_GOSTR3410_DERIVE,
+ Gostr3411 = CKM_GOSTR3411,
+ Gostr3411Hmac = CKM_GOSTR3411_HMAC,
+ Gost28147KeyGen = CKM_GOST28147_KEY_GEN,
+ Gost28147Ecb = CKM_GOST28147_ECB,
+ Gost28147 = CKM_GOST28147,
+ Gost28147Mac = CKM_GOST28147_MAC,
+ Gost28147KeyWrap = CKM_GOST28147_KEY_WRAP,
+ DsaParameterGen = CKM_DSA_PARAMETER_GEN,
+ DhPkcsParameterGen = CKM_DH_PKCS_PARAMETER_GEN,
+ X942DhParameterGen = CKM_X9_42_DH_PARAMETER_GEN,
+ DsaProbablisticParameterGen = CKM_DSA_PROBABLISTIC_PARAMETER_GEN,
+ DsaShaweTaylorParameterGen = CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN,
+ AesOfb = CKM_AES_OFB,
+ AesCfb64 = CKM_AES_CFB64,
+ AesCfb8 = CKM_AES_CFB8,
+ AesCfb128 = CKM_AES_CFB128,
+ AesCfb1 = CKM_AES_CFB1,
+ AesKeyWrap = CKM_AES_KEY_WRAP,
+ AesKeyWrapPad = CKM_AES_KEY_WRAP_PAD,
+ RsaPkcsTpm11 = CKM_RSA_PKCS_TPM_1_1,
+ RsaPkcsOaepTpm11 = CKM_RSA_PKCS_OAEP_TPM_1_1,
+ VendorDefined = CKM_VENDOR_DEFINED,
+ };
+
+enum class Notification : CK_NOTIFICATION
+ {
+ Surrender = CKN_SURRENDER,
+ OtpChanged = CKN_OTP_CHANGED,
+ };
+
+enum class ObjectClass : CK_OBJECT_CLASS
+ {
+ Data = CKO_DATA,
+ Certificate = CKO_CERTIFICATE,
+ PublicKey = CKO_PUBLIC_KEY,
+ PrivateKey = CKO_PRIVATE_KEY,
+ SecretKey = CKO_SECRET_KEY,
+ HwFeature = CKO_HW_FEATURE,
+ DomainParameters = CKO_DOMAIN_PARAMETERS,
+ Mechanism = CKO_MECHANISM,
+ OtpKey = CKO_OTP_KEY,
+ VendorDefined = CKO_VENDOR_DEFINED,
+ };
+
+enum class PseudoRandom : CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE
+ {
+ Pkcs5Pbkd2HmacSha1 = CKP_PKCS5_PBKD2_HMAC_SHA1,
+ Pkcs5Pbkd2HmacGostr3411 = CKP_PKCS5_PBKD2_HMAC_GOSTR3411,
+ Pkcs5Pbkd2HmacSha224 = CKP_PKCS5_PBKD2_HMAC_SHA224,
+ Pkcs5Pbkd2HmacSha256 = CKP_PKCS5_PBKD2_HMAC_SHA256,
+ Pkcs5Pbkd2HmacSha384 = CKP_PKCS5_PBKD2_HMAC_SHA384,
+ Pkcs5Pbkd2HmacSha512 = CKP_PKCS5_PBKD2_HMAC_SHA512,
+ Pkcs5Pbkd2HmacSha512224 = CKP_PKCS5_PBKD2_HMAC_SHA512_224,
+ Pkcs5Pbkd2HmacSha512256 = CKP_PKCS5_PBKD2_HMAC_SHA512_256,
+ };
+
+enum class SessionState : CK_STATE
+ {
+ RoPublicSession = CKS_RO_PUBLIC_SESSION,
+ RoUserFunctions = CKS_RO_USER_FUNCTIONS,
+ RwPublicSession = CKS_RW_PUBLIC_SESSION,
+ RwUserFunctions = CKS_RW_USER_FUNCTIONS,
+ RwSoFunctions = CKS_RW_SO_FUNCTIONS,
+ };
+
+enum class ReturnValue : CK_RV
+ {
+ OK = CKR_OK,
+ Cancel = CKR_CANCEL,
+ HostMemory = CKR_HOST_MEMORY,
+ SlotIdInvalid = CKR_SLOT_ID_INVALID,
+ GeneralError = CKR_GENERAL_ERROR,
+ FunctionFailed = CKR_FUNCTION_FAILED,
+ ArgumentsBad = CKR_ARGUMENTS_BAD,
+ NoEvent = CKR_NO_EVENT,
+ NeedToCreateThreads = CKR_NEED_TO_CREATE_THREADS,
+ CantLock = CKR_CANT_LOCK,
+ AttributeReadOnly = CKR_ATTRIBUTE_READ_ONLY,
+ AttributeSensitive = CKR_ATTRIBUTE_SENSITIVE,
+ AttributeTypeInvalid = CKR_ATTRIBUTE_TYPE_INVALID,
+ AttributeValueInvalid = CKR_ATTRIBUTE_VALUE_INVALID,
+ ActionProhibited = CKR_ACTION_PROHIBITED,
+ DataInvalid = CKR_DATA_INVALID,
+ DataLenRange = CKR_DATA_LEN_RANGE,
+ DeviceError = CKR_DEVICE_ERROR,
+ DeviceMemory = CKR_DEVICE_MEMORY,
+ DeviceRemoved = CKR_DEVICE_REMOVED,
+ EncryptedDataInvalid = CKR_ENCRYPTED_DATA_INVALID,
+ EncryptedDataLenRange = CKR_ENCRYPTED_DATA_LEN_RANGE,
+ FunctionCanceled = CKR_FUNCTION_CANCELED,
+ FunctionNotParallel = CKR_FUNCTION_NOT_PARALLEL,
+ FunctionNotSupported = CKR_FUNCTION_NOT_SUPPORTED,
+ KeyHandleInvalid = CKR_KEY_HANDLE_INVALID,
+ KeySizeRange = CKR_KEY_SIZE_RANGE,
+ KeyTypeInconsistent = CKR_KEY_TYPE_INCONSISTENT,
+ KeyNotNeeded = CKR_KEY_NOT_NEEDED,
+ KeyChanged = CKR_KEY_CHANGED,
+ KeyNeeded = CKR_KEY_NEEDED,
+ KeyIndigestible = CKR_KEY_INDIGESTIBLE,
+ KeyFunctionNotPermitted = CKR_KEY_FUNCTION_NOT_PERMITTED,
+ KeyNotWrappable = CKR_KEY_NOT_WRAPPABLE,
+ KeyUnextractable = CKR_KEY_UNEXTRACTABLE,
+ MechanismInvalid = CKR_MECHANISM_INVALID,
+ MechanismParamInvalid = CKR_MECHANISM_PARAM_INVALID,
+ ObjectHandleInvalid = CKR_OBJECT_HANDLE_INVALID,
+ OperationActive = CKR_OPERATION_ACTIVE,
+ OperationNotInitialized = CKR_OPERATION_NOT_INITIALIZED,
+ PinIncorrect = CKR_PIN_INCORRECT,
+ PinInvalid = CKR_PIN_INVALID,
+ PinLenRange = CKR_PIN_LEN_RANGE,
+ PinExpired = CKR_PIN_EXPIRED,
+ PinLocked = CKR_PIN_LOCKED,
+ SessionClosed = CKR_SESSION_CLOSED,
+ SessionCount = CKR_SESSION_COUNT,
+ SessionHandleInvalid = CKR_SESSION_HANDLE_INVALID,
+ SessionParallelNotSupported = CKR_SESSION_PARALLEL_NOT_SUPPORTED,
+ SessionReadOnly = CKR_SESSION_READ_ONLY,
+ SessionExists = CKR_SESSION_EXISTS,
+ SessionReadOnlyExists = CKR_SESSION_READ_ONLY_EXISTS,
+ SessionReadWriteSoExists = CKR_SESSION_READ_WRITE_SO_EXISTS,
+ SignatureInvalid = CKR_SIGNATURE_INVALID,
+ SignatureLenRange = CKR_SIGNATURE_LEN_RANGE,
+ TemplateIncomplete = CKR_TEMPLATE_INCOMPLETE,
+ TemplateInconsistent = CKR_TEMPLATE_INCONSISTENT,
+ TokenNotPresent = CKR_TOKEN_NOT_PRESENT,
+ TokenNotRecognized = CKR_TOKEN_NOT_RECOGNIZED,
+ TokenWriteProtected = CKR_TOKEN_WRITE_PROTECTED,
+ UnwrappingKeyHandleInvalid = CKR_UNWRAPPING_KEY_HANDLE_INVALID,
+ UnwrappingKeySizeRange = CKR_UNWRAPPING_KEY_SIZE_RANGE,
+ UnwrappingKeyTypeInconsistent = CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT,
+ UserAlreadyLoggedIn = CKR_USER_ALREADY_LOGGED_IN,
+ UserNotLoggedIn = CKR_USER_NOT_LOGGED_IN,
+ UserPinNotInitialized = CKR_USER_PIN_NOT_INITIALIZED,
+ UserTypeInvalid = CKR_USER_TYPE_INVALID,
+ UserAnotherAlreadyLoggedIn = CKR_USER_ANOTHER_ALREADY_LOGGED_IN,
+ UserTooManyTypes = CKR_USER_TOO_MANY_TYPES,
+ WrappedKeyInvalid = CKR_WRAPPED_KEY_INVALID,
+ WrappedKeyLenRange = CKR_WRAPPED_KEY_LEN_RANGE,
+ WrappingKeyHandleInvalid = CKR_WRAPPING_KEY_HANDLE_INVALID,
+ WrappingKeySizeRange = CKR_WRAPPING_KEY_SIZE_RANGE,
+ WrappingKeyTypeInconsistent = CKR_WRAPPING_KEY_TYPE_INCONSISTENT,
+ RandomSeedNotSupported = CKR_RANDOM_SEED_NOT_SUPPORTED,
+ RandomNoRng = CKR_RANDOM_NO_RNG,
+ DomainParamsInvalid = CKR_DOMAIN_PARAMS_INVALID,
+ CurveNotSupported = CKR_CURVE_NOT_SUPPORTED,
+ BufferTooSmall = CKR_BUFFER_TOO_SMALL,
+ SavedStateInvalid = CKR_SAVED_STATE_INVALID,
+ InformationSensitive = CKR_INFORMATION_SENSITIVE,
+ StateUnsaveable = CKR_STATE_UNSAVEABLE,
+ CryptokiNotInitialized = CKR_CRYPTOKI_NOT_INITIALIZED,
+ CryptokiAlreadyInitialized = CKR_CRYPTOKI_ALREADY_INITIALIZED,
+ MutexBad = CKR_MUTEX_BAD,
+ MutexNotLocked = CKR_MUTEX_NOT_LOCKED,
+ NewPinMode = CKR_NEW_PIN_MODE,
+ NextOtp = CKR_NEXT_OTP,
+ ExceededMaxIterations = CKR_EXCEEDED_MAX_ITERATIONS,
+ FipsSelfTestFailed = CKR_FIPS_SELF_TEST_FAILED,
+ LibraryLoadFailed = CKR_LIBRARY_LOAD_FAILED,
+ PinTooWeak = CKR_PIN_TOO_WEAK,
+ PublicKeyInvalid = CKR_PUBLIC_KEY_INVALID,
+ FunctionRejected = CKR_FUNCTION_REJECTED,
+ VendorDefined = CKR_VENDOR_DEFINED,
+ };
+
+enum class UserType : CK_USER_TYPE
+ {
+ SO = CKU_SO,
+ User = CKU_USER,
+ ContextSpecific = CKU_CONTEXT_SPECIFIC,
+ };
+
+enum class PublicPointEncoding : uint32_t
+ {
+ Raw,
+ Der
+ };
+
+using FunctionListPtr = CK_FUNCTION_LIST_PTR;
+using VoidPtr = CK_VOID_PTR;
+using C_InitializeArgs = CK_C_INITIALIZE_ARGS;
+using CreateMutex = CK_CREATEMUTEX;
+using DestroyMutex = CK_DESTROYMUTEX;
+using LockMutex = CK_LOCKMUTEX;
+using UnlockMutex = CK_UNLOCKMUTEX;
+using Flags = CK_FLAGS;
+using Info = CK_INFO;
+using Bbool = CK_BBOOL;
+using SlotId = CK_SLOT_ID;
+using Ulong = CK_ULONG;
+using SlotInfo = CK_SLOT_INFO;
+using TokenInfo = CK_TOKEN_INFO;
+using Mechanism = CK_MECHANISM;
+using MechanismInfo = CK_MECHANISM_INFO;
+using Utf8Char = CK_UTF8CHAR;
+using Notify = CK_NOTIFY;
+using SessionHandle = CK_SESSION_HANDLE;
+using SessionInfo = CK_SESSION_INFO;
+using Attribute = CK_ATTRIBUTE;
+using ObjectHandle = CK_OBJECT_HANDLE;
+using Byte = CK_BYTE;
+using RsaPkcsOaepParams = CK_RSA_PKCS_OAEP_PARAMS;
+using RsaPkcsPssParams = CK_RSA_PKCS_PSS_PARAMS;
+using Ecdh1DeriveParams = CK_ECDH1_DERIVE_PARAMS;
+using Date = CK_DATE;
+
+BOTAN_DLL extern ReturnValue* ThrowException;
+
+const Bbool True = CK_TRUE;
+const Bbool False = CK_FALSE;
+
+inline Flags flags(Flag flags)
+ {
+ return static_cast<Flags>(flags);
+ }
+
+class Slot;
+
+/**
+* Initializes a token
+* @param slot The slot with the attached token that should be initialized
+* @param label The token label
+* @param so_pin PIN of the security officer. Will be set if the token is uninitialized other this has to be the current SO_PIN
+* @param pin The user PIN that will be set
+*/
+BOTAN_DLL void initialize_token(Slot& slot, const std::string& label, const secure_string& so_pin,
+ const secure_string& pin);
+
+/**
+* Change PIN with old PIN to new PIN
+* @param slot The slot with the attached token
+* @param old_pin The old user PIN
+* @param new_pin The new user PIN
+*/
+
+BOTAN_DLL void change_pin(Slot& slot, const secure_string& old_pin, const secure_string& new_pin);
+
+/**
+* Change SO_PIN with old SO_PIN to new SO_PIN
+* @param slot The slot with the attached token
+* @param old_so_pin The old SO_PIN
+* @param new_so_pin The new SO_PIN
+*/
+BOTAN_DLL void change_so_pin(Slot& slot, const secure_string& old_so_pin, const secure_string& new_so_pin);
+
+/**
+* Sets user PIN with SO_PIN
+* @param slot The slot with the attached token
+* @param so_pin PIN of the security officer
+* @param pin The user PIN that should be set
+*/
+BOTAN_DLL void set_pin(Slot& slot, const secure_string& so_pin, const secure_string& pin);
+
+/// Provides access to all PKCS#11 functions
+class BOTAN_DLL LowLevel
+ {
+ public:
+
+ /// @param ptr the functon list pointer to use. Can be retrieved via `LowLevel::C_GetFunctionList`
+ explicit LowLevel(FunctionListPtr ptr);
+
+ ~LowLevel() BOTAN_NOEXCEPT;
+
+ /****************************** General purpose functions ******************************/
+
+ /**
+ * C_Initialize initializes the Cryptoki library.
+ * @param init_args if this is not nullptr, it gets cast to (`C_InitializeArgs`) and dereferenced
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CantLock \li CryptokiAlreadyInitialized
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li NeedToCreateThreads \li OK
+ * @return true on success, false otherwise
+ */
+ bool C_Initialize(VoidPtr init_args,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Finalize indicates that an application is done with the Cryptoki library.
+ * @param reserved reserved. Should be nullptr
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * @return true on success, false otherwise
+ */
+ bool C_Finalize(VoidPtr reserved,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetInfo returns general information about Cryptoki.
+ * @param info_ptr location that receives information
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * @return true on success, false otherwise
+ */
+ bool C_GetInfo(Info* info_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetFunctionList returns the function list.
+ * @param pkcs11_module The PKCS#11 module
+ * @param function_list_ptr_ptr receives pointer to function list
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK
+ * @return true on success, false otherwise
+ */
+ static bool C_GetFunctionList(Dynamically_Loaded_Library& pkcs11_module, FunctionListPtr* function_list_ptr_ptr,
+ ReturnValue* return_value = ThrowException);
+
+ /****************************** Slot and token management functions ******************************/
+
+ /**
+ * C_GetSlotList obtains a list of slots in the system.
+ * @param token_present only slots with tokens
+ * @param slot_list_ptr receives array of slot IDs
+ * @param count_ptr receives number of slots
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK
+ * @return true on success, false otherwise
+ */
+ bool C_GetSlotList(Bbool token_present,
+ SlotId* slot_list_ptr,
+ Ulong* count_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetSlotList obtains a list of slots in the system.
+ * @param token_present only slots with tokens
+ * @param slot_ids receives vector of slot IDs
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK
+ * @return true on success, false otherwise
+ */
+ bool C_GetSlotList(bool token_present,
+ std::vector<SlotId>& slot_ids,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetSlotInfo obtains information about a particular slot in the system.
+ * @param slot_id the ID of the slot
+ * @param info_ptr receives the slot information
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li SlotIdInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_GetSlotInfo(SlotId slot_id,
+ SlotInfo* info_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetTokenInfo obtains information about a particular token in the system.
+ * @param slot_id ID of the token's slot
+ * @param info_ptr receives the token information
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li SlotIdInvalid
+ * \li TokenNotPresent \li TokenNotRecognized \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_GetTokenInfo(SlotId slot_id,
+ TokenInfo* info_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_WaitForSlotEvent waits for a slot event (token insertion, removal, etc.) to occur.
+ * @param flags blocking/nonblocking flag
+ * @param slot_ptr location that receives the slot ID
+ * @param reserved reserved. Should be NULL_PTR
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li FunctionFailed
+ * \li GeneralError \li HostMemory \li NoEvent
+ * \li OK
+ * @return true on success, false otherwise
+ */
+ bool C_WaitForSlotEvent(Flags flags,
+ SlotId* slot_ptr,
+ VoidPtr reserved,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetMechanismList obtains a list of mechanism types supported by a token.
+ * @param slot_id ID of token's slot
+ * @param mechanism_list_ptr gets mech. array
+ * @param count_ptr gets # of mechs.
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li BufferTooSmall \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li SlotIdInvalid \li TokenNotPresent \li TokenNotRecognized
+ * \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_GetMechanismList(SlotId slot_id,
+ MechanismType* mechanism_list_ptr,
+ Ulong* count_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetMechanismList obtains a list of mechanism types supported by a token.
+ * @param slot_id ID of token's slot
+ * @param mechanisms receives vector of supported mechanisms
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li BufferTooSmall \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li SlotIdInvalid \li TokenNotPresent \li TokenNotRecognized
+ * \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_GetMechanismList(SlotId slot_id,
+ std::vector<MechanismType>& mechanisms,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetMechanismInfo obtains information about a particular mechanism possibly supported by a token.
+ * @param slot_id ID of the token's slot
+ * @param type type of mechanism
+ * @param info_ptr receives mechanism info
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li MechanismInvalid \li OK
+ * \li SlotIdInvalid \li TokenNotPresent \li TokenNotRecognized
+ * \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_GetMechanismInfo(SlotId slot_id,
+ MechanismType type,
+ MechanismInfo* info_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_InitToken initializes a token.
+ * @param slot_id ID of the token's slot
+ * @param so_pin_ptr the SO's initial PIN
+ * @param so_pin_len length in bytes of the SO_PIN
+ * @param label_ptr 32-byte token label (blank padded)
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li PinIncorrect \li PinLocked \li SessionExists
+ * \li SlotIdInvalid \li TokenNotPresent \li TokenNotRecognized
+ * \li TokenWriteProtected \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_InitToken(SlotId slot_id,
+ Utf8Char* so_pin_ptr,
+ Ulong so_pin_len,
+ Utf8Char* label_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_InitToken initializes a token.
+ * @param slot_id ID of the token's slot
+ * @param so_pin the SO's initial PIN
+ * @param label token label (at max 32 bytes long)
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li PinIncorrect \li PinLocked \li SessionExists
+ * \li SlotIdInvalid \li TokenNotPresent \li TokenNotRecognized
+ * \li TokenWriteProtected \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_InitToken(SlotId slot_id,
+ const std::vector<byte, TAlloc>& so_pin,
+ const std::string& label,
+ ReturnValue* return_value = ThrowException) const
+ {
+ std::string padded_label = label;
+ if(label.size() < 32)
+ {
+ padded_label.insert(padded_label.end(), 32 - label.size(), ' ');
+ }
+
+ return C_InitToken(slot_id, reinterpret_cast< Utf8Char* >(const_cast< byte* >(so_pin.data())),
+ so_pin.size(), reinterpret_cast< Utf8Char* >(const_cast< char* >(padded_label.c_str())), return_value);
+ }
+
+ /**
+ * C_InitPIN initializes the normal user's PIN.
+ * @param session the session's handle
+ * @param pin_ptr the normal user's PIN
+ * @param pin_len length in bytes of the PIN
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li PinInvalid \li PinLenRange \li SessionClosed
+ * \li SessionReadOnly \li SessionHandleInvalid \li TokenWriteProtected
+ * \li UserNotLoggedIn \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_InitPIN(SessionHandle session,
+ Utf8Char* pin_ptr,
+ Ulong pin_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_InitPIN initializes the normal user's PIN.
+ * @param session the session's handle
+ * @param pin the normal user's PIN
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li PinInvalid \li PinLenRange \li SessionClosed
+ * \li SessionReadOnly \li SessionHandleInvalid \li TokenWriteProtected
+ * \li UserNotLoggedIn \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_InitPIN(SessionHandle session,
+ const std::vector<byte, TAlloc>& pin,
+ ReturnValue* return_value = ThrowException) const
+ {
+ return C_InitPIN(session, reinterpret_cast< Utf8Char* >(const_cast< byte* >(pin.data())), pin.size(), return_value);
+ }
+
+ /**
+ * C_SetPIN modifies the PIN of the user who is logged in.
+ * @param session the session's handle
+ * @param old_pin_ptr the old PIN
+ * @param old_len length of the old PIN
+ * @param new_pin_ptr the new PIN
+ * @param new_len length of the new PIN
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li PinIncorrect \li PinInvalid \li PinLenRange
+ * \li PinLocked \li SessionClosed \li SessionHandleInvalid
+ * \li SessionReadOnly \li TokenWriteProtected \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_SetPIN(SessionHandle session,
+ Utf8Char* old_pin_ptr,
+ Ulong old_len,
+ Utf8Char* new_pin_ptr,
+ Ulong new_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_SetPIN modifies the PIN of the user who is logged in.
+ * @param session the session's handle
+ * @param old_pin the old PIN
+ * @param new_pin the new PIN
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li PinIncorrect \li PinInvalid \li PinLenRange
+ * \li PinLocked \li SessionClosed \li SessionHandleInvalid
+ * \li SessionReadOnly \li TokenWriteProtected \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_SetPIN(SessionHandle session,
+ const std::vector<byte, TAlloc>& old_pin,
+ const std::vector<byte, TAlloc>& new_pin,
+ ReturnValue* return_value = ThrowException) const
+ {
+ return C_SetPIN(session,
+ reinterpret_cast< Utf8Char* >(const_cast< byte* >(old_pin.data())), old_pin.size(),
+ reinterpret_cast< Utf8Char* >(const_cast< byte* >(new_pin.data())), new_pin.size(),
+ return_value);
+ }
+
+
+ /****************************** Session management ******************************/
+
+ /**
+ * C_OpenSession opens a session between an application and a token.
+ * @param slot_id the slot's ID
+ * @param flags from CK_SESSION_INFO
+ * @param application passed to callback
+ * @param notify callback function
+ * @param session_ptr gets session handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li SessionCount
+ * \li SessionParallelNotSupported \li SessionReadWriteSoExists \li SlotIdInvalid
+ * \li TokenNotPresent \li TokenNotRecognized \li TokenWriteProtected
+ * \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_OpenSession(SlotId slot_id,
+ Flags flags,
+ VoidPtr application,
+ Notify notify,
+ SessionHandle* session_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_CloseSession closes a session between an application and a token.
+ * @param session the session's handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li SessionClosed
+ * \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_CloseSession(SessionHandle session,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_CloseAllSessions closes all sessions with a token.
+ * @param slot_id the token's slot
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li SlotIdInvalid
+ * \li TokenNotPresent
+ * @return true on success, false otherwise
+ */
+ bool C_CloseAllSessions(SlotId slot_id,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetSessionInfo obtains information about the session.
+ * @param session the session's handle
+ * @param info receives session info
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li SessionClosed
+ * \li SessionHandleInvalid \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_GetSessionInfo(SessionHandle session,
+ SessionInfo* info_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetOperationState obtains the state of the cryptographic operation in a session.
+ * @param session session's handle
+ * @param operation_state_ptr gets state
+ * @param operation_state_len_ptr gets state length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li BufferTooSmall \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * \li StateUnsaveable \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_GetOperationState(SessionHandle session,
+ Byte* operation_state_ptr,
+ Ulong* operation_state_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_SetOperationState restores the state of the cryptographic operation in a session.
+ * @param session session's handle
+ * @param operation_state_ptr holds state
+ * @param operation_state_len holds state length
+ * @param encryption_key en/decryption key
+ * @param authentication_key sign/verify key
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li KeyChanged \li KeyNeeded
+ * \li KeyNotNeeded \li OK \li SavedStateInvalid
+ * \li SessionClosed \li SessionHandleInvalid \li ArgumentsBad
+ * @return true on success, false otherwise
+ */
+ bool C_SetOperationState(SessionHandle session,
+ Byte* operation_state_ptr,
+ Ulong operation_state_len,
+ ObjectHandle encryption_key,
+ ObjectHandle authentication_key,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Login logs a user into a token.
+ * @param session the session's handle
+ * @param user_type the user type
+ * @param pin_ptr the user's PIN
+ * @param pin_len the length of the PIN
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li PinIncorrect
+ * \li PinLocked \li SessionClosed \li SessionHandleInvalid
+ * \li SessionReadOnlyExists \li UserAlreadyLoggedIn \li UserAnotherAlreadyLoggedIn
+ * \li UserPinNotInitialized \li UserTooManyTypes \li UserTypeInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_Login(SessionHandle session,
+ UserType user_type,
+ Utf8Char* pin_ptr,
+ Ulong pin_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Login logs a user into a token.
+ * @param session the session's handle
+ * @param user_type the user type
+ * @param pin the user or security officer's PIN
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li PinIncorrect
+ * \li PinLocked \li SessionClosed \li SessionHandleInvalid
+ * \li SessionReadOnlyExists \li UserAlreadyLoggedIn \li UserAnotherAlreadyLoggedIn
+ * \li UserPinNotInitialized \li UserTooManyTypes \li UserTypeInvalid
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_Login(SessionHandle session,
+ UserType user_type,
+ const std::vector<byte, TAlloc>& pin,
+ ReturnValue* return_value = ThrowException) const
+ {
+ return C_Login(session, user_type, reinterpret_cast< Utf8Char* >(const_cast< byte* >(pin.data())), pin.size(),
+ return_value);
+ }
+
+ /**
+ * C_Logout logs a user out from a token.
+ * @param session the session's handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_Logout(SessionHandle session,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Object management functions ******************************/
+
+ /**
+ * C_CreateObject creates a new object.
+ * @param session the session's handle
+ * @param attribute_template_ptr the object's template
+ * @param count attributes in template
+ * @param object_ptr gets new object's handle.
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li AttributeReadOnly \li AttributeTypeInvalid
+ * \li AttributeValueInvalid \li CryptokiNotInitialized \li CurveNotSupported
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li DomainParamsInvalid \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li PinExpired
+ * \li SessionClosed \li SessionHandleInvalid \li SessionReadOnly
+ * \li TemplateIncomplete \li TemplateInconsistent \li TokenWriteProtected
+ * \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_CreateObject(SessionHandle session,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ObjectHandle* object_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_CopyObject copies an object, creating a new object for the copy.
+ * @param session the session's handle
+ * @param object the object's handle
+ * @param attribute_template_ptr template for new object
+ * @param count attributes in template
+ * @param new_object_ptr receives handle of copy
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ActionProhibited \li ArgumentsBad \li AttributeReadOnly
+ * \li AttributeTypeInvalid \li AttributeValueInvalid \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li ObjectHandleInvalid \li OK \li PinExpired
+ * \li SessionClosed \li SessionHandleInvalid \li SessionReadOnly
+ * \li TemplateInconsistent \li TokenWriteProtected \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_CopyObject(SessionHandle session,
+ ObjectHandle object,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ObjectHandle* new_object_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_DestroyObject destroys an object.
+ * @param session the session's handle
+ * @param object the object's handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ActionProhibited \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionFailed
+ * \li GeneralError \li HostMemory \li ObjectHandleInvalid
+ * \li OK \li PinExpired \li SessionClosed
+ * \li SessionHandleInvalid \li SessionReadOnly \li TokenWriteProtected
+ * @return true on success, false otherwise
+ */
+ bool C_DestroyObject(SessionHandle session,
+ ObjectHandle object,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetObjectSize gets the size of an object in bytes.
+ * @param session the session's handle
+ * @param object the object's handle
+ * @param size_ptr receives size of object
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionFailed
+ * \li GeneralError \li HostMemory \li InformationSensitive
+ * \li ObjectHandleInvalid \li OK \li SessionClosed
+ * \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_GetObjectSize(SessionHandle session,
+ ObjectHandle object,
+ Ulong* size_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetAttributeValue obtains the value of one or more object attributes.
+ * @param session the session's handle
+ * @param object the object's handle
+ * @param attribute_template_ptr specifies attrs; gets vals
+ * @param count attributes in template
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li AttributeSensitive \li AttributeTypeInvalid
+ * \li BufferTooSmall \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionFailed
+ * \li GeneralError \li HostMemory \li ObjectHandleInvalid
+ * \li OK \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_GetAttributeValue(SessionHandle session,
+ ObjectHandle object,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GetAttributeValue obtains the value of one or more object attributes.
+ * @param session the session's handle
+ * @param object the object's handle
+ * @param attribute_values specifies attrs; gets vals
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li AttributeSensitive \li AttributeTypeInvalid
+ * \li BufferTooSmall \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionFailed
+ * \li GeneralError \li HostMemory \li ObjectHandleInvalid
+ * \li OK \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_GetAttributeValue(SessionHandle session,
+ ObjectHandle object,
+ std::map<AttributeType, std::vector<byte, TAlloc>>& attribute_values,
+ ReturnValue* return_value = ThrowException) const
+ {
+ std::vector<Attribute> getter_template;
+
+ for(const auto& entry : attribute_values)
+ {
+ getter_template.emplace_back(Attribute{ static_cast< CK_ATTRIBUTE_TYPE >(entry.first), nullptr, 0 });
+ }
+
+ bool success = C_GetAttributeValue(session, object, const_cast< Attribute* >(getter_template.data()),
+ getter_template.size(), return_value);
+
+ if(!success)
+ {
+ return success;
+ }
+
+ size_t i = 0;
+ for(auto& entry : attribute_values)
+ {
+ entry.second.clear();
+ entry.second.resize(getter_template.at(i).ulValueLen);
+ getter_template.at(i).pValue = const_cast< byte* >(entry.second.data());
+ i++;
+ }
+
+ return C_GetAttributeValue(session, object, const_cast< Attribute* >(getter_template.data()), getter_template.size(),
+ return_value);
+ }
+
+ /**
+ * C_SetAttributeValue modifies the value of one or more object attributes.
+ * @param session the session's handle
+ * @param object the object's handle
+ * @param attribute_template_ptr specifies attrs and values
+ * @param count attributes in template
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ActionProhibited \li ArgumentsBad \li AttributeReadOnly
+ * \li AttributeTypeInvalid \li AttributeValueInvalid \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li ObjectHandleInvalid \li OK \li SessionClosed
+ * \li SessionHandleInvalid \li SessionReadOnly \li TemplateInconsistent
+ * \li TokenWriteProtected \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_SetAttributeValue(SessionHandle session,
+ ObjectHandle object,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_SetAttributeValue modifies the value of one or more object attributes.
+ * @param session the session's handle
+ * @param object the object's handle
+ * @param attributes specifies attrs and values
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ActionProhibited \li ArgumentsBad \li AttributeReadOnly
+ * \li AttributeTypeInvalid \li AttributeValueInvalid \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li ObjectHandleInvalid \li OK \li SessionClosed
+ * \li SessionHandleInvalid \li SessionReadOnly \li TemplateInconsistent
+ * \li TokenWriteProtected \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_SetAttributeValue(SessionHandle session,
+ ObjectHandle object,
+ std::map<AttributeType, std::vector<byte, TAlloc>>& attribute_values,
+ ReturnValue* return_value = ThrowException) const
+ {
+ std::vector<Attribute> setter_template;
+
+ for(auto& entry : attribute_values)
+ {
+ setter_template.emplace_back(Attribute{ static_cast< CK_ATTRIBUTE_TYPE >(entry.first), entry.second.data(), static_cast<CK_ULONG>(entry.second.size()) });
+ }
+
+ return C_SetAttributeValue(session, object, const_cast< Attribute* >(setter_template.data()), setter_template.size(),
+ return_value);
+ }
+
+ /**
+ * C_FindObjectsInit initializes a search for token and session objects that match a template.
+ * @param session the session's handle
+ * @param attribute_template_ptr attribute values to match
+ * @param count attrs in search template
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li AttributeTypeInvalid \li AttributeValueInvalid
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationActive
+ * \li PinExpired \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_FindObjectsInit(SessionHandle session,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_FindObjects continues a search for token and session objects that match a template, obtaining additional object handles.
+ * @param session session's handle
+ * @param object gets obj. handles
+ * @param max_object_count max handles to get
+ * @param object_count actual # returned
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_FindObjects(SessionHandle session,
+ ObjectHandle* object_ptr,
+ Ulong max_object_count,
+ Ulong* object_count_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_FindObjectsFinal finishes a search for token and session objects.
+ * @param session the session's handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_FindObjectsFinal(SessionHandle session,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Encryption functions ******************************/
+
+ /**
+ * C_EncryptInit initializes an encryption operation.
+ * @param session the session's handle
+ * @param mechanism_ptr the encryption mechanism
+ * @param key handle of encryption key
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li KeyFunctionNotPermitted
+ * \li KeyHandleInvalid \li KeySizeRange \li KeyTypeInconsistent
+ * \li MechanismInvalid \li MechanismParamInvalid \li OK
+ * \li OperationActive \li PinExpired \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_EncryptInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Encrypt encrypts single-part data.
+ * @param session session's handle
+ * @param data_ptr the plaintext data
+ * @param encrypted_data_len_ptr bytes of plaintext
+ * @param encrypted_data gets ciphertext
+ * @param encrypted_data_len gets c-text size
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataInvalid \li DataLenRange \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_Encrypt(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* encrypted_data,
+ Ulong* encrypted_data_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Encrypt encrypts single-part data.
+ * @param session session's handle
+ * @param plaintext_data the plaintext data
+ * @param encrypted_data gets ciphertext
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataInvalid \li DataLenRange \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ template<typename TAllocA, typename TAllocB>
+ bool C_Encrypt(SessionHandle session,
+ const std::vector<byte, TAllocA>& plaintext_data,
+ std::vector<byte, TAllocB>& encrypted_data,
+ ReturnValue* return_value = ThrowException) const
+ {
+ Ulong encrypted_size = 0;
+ if(!C_Encrypt(session, const_cast<Byte*>((plaintext_data.data())), plaintext_data.size(), nullptr, &encrypted_size,
+ return_value))
+ {
+ return false;
+ }
+
+ encrypted_data.resize(encrypted_size);
+ return C_Encrypt(session, const_cast<Byte*>(plaintext_data.data()), plaintext_data.size(), encrypted_data.data(),
+ &encrypted_size, return_value);
+ }
+
+ /**
+ * C_EncryptUpdate continues a multiple-part encryption operation.
+ * @param session session's handle
+ * @param part_ptr the plaintext data
+ * @param part_len plaintext data len
+ * @param encrypted_part_ptr gets ciphertext
+ * @param encrypted_part_len_ptr gets c-text size
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_EncryptUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ Byte* encrypted_part_ptr,
+ Ulong* encrypted_part_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_EncryptFinal finishes a multiple-part encryption operation.
+ * @param session session handle
+ * @param last_encrypted_part_ptr last c-text
+ * @param last_encrypted_part_len_ptr gets last size
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_EncryptFinal(SessionHandle session,
+ Byte* last_encrypted_part_ptr,
+ Ulong* last_encrypted_part_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Decryption functions ******************************/
+
+ /**
+ * C_DecryptInit initializes a decryption operation.
+ * @param session the session's handle
+ * @param mechanism_ptr the decryption mechanism
+ * @param key handle of decryption key
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li KeyFunctionNotPermitted \li KeyHandleInvalid \li KeySizeRange
+ * \li KeyTypeInconsistent \li MechanismInvalid \li MechanismParamInvalid
+ * \li OK \li OperationActive \li PinExpired
+ * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_DecryptInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Decrypt decrypts encrypted data in a single part.
+ * @param session session's handle
+ * @param encrypted_data_ptr ciphertext
+ * @param encrypted_data_len ciphertext length
+ * @param data_ptr gets plaintext
+ * @param data_len_ptr gets p-text size
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li EncryptedDataInvalid \li EncryptedDataLenRange \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_Decrypt(SessionHandle session,
+ Byte* encrypted_data_ptr,
+ Ulong encrypted_data_len,
+ Byte* data_ptr,
+ Ulong* data_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Decrypt decrypts encrypted data in a single part.
+ * @param session session's handle
+ * @param encrypted_data ciphertext
+ * @param decrypted_data gets plaintext
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li EncryptedDataInvalid \li EncryptedDataLenRange \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ template<typename TAllocA, typename TAllocB>
+ bool C_Decrypt(SessionHandle session,
+ const std::vector<byte, TAllocA>& encrypted_data,
+ std::vector<byte, TAllocB>& decrypted_data,
+ ReturnValue* return_value = ThrowException) const
+ {
+ Ulong decrypted_size = 0;
+ if(!C_Decrypt(session, const_cast<Byte*>((encrypted_data.data())), encrypted_data.size(), nullptr, &decrypted_size,
+ return_value))
+ {
+ return false;
+ }
+
+ decrypted_data.resize(decrypted_size);
+ return C_Decrypt(session, const_cast<Byte*>(encrypted_data.data()), encrypted_data.size(), decrypted_data.data(),
+ &decrypted_size, return_value);
+ }
+
+ /**
+ * C_DecryptUpdate continues a multiple-part decryption operation.
+ * @param session session's handle
+ * @param encrypted_part_ptr encrypted data
+ * @param encrypted_part_len input length
+ * @param part_ptr gets plaintext
+ * @param part_len_ptr p-text size
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li EncryptedDataInvalid \li EncryptedDataLenRange \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_DecryptUpdate(SessionHandle session,
+ Byte* encrypted_part_ptr,
+ Ulong encrypted_part_len,
+ Byte* part_ptr,
+ Ulong* part_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_DecryptFinal finishes a multiple-part decryption operation.
+ * @param session the session's handle
+ * @param last_part_ptr gets plaintext
+ * @param last_part_len_ptr p-text size
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li EncryptedDataInvalid \li EncryptedDataLenRange \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_DecryptFinal(SessionHandle session,
+ Byte* last_part_ptr,
+ Ulong* last_part_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Message digesting functions ******************************/
+
+ /**
+ * C_DigestInit initializes a message-digesting operation.
+ * @param session the session's handle
+ * @param mechanism_ptr the digesting mechanism
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li MechanismInvalid \li MechanismParamInvalid \li OK
+ * \li OperationActive \li PinExpired \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_DigestInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Digest digests data in a single part.
+ * @param session the session's handle
+ * @param data_ptr data to be digested
+ * @param data_len bytes of data to digest
+ * @param digest_ptr gets the message digest
+ * @param digest_len_ptr gets digest length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_Digest(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* digest_ptr,
+ Ulong* digest_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_DigestUpdate continues a multiple-part message-digesting operation.
+ * @param session the session's handle
+ * @param part_ptr data to be digested
+ * @param part_len bytes of data to be digested
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_DigestUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_DigestKey continues a multi-part message-digesting operation, by digesting the value of a secret key as part of the data already digested.
+ * @param session the session's handle
+ * @param key secret key to digest
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li KeyHandleInvalid
+ * \li KeyIndigestible \li KeySizeRange \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_DigestKey(SessionHandle session,
+ ObjectHandle key,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_DigestFinal finishes a multiple-part message-digesting operation.
+ * @param session the session's handle
+ * @param digest_ptr gets the message digest
+ * @param digest_len_ptr gets byte count of digest
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_DigestFinal(SessionHandle session,
+ Byte* digest_ptr,
+ Ulong* digest_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Signing and MACing functions ******************************/
+
+ /**
+ * C_SignInit initializes a signature (private key encryption) operation, where the signature is (will be) an appendix to the data, and plaintext cannot be recovered from the signature.
+ * @param session the session's handle
+ * @param mechanism_ptr the signature mechanism
+ * @param key handle of signature key
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li KeyFunctionNotPermitted \li KeyHandleInvalid \li KeySizeRange
+ * \li KeyTypeInconsistent \li MechanismInvalid \li MechanismParamInvalid
+ * \li OK \li OperationActive \li PinExpired
+ * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_SignInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Sign signs (encrypts with private key) data in a single part, where the signature is (will be) an appendix to the data, and plaintext cannot be recovered from the signature.
+ * @param session the session's handle
+ * @param data_ptr the data to sign
+ * @param data_len count of bytes to sign
+ * @param signature_ptr gets the signature
+ * @param signature_len_ptr gets signature length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataInvalid \li DataLenRange \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn \li FunctionRejected
+ * @return true on success, false otherwise
+ */
+ bool C_Sign(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* signature_ptr,
+ Ulong* signature_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Sign signs (encrypts with private key) data in a single part, where the signature is (will be) an appendix to the data, and plaintext cannot be recovered from the signature.
+ * @param session the session's handle
+ * @param data the data to sign
+ * @param signature gets the signature
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataInvalid \li DataLenRange \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn \li FunctionRejected
+ * @return true on success, false otherwise
+ */
+ template<typename TAllocA, typename TAllocB>
+ bool C_Sign(SessionHandle session,
+ const std::vector<byte, TAllocA>& data,
+ std::vector<byte, TAllocB>& signature,
+ ReturnValue* return_value = ThrowException) const
+ {
+ Ulong signature_size = 0;
+ if(!C_Sign(session, const_cast<Byte*>((data.data())), data.size(), nullptr, &signature_size, return_value))
+ {
+ return false;
+ }
+
+ signature.resize(signature_size);
+ return C_Sign(session, const_cast<Byte*>(data.data()), data.size(), signature.data(), &signature_size, return_value);
+ }
+
+ /**
+ * C_SignUpdate continues a multiple-part signature operation, where the signature is (will be) an appendix to the data, and plaintext cannot be recovered from the signature.
+ * @param session the session's handle
+ * @param part_ptr the data to sign
+ * @param part_len count of bytes to sign
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DataLenRange
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_SignUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_SignUpdate continues a multiple-part signature operation, where the signature is (will be) an appendix to the data, and plaintext cannot be recovered from the signature.
+ * @param session the session's handle
+ * @param part the data to sign
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DataLenRange
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_SignUpdate(SessionHandle session,
+ const std::vector<byte, TAlloc>& part,
+ ReturnValue* return_value = ThrowException) const
+ {
+ return C_SignUpdate(session, const_cast<Byte*>(part.data()), part.size(), return_value);
+ }
+
+ /**
+ * C_SignFinal finishes a multiple-part signature operation, returning the signature.
+ * @param session the session's handle
+ * @param signature_ptr gets the signature
+ * @param signature_len_ptr gets signature length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * \li UserNotLoggedIn \li FunctionRejected
+ * @return true on success, false otherwise
+ */
+ bool C_SignFinal(SessionHandle session,
+ Byte* signature_ptr,
+ Ulong* signature_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_SignFinal finishes a multiple-part signature operation, returning the signature.
+ * @param session the session's handle
+ * @param signature gets the signature
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * \li UserNotLoggedIn \li FunctionRejected
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_SignFinal(SessionHandle session,
+ std::vector<byte, TAlloc>& signature,
+ ReturnValue* return_value = ThrowException) const
+ {
+ Ulong signature_size = 0;
+ if(!C_SignFinal(session, nullptr, &signature_size, return_value))
+ {
+ return false;
+ }
+
+ signature.resize(signature_size);
+ return C_SignFinal(session, signature.data(), &signature_size, return_value);
+ }
+
+ /**
+ * C_SignRecoverInit initializes a signature operation, where the data can be recovered from the signature.
+ * @param session the session's handle
+ * @param mechanism_ptr the signature mechanism
+ * @param key handle of the signature key
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li KeyFunctionNotPermitted \li KeyHandleInvalid \li KeySizeRange
+ * \li KeyTypeInconsistent \li MechanismInvalid \li MechanismParamInvalid
+ * \li OK \li OperationActive \li PinExpired
+ * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_SignRecoverInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_SignRecover signs data in a single operation, where the data can be recovered from the signature.
+ * @param session the session's handle
+ * @param data_ptr the data to sign
+ * @param data_len count of bytes to sign
+ * @param signature_ptr gets the signature
+ * @param signature_len_ptr gets signature length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataInvalid \li DataLenRange \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_SignRecover(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* signature_ptr,
+ Ulong* signature_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Functions for verifying signatures and MACs ******************************/
+
+ /**
+ * C_VerifyInit initializes a verification operation, where the signature is an appendix to the data, and plaintext cannot be recovered from the signature (e.g. DSA).
+ * @param session the session's handle
+ * @param mechanism_ptr the verification mechanism
+ * @param key verification key
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li KeyFunctionNotPermitted \li KeyHandleInvalid \li KeySizeRange
+ * \li KeyTypeInconsistent \li MechanismInvalid \li MechanismParamInvalid
+ * \li OK \li OperationActive \li PinExpired
+ * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_VerifyInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Verify verifies a signature in a single-part operation, where the signature is an appendix to the data, and plaintext cannot be recovered from the signature.
+ * @param session the session's handle
+ * @param data_ptr signed data
+ * @param data_len length of signed data
+ * @param signature_ptr signature
+ * @param signature_len signature length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DataInvalid
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * \li SignatureInvalid \li SignatureLenRange
+ * @return true on success, false otherwise
+ */
+ bool C_Verify(SessionHandle session,
+ Byte* data_ptr,
+ Ulong data_len,
+ Byte* signature_ptr,
+ Ulong signature_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_Verify verifies a signature in a single-part operation, where the signature is an appendix to the data, and plaintext cannot be recovered from the signature.
+ * @param session the session's handle
+ * @param data signed data
+ * @param signature signature
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DataInvalid
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * \li SignatureInvalid \li SignatureLenRange
+ * @return true on success, false otherwise
+ */
+ template<typename TAllocA, typename TAllocB>
+ bool C_Verify(SessionHandle session,
+ const std::vector<byte, TAllocA>& data,
+ std::vector<byte, TAllocB>& signature,
+ ReturnValue* return_value = ThrowException) const
+ {
+ return C_Verify(session, const_cast<Byte*>(data.data()), data.size(), signature.data(), signature.size(), return_value);
+ }
+
+ /**
+ * C_VerifyUpdate continues a multiple-part verification operation, where the signature is an appendix to the data, and plaintext cannot be recovered from the signature.
+ * @param session the session's handle
+ * @param part_ptr signed data
+ * @param part_len length of signed data
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DataLenRange
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_VerifyUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_VerifyUpdate continues a multiple-part verification operation, where the signature is an appendix to the data, and plaintext cannot be recovered from the signature.
+ * @param session the session's handle
+ * @param part signed data
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DataLenRange
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ template<typename TAlloc>
+ bool C_VerifyUpdate(SessionHandle session,
+ std::vector<byte, TAlloc> part,
+ ReturnValue* return_value = ThrowException) const
+ {
+ return C_VerifyUpdate(session, part.data(), part.size(), return_value);
+ }
+
+ /**
+ * C_VerifyFinal finishes a multiple-part verification operation, checking the signature.
+ * @param session the session's handle
+ * @param signature_ptr signature to verify
+ * @param signature_len signature length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DataLenRange
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid \li SignatureInvalid
+ * \li SignatureLenRange
+ * @return true on success, false otherwise
+ */
+ bool C_VerifyFinal(SessionHandle session,
+ Byte* signature_ptr,
+ Ulong signature_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_VerifyRecoverInit initializes a signature verification operation, where the data is recovered from the signature.
+ * @param session the session's handle
+ * @param mechanism_ptr the verification mechanism
+ * @param key verification key
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li KeyFunctionNotPermitted \li KeyHandleInvalid \li KeySizeRange
+ * \li KeyTypeInconsistent \li MechanismInvalid \li MechanismParamInvalid
+ * \li OK \li OperationActive \li PinExpired
+ * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_VerifyRecoverInit(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle key,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_VerifyRecover verifies a signature in a single-part operation, where the data is recovered from the signature.
+ * @param session the session's handle
+ * @param signature_ptr signature to verify
+ * @param signature_len signature length
+ * @param data_ptr gets signed data
+ * @param data_len_ptr gets signed data len
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataInvalid \li DataLenRange \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid \li SignatureLenRange \li SignatureInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_VerifyRecover(SessionHandle session,
+ Byte* signature_ptr,
+ Ulong signature_len,
+ Byte* data_ptr,
+ Ulong* data_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Dual-purpose cryptographic functions ******************************/
+
+ /**
+ * C_DigestEncryptUpdate continues a multiple-part digesting and encryption operation.
+ * @param session session's handle
+ * @param part_ptr the plaintext data
+ * @param part_len plaintext length
+ * @param encrypted_part_ptr gets ciphertext
+ * @param encrypted_part_len_ptr gets c-text length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_DigestEncryptUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ Byte* encrypted_part_ptr,
+ Ulong* encrypted_part_len_ptr,
+ ReturnValue* return_value = ThrowException) const ;
+
+ /**
+ * C_DecryptDigestUpdate continues a multiple-part decryption and digesting operation.
+ * @param session session's handle
+ * @param encrypted_part_ptr ciphertext
+ * @param encrypted_part_len ciphertext length
+ * @param part_ptr gets plaintext
+ * @param part_len_ptr gets plaintext len
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li EncryptedDataInvalid \li EncryptedDataLenRange \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationNotInitialized \li SessionClosed
+ * \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_DecryptDigestUpdate(SessionHandle session,
+ Byte* encrypted_part_ptr,
+ Ulong encrypted_part_len,
+ Byte* part_ptr,
+ Ulong* part_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_SignEncryptUpdate continues a multiple-part signing and encryption operation.
+ * @param session session's handle
+ * @param part_ptr the plaintext data
+ * @param part_len plaintext length
+ * @param encrypted_part_ptr gets ciphertext
+ * @param encrypted_part_len_ptr gets c-text length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li OK
+ * \li OperationNotInitialized \li SessionClosed \li SessionHandleInvalid
+ * \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_SignEncryptUpdate(SessionHandle session,
+ Byte* part_ptr,
+ Ulong part_len,
+ Byte* encrypted_part_ptr,
+ Ulong* encrypted_part_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_DecryptVerifyUpdate continues a multiple-part decryption and verify operation.
+ * @param session session's handle
+ * @param encrypted_part_ptr ciphertext
+ * @param encrypted_part_len ciphertext length
+ * @param part_ptr gets plaintext
+ * @param part_len_ptr gets p-text length
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DataLenRange \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li EncryptedDataInvalid \li EncryptedDataLenRange
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li OK \li OperationNotInitialized
+ * \li SessionClosed \li SessionHandleInvalid
+ * @return true on success, false otherwise
+ */
+ bool C_DecryptVerifyUpdate(SessionHandle session,
+ Byte* encrypted_part_ptr,
+ Ulong encrypted_part_len,
+ Byte* part_ptr,
+ Ulong* part_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Key management functions ******************************/
+
+ /**
+ * C_GenerateKey generates a secret key, creating a new key object.
+ * @param session the session's handle
+ * @param mechanism_ptr key generation mech.
+ * @param attribute_template_ptr template for new key
+ * @param count # of attrs in template
+ * @param key_ptr gets handle of new key
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li AttributeReadOnly \li AttributeTypeInvalid
+ * \li AttributeValueInvalid \li CryptokiNotInitialized \li CurveNotSupported
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li MechanismInvalid \li MechanismParamInvalid
+ * \li OK \li OperationActive \li PinExpired
+ * \li SessionClosed \li SessionHandleInvalid \li SessionReadOnly
+ * \li TemplateIncomplete \li TemplateInconsistent \li TokenWriteProtected
+ * \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_GenerateKey(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ Attribute* attribute_template_ptr,
+ Ulong count,
+ ObjectHandle* key_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GenerateKeyPair generates a public-key/private-key pair, creating new key objects.
+ * @param session session handle
+ * @param mechanism_ptr key-gen mech.
+ * @param public_key_template_ptr template for pub. key
+ * @param public_key_attribute_count # pub. attrs.
+ * @param private_key_template_ptr template for priv. key
+ * @param private_key_attribute_count # priv. attrs.
+ * @param public_key_ptr gets pub. key handle
+ * @param private_key_ptr gets priv. key handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li AttributeReadOnly \li AttributeTypeInvalid
+ * \li AttributeValueInvalid \li CryptokiNotInitialized \li CurveNotSupported
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li DomainParamsInvalid \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li MechanismInvalid
+ * \li MechanismParamInvalid \li OK \li OperationActive
+ * \li PinExpired \li SessionClosed \li SessionHandleInvalid
+ * \li SessionReadOnly \li TemplateIncomplete \li TemplateInconsistent
+ * \li TokenWriteProtected \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_GenerateKeyPair(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ Attribute* public_key_template_ptr,
+ Ulong public_key_attribute_count,
+ Attribute* private_key_template_ptr,
+ Ulong private_key_attribute_count,
+ ObjectHandle* public_key_ptr,
+ ObjectHandle* private_key_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_WrapKey wraps (i.e., encrypts) a key.
+ * @param session the session's handle
+ * @param mechanism_ptr the wrapping mechanism
+ * @param wrapping_key wrapping key
+ * @param key key to be wrapped
+ * @param wrapped_key_ptr gets wrapped key
+ * @param wrapped_key_len_ptr gets wrapped key size
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li BufferTooSmall \li CryptokiNotInitialized
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li FunctionCanceled \li FunctionFailed \li GeneralError
+ * \li HostMemory \li KeyHandleInvalid \li KeyNotWrappable
+ * \li KeySizeRange \li KeyUnextractable \li MechanismInvalid
+ * \li MechanismParamInvalid \li OK \li OperationActive
+ * \li PinExpired \li SessionClosed \li SessionHandleInvalid
+ * \li UserNotLoggedIn \li WrappingKeyHandleInvalid \li WrappingKeySizeRange
+ * \li WrappingKeyTypeInconsistent
+ * @return true on success, false otherwise
+ */
+ bool C_WrapKey(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle wrapping_key,
+ ObjectHandle key,
+ Byte* wrapped_key_ptr,
+ Ulong* wrapped_key_len_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new key object.
+ * @param session session's handle
+ * @param mechanism_ptr unwrapping mech.
+ * @param unwrapping_key unwrapping key
+ * @param wrapped_key_ptr the wrapped key
+ * @param wrapped_key_len wrapped key len
+ * @param attribute_template_ptr new key template
+ * @param attribute_count template length
+ * @param key_ptr gets new handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li AttributeReadOnly \li AttributeTypeInvalid
+ * \li AttributeValueInvalid \li BufferTooSmall \li CryptokiNotInitialized
+ * \li CurveNotSupported \li DeviceError \li DeviceMemory
+ * \li DeviceRemoved \li DomainParamsInvalid \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li MechanismInvalid \li MechanismParamInvalid \li OK
+ * \li OperationActive \li PinExpired \li SessionClosed
+ * \li SessionHandleInvalid \li SessionReadOnly \li TemplateIncomplete
+ * \li TemplateInconsistent \li TokenWriteProtected \li UnwrappingKeyHandleInvalid
+ * \li UnwrappingKeySizeRange \li UnwrappingKeyTypeInconsistent \li UserNotLoggedIn
+ * \li WrappedKeyInvalid \li WrappedKeyLenRange
+ * @return true on success, false otherwise
+ */
+ bool C_UnwrapKey(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle unwrapping_key,
+ Byte* wrapped_key_ptr,
+ Ulong wrapped_key_len,
+ Attribute* attribute_template_ptr,
+ Ulong attribute_count,
+ ObjectHandle* key_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_DeriveKey derives a key from a base key, creating a new key object.
+ * @param session session's handle
+ * @param mechanism_ptr key deriv. mech.
+ * @param base_key base key
+ * @param attribute_template_ptr new key template
+ * @param attribute_count template length
+ * @param key_ptr gets new handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li AttributeReadOnly \li AttributeTypeInvalid
+ * \li AttributeValueInvalid \li CryptokiNotInitialized \li CurveNotSupported
+ * \li DeviceError \li DeviceMemory \li DeviceRemoved
+ * \li DomainParamsInvalid \li FunctionCanceled \li FunctionFailed
+ * \li GeneralError \li HostMemory \li KeyHandleInvalid
+ * \li KeySizeRange \li KeyTypeInconsistent \li MechanismInvalid
+ * \li MechanismParamInvalid \li OK \li OperationActive
+ * \li PinExpired \li SessionClosed \li SessionHandleInvalid
+ * \li SessionReadOnly \li TemplateIncomplete \li TemplateInconsistent
+ * \li TokenWriteProtected \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_DeriveKey(SessionHandle session,
+ Mechanism* mechanism_ptr,
+ ObjectHandle base_key,
+ Attribute* attribute_template_ptr,
+ Ulong attribute_count,
+ ObjectHandle* key_ptr,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Random number generation functions ******************************/
+
+ /**
+ * C_SeedRandom mixes additional seed material into the token's random number generator.
+ * @param session the session's handle
+ * @param seed_ptr the seed material
+ * @param seed_len length of seed material
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationActive \li RandomSeedNotSupported
+ * \li RandomNoRng \li SessionClosed \li SessionHandleInvalid
+ * \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_SeedRandom(SessionHandle session,
+ Byte* seed_ptr,
+ Ulong seed_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_GenerateRandom generates random data.
+ * @param session the session's handle
+ * @param random_data_ptr receives the random data
+ * @param random_len # of bytes to generate
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li ArgumentsBad \li CryptokiNotInitialized \li DeviceError
+ * \li DeviceMemory \li DeviceRemoved \li FunctionCanceled
+ * \li FunctionFailed \li GeneralError \li HostMemory
+ * \li OK \li OperationActive \li RandomNoRng
+ * \li SessionClosed \li SessionHandleInvalid \li UserNotLoggedIn
+ * @return true on success, false otherwise
+ */
+ bool C_GenerateRandom(SessionHandle session,
+ Byte* random_data_ptr,
+ Ulong random_len,
+ ReturnValue* return_value = ThrowException) const;
+
+ /****************************** Parallel function management functions ******************************/
+
+ /**
+ * C_GetFunctionStatus is a legacy function; it obtains an updated status of a function running in parallel with an application.
+ * @param session the session's handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li FunctionFailed \li FunctionNotParallel
+ * \li GeneralError \li HostMemory \li SessionHandleInvalid
+ * \li SessionClosed
+ * @return true on success, false otherwise
+ */
+ bool C_GetFunctionStatus(SessionHandle session,
+ ReturnValue* return_value = ThrowException) const;
+
+ /**
+ * C_CancelFunction is a legacy function; it cancels a function running in parallel.
+ * @param session the session's handle
+ * @param return_value default value (`ThrowException`): throw exception on error.
+ * if a non-NULL pointer is passed: return_value receives the return value of the PKCS#11 function and no exception is thrown.
+ * At least the following PKCS#11 return values may be returned:
+ * \li CryptokiNotInitialized \li FunctionFailed \li FunctionNotParallel
+ * \li GeneralError \li HostMemory \li SessionHandleInvalid
+ * \li SessionClosed
+ * @return true on success, false otherwise
+ */
+ bool C_CancelFunction(SessionHandle session,
+ ReturnValue* return_value = ThrowException) const;
+
+ private:
+ const FunctionListPtr m_func_list_ptr;
+ };
+
+class PKCS11_Error : public Exception
+ {
+ public:
+ explicit PKCS11_Error(const std::string& what) :
+ Exception("PKCS11 error", what)
+ {
+ }
+ };
+
+class PKCS11_ReturnError : public PKCS11_Error
+ {
+ public:
+ explicit PKCS11_ReturnError(ReturnValue return_val) :
+ PKCS11_Error(std::to_string(static_cast< uint32_t >(return_val))),
+ m_return_val(return_val)
+ {}
+
+ inline ReturnValue get_return_value() const
+ {
+ return m_return_val;
+ }
+
+ private:
+ const ReturnValue m_return_val;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_ecc_key.cpp b/src/lib/prov/pkcs11/p11_ecc_key.cpp
new file mode 100644
index 000000000..0c3e879d9
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_ecc_key.cpp
@@ -0,0 +1,137 @@
+/*
+* PKCS#11 ECC
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_ecc_key.h>
+
+#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
+
+#include <botan/workfactor.h>
+#include <botan/ber_dec.h>
+
+namespace Botan {
+namespace PKCS11 {
+namespace {
+/// Converts a DER-encoded ANSI X9.62 ECPoint to PointGFp
+PointGFp decode_public_point(const secure_vector<byte>& ec_point_data, const CurveGFp& curve)
+ {
+ secure_vector<byte> ec_point;
+ BER_Decoder(ec_point_data).decode(ec_point, OCTET_STRING);
+ return OS2ECP(ec_point, curve);
+ }
+}
+
+EC_PublicKeyGenerationProperties::EC_PublicKeyGenerationProperties(const std::vector<byte>& ec_params)
+ : PublicKeyProperties(KeyType::Ec), m_ec_params(ec_params)
+ {
+ add_binary(AttributeType::EcParams, m_ec_params);
+ }
+
+EC_PublicKeyImportProperties::EC_PublicKeyImportProperties(const std::vector<byte>& ec_params,
+ const std::vector<byte>& ec_point)
+ : PublicKeyProperties(KeyType::Ec), m_ec_params(ec_params), m_ec_point(ec_point)
+ {
+ add_binary(AttributeType::EcParams, m_ec_params);
+ add_binary(AttributeType::EcPoint, m_ec_point);
+ }
+
+PKCS11_EC_PublicKey::PKCS11_EC_PublicKey(Session& session, ObjectHandle handle)
+ : Object(session, handle)
+ {
+ secure_vector<byte> ec_parameters = get_attribute_value(AttributeType::EcParams);
+ m_domain_params = EC_Group(unlock(ec_parameters));
+ m_public_key = decode_public_point(get_attribute_value(AttributeType::EcPoint), m_domain_params.get_curve());
+ m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT;
+ }
+
+size_t PKCS11_EC_PublicKey::max_input_bits() const
+ {
+ return domain().get_order().bits();
+ }
+
+PKCS11_EC_PublicKey::PKCS11_EC_PublicKey(Session& session, const EC_PublicKeyImportProperties& props)
+ : Object(session, props)
+ {
+ m_domain_params = EC_Group(props.ec_params());
+
+ secure_vector<byte> ec_point;
+ BER_Decoder(props.ec_point()).decode(ec_point, OCTET_STRING);
+ m_public_key = OS2ECP(ec_point, m_domain_params.get_curve());
+ m_domain_encoding = EC_DOMPAR_ENC_EXPLICIT;
+ }
+
+EC_PrivateKeyImportProperties::EC_PrivateKeyImportProperties(const std::vector<byte>& ec_params, const BigInt& value)
+ : PrivateKeyProperties(KeyType::Ec), m_ec_params(ec_params), m_value(value)
+ {
+ add_binary(AttributeType::EcParams, m_ec_params);
+ add_binary(AttributeType::Value, BigInt::encode(m_value));
+ }
+
+PKCS11_EC_PrivateKey::PKCS11_EC_PrivateKey(Session& session, ObjectHandle handle)
+ : Object(session, handle), m_domain_params(), m_public_key(), m_point_encoding(PublicPointEncoding::Der)
+ {
+ secure_vector<byte> ec_parameters = get_attribute_value(AttributeType::EcParams);
+ m_domain_params = EC_Group(unlock(ec_parameters));
+ }
+
+PKCS11_EC_PrivateKey::PKCS11_EC_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props)
+ : Object(session, props)
+ {
+ m_domain_params = EC_Group(props.ec_params());
+ }
+
+PKCS11_EC_PrivateKey::PKCS11_EC_PrivateKey(Session& session, const std::vector<byte>& ec_params,
+ const EC_PrivateKeyGenerationProperties& props)
+ : Object(session)
+ {
+ m_domain_params = EC_Group(ec_params);
+
+ EC_PublicKeyGenerationProperties pub_key_props(ec_params);
+ pub_key_props.set_verify(true);
+ pub_key_props.set_private(false);
+ pub_key_props.set_token(false); // don't create a persistent public key object
+
+ ObjectHandle pub_key_handle = 0;
+ m_handle = 0;
+ Mechanism mechanism = { CKM_EC_KEY_PAIR_GEN, nullptr, 0 };
+ session.module()->C_GenerateKeyPair(session.handle(), &mechanism,
+ pub_key_props.data(), pub_key_props.count(), props.data(), props.count(),
+ &pub_key_handle, &m_handle);
+
+ Object public_key(session, pub_key_handle);
+ m_public_key = decode_public_point(public_key.get_attribute_value(AttributeType::EcPoint), m_domain_params.get_curve());
+ }
+
+size_t PKCS11_EC_PrivateKey::max_input_bits() const
+ {
+ return m_domain_params.get_order().bits();
+ }
+
+std::vector<byte> PKCS11_EC_PrivateKey::x509_subject_public_key() const
+ {
+ return unlock(EC2OSP(public_point(), PointGFp::COMPRESSED));
+ }
+
+size_t PKCS11_EC_PrivateKey::estimated_strength() const
+ {
+ return ecp_work_factor(domain().get_curve().get_p().bits());
+ }
+
+bool PKCS11_EC_PrivateKey::check_key(RandomNumberGenerator&, bool) const
+ {
+ return m_public_key.on_the_curve();
+ }
+
+AlgorithmIdentifier PKCS11_EC_PrivateKey::algorithm_identifier() const
+ {
+ return AlgorithmIdentifier(get_oid(), domain().DER_encode(EC_DOMPAR_ENC_EXPLICIT));
+ }
+}
+
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_ecc_key.h b/src/lib/prov/pkcs11/p11_ecc_key.h
new file mode 100644
index 000000000..3d10ae85e
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_ecc_key.h
@@ -0,0 +1,228 @@
+/*
+* PKCS#11 ECC
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_ECC_H__
+#define BOTAN_P11_ECC_H__
+
+#include <botan/build.h>
+#include <botan/p11_object.h>
+
+#if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
+#include <botan/pk_keys.h>
+#include <botan/ecc_key.h>
+#include <botan/ec_group.h>
+#include <botan/rng.h>
+#include <botan/alg_id.h>
+#include <vector>
+
+namespace Botan {
+namespace PKCS11 {
+
+class Session;
+
+/// Properties for generating a PKCS#11 EC public key
+class BOTAN_DLL EC_PublicKeyGenerationProperties final : public PublicKeyProperties
+ {
+ public:
+ /// @param ec_params DER-encoding of an ANSI X9.62 Parameters value
+ EC_PublicKeyGenerationProperties(const std::vector<byte>& ec_params);
+
+ /// @return the DER-encoding of the ec parameters according to ANSI X9.62
+ inline const std::vector<byte>& ec_params() const
+ {
+ return m_ec_params;
+ }
+
+ private:
+ const std::vector<byte> m_ec_params;
+ };
+
+/// Properties for importing a PKCS#11 EC public key
+class BOTAN_DLL EC_PublicKeyImportProperties final : public PublicKeyProperties
+ {
+ public:
+ /**
+ * @param ec_params DER-encoding of an ANSI X9.62 Parameters value
+ * @param ec_point DER-encoding of ANSI X9.62 ECPoint value Q
+ */
+ EC_PublicKeyImportProperties(const std::vector<byte>& ec_params, const std::vector<byte>& ec_point);
+
+ /// @return the DER-encoding of the ec parameters according to ANSI X9.62
+ inline const std::vector<byte>& ec_params() const
+ {
+ return m_ec_params;
+ }
+
+ /// @return the DER-encoding of the ec public point according to ANSI X9.62
+ inline const std::vector<byte>& ec_point() const
+ {
+ return m_ec_point;
+ }
+
+ private:
+ const std::vector<byte> m_ec_params;
+ const std::vector<byte> m_ec_point;
+ };
+
+/// Represents a PKCS#11 EC public key
+class BOTAN_DLL PKCS11_EC_PublicKey : public virtual EC_PublicKey,
+ public Object
+ {
+ public:
+ static const ObjectClass Class = ObjectClass::PublicKey;
+
+ /**
+ * Creates a PKCS11_EC_PublicKey object from an existing PKCS#11 EC public key
+ * @param session the session to use
+ * @param handle the handle of the ecc public key
+ */
+ PKCS11_EC_PublicKey(Session& session, ObjectHandle handle);
+
+ /**
+ * Imports an EC public key
+ * @param session the session to use
+ * @param props the attributes of the public key
+ */
+ PKCS11_EC_PublicKey(Session& session, const EC_PublicKeyImportProperties& props);
+
+ size_t max_input_bits() const override;
+ };
+
+/// Properties for generating a PKCS#11 EC private key
+class BOTAN_DLL EC_PrivateKeyGenerationProperties final : public PrivateKeyProperties
+ {
+ public:
+ EC_PrivateKeyGenerationProperties()
+ : PrivateKeyProperties(KeyType::Ec)
+ {}
+ };
+
+/// Properties for importing a PKCS#11 EC private key
+class BOTAN_DLL EC_PrivateKeyImportProperties final : public PrivateKeyProperties
+ {
+ public:
+ /**
+ * @param ec_params DER-encoding of an ANSI X9.62 Parameters value
+ * @param value ANSI X9.62 private value d
+ */
+ EC_PrivateKeyImportProperties(const std::vector<byte>& ec_params, const BigInt& value);
+
+ /// @return the DER-encoding of the ec parameters according to ANSI X9.62
+ inline const std::vector<byte>& ec_params() const
+ {
+ return m_ec_params;
+ }
+
+ /// @return the value of the ec private key
+ inline const BigInt& value() const
+ {
+ return m_value;
+ }
+
+ private:
+ const std::vector<byte> m_ec_params;
+ const BigInt m_value;
+ };
+
+// note: don't inherit from PKCS11_EC_PublicKey: a private key object IS NOT A public key object on a smartcard (-> two different objects)
+// note: don't inherit from EC_PublicKey: the public key can not be extracted from a PKCS11-EC-PrivateKey (its only attributes are CKA_EC_PARAMS and CKA_VALUE)
+/// Represents a PKCS#11 EC private key
+class BOTAN_DLL PKCS11_EC_PrivateKey : public virtual Private_Key,
+ public Object
+ {
+ public:
+ static const ObjectClass Class = ObjectClass::PrivateKey;
+
+ /**
+ * Creates a PKCS11_EC_PrivateKey object from an existing PKCS#11 EC private key
+ * @param session the session to use
+ * @param handle the handle of the EC private key
+ */
+ PKCS11_EC_PrivateKey(Session& session, ObjectHandle handle);
+
+ /**
+ * Imports an EC private key
+ * @param session the session to use
+ * @param props the attributes of the private key
+ */
+ PKCS11_EC_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props);
+
+ /**
+ * Generates a PKCS#11 EC private key
+ * @param session the session to use
+ * @param ec_params DER-encoding of an ANSI X9.62 Parameters value
+ * @param props the attributes of the private key
+ * @note no persistent public key object will be created
+ */
+ PKCS11_EC_PrivateKey(Session& session, const std::vector<byte>& ec_params,
+ const EC_PrivateKeyGenerationProperties& props);
+
+ /// @returns the domain of the EC private key
+ inline const EC_Group& domain() const
+ {
+ return m_domain_params;
+ }
+
+ /**
+ * Sets the associated public point of this private key
+ * @param point the public point
+ * @param point_encoding encoding of the point (default DER-encoded)
+ */
+ void set_public_point(const PointGFp& point, PublicPointEncoding point_encoding = PublicPointEncoding::Der)
+ {
+ m_public_key = point;
+ m_point_encoding = point_encoding;
+ }
+
+ /**
+ * Gets the public_point
+ * @note: the public key must be set using `set_public_point`
+ * because it is not possible to infer the public key from a PKCS#11 EC private key
+ * @return the public point of the private key
+ * @throws Exception if the public point was not set using set_public_point()
+ */
+
+ const PointGFp& public_point() const
+ {
+ if(m_public_key.is_zero())
+ {
+ throw Exception("Public point not set. Inferring the public key from a PKCS#11 ec private key is not possible.");
+ }
+ return m_public_key;
+ }
+
+ /// @return the encoding format for the public point when it is passed to cryptoki functions as an argument
+ PublicPointEncoding point_encoding() const
+ {
+ return m_point_encoding;
+ }
+
+ // Private_Key methods
+
+ std::size_t max_input_bits() const override;
+
+ std::vector<byte> x509_subject_public_key() const override;
+
+ std::size_t estimated_strength() const override;
+
+ bool check_key(RandomNumberGenerator&, bool) const override;
+
+ AlgorithmIdentifier algorithm_identifier() const override;
+
+ private:
+ EC_Group m_domain_params;
+ PointGFp m_public_key;
+ PublicPointEncoding m_point_encoding;
+ };
+}
+
+}
+
+#endif
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_ecdh.cpp b/src/lib/prov/pkcs11/p11_ecdh.cpp
new file mode 100644
index 000000000..de24d6da4
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_ecdh.cpp
@@ -0,0 +1,141 @@
+/*
+* PKCS#11 ECDH
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_ecdh.h>
+
+#if defined(BOTAN_HAS_ECDH)
+
+#include <botan/internal/p11_mechanism.h>
+#include <botan/ber_dec.h>
+#include <botan/der_enc.h>
+#include <botan/internal/algo_registry.h>
+#include <botan/internal/pk_utils.h>
+#include <botan/rng.h>
+
+namespace Botan {
+
+namespace PKCS11 {
+
+ECDH_PublicKey PKCS11_ECDH_PublicKey::export_key() const
+ {
+ return ECDH_PublicKey(domain(), public_point());
+ }
+
+ECDH_PrivateKey PKCS11_ECDH_PrivateKey::export_key() const
+ {
+ auto priv_key = get_attribute_value(AttributeType::Value);
+
+ Null_RNG rng;
+ return ECDH_PrivateKey(rng, domain(), BigInt::decode(priv_key));
+ }
+
+secure_vector<byte> PKCS11_ECDH_PrivateKey::pkcs8_private_key() const
+ {
+ return export_key().pkcs8_private_key();
+ }
+
+namespace {
+class PKCS11_ECDH_KA_Operation : public PK_Ops::Key_Agreement
+ {
+ public:
+ typedef PKCS11_EC_PrivateKey Key_Type;
+
+ static PKCS11_ECDH_KA_Operation* make_ecdh(const Spec& spec, bool use_cofactor)
+ {
+ try
+ {
+ if(auto* key = dynamic_cast< const PKCS11_EC_PrivateKey* >(&spec.key()))
+ {
+ return new PKCS11_ECDH_KA_Operation(*key, spec.padding(), use_cofactor);
+ }
+ }
+ catch(...)
+ {
+ }
+
+ return nullptr;
+ }
+
+ PKCS11_ECDH_KA_Operation(const PKCS11_EC_PrivateKey& key, const std::string& kdf, bool use_cofactor)
+ : PK_Ops::Key_Agreement(), m_key(key), m_mechanism(MechanismWrapper::create_ecdh_mechanism(kdf, use_cofactor))
+ {}
+
+
+ /// The encoding in V2.20 was not specified and resulted in different implementations choosing different encodings.
+ /// Applications relying only on a V2.20 encoding (e.g. the DER variant) other than the one specified now (raw) may not work with all V2.30 compliant tokens.
+ secure_vector<byte> agree(size_t key_len, const byte other_key[], size_t other_key_len, const byte salt[],
+ size_t salt_len) override
+ {
+ std::vector<byte> der_encoded_other_key;
+ if(m_key.point_encoding() == PublicPointEncoding::Der)
+ {
+ der_encoded_other_key = DER_Encoder().encode(other_key, other_key_len, OCTET_STRING).get_contents_unlocked();
+ m_mechanism.set_ecdh_other_key(der_encoded_other_key.data(), der_encoded_other_key.size());
+ }
+ else
+ {
+ m_mechanism.set_ecdh_other_key(other_key, other_key_len);
+ }
+
+ if(salt != nullptr && salt_len > 0)
+ {
+ m_mechanism.set_ecdh_salt(salt, salt_len);
+ }
+
+ ObjectHandle secret_handle = 0;
+ AttributeContainer attributes;
+ attributes.add_bool(AttributeType::Sensitive, false);
+ attributes.add_bool(AttributeType::Extractable, true);
+ attributes.add_numeric(AttributeType::Class, static_cast< CK_OBJECT_CLASS >(ObjectClass::SecretKey));
+ attributes.add_numeric(AttributeType::KeyType, static_cast< CK_KEY_TYPE >(KeyType::GenericSecret));
+ attributes.add_numeric(AttributeType::ValueLen, key_len);
+ m_key.module()->C_DeriveKey(m_key.session().handle(), m_mechanism.data(), m_key.handle(), attributes.data(),
+ attributes.count(), &secret_handle);
+
+ Object secret_object(m_key.session(), secret_handle);
+ secure_vector<byte> secret = secret_object.get_attribute_value(AttributeType::Value);
+ if(secret.size() < key_len)
+ {
+ throw PKCS11_Error("ECDH key derivation secret length is too short");
+ }
+ secret.resize(key_len);
+ return secret;
+ }
+
+ private:
+ const PKCS11_EC_PrivateKey& m_key;
+ MechanismWrapper m_mechanism;
+ };
+
+Algo_Registry<PK_Ops::Key_Agreement>::Add g_PKCS11_ECDH_KA_Operation_reg("ECDH",
+ std::bind(&PKCS11_ECDH_KA_Operation::make_ecdh, std::placeholders::_1, false), "pkcs11", BOTAN_PKCS11_ECDH_PRIO);
+
+Algo_Registry<PK_Ops::Key_Agreement>::Add g_PKCS11_ECDHC_KA_Operation_reg("ECDHC",
+ std::bind(&PKCS11_ECDH_KA_Operation::make_ecdh, std::placeholders::_1, true), "pkcs11", BOTAN_PKCS11_ECDH_PRIO);
+
+}
+
+PKCS11_ECDH_KeyPair generate_ecdh_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props,
+ const EC_PrivateKeyGenerationProperties& priv_props)
+ {
+ ObjectHandle pub_key_handle = 0;
+ ObjectHandle priv_key_handle = 0;
+
+ Mechanism mechanism = { static_cast< CK_MECHANISM_TYPE >(MechanismType::EcKeyPairGen), nullptr, 0 };
+
+ session.module()->C_GenerateKeyPair(session.handle(), &mechanism,
+ pub_props.data(), pub_props.count(), priv_props.data(), priv_props.count(),
+ &pub_key_handle, &priv_key_handle);
+
+ return std::make_pair(PKCS11_ECDH_PublicKey(session, pub_key_handle), PKCS11_ECDH_PrivateKey(session, priv_key_handle));
+ }
+
+}
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_ecdh.h b/src/lib/prov/pkcs11/p11_ecdh.h
new file mode 100644
index 000000000..749a00d52
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_ecdh.h
@@ -0,0 +1,122 @@
+/*
+* PKCS#11 ECDH
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_ECDH_H__
+#define BOTAN_P11_ECDH_H__
+
+#include <botan/build.h>
+#if defined(BOTAN_HAS_ECDH)
+
+#include <botan/p11.h>
+#include <botan/p11_ecc_key.h>
+#include <botan/ecdh.h>
+
+#include <string>
+#include <vector>
+
+namespace Botan {
+namespace PKCS11 {
+class Session;
+
+/// Represents a PKCS#11 ECDH public key
+class BOTAN_DLL PKCS11_ECDH_PublicKey final : public PKCS11_EC_PublicKey
+ {
+ public:
+ /**
+ * Create a PKCS11_ECDH_PublicKey object from an existing PKCS#11 ECDH public key
+ * @param session the session to use
+ * @param handle the handle of the ECDH public key
+ */
+ PKCS11_ECDH_PublicKey(Session& session, ObjectHandle handle)
+ : EC_PublicKey(), PKCS11_EC_PublicKey(session, handle)
+ {}
+
+ /**
+ * Imports a ECDH public key
+ * @param session the session to use
+ * @param props the attributes of the public key
+ */
+ PKCS11_ECDH_PublicKey(Session& session, const EC_PublicKeyImportProperties& props)
+ : EC_PublicKey(), PKCS11_EC_PublicKey(session, props)
+ {}
+
+ inline std::string algo_name() const override
+ {
+ return "ECDH";
+ }
+
+ /// @return the exported ECDH public key
+ ECDH_PublicKey export_key() const;
+ };
+
+/// Represents a PKCS#11 ECDH private key
+class BOTAN_DLL PKCS11_ECDH_PrivateKey final : public virtual PKCS11_EC_PrivateKey, public virtual PK_Key_Agreement_Key
+ {
+ public:
+ /**
+ * Creates a PKCS11_ECDH_PrivateKey object from an existing PKCS#11 ECDH private key
+ * @param session the session to use
+ * @param handle the handle of the ECDH private key
+ */
+ PKCS11_ECDH_PrivateKey(Session& session, ObjectHandle handle)
+ : PKCS11_EC_PrivateKey(session, handle)
+ {}
+
+ /**
+ * Imports an ECDH private key
+ * @param session the session to use
+ * @param props the attributes of the private key
+ */
+ PKCS11_ECDH_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props)
+ : PKCS11_EC_PrivateKey(session, props)
+ {}
+
+ /**
+ * Generates a PKCS#11 ECDH private key
+ * @param session the session to use
+ * @param ec_params DER-encoding of an ANSI X9.62 Parameters value
+ * @param props the attributes of the private key
+ * @note no persistent public key object will be created
+ */
+ PKCS11_ECDH_PrivateKey(Session& session, const std::vector<byte>& ec_params,
+ const EC_PrivateKeyGenerationProperties& props)
+ : PKCS11_EC_PrivateKey(session, ec_params, props)
+ {}
+
+ inline std::string algo_name() const override
+ {
+ return "ECDH";
+ }
+
+ inline std::vector<byte> public_value() const override
+ {
+ return unlock(EC2OSP(public_point(), PointGFp::UNCOMPRESSED));
+ }
+
+ /// @return the exported ECDH private key
+ ECDH_PrivateKey export_key() const;
+
+ secure_vector<byte> pkcs8_private_key() const override;
+ };
+
+using PKCS11_ECDH_KeyPair = std::pair<PKCS11_ECDH_PublicKey, PKCS11_ECDH_PrivateKey>;
+
+/**
+* PKCS#11 ECDH key pair generation
+* @param session the session that should be used for the key generation
+* @param pub_props the properties of the public key
+* @param priv_props the properties of the private key
+*/
+BOTAN_DLL PKCS11_ECDH_KeyPair generate_ecdh_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props,
+ const EC_PrivateKeyGenerationProperties& priv_props);
+}
+
+}
+
+#endif
+#endif
diff --git a/src/lib/prov/pkcs11/p11_ecdsa.cpp b/src/lib/prov/pkcs11/p11_ecdsa.cpp
new file mode 100644
index 000000000..078bc429d
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_ecdsa.cpp
@@ -0,0 +1,229 @@
+/*
+* PKCS#11 ECDSA
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_ecdsa.h>
+
+#if defined(BOTAN_HAS_ECDSA)
+
+#include <botan/internal/p11_mechanism.h>
+#include <botan/internal/algo_registry.h>
+#include <botan/internal/pk_utils.h>
+#include <botan/keypair.h>
+#include <botan/rng.h>
+
+namespace Botan {
+namespace PKCS11 {
+
+ECDSA_PublicKey PKCS11_ECDSA_PublicKey::export_key() const
+ {
+ return ECDSA_PublicKey(domain(), public_point());
+ }
+
+bool PKCS11_ECDSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const
+ {
+ if(!public_point().on_the_curve())
+ {
+ return false;
+ }
+
+
+ if(!strong)
+ {
+ return true;
+ }
+
+ return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)");
+ }
+
+ECDSA_PrivateKey PKCS11_ECDSA_PrivateKey::export_key() const
+ {
+ auto priv_key = get_attribute_value(AttributeType::Value);
+
+ Null_RNG rng;
+ return ECDSA_PrivateKey(rng, domain(), BigInt::decode(priv_key));
+ }
+
+secure_vector<byte> PKCS11_ECDSA_PrivateKey::pkcs8_private_key() const
+ {
+ return export_key().pkcs8_private_key();
+ }
+
+namespace {
+
+class PKCS11_ECDSA_Signature_Operation : public PK_Ops::Signature
+ {
+ public:
+ typedef PKCS11_EC_PrivateKey Key_Type;
+
+ PKCS11_ECDSA_Signature_Operation(const PKCS11_EC_PrivateKey& key, const std::string& emsa)
+ : PK_Ops::Signature(), m_key(key), m_order(key.domain().get_order()), m_mechanism(MechanismWrapper::create_ecdsa_mechanism(emsa))
+ {}
+
+ size_t message_parts() const override
+ {
+ return 2;
+ }
+
+ size_t message_part_size() const override
+ {
+ return m_order.bytes();
+ }
+
+ void update(const byte msg[], size_t msg_len) override
+ {
+ if(!m_initialized)
+ {
+ // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed
+ m_key.module()->C_SignInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
+ m_initialized = true;
+ m_first_message = secure_vector<byte>(msg, msg + msg_len);
+ return;
+ }
+
+ if(!m_first_message.empty())
+ {
+ // second call to update: start multiple-part operation
+ m_key.module()->C_SignUpdate(m_key.session().handle(), m_first_message);
+ m_first_message.clear();
+ }
+
+ m_key.module()->C_SignUpdate(m_key.session().handle(), const_cast<Byte*>(msg), msg_len);
+ }
+
+ secure_vector<byte> sign(RandomNumberGenerator&) override
+ {
+ secure_vector<byte> signature;
+ if(!m_first_message.empty())
+ {
+ // single call to update: perform single-part operation
+ m_key.module()->C_Sign(m_key.session().handle(), m_first_message, signature);
+ m_first_message.clear();
+ }
+ else
+ {
+ // multiple calls to update (or none): finish multiple-part operation
+ m_key.module()->C_SignFinal(m_key.session().handle(), signature);
+ }
+ m_initialized = false;
+ return signature;
+ }
+
+ private:
+ const PKCS11_EC_PrivateKey& m_key;
+ const BigInt& m_order;
+ MechanismWrapper m_mechanism;
+ secure_vector<byte> m_first_message;
+ bool m_initialized = false;
+ };
+
+
+class PKCS11_ECDSA_Verification_Operation : public PK_Ops::Verification
+ {
+ public:
+ typedef PKCS11_EC_PublicKey Key_Type;
+
+ PKCS11_ECDSA_Verification_Operation(const PKCS11_EC_PublicKey& key, const std::string& emsa)
+ : PK_Ops::Verification(), m_key(key), m_order(key.domain().get_order()), m_mechanism(MechanismWrapper::create_ecdsa_mechanism(emsa))
+ {}
+
+ size_t message_parts() const override
+ {
+ return 2;
+ }
+
+ size_t message_part_size() const override
+ {
+ return m_order.bytes();
+ }
+
+ size_t max_input_bits() const override
+ {
+ return m_order.bits();
+ }
+
+ void update(const byte msg[], size_t msg_len) override
+ {
+ if(!m_initialized)
+ {
+ // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed
+ m_key.module()->C_VerifyInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
+ m_initialized = true;
+ m_first_message = secure_vector<byte>(msg, msg + msg_len);
+ return;
+ }
+
+ if(!m_first_message.empty())
+ {
+ // second call to update: start multiple-part operation
+ m_key.module()->C_VerifyUpdate(m_key.session().handle(), m_first_message);
+ m_first_message.clear();
+ }
+
+ m_key.module()->C_VerifyUpdate(m_key.session().handle(), const_cast<Byte*>(msg), msg_len);
+ }
+
+ bool is_valid_signature(const byte sig[], size_t sig_len) override
+ {
+ ReturnValue return_value = ReturnValue::SignatureInvalid;
+ if(!m_first_message.empty())
+ {
+ // single call to update: perform single-part operation
+ m_key.module()->C_Verify(m_key.session().handle(), m_first_message.data(), m_first_message.size(),
+ const_cast<Byte*>(sig), sig_len, &return_value);
+ m_first_message.clear();
+ }
+ else
+ {
+ // multiple calls to update (or none): finish multiple-part operation
+ m_key.module()->C_VerifyFinal(m_key.session().handle(), const_cast<Byte*>(sig), sig_len, &return_value);
+ }
+ m_initialized = false;
+ if(return_value != ReturnValue::OK && return_value != ReturnValue::SignatureInvalid)
+ {
+ throw PKCS11_ReturnError(return_value);
+ }
+ return return_value == ReturnValue::OK;
+ }
+
+ private:
+ const PKCS11_EC_PublicKey& m_key;
+ const BigInt& m_order;
+ MechanismWrapper m_mechanism;
+ secure_vector<byte> m_first_message;
+ bool m_initialized = false;
+ };
+
+BOTAN_REGISTER_TYPE(PK_Ops::Signature, PKCS11_ECDSA_Signature_Operation, "ECDSA",
+ (make_pk_op<PK_Ops::Signature, PKCS11_ECDSA_Signature_Operation>), "pkcs11", BOTAN_PKCS11_ECDSA_PRIO);
+
+BOTAN_REGISTER_TYPE(PK_Ops::Verification, PKCS11_ECDSA_Verification_Operation, "ECDSA",
+ (make_pk_op<PK_Ops::Verification, PKCS11_ECDSA_Verification_Operation>), "pkcs11", BOTAN_PKCS11_ECDSA_PRIO);
+
+}
+
+PKCS11_ECDSA_KeyPair generate_ecdsa_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props,
+ const EC_PrivateKeyGenerationProperties& priv_props)
+ {
+ ObjectHandle pub_key_handle = 0;
+ ObjectHandle priv_key_handle = 0;
+
+ Mechanism mechanism = { static_cast<CK_MECHANISM_TYPE>(MechanismType::EcKeyPairGen), nullptr, 0 };
+
+ session.module()->C_GenerateKeyPair(session.handle(), &mechanism,
+ pub_props.data(), pub_props.count(), priv_props.data(), priv_props.count(),
+ &pub_key_handle, &priv_key_handle);
+
+ return std::make_pair(PKCS11_ECDSA_PublicKey(session, pub_key_handle), PKCS11_ECDSA_PrivateKey(session,
+ priv_key_handle));
+ }
+
+}
+
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_ecdsa.h b/src/lib/prov/pkcs11/p11_ecdsa.h
new file mode 100644
index 000000000..d3d07a780
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_ecdsa.h
@@ -0,0 +1,127 @@
+/*
+* PKCS#11 ECDSA
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_ECDSA_H__
+#define BOTAN_P11_ECDSA_H__
+
+#include <botan/build.h>
+#if defined(BOTAN_HAS_ECDSA)
+
+#include <botan/p11_ecc_key.h>
+#include <botan/ecdsa.h>
+
+#include <string>
+
+namespace Botan {
+namespace PKCS11 {
+class Session;
+
+/// Represents a PKCS#11 ECDSA public key
+class BOTAN_DLL PKCS11_ECDSA_PublicKey final : public PKCS11_EC_PublicKey, public virtual ECDSA_PublicKey
+ {
+ public:
+ /**
+ * Creates a PKCS11_ECDSA_PublicKey object from an existing PKCS#11 ECDSA public key
+ * @param session the session to use
+ * @param handle the handle of the ECDSA public key
+ */
+ PKCS11_ECDSA_PublicKey(Session& session, ObjectHandle handle)
+ : EC_PublicKey(), PKCS11_EC_PublicKey(session, handle)
+ {}
+
+ /**
+ * Imports an ECDSA public key
+ * @param session the session to use
+ * @param props the attributes of the public key
+ */
+ PKCS11_ECDSA_PublicKey(Session& session, const EC_PublicKeyImportProperties& props)
+ : EC_PublicKey(), PKCS11_EC_PublicKey(session, props)
+ {}
+
+ inline std::string algo_name() const override
+ {
+ return "ECDSA";
+ }
+
+ inline std::size_t max_input_bits() const override
+ {
+ return domain().get_order().bits();
+ }
+
+ /// @return the exported ECDSA public key
+ ECDSA_PublicKey export_key() const;
+ };
+
+/// Represents a PKCS#11 ECDSA private key
+class BOTAN_DLL PKCS11_ECDSA_PrivateKey final : public PKCS11_EC_PrivateKey
+ {
+ public:
+ /**
+ * Creates a PKCS11_ECDSA_PrivateKey object from an existing PKCS#11 ECDSA private key
+ * @param session the session to use
+ * @param handle the handle of the ECDSA private key
+ */
+ PKCS11_ECDSA_PrivateKey(Session& session, ObjectHandle handle)
+ : PKCS11_EC_PrivateKey(session, handle)
+ {}
+
+ /**
+ * Imports a ECDSA private key
+ * @param session the session to use
+ * @param props the attributes of the private key
+ */
+ PKCS11_ECDSA_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props)
+ : PKCS11_EC_PrivateKey(session, props)
+ {}
+
+ /**
+ * Generates a PKCS#11 ECDSA private key
+ * @param session the session to use
+ * @param ec_params DER-encoding of an ANSI X9.62 Parameters value
+ * @param props the attributes of the private key
+ * @note no persistent public key object will be created
+ */
+ PKCS11_ECDSA_PrivateKey(Session& session, const std::vector<byte>& ec_params,
+ const EC_PrivateKeyGenerationProperties& props)
+ : PKCS11_EC_PrivateKey(session, ec_params, props)
+ {}
+
+ inline std::string algo_name() const override
+ {
+ return "ECDSA";
+ }
+
+ inline size_t message_parts() const override
+ {
+ return 2;
+ }
+
+ /// @return the exported ECDSA private key
+ ECDSA_PrivateKey export_key() const;
+
+ secure_vector<byte> pkcs8_private_key() const override;
+
+ bool check_key(RandomNumberGenerator&, bool) const override;
+ };
+
+using PKCS11_ECDSA_KeyPair = std::pair<PKCS11_ECDSA_PublicKey, PKCS11_ECDSA_PrivateKey>;
+
+/**
+* ECDSA key pair generation
+* @param session the session that should be used for the key generation
+* @param pub_props the properties of the public key
+* @param priv_props the properties of the private key
+*/
+BOTAN_DLL PKCS11_ECDSA_KeyPair generate_ecdsa_keypair(Session& session,
+ const EC_PublicKeyGenerationProperties& pub_props, const EC_PrivateKeyGenerationProperties& priv_props);
+}
+
+}
+
+#endif
+#endif
diff --git a/src/lib/prov/pkcs11/p11_mechanism.cpp b/src/lib/prov/pkcs11/p11_mechanism.cpp
new file mode 100644
index 000000000..07ac00770
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_mechanism.cpp
@@ -0,0 +1,250 @@
+/*
+* PKCS#11 Mechanism
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/internal/p11_mechanism.h>
+#include <botan/scan_name.h>
+#include <botan/emsa.h>
+
+#include <tuple>
+
+namespace Botan {
+namespace PKCS11 {
+
+namespace {
+using PSS_Params = std::tuple<size_t, MechanismType, MGF>;
+
+// maps a PSS mechanism type to the number of bytes used for the salt, the mechanism type of the underlying hash algorithm and the MGF
+static const std::map<MechanismType, PSS_Params> PssOptions =
+ {
+ { MechanismType::RsaPkcsPss, PSS_Params(0, MechanismType::Sha1, MGF::Mgf1Sha1) },
+ { MechanismType::Sha1RsaPkcsPss, PSS_Params(20, MechanismType::Sha1, MGF::Mgf1Sha1) },
+ { MechanismType::Sha224RsaPkcsPss, PSS_Params(28, MechanismType::Sha224, MGF::Mgf1Sha224) },
+ { MechanismType::Sha256RsaPkcsPss, PSS_Params(32, MechanismType::Sha256, MGF::Mgf1Sha256) },
+ { MechanismType::Sha384RsaPkcsPss, PSS_Params(48, MechanismType::Sha384, MGF::Mgf1Sha384) },
+ { MechanismType::Sha512RsaPkcsPss, PSS_Params(64, MechanismType::Sha512, MGF::Mgf1Sha512) }
+ };
+
+struct MechanismData
+ {
+ explicit MechanismData(MechanismType _type)
+ : type(_type)
+ {}
+
+ virtual ~MechanismData() = default;
+
+ // the mechanism to perform
+ MechanismType type;
+ };
+
+struct RSA_SignMechanism : public MechanismData
+ {
+ explicit RSA_SignMechanism(MechanismType _type)
+ : MechanismData(_type), hash(static_cast<MechanismType>(0)), mgf(static_cast<MGF>(0)), salt_size(0)
+ {
+ auto pss_option = PssOptions.find(type);
+ if(pss_option != PssOptions.end())
+ {
+ hash = std::get<1>(pss_option->second);
+ mgf = std::get<2>(pss_option->second);
+ salt_size = std::get<0>(pss_option->second);
+ }
+ }
+
+ // hash algorithm used in the PSS encoding; if the signature mechanism does not include message hashing,
+ // then this value must be the mechanism used by the application to generate the message hash;
+ // if the signature mechanism includes hashing, then this value must match the hash algorithm indicated by the signature mechanism
+ MechanismType hash;
+
+ // mask generation function to use on the encoded block
+ MGF mgf;
+
+ // length, in bytes, of the salt value used in the PSS encoding; typical values are the length of the message hash and zero
+ size_t salt_size;
+ };
+
+// note: when updating this map, update the documentation for `MechanismWrapper::create_rsa_sign_mechanism`
+static std::map<std::string, RSA_SignMechanism> SignMechanisms =
+ {
+ { "Raw", RSA_SignMechanism(MechanismType::RsaX509) },
+
+ { "EMSA2(Raw)", RSA_SignMechanism(MechanismType::RsaX931) },
+ { "EMSA2(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaX931) },
+
+ // RSASSA PKCS#1 v1.5
+ { "EMSA3(Raw)", RSA_SignMechanism(MechanismType::RsaPkcs) },
+ { "EMSA3(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaPkcs) },
+ { "EMSA3(SHA-224)", RSA_SignMechanism(MechanismType::Sha224RsaPkcs) },
+ { "EMSA3(SHA-256)", RSA_SignMechanism(MechanismType::Sha256RsaPkcs) },
+ { "EMSA3(SHA-384)", RSA_SignMechanism(MechanismType::Sha384RsaPkcs) },
+ { "EMSA3(SHA-512)", RSA_SignMechanism(MechanismType::Sha512RsaPkcs) },
+
+ // RSASSA PKCS#1 PSS
+ { "EMSA4(Raw)", RSA_SignMechanism(MechanismType::RsaPkcsPss) },
+ { "EMSA4(SHA-1)", RSA_SignMechanism(MechanismType::Sha1RsaPkcsPss) },
+ { "EMSA4(SHA-224)", RSA_SignMechanism(MechanismType::Sha224RsaPkcsPss) },
+ { "EMSA4(SHA-256)", RSA_SignMechanism(MechanismType::Sha256RsaPkcsPss) },
+ { "EMSA4(SHA-384)", RSA_SignMechanism(MechanismType::Sha384RsaPkcsPss) },
+ { "EMSA4(SHA-512)", RSA_SignMechanism(MechanismType::Sha512RsaPkcsPss) },
+
+ { "ISO9796", RSA_SignMechanism(MechanismType::Rsa9796) }
+ };
+
+struct RSA_CryptMechanism : public MechanismData
+ {
+ RSA_CryptMechanism(MechanismType _type, size_t _padding_size, MechanismType _hash, MGF _mgf)
+ : MechanismData(_type), hash(_hash), mgf(_mgf), padding_size(_padding_size)
+ {}
+
+ RSA_CryptMechanism(MechanismType _type, size_t _padding_size)
+ : RSA_CryptMechanism(_type, _padding_size, static_cast<MechanismType>(0), static_cast<MGF>(0))
+ {}
+
+ // mechanism ID of the message digest algorithm used to calculate the digest of the encoding parameter
+ MechanismType hash;
+
+ // mask generation function to use on the encoded block
+ MGF mgf;
+
+ // number of bytes required for the padding
+ size_t padding_size;
+ };
+
+// note: when updating this map, update the documentation for `MechanismWrapper::create_rsa_crypt_mechanism`
+static const std::map<std::string, RSA_CryptMechanism> CryptMechanisms =
+ {
+ { "Raw", RSA_CryptMechanism(MechanismType::RsaX509, 0) },
+ { "EME-PKCS1-v1_5", RSA_CryptMechanism(MechanismType::RsaPkcs, 11) },
+ { "OAEP(SHA-1)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 20, MechanismType::Sha1, MGF::Mgf1Sha1) },
+ { "OAEP(SHA-224)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 28, MechanismType::Sha224, MGF::Mgf1Sha224) },
+ { "OAEP(SHA-256)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 32, MechanismType::Sha256, MGF::Mgf1Sha256) },
+ { "OAEP(SHA-384)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 48, MechanismType::Sha384, MGF::Mgf1Sha384) },
+ { "OAEP(SHA-512)", RSA_CryptMechanism(MechanismType::RsaPkcsOaep, 2 + 2 * 64, MechanismType::Sha512, MGF::Mgf1Sha512) }
+ };
+
+// note: when updating this map, update the documentation for `MechanismWrapper::create_ecdsa_mechanism`
+static std::map<std::string, MechanismType> EcdsaHash =
+ {
+ { "Raw", MechanismType::Ecdsa },
+ { "SHA-160", MechanismType::EcdsaSha1 },
+ { "SHA-224", MechanismType::EcdsaSha224 },
+ { "SHA-256", MechanismType::EcdsaSha256 },
+ { "SHA-384", MechanismType::EcdsaSha384 },
+ { "SHA-512", MechanismType::EcdsaSha512 }
+ };
+
+// note: when updating this map, update the documentation for `MechanismWrapper::create_ecdh_mechanism`
+static std::map<std::string, KeyDerivation> EcdhHash =
+ {
+ { "Raw", KeyDerivation::Null },
+ { "SHA-160", KeyDerivation::Sha1Kdf },
+ { "SHA-224", KeyDerivation::Sha224Kdf },
+ { "SHA-256", KeyDerivation::Sha256Kdf },
+ { "SHA-384", KeyDerivation::Sha384Kdf },
+ { "SHA-512", KeyDerivation::Sha512Kdf }
+ };
+}
+
+MechanismWrapper::MechanismWrapper(MechanismType mechanism_type)
+ : m_mechanism( { static_cast<CK_MECHANISM_TYPE>(mechanism_type), nullptr, 0 }), m_parameters(nullptr)
+ {}
+
+MechanismWrapper MechanismWrapper::create_rsa_crypt_mechanism(const std::string& padding)
+ {
+ auto mechanism_info_it = CryptMechanisms.find(padding);
+ if(mechanism_info_it == CryptMechanisms.end())
+ {
+ // at this point it would be possible to support additional configurations that are not predefined above by parsing `padding`
+ throw Lookup_Error("PKCS#11 RSA encrypt/decrypt does not support EME " + padding);
+ }
+ RSA_CryptMechanism mechanism_info = mechanism_info_it->second;
+
+ MechanismWrapper mech(mechanism_info.type);
+ if(mechanism_info.type == MechanismType::RsaPkcsOaep)
+ {
+ mech.m_parameters = std::make_shared<MechanismParameters>();
+ mech.m_parameters->oaep_params.hashAlg = static_cast<CK_MECHANISM_TYPE>(mechanism_info.hash);
+ mech.m_parameters->oaep_params.mgf = static_cast<CK_RSA_PKCS_MGF_TYPE>(mechanism_info.mgf);
+ mech.m_parameters->oaep_params.source = CKZ_DATA_SPECIFIED;
+ mech.m_parameters->oaep_params.pSourceData = nullptr;
+ mech.m_parameters->oaep_params.ulSourceDataLen = 0;
+ mech.m_mechanism.pParameter = mech.m_parameters.get();
+ mech.m_mechanism.ulParameterLen = sizeof(RsaPkcsOaepParams);
+ }
+ mech.m_padding_size = mechanism_info.padding_size;
+ return mech;
+ }
+
+MechanismWrapper MechanismWrapper::create_rsa_sign_mechanism(const std::string& padding)
+ {
+ auto mechanism_info_it = SignMechanisms.find(padding);
+ if(mechanism_info_it == SignMechanisms.end())
+ {
+ // at this point it would be possible to support additional configurations that are not predefined above by parsing `padding`
+ throw Lookup_Error("PKCS#11 RSA sign/verify does not support EMSA " + padding);
+ }
+ RSA_SignMechanism mechanism_info = mechanism_info_it->second;
+
+ MechanismWrapper mech(mechanism_info.type);
+ if(PssOptions.find(mechanism_info.type) != PssOptions.end())
+ {
+ mech.m_parameters = std::make_shared<MechanismParameters>();
+ mech.m_parameters->pss_params.hashAlg = static_cast<CK_MECHANISM_TYPE>(mechanism_info.hash);
+ mech.m_parameters->pss_params.mgf = static_cast<CK_RSA_PKCS_MGF_TYPE>(mechanism_info.mgf);
+ mech.m_parameters->pss_params.sLen = mechanism_info.salt_size;
+ mech.m_mechanism.pParameter = mech.m_parameters.get();
+ mech.m_mechanism.ulParameterLen = sizeof(RsaPkcsPssParams);
+ }
+ return mech;
+ }
+
+MechanismWrapper MechanismWrapper::create_ecdsa_mechanism(const std::string& hash)
+ {
+ std::string hash_name = hash;
+
+ if(hash_name != "Raw")
+ {
+ hash_name = hash_for_emsa(hash);
+ }
+
+ auto mechanism_type = EcdsaHash.find(hash_name);
+ if(mechanism_type == EcdsaHash.end())
+ {
+ throw Lookup_Error("PKCS#11 ECDSA sign/verify does not support " + hash);
+ }
+ return MechanismWrapper(mechanism_type->second);
+ }
+
+MechanismWrapper MechanismWrapper::create_ecdh_mechanism(const std::string& kdf_name, bool use_cofactor)
+ {
+ std::string hash = kdf_name;
+
+ if(kdf_name != "Raw")
+ {
+ SCAN_Name kdf_hash(kdf_name);
+
+ if(kdf_hash.arg_count() > 0)
+ {
+ hash = kdf_hash.arg(0);
+ }
+ }
+
+ auto kdf = EcdhHash.find(hash);
+ if(kdf == EcdhHash.end())
+ {
+ throw Lookup_Error("PKCS#11 ECDH key derivation does not support KDF " + kdf_name);
+ }
+ MechanismWrapper mech(use_cofactor ? MechanismType::Ecdh1CofactorDerive : MechanismType::Ecdh1Derive);
+ mech.m_parameters = std::make_shared<MechanismParameters>();
+ mech.m_parameters->ecdh_params.kdf = static_cast<CK_EC_KDF_TYPE>(kdf->second);
+ mech.m_mechanism.pParameter = mech.m_parameters.get();
+ mech.m_mechanism.ulParameterLen = sizeof(Ecdh1DeriveParams);
+ return mech;
+ }
+
+}
+}
diff --git a/src/lib/prov/pkcs11/p11_mechanism.h b/src/lib/prov/pkcs11/p11_mechanism.h
new file mode 100644
index 000000000..5d8c826ee
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_mechanism.h
@@ -0,0 +1,108 @@
+/*
+* PKCS#11 Mechanism
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_MECHANISM_H__
+#define BOTAN_P11_MECHANISM_H__
+
+#include <botan/p11.h>
+
+#include <utility>
+#include <string>
+#include <memory>
+
+namespace Botan {
+namespace PKCS11 {
+
+/**
+* Simple class to build and hold the data for a CK_MECHANISM struct
+* for RSA (encryption/decryption, signature/verification)
+* and EC (ecdsa signature/verification, ecdh key derivation)
+*/
+class MechanismWrapper final
+ {
+ public:
+ /// @param mechanism_type the CK_MECHANISM_TYPE for the `mechanism` field of the CK_MECHANISM struct
+ explicit MechanismWrapper(MechanismType mechanism_type);
+
+ /**
+ * Creates the CK_MECHANISM data for RSA encryption/decryption
+ * @param padding supported paddings are Raw (X.509), EME-PKCS1-v1_5 (PKCS#1 v1.5) and OAEP (PKCS#1 OAEP)
+ */
+ static MechanismWrapper create_rsa_crypt_mechanism(const std::string& padding);
+
+ /**
+ * Creates the CK_MECHANISM data for RSA signature/verification
+ * @param padding supported paddings are Raw (X.509), EMSA3 (PKCS#1 v1.5), EMSA4 (PKCS#1 PSS),
+ * EMSA2 (ANSI X9.31) and ISO9796 (ISO/IEC 9796)
+ */
+ static MechanismWrapper create_rsa_sign_mechanism(const std::string& padding);
+
+ /**
+ * Creates the CK_MECHANISM data for ECDSA signature/verification
+ * @param hash the hash algorithm used to hash the data to sign.
+ * supported hash functions are Raw and SHA-160 to SHA-512
+ */
+ static MechanismWrapper create_ecdsa_mechanism(const std::string& hash);
+
+ /**
+ * Creates the CK_MECHANISM data for ECDH key derivation (CKM_ECDH1_DERIVE or CKM_ECDH1_COFACTOR_DERIVE)
+ * @param kdf_name the key derivation function to use. Supported KDFs are Raw and SHA-160 to SHA-512
+ * @param use_cofactor true if the cofactor key derivation mechanism should be used
+ */
+ static MechanismWrapper create_ecdh_mechanism(const std::string& kdf_name, bool use_cofactor);
+
+ /// Sets the salt for the ECDH mechanism parameters
+ inline void set_ecdh_salt(const byte salt[], size_t salt_len)
+ {
+ m_parameters->ecdh_params.pSharedData = const_cast<byte*>(salt);
+ m_parameters->ecdh_params.ulSharedDataLen = salt_len;
+ }
+
+ /// Sets the public key of the other party for the ECDH mechanism parameters
+ inline void set_ecdh_other_key(const byte other_key[], size_t other_key_len)
+ {
+ m_parameters->ecdh_params.pPublicData = const_cast<byte*>(other_key);
+ m_parameters->ecdh_params.ulPublicDataLen = other_key_len;
+ }
+
+ /// @return a pointer to the CK_MECHANISM struct that can be passed to the cryptoki functions
+ inline Mechanism* data() const
+ {
+ return const_cast<Mechanism*>(&m_mechanism);
+ }
+
+ /// @return the size of the padding in bytes (for encryption/decryption)
+ inline size_t padding_size() const
+ {
+ return m_padding_size;
+ }
+
+ /// Holds the mechanism parameters for OEAP, PSS and ECDH
+ union MechanismParameters
+ {
+ MechanismParameters()
+ {
+ std::memset(this, 0, sizeof(MechanismParameters));
+ }
+
+ RsaPkcsOaepParams oaep_params;
+ RsaPkcsPssParams pss_params;
+ Ecdh1DeriveParams ecdh_params;
+ };
+
+ private:
+ Mechanism m_mechanism;
+ std::shared_ptr<MechanismParameters> m_parameters;
+ size_t m_padding_size = 0;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_module.cpp b/src/lib/prov/pkcs11/p11_module.cpp
new file mode 100644
index 000000000..4ea3dc56d
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_module.cpp
@@ -0,0 +1,41 @@
+/*
+* PKCS#11 Module
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_module.h>
+
+namespace Botan {
+
+namespace PKCS11 {
+
+Module::Module(const std::string& file_path, C_InitializeArgs init_args)
+ : m_file_path(file_path)
+ {
+ reload(init_args);
+ }
+
+Module::~Module() BOTAN_NOEXCEPT
+ {
+ m_low_level->C_Finalize(nullptr, nullptr);
+ }
+
+void Module::reload(C_InitializeArgs init_args)
+ {
+ if(m_low_level)
+ {
+ m_low_level->C_Finalize(nullptr);
+ }
+
+ m_library.reset(new Dynamically_Loaded_Library(m_file_path));
+ LowLevel::C_GetFunctionList(*m_library, &m_func_list);
+ m_low_level.reset(new LowLevel(m_func_list));
+
+ m_low_level->C_Initialize(&init_args);
+ }
+
+}
+}
diff --git a/src/lib/prov/pkcs11/p11_module.h b/src/lib/prov/pkcs11/p11_module.h
new file mode 100644
index 000000000..990458a4d
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_module.h
@@ -0,0 +1,79 @@
+/*
+* PKCS#11 Module
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_MODULE_H__
+#define BOTAN_P11_MODULE_H__
+
+#include <string>
+#include <memory>
+
+#include <botan/p11.h>
+#include <botan/dyn_load.h>
+
+namespace Botan {
+namespace PKCS11 {
+
+/**
+* Loads the PKCS#11 shared library
+* Calls C_Initialize on load and C_Finalize on destruction
+*/
+class BOTAN_DLL Module final
+ {
+ public:
+ /**
+ * Loads the shared library and calls C_Initialize
+ * @param file_path the path to the PKCS#11 shared library
+ * @param init_args flags to use for `C_Initialize`
+ */
+ Module(const std::string& file_path, C_InitializeArgs init_args = { nullptr, nullptr, nullptr, nullptr, static_cast< CK_FLAGS >(Flag::OsLockingOk), nullptr });
+
+/* Microsoft Visual Studio <= 2013 does not support default generated move special member functions.
+ Everything else we target should support it */
+#if !defined( _MSC_VER ) || ( _MSC_VER >= 1900 )
+ Module(Module&& other) = default;
+ Module& operator=(Module&& other) = default;
+#endif
+
+ // Dtor calls C_Finalize(). A copy could be deleted while the origin still exists
+ // Furthermore std::unique_ptr member -> not copyable
+ Module(const Module& other) = delete;
+ Module& operator=(const Module& other) = delete;
+
+ /// Calls C_Finalize()
+ ~Module() BOTAN_NOEXCEPT;
+
+ /**
+ * Reloads the module and reinitializes it
+ * @param init_args flags to use for `C_Initialize`
+ */
+ void reload(C_InitializeArgs init_args = { nullptr, nullptr, nullptr, nullptr, static_cast< CK_FLAGS >(Flag::OsLockingOk), nullptr });
+
+ inline LowLevel* operator->() const
+ {
+ return m_low_level.get();
+ }
+
+ /// @return general information about Cryptoki
+ inline Info get_info() const
+ {
+ Info info;
+ m_low_level->C_GetInfo(&info);
+ return info;
+ }
+
+ private:
+ const std::string m_file_path;
+ FunctionListPtr m_func_list = nullptr;
+ std::unique_ptr<Dynamically_Loaded_Library> m_library = nullptr;
+ std::unique_ptr<LowLevel> m_low_level = nullptr;
+ };
+
+}
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_object.cpp b/src/lib/prov/pkcs11/p11_object.cpp
new file mode 100644
index 000000000..ef7477284
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_object.cpp
@@ -0,0 +1,217 @@
+/*
+* PKCS#11 Object
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_object.h>
+
+#include <map>
+
+namespace Botan {
+
+namespace PKCS11 {
+
+AttributeContainer::AttributeContainer(ObjectClass object_class)
+ {
+ add_class(object_class);
+ }
+
+void AttributeContainer::add_class(ObjectClass object_class)
+ {
+ m_numerics.push_back(static_cast< uint64_t >(object_class));
+ add_attribute(AttributeType::Class, reinterpret_cast< byte* >(&m_numerics.back()), sizeof(ObjectClass));
+ }
+
+void AttributeContainer::add_string(AttributeType attribute, const std::string& value)
+ {
+ m_strings.push_back(value);
+ add_attribute(attribute, reinterpret_cast< const byte* >(m_strings.back().data()), value.size());
+ }
+
+void AttributeContainer::add_binary(AttributeType attribute, const byte* value, size_t length)
+ {
+ m_vectors.push_back(secure_vector<byte>(value, value + length));
+ add_attribute(attribute, reinterpret_cast< const byte* >(m_vectors.back().data()), length);
+ }
+
+void AttributeContainer::add_bool(AttributeType attribute, bool value)
+ {
+ m_numerics.push_back(value ? True : False);
+ add_attribute(attribute, reinterpret_cast< byte* >(&m_numerics.back()), sizeof(Bbool));
+ }
+
+void AttributeContainer::add_attribute(AttributeType attribute, const byte* value, uint32_t size)
+ {
+ bool exists = false;
+ // check if the attribute has been added already
+ for(auto& existing_attribute : m_attributes)
+ {
+ if(existing_attribute.type == static_cast< CK_ATTRIBUTE_TYPE >(attribute))
+ {
+ // remove old entries
+ m_strings.erase(std::remove_if(m_strings.begin(), m_strings.end(), [ &existing_attribute ](const std::string& data)
+ {
+ return data.data() == existing_attribute.pValue;
+ }), m_strings.end());
+
+ m_numerics.erase(std::remove_if(m_numerics.begin(), m_numerics.end(), [ &existing_attribute ](const uint64_t& data)
+ {
+ return &data == existing_attribute.pValue;
+ }), m_numerics.end());
+
+ m_vectors.erase(std::remove_if(m_vectors.begin(),
+ m_vectors.end(), [ &existing_attribute ](const secure_vector<byte>& data)
+ {
+ return data.data() == existing_attribute.pValue;
+ }), m_vectors.end());
+
+ existing_attribute.pValue = const_cast< byte* >(value);
+ existing_attribute.ulValueLen = size;
+ exists = true;
+ break;
+ }
+ }
+
+ if(!exists)
+ {
+ m_attributes.push_back(Attribute{ static_cast< CK_ATTRIBUTE_TYPE >(attribute), const_cast< byte* >(value), size });
+ }
+ }
+
+// ====================================================================================================
+
+ObjectFinder::ObjectFinder(Session& session, const std::vector<Attribute>& search_template)
+ : m_session(session), m_search_terminated(false)
+ {
+ module()->C_FindObjectsInit(m_session.get().handle(), const_cast< Attribute* >(search_template.data()),
+ search_template.size());
+ }
+
+ObjectFinder::~ObjectFinder() BOTAN_NOEXCEPT
+ {
+ if(m_search_terminated == false)
+ {
+ module()->C_FindObjectsFinal(m_session.get().handle(), nullptr);
+ }
+ }
+
+std::vector<ObjectHandle> ObjectFinder::find(uint32_t max_count) const
+ {
+ std::vector<ObjectHandle> result(max_count);
+ Ulong objectCount = 0;
+ module()->C_FindObjects(m_session.get().handle(), result.data(), max_count, &objectCount);
+ if(objectCount < max_count)
+ {
+ result.resize(objectCount);
+ }
+ return result;
+ }
+
+void ObjectFinder::finish()
+ {
+ module()->C_FindObjectsFinal(m_session.get().handle());
+ m_search_terminated = true;
+ }
+
+// ====================================================================================================
+
+ObjectProperties::ObjectProperties(ObjectClass object_class)
+ : AttributeContainer(object_class), m_object_class(object_class)
+ {}
+
+// ====================================================================================================
+
+StorageObjectProperties::StorageObjectProperties(ObjectClass object_class)
+ : ObjectProperties(object_class)
+ {}
+
+// ====================================================================================================
+
+DataObjectProperties::DataObjectProperties()
+ : StorageObjectProperties(ObjectClass::Data)
+ {}
+
+// ====================================================================================================
+
+CertificateProperties::CertificateProperties(CertificateType cert_type)
+ : StorageObjectProperties(ObjectClass::Certificate), m_cert_type(cert_type)
+ {
+ add_numeric(AttributeType::CertificateType, static_cast< CK_CERTIFICATE_TYPE >(m_cert_type));
+ }
+
+// ====================================================================================================
+
+KeyProperties::KeyProperties(ObjectClass object_class, KeyType key_type)
+ : StorageObjectProperties(object_class), m_key_type(key_type)
+ {
+ add_numeric(AttributeType::KeyType, static_cast< CK_ULONG >(m_key_type));
+ }
+
+// ====================================================================================================
+
+PublicKeyProperties::PublicKeyProperties(KeyType key_type)
+ : KeyProperties(ObjectClass::PublicKey, key_type)
+ {}
+
+// ====================================================================================================
+
+PrivateKeyProperties::PrivateKeyProperties(KeyType key_type)
+ : KeyProperties(ObjectClass::PrivateKey, key_type)
+ {}
+
+// ====================================================================================================
+
+SecretKeyProperties::SecretKeyProperties(KeyType key_type)
+ : KeyProperties(ObjectClass::SecretKey, key_type)
+ {}
+
+// ====================================================================================================
+
+DomainParameterProperties::DomainParameterProperties(KeyType key_type)
+ : StorageObjectProperties(ObjectClass::DomainParameters), m_key_type(key_type)
+ {
+ add_numeric(AttributeType::KeyType, static_cast< CK_ULONG >(m_key_type));
+ }
+
+// ====================================================================================================
+
+Object::Object(Session& session, ObjectHandle handle)
+ : m_session(session), m_handle(handle)
+ {}
+
+Object::Object(Session& session, const ObjectProperties& obj_props)
+ : m_session(session), m_handle(0)
+ {
+ m_session.get().module()->C_CreateObject(m_session.get().handle(), obj_props.data(), obj_props.count(), &m_handle);
+ }
+
+secure_vector<byte> Object::get_attribute_value(AttributeType attribute) const
+ {
+ std::map<AttributeType, secure_vector<byte>> attribute_map = { { attribute, secure_vector<byte>() } };
+ module()->C_GetAttributeValue(m_session.get().handle(), m_handle, attribute_map);
+ return attribute_map.at(attribute);
+ }
+
+void Object::set_attribute_value(AttributeType attribute, const secure_vector<byte>& value) const
+ {
+ std::map<AttributeType, secure_vector<byte>> attribute_map = { { attribute, value } };
+ module()->C_SetAttributeValue(m_session.get().handle(), m_handle, attribute_map);
+ }
+
+void Object::destroy() const
+ {
+ module()->C_DestroyObject(m_session.get().handle(), m_handle);
+ }
+
+ObjectHandle Object::copy(const AttributeContainer& modified_attributes) const
+ {
+ ObjectHandle copied_handle;
+ module()->C_CopyObject(m_session.get().handle(), m_handle, modified_attributes.data(), modified_attributes.count(),
+ &copied_handle);
+ return copied_handle;
+ }
+}
+}
diff --git a/src/lib/prov/pkcs11/p11_object.h b/src/lib/prov/pkcs11/p11_object.h
new file mode 100644
index 000000000..4a6a54b20
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_object.h
@@ -0,0 +1,743 @@
+/*
+* PKCS#11 Object
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_OBJECT_H__
+#define BOTAN_P11_OBJECT_H__
+
+#include <botan/p11.h>
+#include <botan/p11_session.h>
+#include <botan/secmem.h>
+
+#include <vector>
+#include <string>
+#include <type_traits>
+#include <list>
+#include <functional>
+
+namespace Botan {
+namespace PKCS11 {
+
+class Module;
+
+/// Helper class to build the Attribute / CK_ATTRIBUTE structures
+class BOTAN_DLL AttributeContainer
+ {
+ public:
+ AttributeContainer() = default;
+
+ /// @param object_class the class type of this container
+ AttributeContainer(ObjectClass object_class);
+
+ virtual ~AttributeContainer() = default;
+
+/* Microsoft Visual Studio <= 2013 does not support default generated move special member functions.
+ Everything else we target should support it */
+#if !defined( _MSC_VER ) || ( _MSC_VER >= 1900 )
+ AttributeContainer(AttributeContainer&& other) = default;
+ AttributeContainer& operator=(AttributeContainer&& other) = default;
+#endif
+
+ // Warning when implementing copy/assignment: m_attributes contains pointers to the other members which must be updated after a copy
+ AttributeContainer(const AttributeContainer& other) = delete;
+ AttributeContainer& operator=(const AttributeContainer& other) = delete;
+
+ /// @return the attributes this container contains
+ inline const std::vector<Attribute>& attributes() const
+ {
+ return m_attributes;
+ }
+
+ inline Attribute* data() const
+ {
+ return const_cast< Attribute* >(m_attributes.data());
+ }
+
+ /// @return the number of attributes in this container
+ inline size_t count() const
+ {
+ return m_attributes.size();
+ }
+
+ /// Add a class attribute (CKA_CLASS / AttributeType::Class)
+ void add_class(ObjectClass object_class);
+
+ /// Add a string attribute (e.g. CKA_LABEL / AttributeType::Label)
+ void add_string(AttributeType attribute, const std::string& value);
+
+ /// Add a binary attribute (e.g. CKA_ID / AttributeType::Id)
+ void add_binary(AttributeType attribute, const byte* value, size_t length);
+
+ /// Add a binary attribute (e.g. CKA_ID / AttributeType::Id)
+ template<typename TAlloc>
+ void add_binary(AttributeType attribute, const std::vector<byte, TAlloc>& binary)
+ {
+ add_binary(attribute, binary.data(), binary.size());
+ }
+
+ /// Add a bool attribute (e.g. CKA_SENSITIVE / AttributeType::Sensitive)
+ void add_bool(AttributeType attribute, bool value);
+
+ /// Add a numeric attribute (e.g. CKA_MODULUS_BITS / AttributeType::ModulusBits)
+ template<typename T>
+ void add_numeric(AttributeType attribute, T value)
+ {
+ static_assert(std::is_integral<T>::value, "Numeric value required.");
+ m_numerics.push_back(static_cast< uint64_t >(value));
+ add_attribute(attribute, reinterpret_cast< byte* >(&m_numerics.back()), sizeof(T));
+ }
+
+ protected:
+ /// Add a attribute with the given value and size to the attribute collection `m_attributes`
+ void add_attribute(AttributeType attribute, const byte* value, uint32_t size);
+
+ private:
+ std::vector<Attribute> m_attributes;
+ std::list<uint64_t> m_numerics;
+ std::list<std::string> m_strings;
+ std::list<secure_vector<byte>> m_vectors;
+ };
+
+/// Manages calls to C_FindObjects* functions (C_FindObjectsInit -> C_FindObjects -> C_FindObjectsFinal)
+class BOTAN_DLL ObjectFinder final
+ {
+ public:
+ /**
+ * Initializes a search for token and session objects that match a template (calls C_FindObjectsInit)
+ * @param session the session to use for the search
+ * @param search_template the search_template as a vector of `Attribute`
+ */
+ ObjectFinder(Session& session, const std::vector<Attribute>& search_template);
+
+ ObjectFinder(const ObjectFinder& other) = default;
+ ObjectFinder& operator=(const ObjectFinder& other) = default;
+
+/* Microsoft Visual Studio <= 2013 does not support default generated move special member functions.
+ Everything else we target should support it */
+#if !defined( _MSC_VER ) || ( _MSC_VER >= 1900 )
+ ObjectFinder(ObjectFinder&& other) = default;
+ ObjectFinder& operator=(ObjectFinder&& other) = default;
+#endif
+
+ /// Terminates a search for token and session objects (calls C_FindObjectsFinal)
+ ~ObjectFinder() BOTAN_NOEXCEPT;
+
+ /**
+ * Starts or continues a search for token and session objects that match a template, obtaining additional object handles (calls C_FindObjects)
+ * @param max_count maximum amount of object handles to retrieve. Default = 100
+ * @return the result of the search as a vector of `ObjectHandle`
+ */
+ std::vector<ObjectHandle> find(std::uint32_t max_count = 100) const;
+
+ /// Finishes the search operation manually to allow a new ObjectFinder to exist
+ void finish();
+
+ /// @return the module this `ObjectFinder` belongs to
+ inline Module& module() const
+ {
+ return m_session.get().module();
+ }
+
+ private:
+ const std::reference_wrapper<Session> m_session;
+ bool m_search_terminated;
+ };
+
+/// Common attributes of all objects
+class BOTAN_DLL ObjectProperties : public AttributeContainer
+ {
+ public:
+ /// @param object_class the object class of the object
+ ObjectProperties(ObjectClass object_class);
+
+ /// @return the object class of this object
+ inline ObjectClass object_class() const
+ {
+ return m_object_class;
+ }
+
+ private:
+ const ObjectClass m_object_class;
+ };
+
+/// Common attributes of all storage objects
+class BOTAN_DLL StorageObjectProperties : public ObjectProperties
+ {
+ public:
+ /// @param object_class the CK_OBJECT_CLASS this storage object belongs to
+ StorageObjectProperties(ObjectClass object_class);
+
+ /// @param label description of the object (RFC2279 string)
+ inline void set_label(const std::string& label)
+ {
+ add_string(AttributeType::Label, label);
+ }
+
+ /// @param value if true the object is a token object; otherwise the object is a session object
+ inline void set_token(bool value)
+ {
+ add_bool(AttributeType::Token, value);
+ }
+
+ /**
+ * @param value if true the object is a private object; otherwise the object is a public object
+ * When private, a user may not access the object until the user has been authenticated to the token
+ */
+ inline void set_private(bool value)
+ {
+ add_bool(AttributeType::Private, value);
+ }
+
+ /// @param value if true the object can be modified, otherwise it is read-only
+ void set_modifiable(bool value)
+ {
+ add_bool(AttributeType::Modifiable, value);
+ }
+
+ /// @param value if true the object can be copied using C_CopyObject
+ void set_copyable(bool value)
+ {
+ add_bool(AttributeType::Copyable, value);
+ }
+
+ /// @param value if true the object can be destroyed using C_DestroyObject
+ void set_destroyable(bool value)
+ {
+ add_bool(AttributeType::Destroyable, value);
+ }
+ };
+
+/// Common attributes of all data objects
+class BOTAN_DLL DataObjectProperties : public StorageObjectProperties
+ {
+ public:
+ DataObjectProperties();
+
+ /// @param value description of the application that manages the object (RFC2279 string)
+ inline void set_application(const std::string& value)
+ {
+ add_string(AttributeType::Application, value);
+ }
+
+ /// @param object_id DER-encoding of the object identifier indicating the data object type
+ inline void set_object_id(const std::vector<byte>& object_id)
+ {
+ add_binary(AttributeType::ObjectId, object_id);
+ }
+
+ /// @param value value of the object
+ inline void set_value(const secure_vector<byte>& value)
+ {
+ add_binary(AttributeType::Value, value);
+ }
+ };
+
+/// Common attributes of all certificate objects
+class BOTAN_DLL CertificateProperties : public StorageObjectProperties
+ {
+ public:
+ /// @param cert_type type of certificate
+ CertificateProperties(CertificateType cert_type);
+
+ /// @param value the certificate can be trusted for the application that it was created (can only be set to true by SO user)
+ inline void set_trusted(bool value)
+ {
+ add_bool(AttributeType::Trusted, value);
+ }
+
+ /// @param category one of `CertificateCategory`
+ inline void set_category(CertificateCategory category)
+ {
+ add_numeric(AttributeType::CertificateCategory, static_cast< CK_CERTIFICATE_CATEGORY >(category));
+ }
+
+ /**
+ * @param checksum the value of this attribute is derived from the certificate by taking the
+ * first three bytes of the SHA - 1 hash of the certificate object�s `CKA_VALUE` attribute
+ */
+ inline void set_check_value(const std::vector<byte>& checksum)
+ {
+ add_binary(AttributeType::CheckValue, checksum);
+ }
+
+ /// @param date start date for the certificate
+ inline void set_start_date(Date date)
+ {
+ add_binary(AttributeType::StartDate, reinterpret_cast<byte*>(&date), sizeof(Date));
+ }
+
+ /// @param date end date for the certificate
+ inline void set_end_date(Date date)
+ {
+ add_binary(AttributeType::EndDate, reinterpret_cast<byte*>(&date), sizeof(Date));
+ }
+
+ /// @param pubkey_info DER-encoding of the SubjectPublicKeyInfo for the public key contained in this certificate
+ inline void set_public_key_info(const std::vector<byte>& pubkey_info)
+ {
+ add_binary(AttributeType::PublicKeyInfo, pubkey_info);
+ }
+
+ /// @return the certificate type of this certificate object
+ inline CertificateType cert_type() const
+ {
+ return m_cert_type;
+ }
+
+ private:
+ const CertificateType m_cert_type;
+ };
+
+/// Common attributes of all key objects
+class BOTAN_DLL KeyProperties : public StorageObjectProperties
+ {
+ public:
+ /**
+ * @param object_class the `CK_OBJECT_CLASS` this key object belongs to
+ * @param key_type type of key
+ */
+ KeyProperties(ObjectClass object_class, KeyType key_type);
+
+ /// @param id key identifier for key
+ inline void set_id(const std::vector<byte>& id)
+ {
+ add_binary(AttributeType::Id, id);
+ }
+
+ /// @param date start date for the key
+ inline void set_start_date(Date date)
+ {
+ add_binary(AttributeType::StartDate, reinterpret_cast<byte*>(&date), sizeof(Date));
+ }
+
+ /// @param date end date for the key
+ inline void set_end_date(Date date)
+ {
+ add_binary(AttributeType::EndDate, reinterpret_cast<byte*>(&date), sizeof(Date));
+ }
+
+ /// @param value true if key supports key derivation (i.e., if other keys can be derived from this one)
+ inline void set_derive(bool value)
+ {
+ add_bool(AttributeType::Derive, value);
+ }
+
+ /**
+ * Sets a list of mechanisms allowed to be used with this key
+ * Not implemented
+ */
+ inline void set_allowed_mechanisms(const std::vector<MechanismType>&)
+ {
+ throw Exception("Not implemented (KeyProperties::set_allowed_mechanisms)");
+ }
+
+ /// @return the key type of this key object
+ inline KeyType key_type() const
+ {
+ return m_key_type;
+ }
+
+ private:
+ const KeyType m_key_type;
+ };
+
+/// Common attributes of all public key objects
+class BOTAN_DLL PublicKeyProperties : public KeyProperties
+ {
+ public:
+ /// @param key_type type of key
+ PublicKeyProperties(KeyType key_type);
+
+ /// @param subject DER-encoding of the key subject name
+ inline void set_subject(const std::vector<byte>& subject)
+ {
+ add_binary(AttributeType::Subject, subject);
+ }
+
+ /// @param value true if the key supports encryption
+ inline void set_encrypt(bool value)
+ {
+ add_bool(AttributeType::Encrypt, value);
+ }
+
+ /// @param value true if the key supports verification where the signature is an appendix to the data
+ inline void set_verify(bool value)
+ {
+ add_bool(AttributeType::Verify, value);
+ }
+
+ /// @param value true if the key supports verification where the data is recovered from the signature
+ inline void set_verify_recover(bool value)
+ {
+ add_bool(AttributeType::VerifyRecover, value);
+ }
+
+ /// @param value true if the key supports wrapping (i.e., can be used to wrap other keys)
+ inline void set_wrap(bool value)
+ {
+ add_bool(AttributeType::Wrap, value);
+ }
+
+ /**
+ * @param value true if the key can be trusted for the application that it was created.
+ * The wrapping key can be used to wrap keys with `CKA_WRAP_WITH_TRUSTED` set to `CK_TRUE`
+ */
+ inline void set_trusted(bool value)
+ {
+ add_bool(AttributeType::Trusted, value);
+ }
+
+ /**
+ * For wrapping keys
+ * The attribute template to match against any keys wrapped using this wrapping key.
+ * Keys that do not match cannot be wrapped
+ * Not implemented
+ */
+ inline void set_wrap_template(const AttributeContainer&)
+ {
+ throw Exception("Not implemented (PublicKeyProperties::set_wrap_template)");
+ }
+
+ /// @param pubkey_info DER-encoding of the SubjectPublicKeyInfo for this public key
+ inline void set_public_key_info(const std::vector<byte>& pubkey_info)
+ {
+ add_binary(AttributeType::PublicKeyInfo, pubkey_info);
+ }
+ };
+
+/// Common attributes of all private keys
+class BOTAN_DLL PrivateKeyProperties : public KeyProperties
+ {
+ public:
+ /// @param key_type type of key
+ PrivateKeyProperties(KeyType key_type);
+
+ /// @param subject DER-encoding of the key subject name
+ inline void set_subject(const std::vector<byte>& subject)
+ {
+ add_binary(AttributeType::Subject, subject);
+ }
+
+ /// @param value true if the key is sensitive
+ inline void set_sensitive(bool value)
+ {
+ add_bool(AttributeType::Sensitive, value);
+ }
+
+ /// @param value true if the key supports decryption
+ inline void set_decrypt(bool value)
+ {
+ add_bool(AttributeType::Decrypt, value);
+ }
+
+ /// @param value true if the key supports signatures where the signature is an appendix to the data
+ inline void set_sign(bool value)
+ {
+ add_bool(AttributeType::Sign, value);
+ }
+
+ /// @param value true if the key supports signatures where the data can be recovered from the signature
+ inline void set_sign_recover(bool value)
+ {
+ add_bool(AttributeType::SignRecover, value);
+ }
+
+ /// @param value true if the key supports unwrapping (i.e., can be used to unwrap other keys)
+ inline void set_unwrap(bool value)
+ {
+ add_bool(AttributeType::Unwrap, value);
+ }
+
+ /// @param value true if the key is extractable and can be wrapped
+ inline void set_extractable(bool value)
+ {
+ add_bool(AttributeType::Extractable, value);
+ }
+
+ /// @param value true if the key can only be wrapped with a wrapping key that has `CKA_TRUSTED` set to `CK_TRUE`
+ inline void set_wrap_with_trusted(bool value)
+ {
+ add_bool(AttributeType::WrapWithTrusted, value);
+ }
+
+ /// @param value If true, the user has to supply the PIN for each use (sign or decrypt) with the key
+ inline void set_always_authenticate(bool value)
+ {
+ add_bool(AttributeType::AlwaysAuthenticate, value);
+ }
+
+ /**
+ * For wrapping keys
+ * The attribute template to apply to any keys unwrapped using this wrapping key.
+ * Any user supplied template is applied after this template as if the object has already been created
+ * Not implemented
+ */
+ inline void set_unwrap_template(const AttributeContainer&)
+ {
+ throw Exception("Not implemented (PrivateKeyProperties::set_unwrap_template)");
+ }
+
+ /// @param pubkey_info DER-encoding of the SubjectPublicKeyInfo for this public key
+ inline void set_public_key_info(const std::vector<byte>& pubkey_info)
+ {
+ add_binary(AttributeType::PublicKeyInfo, pubkey_info);
+ }
+ };
+
+/// Common attributes of all secret (symmetric) keys
+class BOTAN_DLL SecretKeyProperties : public KeyProperties
+ {
+ public:
+ /// @param key_type type of key
+ SecretKeyProperties(KeyType key_type);
+
+ /// @param value true if the key is sensitive
+ inline void set_sensitive(bool value)
+ {
+ add_bool(AttributeType::Sensitive, value);
+ }
+
+ /// @param value true if the key supports encryption
+ inline void set_encrypt(bool value)
+ {
+ add_bool(AttributeType::Encrypt, value);
+ }
+
+ /// @param value true if the key supports decryption
+ inline void set_decrypt(bool value)
+ {
+ add_bool(AttributeType::Decrypt, value);
+ }
+
+ /// @param value true if the key supports signatures where the signature is an appendix to the data
+ inline void set_sign(bool value)
+ {
+ add_bool(AttributeType::Sign, value);
+ }
+
+ /// @param value true if the key supports verification where the signature is an appendix to the data
+ inline void set_verify(bool value)
+ {
+ add_bool(AttributeType::Verify, value);
+ }
+
+ /// @param value true if the key supports unwrapping (i.e., can be used to unwrap other keys)
+ inline void set_unwrap(bool value)
+ {
+ add_bool(AttributeType::Unwrap, value);
+ }
+
+ /// @param value true if the key is extractable and can be wrapped
+ inline void set_extractable(bool value)
+ {
+ add_bool(AttributeType::Extractable, value);
+ }
+
+ /// @param value true if the key can only be wrapped with a wrapping key that has `CKA_TRUSTED` set to `CK_TRUE`
+ inline void set_wrap_with_trusted(bool value)
+ {
+ add_bool(AttributeType::WrapWithTrusted, value);
+ }
+
+ /// @param value if true, the user has to supply the PIN for each use (sign or decrypt) with the key
+ inline void set_always_authenticate(bool value)
+ {
+ add_bool(AttributeType::AlwaysAuthenticate, value);
+ }
+
+ /// @param value true if the key supports wrapping (i.e., can be used to wrap other keys)
+ inline void set_wrap(bool value)
+ {
+ add_bool(AttributeType::Wrap, value);
+ }
+
+ /**
+ * @param value the key can be trusted for the application that it was created.
+ * The wrapping key can be used to wrap keys with `CKA_WRAP_WITH_TRUSTED` set to `CK_TRUE`
+ */
+ inline void set_trusted(bool value)
+ {
+ add_bool(AttributeType::Trusted, value);
+ }
+
+ /// @param checksum the key check value of this key
+ inline void set_check_value(const std::vector<byte>& checksum)
+ {
+ add_binary(AttributeType::CheckValue, checksum);
+ }
+
+ /**
+ * For wrapping keys
+ * The attribute template to match against any keys wrapped using this wrapping key.
+ * Keys that do not match cannot be wrapped
+ * Not implemented
+ */
+ inline void set_wrap_template(const AttributeContainer&)
+ {
+ throw Exception("Not implemented (SecretKeyProperties::set_wrap_template)");
+ }
+
+ /**
+ * For wrapping keys
+ * The attribute template to apply to any keys unwrapped using this wrapping key
+ * Any user supplied template is applied after this template as if the object has already been created
+ * Not Implemented
+ */
+ inline void set_unwrap_template(const AttributeContainer&)
+ {
+ throw Exception("Not implemented (SecretKeyProperties::set_unwrap_template)");
+ }
+ };
+
+/// Common attributes of domain parameter
+class BOTAN_DLL DomainParameterProperties : public StorageObjectProperties
+ {
+ public:
+ /// @param key_type type of key the domain parameters can be used to generate
+ DomainParameterProperties(KeyType key_type);
+
+ /// @return the key type
+ inline KeyType key_type() const
+ {
+ return m_key_type;
+ }
+
+ private:
+ const KeyType m_key_type;
+ };
+
+class BOTAN_DLL Object
+ {
+ public:
+ /**
+ * Creates an `Object` from an existing PKCS#11 object
+ * @param session the session the object belongs to
+ * @param handle handle of the object
+ */
+
+ Object(Session& session, ObjectHandle handle);
+
+ /**
+ * Creates the object
+ * @param session the session in which the object should be created
+ * @param obj_props properties of this object
+ */
+ Object(Session& session, const ObjectProperties& obj_props);
+
+ virtual ~Object() = default;
+
+ /// Searches for all objects of the given type that match `search_template`
+ template<typename T>
+ static std::vector<T> search(Session& session, const std::vector<Attribute>& search_template);
+
+ /// Searches for all objects of the given type using the label (`CKA_LABEL`)
+ template<typename T>
+ static std::vector<T> search(Session& session, const std::string& label);
+
+ /// Searches for all objects of the given type using the id (`CKA_ID`)
+ template<typename T>
+ static std::vector<T> search(Session& session, const std::vector<byte>& id);
+
+ /// Searches for all objects of the given type using the label (`CKA_LABEL`) and id (`CKA_ID`)
+ template<typename T>
+ static std::vector<T> search(Session& session, const std::string& label, const std::vector<byte>& id);
+
+ /// Searches for all objects of the given type
+ template<typename T>
+ static std::vector<T> search(Session& session);
+
+ /// @returns the value of the given attribute (using `C_GetAttributeValue`)
+ secure_vector<byte> get_attribute_value(AttributeType attribute) const;
+
+ /// Sets the given value for the attribute (using `C_SetAttributeValue`)
+ void set_attribute_value(AttributeType attribute, const secure_vector<byte>& value) const;
+
+ /// Destroys the object
+ void destroy() const;
+
+ /**
+ * Copies the object
+ * @param modified_attributes the attributes of the copied object
+ */
+ ObjectHandle copy(const AttributeContainer& modified_attributes) const;
+
+ /// @return the handle of this object.
+ inline ObjectHandle handle() const
+ {
+ return m_handle;
+ }
+
+ /// @return the session this objects belongs to
+ inline Session& session() const
+ {
+ return m_session;
+ }
+
+ /// @return the module this object belongs to
+ inline Module& module() const
+ {
+ return m_session.get().module();
+ }
+ protected:
+ Object(Session& session)
+ : m_session(session)
+ {}
+
+ const std::reference_wrapper<Session> m_session;
+ ObjectHandle m_handle;
+ };
+
+template<typename T>
+std::vector<T> Object::search(Session& session, const std::vector<Attribute>& search_template)
+ {
+ ObjectFinder finder(session, search_template);
+ std::vector<ObjectHandle> handles = finder.find();
+ std::vector<T> result;
+ result.reserve(handles.size());
+ for(const auto& handle : handles)
+ {
+ result.emplace_back(T(session, handle));
+ }
+ return result;
+ }
+
+template<typename T>
+std::vector<T> Object::search(Session& session, const std::string& label)
+ {
+ AttributeContainer search_template(T::Class);
+ search_template.add_string(AttributeType::Label, label);
+ return search<T>(session, search_template.attributes());
+ }
+
+template<typename T>
+std::vector<T> Object::search(Session& session, const std::vector<byte>& id)
+ {
+ AttributeContainer search_template(T::Class);
+ search_template.add_binary(AttributeType::Id, id);
+ return search<T>(session, search_template.attributes());
+ }
+
+template<typename T>
+std::vector<T> Object::search(Session& session, const std::string& label, const std::vector<byte>& id)
+ {
+ AttributeContainer search_template(T::Class);
+ search_template.add_string(AttributeType::Label, label);
+ search_template.add_binary(AttributeType::Id, id);
+ return search<T>(session, search_template.attributes());
+ }
+
+template<typename T>
+std::vector<T> Object::search(Session& session)
+ {
+ return search<T>(session, AttributeContainer(T::Class).attributes());
+ }
+
+}
+
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_randomgenerator.cpp b/src/lib/prov/pkcs11/p11_randomgenerator.cpp
new file mode 100644
index 000000000..eaf9933c6
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_randomgenerator.cpp
@@ -0,0 +1,31 @@
+/*
+* PKCS#11 Random Generator
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_randomgenerator.h>
+
+namespace Botan {
+
+namespace PKCS11 {
+
+PKCS11_RNG::PKCS11_RNG(Session& session)
+ : m_session(session)
+ {}
+
+void PKCS11_RNG::randomize(Botan::byte output[], std::size_t length)
+ {
+ module()->C_GenerateRandom(m_session.get().handle(), output, length);
+ }
+
+void PKCS11_RNG::add_entropy(const Botan::byte in[], std::size_t length)
+ {
+ module()->C_SeedRandom(m_session.get().handle(), const_cast<Botan::byte*>(in), length);
+ }
+
+}
+}
+
diff --git a/src/lib/prov/pkcs11/p11_randomgenerator.h b/src/lib/prov/pkcs11/p11_randomgenerator.h
new file mode 100644
index 000000000..a291c89f3
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_randomgenerator.h
@@ -0,0 +1,70 @@
+/*
+* PKCS#11 Random Generator
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_RNG_H__
+#define BOTAN_P11_RNG_H__
+
+#include <botan/rng.h>
+#include <botan/p11_session.h>
+#include <botan/entropy_src.h>
+
+#include <string>
+#include <functional>
+
+namespace Botan {
+namespace PKCS11 {
+
+class Module;
+
+/// A random generator that only fetches random from the PKCS#11 RNG
+class BOTAN_DLL PKCS11_RNG final : public Hardware_RNG
+ {
+ public:
+ /// Initialize the RNG with the PKCS#11 session that provides access to the cryptoki functions
+ explicit PKCS11_RNG(Session& session);
+
+ void clear() override
+ {}
+
+ std::string name() const override
+ {
+ return "PKCS11_RNG";
+ }
+
+ /// Always returns true
+ bool is_seeded() const override
+ {
+ return true;
+ }
+
+ /// No operation - always returns 0
+ size_t reseed(Entropy_Sources&, size_t, std::chrono::milliseconds) override
+ {
+ return 0;
+ }
+
+ /// @return the module used by this RNG
+ inline Module& module() const
+ {
+ return m_session.get().module();
+ }
+
+ /// Calls `C_GenerateRandom` to generate random data
+ void randomize(Botan::byte output[], std::size_t length) override;
+
+ /// Calls `C_SeedRandom` to add entropy to the random generation function of the token/middleware
+ void add_entropy(const Botan::byte in[], std::size_t length) override;
+
+ private:
+ const std::reference_wrapper<Session> m_session;
+ };
+}
+
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_rsa.cpp b/src/lib/prov/pkcs11/p11_rsa.cpp
new file mode 100644
index 000000000..9e5675301
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_rsa.cpp
@@ -0,0 +1,377 @@
+/*
+* PKCS#11 RSA
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_rsa.h>
+
+#if defined(BOTAN_HAS_RSA)
+
+#include <botan/internal/p11_mechanism.h>
+#include <botan/pk_ops.h>
+#include <botan/internal/algo_registry.h>
+#include <botan/internal/pk_utils.h>
+#include <botan/rng.h>
+#include <botan/blinding.h>
+
+#if defined(BOTAN_HAS_SYSTEM_RNG)
+ #include <botan/system_rng.h>
+#else
+ #include <botan/auto_rng.h>
+#endif
+
+namespace Botan {
+
+namespace PKCS11 {
+
+RSA_PublicKeyImportProperties::RSA_PublicKeyImportProperties(const BigInt& modulus, const BigInt& pub_exponent)
+ : PublicKeyProperties(KeyType::Rsa), m_modulus(modulus), m_pub_exponent(pub_exponent)
+ {
+ add_binary(AttributeType::Modulus, BigInt::encode(m_modulus));
+ add_binary(AttributeType::PublicExponent, BigInt::encode(m_pub_exponent));
+ }
+
+RSA_PublicKeyGenerationProperties::RSA_PublicKeyGenerationProperties(Ulong bits)
+ : PublicKeyProperties(KeyType::Rsa)
+ {
+ add_numeric(AttributeType::ModulusBits, bits);
+ }
+
+PKCS11_RSA_PublicKey::PKCS11_RSA_PublicKey(Session& session, ObjectHandle handle)
+ : Object(session, handle)
+ {
+ m_n = BigInt::decode(get_attribute_value(AttributeType::Modulus));
+ m_e = BigInt::decode(get_attribute_value(AttributeType::PublicExponent));
+ }
+
+PKCS11_RSA_PublicKey::PKCS11_RSA_PublicKey(Session& session, const RSA_PublicKeyImportProperties& pubkey_props)
+ : RSA_PublicKey(pubkey_props.modulus(), pubkey_props.pub_exponent()), Object(session, pubkey_props)
+ {}
+
+
+RSA_PrivateKeyImportProperties::RSA_PrivateKeyImportProperties(const BigInt& modulus, const BigInt& priv_exponent)
+ : PrivateKeyProperties(KeyType::Rsa), m_modulus(modulus), m_priv_exponent(priv_exponent)
+ {
+ add_binary(AttributeType::Modulus, BigInt::encode(m_modulus));
+ add_binary(AttributeType::PrivateExponent, BigInt::encode(m_priv_exponent));
+ }
+
+
+PKCS11_RSA_PrivateKey::PKCS11_RSA_PrivateKey(Session& session, ObjectHandle handle)
+ : Object(session, handle)
+ {
+ m_n = BigInt::decode(get_attribute_value(AttributeType::Modulus));
+ m_e = BigInt::decode(get_attribute_value(AttributeType::PublicExponent));
+ }
+
+PKCS11_RSA_PrivateKey::PKCS11_RSA_PrivateKey(Session& session, const RSA_PrivateKeyImportProperties& priv_key_props)
+ : Object(session, priv_key_props)
+ {
+ m_n = priv_key_props.modulus();
+ m_e = BigInt::decode(get_attribute_value(AttributeType::PublicExponent));
+ }
+
+PKCS11_RSA_PrivateKey::PKCS11_RSA_PrivateKey(Session& session, uint32_t bits,
+ const RSA_PrivateKeyGenerationProperties& priv_key_props)
+ : RSA_PublicKey(), Object(session)
+ {
+ RSA_PublicKeyGenerationProperties pub_key_props(bits);
+ pub_key_props.set_encrypt(true);
+ pub_key_props.set_verify(true);
+ pub_key_props.set_token(false); // don't create a persistent public key object
+
+ ObjectHandle pub_key_handle = 0;
+ m_handle = 0;
+ Mechanism mechanism = { static_cast< CK_MECHANISM_TYPE >(MechanismType::RsaPkcsKeyPairGen), nullptr, 0 };
+ session.module()->C_GenerateKeyPair(session.handle(), &mechanism,
+ pub_key_props.data(), pub_key_props.count(), priv_key_props.data(), priv_key_props.count(),
+ &pub_key_handle, &m_handle);
+
+ m_n = BigInt::decode(get_attribute_value(AttributeType::Modulus));
+ m_e = BigInt::decode(get_attribute_value(AttributeType::PublicExponent));
+ }
+
+RSA_PrivateKey PKCS11_RSA_PrivateKey::export_key() const
+ {
+ auto p = get_attribute_value(AttributeType::Prime1);
+ auto q = get_attribute_value(AttributeType::Prime2);
+ auto e = get_attribute_value(AttributeType::PublicExponent);
+ auto d = get_attribute_value(AttributeType::PrivateExponent);
+ auto n = get_attribute_value(AttributeType::Modulus);
+
+#if defined(BOTAN_HAS_SYSTEM_RNG)
+ System_RNG rng;
+#else
+ AutoSeeded_RNG rng;
+#endif
+
+ return RSA_PrivateKey(rng
+ , BigInt::decode(p)
+ , BigInt::decode(q)
+ , BigInt::decode(e)
+ , BigInt::decode(d)
+ , BigInt::decode(n));
+ }
+
+secure_vector<byte> PKCS11_RSA_PrivateKey::pkcs8_private_key() const
+ {
+ return export_key().pkcs8_private_key();
+ }
+
+
+namespace {
+// note: multiple-part decryption operations (with C_DecryptUpdate/C_DecryptFinal)
+// are not supported (PK_Ops::Decryption does not provide an `update` method)
+class PKCS11_RSA_Decryption_Operation : public PK_Ops::Decryption
+ {
+ public:
+ typedef PKCS11_RSA_PrivateKey Key_Type;
+
+ PKCS11_RSA_Decryption_Operation(const PKCS11_RSA_PrivateKey& key, const std::string& padding)
+ : m_key(key), m_mechanism(MechanismWrapper::create_rsa_crypt_mechanism(padding)),
+ m_powermod(m_key.get_e(), m_key.get_n()), m_blinder(m_key.get_n(),
+ [ this ](const BigInt& k) { return m_powermod(k); },
+ [ this ](const BigInt& k) { return inverse_mod(k, m_key.get_n()); })
+ {
+ m_bits = m_key.get_n().bits() - 1;
+ }
+
+ size_t max_input_bits() const override
+ {
+ return m_bits;
+ }
+
+ secure_vector<byte> decrypt(byte& valid_mask, const byte ciphertext[], size_t ciphertext_len) override
+ {
+ valid_mask = 0;
+ m_key.module()->C_DecryptInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
+
+ std::vector<byte> encrypted_data(ciphertext, ciphertext + ciphertext_len);
+
+ // blind for RSA/RAW decryption
+ if(! m_mechanism.padding_size())
+ {
+ encrypted_data = BigInt::encode(m_blinder.blind(BigInt::decode(encrypted_data)));
+ }
+
+ secure_vector<byte> decrypted_data;
+ m_key.module()->C_Decrypt(m_key.session().handle(), encrypted_data, decrypted_data);
+
+ // Unblind for RSA/RAW decryption
+ if(!m_mechanism.padding_size())
+ {
+ decrypted_data = BigInt::encode_1363(m_blinder.unblind(BigInt::decode(decrypted_data)), m_key.get_n().bits() / 8 );
+ }
+
+ valid_mask = 0xFF;
+ return decrypted_data;
+ }
+
+ private:
+ const PKCS11_RSA_PrivateKey& m_key;
+ MechanismWrapper m_mechanism;
+ size_t m_bits = 0;
+ Fixed_Exponent_Power_Mod m_powermod;
+ Blinder m_blinder;
+ };
+
+// note: multiple-part encryption operations (with C_EncryptUpdate/C_EncryptFinal)
+// are not supported (PK_Ops::Encryption does not provide an `update` method)
+class PKCS11_RSA_Encryption_Operation : public PK_Ops::Encryption
+ {
+ public:
+ typedef PKCS11_RSA_PublicKey Key_Type;
+
+ PKCS11_RSA_Encryption_Operation(const PKCS11_RSA_PublicKey& key, const std::string& padding)
+ : m_key(key), m_mechanism(MechanismWrapper::create_rsa_crypt_mechanism(padding))
+ {
+ m_bits = 8 * (key.get_n().bytes() - m_mechanism.padding_size()) - 1;
+ }
+
+ size_t max_input_bits() const override
+ {
+ return m_bits;
+ }
+
+ secure_vector<byte> encrypt(const byte msg[], size_t msg_len, RandomNumberGenerator&) override
+ {
+ m_key.module()->C_EncryptInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
+
+ secure_vector<byte> encrytped_data;
+ m_key.module()->C_Encrypt(m_key.session().handle(), secure_vector<byte>(msg, msg + msg_len), encrytped_data);
+ return encrytped_data;
+ }
+
+ private:
+ const PKCS11_RSA_PublicKey& m_key;
+ MechanismWrapper m_mechanism;
+ size_t m_bits = 0;
+ };
+
+
+class PKCS11_RSA_Signature_Operation : public PK_Ops::Signature
+ {
+ public:
+ typedef PKCS11_RSA_PrivateKey Key_Type;
+
+ PKCS11_RSA_Signature_Operation(const PKCS11_RSA_PrivateKey& key, const std::string& padding)
+ : m_key(key), m_mechanism(MechanismWrapper::create_rsa_sign_mechanism(padding))
+ {}
+
+ size_t message_part_size() const override
+ {
+ return m_key.get_n().bytes();
+ }
+
+ void update(const byte msg[], size_t msg_len) override
+ {
+ if(!m_initialized)
+ {
+ // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed
+ m_key.module()->C_SignInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
+ m_initialized = true;
+ m_first_message = secure_vector<byte>(msg, msg + msg_len);
+ return;
+ }
+
+ if(!m_first_message.empty())
+ {
+ // second call to update: start multiple-part operation
+ m_key.module()->C_SignUpdate(m_key.session().handle(), m_first_message);
+ m_first_message.clear();
+ }
+
+ m_key.module()->C_SignUpdate(m_key.session().handle(), const_cast< Byte* >(msg), msg_len);
+ }
+
+ secure_vector<byte> sign(RandomNumberGenerator&) override
+ {
+ secure_vector<byte> signature;
+ if(!m_first_message.empty())
+ {
+ // single call to update: perform single-part operation
+ m_key.module()->C_Sign(m_key.session().handle(), m_first_message, signature);
+ m_first_message.clear();
+ }
+ else
+ {
+ // multiple calls to update (or none): finish multiple-part operation
+ m_key.module()->C_SignFinal(m_key.session().handle(), signature);
+ }
+ m_initialized = false;
+ return signature;
+ }
+
+ private:
+ const PKCS11_RSA_PrivateKey& m_key;
+ bool m_initialized = false;
+ secure_vector<byte> m_first_message;
+ MechanismWrapper m_mechanism;
+ };
+
+
+class PKCS11_RSA_Verification_Operation : public PK_Ops::Verification
+ {
+ public:
+ typedef PKCS11_RSA_PublicKey Key_Type;
+
+ PKCS11_RSA_Verification_Operation(const PKCS11_RSA_PublicKey& key, const std::string& padding)
+ : m_key(key), m_mechanism(MechanismWrapper::create_rsa_sign_mechanism(padding))
+ {}
+
+ size_t message_part_size() const override
+ {
+ return m_key.get_n().bytes();
+ }
+
+ size_t max_input_bits() const override
+ {
+ return m_key.get_n().bits() - 1;
+ }
+
+ void update(const byte msg[], size_t msg_len) override
+ {
+ if(!m_initialized)
+ {
+ // first call to update: initialize and cache message because we can not determine yet whether a single- or multiple-part operation will be performed
+ m_key.module()->C_VerifyInit(m_key.session().handle(), m_mechanism.data(), m_key.handle());
+ m_initialized = true;
+ m_first_message = secure_vector<byte>(msg, msg + msg_len);
+ return;
+ }
+
+ if(!m_first_message.empty())
+ {
+ // second call to update: start multiple-part operation
+ m_key.module()->C_VerifyUpdate(m_key.session().handle(), m_first_message);
+ m_first_message.clear();
+ }
+
+ m_key.module()->C_VerifyUpdate(m_key.session().handle(), const_cast< Byte* >(msg), msg_len);
+ }
+
+ bool is_valid_signature(const byte sig[], size_t sig_len) override
+ {
+ ReturnValue return_value = ReturnValue::SignatureInvalid;
+ if(!m_first_message.empty())
+ {
+ // single call to update: perform single-part operation
+ m_key.module()->C_Verify(m_key.session().handle(), m_first_message.data(), m_first_message.size(),
+ const_cast< Byte* >(sig), sig_len, &return_value);
+ m_first_message.clear();
+ }
+ else
+ {
+ // multiple calls to update (or none): finish multiple-part operation
+ m_key.module()->C_VerifyFinal(m_key.session().handle(), const_cast< Byte* >(sig), sig_len, &return_value);
+ }
+ m_initialized = false;
+ if(return_value != ReturnValue::OK && return_value != ReturnValue::SignatureInvalid)
+ {
+ throw PKCS11_ReturnError(return_value);
+ }
+ return return_value == ReturnValue::OK;
+ }
+
+ private:
+ const PKCS11_RSA_PublicKey& m_key;
+ bool m_initialized = false;
+ secure_vector<byte> m_first_message;
+ MechanismWrapper m_mechanism;
+ };
+
+BOTAN_REGISTER_TYPE(PK_Ops::Decryption, PKCS11_RSA_Decryption_Operation, "RSA",
+ (make_pk_op<PK_Ops::Decryption, PKCS11_RSA_Decryption_Operation>), "pkcs11", BOTAN_PKCS11_RSA_PRIO);
+
+BOTAN_REGISTER_TYPE(PK_Ops::Encryption, PKCS11_RSA_Encryption_Operation, "RSA",
+ (make_pk_op<PK_Ops::Encryption, PKCS11_RSA_Encryption_Operation>), "pkcs11", BOTAN_PKCS11_RSA_PRIO);
+
+BOTAN_REGISTER_TYPE(PK_Ops::Signature, PKCS11_RSA_Signature_Operation, "RSA",
+ (make_pk_op<PK_Ops::Signature, PKCS11_RSA_Signature_Operation>), "pkcs11", BOTAN_PKCS11_RSA_PRIO);
+
+BOTAN_REGISTER_TYPE(PK_Ops::Verification, PKCS11_RSA_Verification_Operation, "RSA",
+ (make_pk_op<PK_Ops::Verification, PKCS11_RSA_Verification_Operation>), "pkcs11", BOTAN_PKCS11_RSA_PRIO);
+
+}
+
+PKCS11_RSA_KeyPair generate_rsa_keypair(Session& session, const RSA_PublicKeyGenerationProperties& pub_props,
+ const RSA_PrivateKeyGenerationProperties& priv_props)
+ {
+ ObjectHandle pub_key_handle = 0;
+ ObjectHandle priv_key_handle = 0;
+
+ Mechanism mechanism = { static_cast< CK_MECHANISM_TYPE >(MechanismType::RsaPkcsKeyPairGen), nullptr, 0 };
+
+ session.module()->C_GenerateKeyPair(session.handle(), &mechanism,
+ pub_props.data(), pub_props.count(), priv_props.data(), priv_props.count(),
+ &pub_key_handle, &priv_key_handle);
+
+ return std::make_pair(PKCS11_RSA_PublicKey(session, pub_key_handle), PKCS11_RSA_PrivateKey(session, priv_key_handle));
+ }
+
+}
+}
+#endif
diff --git a/src/lib/prov/pkcs11/p11_rsa.h b/src/lib/prov/pkcs11/p11_rsa.h
new file mode 100644
index 000000000..2739cf3e5
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_rsa.h
@@ -0,0 +1,212 @@
+/*
+* PKCS#11 RSA
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_RSA_H__
+#define BOTAN_P11_RSA_H__
+
+#include <botan/build.h>
+#include <botan/p11.h>
+#include <botan/p11_session.h>
+#include <botan/p11_object.h>
+
+#if defined(BOTAN_HAS_RSA)
+#include <botan/rsa.h>
+#include <utility>
+
+namespace Botan {
+namespace PKCS11 {
+
+/// Properties for generating a PKCS#11 RSA public key
+class BOTAN_DLL RSA_PublicKeyGenerationProperties final : public PublicKeyProperties
+ {
+ public:
+ /// @param bits length in bits of modulus n
+ explicit RSA_PublicKeyGenerationProperties(Ulong bits);
+
+ /// @param pub_exponent public exponent e
+ inline void set_pub_exponent(const BigInt& pub_exponent = BigInt(0x10001))
+ {
+ add_binary(AttributeType::PublicExponent, BigInt::encode(pub_exponent));
+ }
+
+ virtual ~RSA_PublicKeyGenerationProperties() = default;
+ };
+
+/// Properties for importing a PKCS#11 RSA public key
+class BOTAN_DLL RSA_PublicKeyImportProperties final : public PublicKeyProperties
+ {
+ public:
+ /// @param modulus modulus n
+ /// @param pub_exponent public exponent e
+ RSA_PublicKeyImportProperties(const BigInt& modulus, const BigInt& pub_exponent);
+
+ /// @return the modulus
+ inline const BigInt& modulus() const
+ {
+ return m_modulus;
+ }
+
+ /// @return the public exponent
+ inline const BigInt& pub_exponent() const
+ {
+ return m_pub_exponent;
+ }
+
+ virtual ~RSA_PublicKeyImportProperties() = default;
+ private:
+ const BigInt m_modulus;
+ const BigInt m_pub_exponent;
+ };
+
+/// Represents a PKCS#11 RSA public key
+class BOTAN_DLL PKCS11_RSA_PublicKey final : public RSA_PublicKey,
+ public Object
+ {
+ public:
+ static const ObjectClass Class = ObjectClass::PublicKey;
+
+ /**
+ * Creates a PKCS11_RSA_PublicKey object from an existing PKCS#11 RSA public key
+ * @param session the session to use
+ * @param handle the handle of the RSA public key
+ */
+ PKCS11_RSA_PublicKey(Session& session, ObjectHandle handle);
+
+ /**
+ * Imports a RSA public key
+ * @param session the session to use
+ * @param pubkey_props the attributes of the public key
+ */
+ PKCS11_RSA_PublicKey(Session& session, const RSA_PublicKeyImportProperties& pubkey_props);
+ };
+
+/// Properties for importing a PKCS#11 RSA private key
+class BOTAN_DLL RSA_PrivateKeyImportProperties final : public PrivateKeyProperties
+ {
+ public:
+ /**
+ * @param modulus modulus n
+ * @param priv_exponent private exponent d
+ */
+ RSA_PrivateKeyImportProperties(const BigInt& modulus, const BigInt& priv_exponent);
+
+ /// @param pub_exponent public exponent e
+ inline void set_pub_exponent(const BigInt& pub_exponent)
+ {
+ add_binary(AttributeType::PublicExponent, BigInt::encode(pub_exponent));
+ }
+
+ /// @param prime1 prime p
+ inline void set_prime_1(const BigInt& prime1)
+ {
+ add_binary(AttributeType::Prime1, BigInt::encode(prime1));
+ }
+
+ /// @param prime2 prime q
+ inline void set_prime_2(const BigInt& prime2)
+ {
+ add_binary(AttributeType::Prime2, BigInt::encode(prime2));
+ }
+
+ /// @param exp1 private exponent d modulo p-1
+ inline void set_exponent_1(const BigInt& exp1)
+ {
+ add_binary(AttributeType::Exponent1, BigInt::encode(exp1));
+ }
+
+ /// @param exp2 private exponent d modulo q-1
+ inline void set_exponent_2(const BigInt& exp2)
+ {
+ add_binary(AttributeType::Exponent2, BigInt::encode(exp2));
+ }
+
+ /// @param coeff CRT coefficient q^-1 mod p
+ inline void set_coefficient(const BigInt& coeff)
+ {
+ add_binary(AttributeType::Coefficient, BigInt::encode(coeff));
+ }
+
+ /// @return the modulus
+ inline const BigInt& modulus() const
+ {
+ return m_modulus;
+ }
+
+ /// @return the private exponent
+ inline const BigInt& priv_exponent() const
+ {
+ return m_priv_exponent;
+ }
+
+ virtual ~RSA_PrivateKeyImportProperties() = default;
+
+ private:
+ const BigInt m_modulus;
+ const BigInt m_priv_exponent;
+ };
+
+/// Properties for generating a PKCS#11 RSA private key
+class BOTAN_DLL RSA_PrivateKeyGenerationProperties final : public PrivateKeyProperties
+ {
+ public:
+ RSA_PrivateKeyGenerationProperties()
+ : PrivateKeyProperties(KeyType::Rsa)
+ {}
+
+ virtual ~RSA_PrivateKeyGenerationProperties() = default;
+ };
+
+/// Represents a PKCS#11 RSA private key
+class BOTAN_DLL PKCS11_RSA_PrivateKey final : public Private_Key,
+ public RSA_PublicKey,
+ public Object
+ {
+ public:
+ static const ObjectClass Class = ObjectClass::PrivateKey;
+
+ /// Creates a PKCS11_RSA_PrivateKey object from an existing PKCS#11 RSA private key
+ PKCS11_RSA_PrivateKey(Session& session, ObjectHandle handle);
+
+ /**
+ * Imports a RSA private key
+ * @param session the session to use
+ * @param priv_key_props the properties of the RSA private key
+ */
+ PKCS11_RSA_PrivateKey(Session& session, const RSA_PrivateKeyImportProperties& priv_key_props);
+
+ /**
+ * Generates a PKCS#11 RSA private key
+ * @param session
+ * @param bits length in bits of modulus n
+ * @param priv_key_props the properties of the RSA private key
+ * @note no persistent public key object will be created
+ */
+ PKCS11_RSA_PrivateKey(Session& session, uint32_t bits, const RSA_PrivateKeyGenerationProperties& priv_key_props);
+
+ /// @return the exported RSA private key
+ RSA_PrivateKey export_key() const;
+
+ secure_vector<byte> pkcs8_private_key() const override;
+ };
+
+using PKCS11_RSA_KeyPair = std::pair<PKCS11_RSA_PublicKey, PKCS11_RSA_PrivateKey>;
+
+/**
+* RSA key pair generation
+* @param session the session that should be used for the key generation
+* @param pub_props properties of the public key
+* @param priv_props properties of the private key
+*/
+BOTAN_DLL PKCS11_RSA_KeyPair generate_rsa_keypair(Session& session, const RSA_PublicKeyGenerationProperties& pub_props,
+ const RSA_PrivateKeyGenerationProperties& priv_props);
+}
+
+}
+#endif
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_session.cpp b/src/lib/prov/pkcs11/p11_session.cpp
new file mode 100644
index 000000000..ceb316169
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_session.cpp
@@ -0,0 +1,89 @@
+/*
+* PKCS#11 Session
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_session.h>
+
+namespace Botan {
+namespace PKCS11 {
+
+Session::Session(Slot& slot, bool read_only)
+ : Session(slot, PKCS11::flags(Flag::SerialSession | (read_only ? Flag::None : Flag::RwSession)), nullptr, nullptr)
+ {}
+
+Session::Session(Slot& slot, Flags flags, VoidPtr callback_data, Notify notify_callback)
+ : m_slot(slot), m_handle(0), m_logged_in(false)
+ {
+ module()->C_OpenSession(m_slot.slot_id(), flags, callback_data, notify_callback, &m_handle);
+ }
+
+Session::Session(Slot& slot, SessionHandle handle)
+ : m_slot(slot), m_handle(handle)
+ {
+ SessionInfo info = get_info();
+ if(info.state == static_cast<CK_STATE>(SessionState::RoPublicSession)
+ || info.state == static_cast<CK_STATE>(SessionState::RwPublicSession))
+ {
+ m_logged_in = false;
+ }
+ else
+ {
+ m_logged_in = true;
+ }
+ }
+
+Session::~Session() BOTAN_NOEXCEPT
+ {
+ if(m_handle)
+ {
+ if(m_logged_in)
+ {
+ module()->C_Logout(m_handle, nullptr);
+ }
+ module()->C_CloseSession(m_handle, nullptr);
+ m_handle = 0;
+ }
+ }
+
+SessionHandle Session::release()
+ {
+ SessionHandle handle = 0;
+ std::swap(handle, m_handle);
+ return handle;
+ }
+
+void Session::login(UserType user_type, const secure_string& pin)
+ {
+ module()->C_Login(m_handle, user_type, pin);
+ m_logged_in = true;
+ }
+
+void Session::logoff()
+ {
+ module()->C_Logout(m_handle);
+ m_logged_in = false;
+ }
+
+SessionInfo Session::get_info() const
+ {
+ SessionInfo info;
+ module()->C_GetSessionInfo(m_handle, &info);
+ return info;
+ }
+
+void Session::set_pin(const secure_string& old_pin, const secure_string& new_pin) const
+ {
+ module()->C_SetPIN(m_handle, old_pin, new_pin);
+ }
+
+void Session::init_pin(const secure_string& new_pin)
+ {
+ module()->C_InitPIN(m_handle, new_pin);
+ }
+
+}
+}
diff --git a/src/lib/prov/pkcs11/p11_session.h b/src/lib/prov/pkcs11/p11_session.h
new file mode 100644
index 000000000..49f223a90
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_session.h
@@ -0,0 +1,105 @@
+/*
+* PKCS#11 Session
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_SESSION_H__
+#define BOTAN_P11_SESSION_H__
+
+#include <botan/p11.h>
+#include <botan/p11_slot.h>
+
+#include <utility>
+
+namespace Botan {
+namespace PKCS11 {
+class Module;
+
+/// Represents a PKCS#11 session
+class BOTAN_DLL Session final
+ {
+ public:
+ /**
+ * @param slot the slot to use
+ * @param read_only true if the session should be read only, false to create a read-write session
+ */
+ Session(Slot& slot, bool read_only);
+
+ /**
+ * @param slot the slot to use
+ * @param flags the flags to use for the session. Remark: Flag::SerialSession is mandatory
+ * @param callback_data application-defined pointer to be passed to the notification callback
+ * @param notify_callback address of the notification callback function
+ */
+ Session(Slot& slot, Flags flags, VoidPtr callback_data, Notify notify_callback);
+
+ /// Takes ownership of a session
+ Session(Slot& slot, SessionHandle handle);
+
+/* Microsoft Visual Studio <= 2013 does not support default generated move special member functions.
+ Everything else we target should support it */
+#if !defined( _MSC_VER ) || ( _MSC_VER >= 1900 )
+ Session(Session&& other) = default;
+ Session& operator=(Session&& other) = default;
+#endif
+
+ // Dtor calls C_CloseSession() and eventually C_Logout. A copy could close the session while the origin still exists
+ Session(const Session& other) = delete;
+ Session& operator=(const Session& other) = delete;
+
+ /// Logout user and close the session on destruction
+ ~Session() BOTAN_NOEXCEPT;
+
+ /// @return a reference to the slot
+ inline const Slot& slot() const
+ {
+ return m_slot;
+ }
+
+ /// @return the session handle of this session
+ inline SessionHandle handle() const
+ {
+ return m_handle;
+ }
+
+ /// @return a reference to the used module
+ inline Module& module() const
+ {
+ return m_slot.module();
+ }
+
+ /// @return the released session handle
+ SessionHandle release();
+
+ /**
+ * Login to this session
+ * @param userType the user type to use for the login
+ * @param pin the PIN of the user
+ */
+ void login(UserType userType, const secure_string& pin);
+
+ /// Logout from this session
+ void logoff();
+
+ /// @return information about this session
+ SessionInfo get_info() const;
+
+ /// Calls `C_SetPIN` to change the PIN using the old PIN (requires a logged in session)
+ void set_pin(const secure_string& old_pin, const secure_string& new_pin) const;
+
+ /// Calls `C_InitPIN` to change or initialize the PIN using the SO_PIN (requires a logged in session)
+ void init_pin(const secure_string& new_pin);
+
+ private:
+ const Slot& m_slot;
+ SessionHandle m_handle;
+ bool m_logged_in;
+ };
+
+}
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_slot.cpp b/src/lib/prov/pkcs11/p11_slot.cpp
new file mode 100644
index 000000000..95a0fad50
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_slot.cpp
@@ -0,0 +1,60 @@
+/*
+* PKCS#11 Slot
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_slot.h>
+
+namespace Botan {
+
+namespace PKCS11 {
+
+Slot::Slot(Module& module, SlotId slot_id)
+ : m_module(module), m_slot_id(slot_id)
+ {}
+
+SlotInfo Slot::get_slot_info() const
+ {
+ SlotInfo slot_info = {};
+ m_module.get()->C_GetSlotInfo(m_slot_id, &slot_info);
+ return slot_info;
+ }
+
+std::vector<MechanismType> Slot::get_mechanism_list() const
+ {
+ std::vector<MechanismType> mechanism_list;
+ m_module.get()->C_GetMechanismList(m_slot_id, mechanism_list);
+ return mechanism_list;
+ }
+
+MechanismInfo Slot::get_mechanism_info(MechanismType mechanism_type) const
+ {
+ MechanismInfo mechanism_info = {};
+ m_module.get()->C_GetMechanismInfo(m_slot_id, mechanism_type, &mechanism_info);
+ return mechanism_info;
+ }
+
+std::vector<SlotId> Slot::get_available_slots(Module& module, bool token_present)
+ {
+ std::vector<SlotId> slot_vec;
+ module->C_GetSlotList(token_present, slot_vec);
+ return slot_vec;
+ }
+
+TokenInfo Slot::get_token_info() const
+ {
+ TokenInfo token_info;
+ m_module.get()->C_GetTokenInfo(m_slot_id, &token_info);
+ return token_info;
+ }
+
+void Slot::initialize(const std::string& label, const secure_string& so_pin) const
+ {
+ m_module.get()->C_InitToken(m_slot_id, so_pin, label);
+ }
+}
+
+}
diff --git a/src/lib/prov/pkcs11/p11_slot.h b/src/lib/prov/pkcs11/p11_slot.h
new file mode 100644
index 000000000..92e585ba1
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_slot.h
@@ -0,0 +1,79 @@
+/*
+* PKCS#11 Slot
+* (C) 2016 Daniel Neus
+* (C) 2016 Philipp Weber
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_SLOT_H__
+#define BOTAN_P11_SLOT_H__
+
+#include <string>
+#include <vector>
+#include <functional>
+
+#include <botan/p11.h>
+#include <botan/p11_module.h>
+
+namespace Botan {
+namespace PKCS11 {
+
+/// Represents a PKCS#11 Slot, i.e., a card reader
+class BOTAN_DLL Slot final
+ {
+ public:
+ /**
+ * @param module the PKCS#11 module to use
+ * @param slot_id the slot id to use
+ */
+ Slot(Module& module, SlotId slot_id);
+
+ /// @return a reference to the module that is used
+ inline Module& module() const
+ {
+ return m_module;
+ }
+
+ /// @return the slot id
+ inline SlotId slot_id() const
+ {
+ return m_slot_id;
+ }
+
+ /**
+ * Get available slots
+ * @param module the module to use
+ * @param token_present true if only slots with attached tokens should be returned, false for all slots
+ * @return a list of available slots (calls C_GetSlotList)
+ */
+ static std::vector<SlotId> get_available_slots(Module& module, bool token_present);
+
+ /// @return information about the slot (`C_GetSlotInfo`)
+ SlotInfo get_slot_info() const;
+
+ /// Obtains a list of mechanism types supported by the slot (`C_GetMechanismList`)
+ std::vector<MechanismType> get_mechanism_list() const;
+
+ /// Obtains information about a particular mechanism possibly supported by a slot (`C_GetMechanismInfo`)
+ MechanismInfo get_mechanism_info(MechanismType mechanism_type) const;
+
+ /// Obtains information about a particular token in the system (`C_GetTokenInfo`)
+ TokenInfo get_token_info() const;
+
+ /**
+ * Calls `C_InitToken` to initialize the token
+ * @param label the label for the token (must not exceed 32 bytes according to PKCS#11)
+ * @param so_pin the PIN of the security officer
+ */
+ void initialize(const std::string& label, const secure_string& so_pin) const;
+
+ private:
+ const std::reference_wrapper<Module> m_module;
+ const SlotId m_slot_id;
+ };
+
+}
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_x509.cpp b/src/lib/prov/pkcs11/p11_x509.cpp
new file mode 100644
index 000000000..76b120368
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_x509.cpp
@@ -0,0 +1,37 @@
+/*
+* PKCS#11 X.509
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/p11_x509.h>
+
+#if defined(BOTAN_HAS_X509_CERTIFICATES)
+
+namespace Botan {
+namespace PKCS11 {
+
+X509_CertificateProperties::X509_CertificateProperties(const std::vector<byte>& subject, const std::vector<byte>& value)
+ : CertificateProperties(CertificateType::X509), m_subject(subject), m_value(value)
+ {
+ add_binary(AttributeType::Subject, m_subject);
+ add_binary(AttributeType::Value, m_value);
+ }
+
+PKCS11_X509_Certificate::PKCS11_X509_Certificate(Session& session, ObjectHandle handle)
+ : Object(session, handle), X509_Certificate(unlock(get_attribute_value(AttributeType::Value)))
+ {
+ }
+
+PKCS11_X509_Certificate::PKCS11_X509_Certificate(Session& session, const X509_CertificateProperties& props)
+ : Object(session, props), X509_Certificate(props.value())
+ {
+ }
+
+}
+
+}
+
+#endif
diff --git a/src/lib/prov/pkcs11/p11_x509.h b/src/lib/prov/pkcs11/p11_x509.h
new file mode 100644
index 000000000..f0e025ff4
--- /dev/null
+++ b/src/lib/prov/pkcs11/p11_x509.h
@@ -0,0 +1,115 @@
+/*
+* PKCS#11 X.509
+* (C) 2016 Daniel Neus, Sirrix AG
+* (C) 2016 Philipp Weber, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_P11_X509_H__
+#define BOTAN_P11_X509_H__
+
+#include <botan/build.h>
+#if defined(BOTAN_HAS_X509_CERTIFICATES)
+
+#include <botan/p11_object.h>
+
+#include <botan/x509cert.h>
+
+#include <vector>
+
+namespace Botan {
+namespace PKCS11 {
+
+class Session;
+
+/// Common attributes of all PKCS#11 X509 certificates
+class BOTAN_DLL X509_CertificateProperties final : public CertificateProperties
+ {
+ public:
+ /**
+ * @param subject DER-encoding of the certificate subject name
+ * @param value BER-encoding of the certificate
+ */
+ X509_CertificateProperties(const std::vector<byte>& subject, const std::vector<byte>& value);
+
+ /// @param id key identifier for public/private key pair
+ inline void set_id(const std::vector<byte>& id)
+ {
+ add_binary(AttributeType::Id, id);
+ }
+
+ /// @param issuer DER-encoding of the certificate issuer name
+ inline void set_issuer(const std::vector<byte>& issuer)
+ {
+ add_binary(AttributeType::Issuer, issuer);
+ }
+
+ /// @param serial DER-encoding of the certificate serial number
+ inline void set_serial(const std::vector<byte>& serial)
+ {
+ add_binary(AttributeType::SerialNumber, serial);
+ }
+
+ /// @param hash hash value of the subject public key
+ inline void set_subject_pubkey_hash(const std::vector<byte>& hash)
+ {
+ add_binary(AttributeType::HashOfSubjectPublicKey, hash);
+ }
+
+ /// @param hash hash value of the issuer public key
+ inline void set_issuer_pubkey_hash(const std::vector<byte>& hash)
+ {
+ add_binary(AttributeType::HashOfIssuerPublicKey, hash);
+ }
+
+ /// @param alg defines the mechanism used to calculate `CKA_HASH_OF_SUBJECT_PUBLIC_KEY` and `CKA_HASH_OF_ISSUER_PUBLIC_KEY`
+ inline void set_hash_alg(MechanismType alg)
+ {
+ add_numeric(AttributeType::NameHashAlgorithm, static_cast<Ulong>(alg));
+ }
+
+ /// @return the subject
+ inline const std::vector<byte>& subject() const
+ {
+ return m_subject;
+ }
+
+ /// @return the BER-encoding of the certificate
+ inline const std::vector<byte>& value() const
+ {
+ return m_value;
+ }
+
+ private:
+ const std::vector<byte> m_subject;
+ const std::vector<byte> m_value;
+ };
+
+/// Represents a PKCS#11 X509 certificate
+class BOTAN_DLL PKCS11_X509_Certificate final : public Object, public X509_Certificate
+ {
+ public:
+ static const ObjectClass Class = ObjectClass::Certificate;
+
+ /**
+ * Create a PKCS11_X509_Certificate object from an existing PKCS#11 X509 cert
+ * @param session the session to use
+ * @param handle the handle of the X.509 certificate
+ */
+ PKCS11_X509_Certificate(Session& session, ObjectHandle handle);
+
+ /**
+ * Imports a X.509 certificate
+ * @param session the session to use
+ * @param props the attributes of the X.509 certificate
+ */
+ PKCS11_X509_Certificate(Session& session, const X509_CertificateProperties& props);
+ };
+
+}
+}
+
+#endif
+
+#endif
diff --git a/src/lib/prov/pkcs11/pkcs11.h b/src/lib/prov/pkcs11/pkcs11.h
new file mode 100644
index 000000000..c66b0bca9
--- /dev/null
+++ b/src/lib/prov/pkcs11/pkcs11.h
@@ -0,0 +1,264 @@
+/*
+ * PKCS #11 Cryptographic Token Interface Base Specification Version 2.40 Errata 01
+ * Committee Specification Draft 01 / Public Review Draft 01
+ * 09 December 2015
+ * Copyright (c) OASIS Open 2015. All Rights Reserved.
+ * Source: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/csprd01/include/pkcs11-v2.40/
+ * Latest version of the specification: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
+ * https://www.oasis-open.org/policies-guidelines/ipr
+ */
+
+#ifndef _PKCS11_H_
+#define _PKCS11_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Before including this file (pkcs11.h) (or pkcs11t.h by
+ * itself), 5 platform-specific macros must be defined. These
+ * macros are described below, and typical definitions for them
+ * are also given. Be advised that these definitions can depend
+ * on both the platform and the compiler used (and possibly also
+ * on whether a Cryptoki library is linked statically or
+ * dynamically).
+ *
+ * In addition to defining these 5 macros, the packing convention
+ * for Cryptoki structures should be set. The Cryptoki
+ * convention on packing is that structures should be 1-byte
+ * aligned.
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, this might be done by using the following
+ * preprocessor directive before including pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(push, cryptoki, 1)
+ *
+ * and using the following preprocessor directive after including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(pop, cryptoki)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, this might be done by using
+ * the following preprocessor directive before including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(1)
+ *
+ * In a UNIX environment, you're on your own for this. You might
+ * not need to do (or be able to do!) anything.
+ *
+ *
+ * Now for the macros:
+ *
+ *
+ * 1. CK_PTR: The indirection string for making a pointer to an
+ * object. It can be used like this:
+ *
+ * typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, it might be defined by:
+ *
+ * #define CK_PTR far *
+ *
+ * In a typical UNIX environment, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ *
+ * 2. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
+ * an importable Cryptoki library function declaration out of a
+ * return type and a function name. It should be used in the
+ * following fashion:
+ *
+ * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)(
+ * CK_VOID_PTR pReserved
+ * );
+ *
+ * If you're using Microsoft Developer Studio 5.0 to declare a
+ * function in a Win32 Cryptoki .dll, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType __declspec(dllimport) name
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to declare a function in a Win16 Cryptoki .dll, it
+ * might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType __export _far _pascal name
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType name
+ *
+ *
+ * 3. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
+ * which makes a Cryptoki API function pointer declaration or
+ * function pointer type declaration out of a return type and a
+ * function name. It should be used in the following fashion:
+ *
+ * // Define funcPtr to be a pointer to a Cryptoki API function
+ * // taking arguments args and returning CK_RV.
+ * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args);
+ *
+ * or
+ *
+ * // Define funcPtrType to be the type of a pointer to a
+ * // Cryptoki API function taking arguments args and returning
+ * // CK_RV, and then define funcPtr to be a variable of type
+ * // funcPtrType.
+ * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args);
+ * funcPtrType funcPtr;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to access
+ * functions in a Win32 Cryptoki .dll, in might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType __declspec(dllimport) (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to access functions in a Win16 Cryptoki .dll, it might
+ * be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType __export _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType (* name)
+ *
+ *
+ * 4. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
+ * a function pointer type for an application callback out of
+ * a return type for the callback and a name for the callback.
+ * It should be used in the following fashion:
+ *
+ * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args);
+ *
+ * to declare a function pointer, myCallback, to a callback
+ * which takes arguments args and returns a CK_RV. It can also
+ * be used like this:
+ *
+ * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args);
+ * myCallbackType myCallback;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to do Win32
+ * Cryptoki development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to do Win16 development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType (* name)
+ *
+ *
+ * 5. NULL_PTR: This macro is the value of a NULL pointer.
+ *
+ * In any ANSI/ISO C environment (and in many others as well),
+ * this should best be defined by
+ *
+ * #ifndef NULL_PTR
+ * #define NULL_PTR 0
+ * #endif
+ */
+
+
+/* All the various Cryptoki types and #define'd values are in the
+ * file pkcs11t.h.
+ */
+#include "pkcs11t.h"
+
+#define __PASTE(x,y) x##y
+
+
+/* ==============================================================
+ * Define the "extern" form of all the entry points.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST 1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ extern CK_DECLARE_FUNCTION(CK_RV, name)
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes.
+ */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define the typedef form of all the entry points. That is, for
+ * each Cryptoki function C_XXX, define a type CK_C_XXX which is
+ * a pointer to that kind of function.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST 1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name))
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes.
+ */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define structed vector of entry points. A CK_FUNCTION_LIST
+ * contains a CK_VERSION indicating a library's Cryptoki version
+ * and then a whole slew of function pointers to the routines in
+ * the library. This type was declared, but not defined, in
+ * pkcs11t.h.
+ * ==============================================================
+ */
+
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ __PASTE(CK_,name) name;
+
+struct CK_FUNCTION_LIST {
+
+ CK_VERSION version; /* Cryptoki version */
+
+/* Pile all the function pointers into the CK_FUNCTION_LIST. */
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes.
+ */
+#include "pkcs11f.h"
+
+};
+
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+#undef __PASTE
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKCS11_H_ */
+
diff --git a/src/lib/prov/pkcs11/pkcs11f.h b/src/lib/prov/pkcs11/pkcs11f.h
new file mode 100644
index 000000000..48ba5726f
--- /dev/null
+++ b/src/lib/prov/pkcs11/pkcs11f.h
@@ -0,0 +1,938 @@
+/*
+ * PKCS #11 Cryptographic Token Interface Base Specification Version 2.40 Errata 01
+ * Committee Specification Draft 01 / Public Review Draft 01
+ * 09 December 2015
+ * Copyright (c) OASIS Open 2015. All Rights Reserved.
+ * Source: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/csprd01/include/pkcs11-v2.40/
+ * Latest version of the specification: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
+ * https://www.oasis-open.org/policies-guidelines/ipr
+ */
+
+/* This header file contains pretty much everything about all the
+ * Cryptoki function prototypes. Because this information is
+ * used for more than just declaring function prototypes, the
+ * order of the functions appearing herein is important, and
+ * should not be altered.
+ */
+
+/* General-purpose */
+
+/* C_Initialize initializes the Cryptoki library. */
+CK_PKCS11_FUNCTION_INFO(C_Initialize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_VOID_PTR pInitArgs /* if this is not NULL_PTR, it gets
+ * cast to CK_C_INITIALIZE_ARGS_PTR
+ * and dereferenced
+ */
+);
+#endif
+
+
+/* C_Finalize indicates that an application is done with the
+ * Cryptoki library.
+ */
+CK_PKCS11_FUNCTION_INFO(C_Finalize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_VOID_PTR pReserved /* reserved. Should be NULL_PTR */
+);
+#endif
+
+
+/* C_GetInfo returns general information about Cryptoki. */
+CK_PKCS11_FUNCTION_INFO(C_GetInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_INFO_PTR pInfo /* location that receives information */
+);
+#endif
+
+
+/* C_GetFunctionList returns the function list. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_FUNCTION_LIST_PTR_PTR ppFunctionList /* receives pointer to
+ * function list
+ */
+);
+#endif
+
+
+
+/* Slot and token management */
+
+/* C_GetSlotList obtains a list of slots in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_BBOOL tokenPresent, /* only slots with tokens */
+ CK_SLOT_ID_PTR pSlotList, /* receives array of slot IDs */
+ CK_ULONG_PTR pulCount /* receives number of slots */
+);
+#endif
+
+
+/* C_GetSlotInfo obtains information about a particular slot in
+ * the system.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* the ID of the slot */
+ CK_SLOT_INFO_PTR pInfo /* receives the slot information */
+);
+#endif
+
+
+/* C_GetTokenInfo obtains information about a particular token
+ * in the system.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_TOKEN_INFO_PTR pInfo /* receives the token information */
+);
+#endif
+
+
+/* C_GetMechanismList obtains a list of mechanism types
+ * supported by a token.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of token's slot */
+ CK_MECHANISM_TYPE_PTR pMechanismList, /* gets mech. array */
+ CK_ULONG_PTR pulCount /* gets # of mechs. */
+);
+#endif
+
+
+/* C_GetMechanismInfo obtains information about a particular
+ * mechanism possibly supported by a token.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_MECHANISM_TYPE type, /* type of mechanism */
+ CK_MECHANISM_INFO_PTR pInfo /* receives mechanism info */
+);
+#endif
+
+
+/* C_InitToken initializes a token. */
+CK_PKCS11_FUNCTION_INFO(C_InitToken)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_UTF8CHAR_PTR pPin, /* the SO's initial PIN */
+ CK_ULONG ulPinLen, /* length in bytes of the PIN */
+ CK_UTF8CHAR_PTR pLabel /* 32-byte token label (blank padded) */
+);
+#endif
+
+
+/* C_InitPIN initializes the normal user's PIN. */
+CK_PKCS11_FUNCTION_INFO(C_InitPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_UTF8CHAR_PTR pPin, /* the normal user's PIN */
+ CK_ULONG ulPinLen /* length in bytes of the PIN */
+);
+#endif
+
+
+/* C_SetPIN modifies the PIN of the user who is logged in. */
+CK_PKCS11_FUNCTION_INFO(C_SetPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_UTF8CHAR_PTR pOldPin, /* the old PIN */
+ CK_ULONG ulOldLen, /* length of the old PIN */
+ CK_UTF8CHAR_PTR pNewPin, /* the new PIN */
+ CK_ULONG ulNewLen /* length of the new PIN */
+);
+#endif
+
+
+
+/* Session management */
+
+/* C_OpenSession opens a session between an application and a
+ * token.
+ */
+CK_PKCS11_FUNCTION_INFO(C_OpenSession)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* the slot's ID */
+ CK_FLAGS flags, /* from CK_SESSION_INFO */
+ CK_VOID_PTR pApplication, /* passed to callback */
+ CK_NOTIFY Notify, /* callback function */
+ CK_SESSION_HANDLE_PTR phSession /* gets session handle */
+);
+#endif
+
+
+/* C_CloseSession closes a session between an application and a
+ * token.
+ */
+CK_PKCS11_FUNCTION_INFO(C_CloseSession)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+/* C_CloseAllSessions closes all sessions with a token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID /* the token's slot */
+);
+#endif
+
+
+/* C_GetSessionInfo obtains information about the session. */
+CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_SESSION_INFO_PTR pInfo /* receives session info */
+);
+#endif
+
+
+/* C_GetOperationState obtains the state of the cryptographic operation
+ * in a session.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pOperationState, /* gets state */
+ CK_ULONG_PTR pulOperationStateLen /* gets state length */
+);
+#endif
+
+
+/* C_SetOperationState restores the state of the cryptographic
+ * operation in a session.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pOperationState, /* holds state */
+ CK_ULONG ulOperationStateLen, /* holds state length */
+ CK_OBJECT_HANDLE hEncryptionKey, /* en/decryption key */
+ CK_OBJECT_HANDLE hAuthenticationKey /* sign/verify key */
+);
+#endif
+
+
+/* C_Login logs a user into a token. */
+CK_PKCS11_FUNCTION_INFO(C_Login)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_USER_TYPE userType, /* the user type */
+ CK_UTF8CHAR_PTR pPin, /* the user's PIN */
+ CK_ULONG ulPinLen /* the length of the PIN */
+);
+#endif
+
+
+/* C_Logout logs a user out from a token. */
+CK_PKCS11_FUNCTION_INFO(C_Logout)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Object management */
+
+/* C_CreateObject creates a new object. */
+CK_PKCS11_FUNCTION_INFO(C_CreateObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* the object's template */
+ CK_ULONG ulCount, /* attributes in template */
+ CK_OBJECT_HANDLE_PTR phObject /* gets new object's handle. */
+);
+#endif
+
+
+/* C_CopyObject copies an object, creating a new object for the
+ * copy.
+ */
+CK_PKCS11_FUNCTION_INFO(C_CopyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* template for new object */
+ CK_ULONG ulCount, /* attributes in template */
+ CK_OBJECT_HANDLE_PTR phNewObject /* receives handle of copy */
+);
+#endif
+
+
+/* C_DestroyObject destroys an object. */
+CK_PKCS11_FUNCTION_INFO(C_DestroyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject /* the object's handle */
+);
+#endif
+
+
+/* C_GetObjectSize gets the size of an object in bytes. */
+CK_PKCS11_FUNCTION_INFO(C_GetObjectSize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ULONG_PTR pulSize /* receives size of object */
+);
+#endif
+
+
+/* C_GetAttributeValue obtains the value of one or more object
+ * attributes.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs; gets vals */
+ CK_ULONG ulCount /* attributes in template */
+);
+#endif
+
+
+/* C_SetAttributeValue modifies the value of one or more object
+ * attributes.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs and values */
+ CK_ULONG ulCount /* attributes in template */
+);
+#endif
+
+
+/* C_FindObjectsInit initializes a search for token and session
+ * objects that match a template.
+ */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */
+ CK_ULONG ulCount /* attrs in search template */
+);
+#endif
+
+
+/* C_FindObjects continues a search for token and session
+ * objects that match a template, obtaining additional object
+ * handles.
+ */
+CK_PKCS11_FUNCTION_INFO(C_FindObjects)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_OBJECT_HANDLE_PTR phObject, /* gets obj. handles */
+ CK_ULONG ulMaxObjectCount, /* max handles to get */
+ CK_ULONG_PTR pulObjectCount /* actual # returned */
+);
+#endif
+
+
+/* C_FindObjectsFinal finishes a search for token and session
+ * objects.
+ */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Encryption and decryption */
+
+/* C_EncryptInit initializes an encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of encryption key */
+);
+#endif
+
+
+/* C_Encrypt encrypts single-part data. */
+CK_PKCS11_FUNCTION_INFO(C_Encrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pData, /* the plaintext data */
+ CK_ULONG ulDataLen, /* bytes of plaintext */
+ CK_BYTE_PTR pEncryptedData, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedDataLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptUpdate continues a multiple-part encryption
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext data len */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptFinal finishes a multiple-part encryption
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_EncryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session handle */
+ CK_BYTE_PTR pLastEncryptedPart, /* last c-text */
+ CK_ULONG_PTR pulLastEncryptedPartLen /* gets last size */
+);
+#endif
+
+
+/* C_DecryptInit initializes a decryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of decryption key */
+);
+#endif
+
+
+/* C_Decrypt decrypts encrypted data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Decrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedData, /* ciphertext */
+ CK_ULONG ulEncryptedDataLen, /* ciphertext length */
+ CK_BYTE_PTR pData, /* gets plaintext */
+ CK_ULONG_PTR pulDataLen /* gets p-text size */
+);
+#endif
+
+
+/* C_DecryptUpdate continues a multiple-part decryption
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* encrypted data */
+ CK_ULONG ulEncryptedPartLen, /* input length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* p-text size */
+);
+#endif
+
+
+/* C_DecryptFinal finishes a multiple-part decryption
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DecryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pLastPart, /* gets plaintext */
+ CK_ULONG_PTR pulLastPartLen /* p-text size */
+);
+#endif
+
+
+
+/* Message digesting */
+
+/* C_DigestInit initializes a message-digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism /* the digesting mechanism */
+);
+#endif
+
+
+/* C_Digest digests data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Digest)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* data to be digested */
+ CK_ULONG ulDataLen, /* bytes of data to digest */
+ CK_BYTE_PTR pDigest, /* gets the message digest */
+ CK_ULONG_PTR pulDigestLen /* gets digest length */
+);
+#endif
+
+
+/* C_DigestUpdate continues a multiple-part message-digesting
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* data to be digested */
+ CK_ULONG ulPartLen /* bytes of data to be digested */
+);
+#endif
+
+
+/* C_DigestKey continues a multi-part message-digesting
+ * operation, by digesting the value of a secret key as part of
+ * the data already digested.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DigestKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hKey /* secret key to digest */
+);
+#endif
+
+
+/* C_DigestFinal finishes a multiple-part message-digesting
+ * operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DigestFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pDigest, /* gets the message digest */
+ CK_ULONG_PTR pulDigestLen /* gets byte count of digest */
+);
+#endif
+
+
+
+/* Signing and MACing */
+
+/* C_SignInit initializes a signature (private key encryption)
+ * operation, where the signature is (will be) an appendix to
+ * the data, and plaintext cannot be recovered from the
+ * signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of signature key */
+);
+#endif
+
+
+/* C_Sign signs (encrypts with private key) data in a single
+ * part, where the signature is (will be) an appendix to the
+ * data, and plaintext cannot be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_Sign)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* the data to sign */
+ CK_ULONG ulDataLen, /* count of bytes to sign */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+/* C_SignUpdate continues a multiple-part signature operation,
+ * where the signature is (will be) an appendix to the data,
+ * and plaintext cannot be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* the data to sign */
+ CK_ULONG ulPartLen /* count of bytes to sign */
+);
+#endif
+
+
+/* C_SignFinal finishes a multiple-part signature operation,
+ * returning the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+/* C_SignRecoverInit initializes a signature operation, where
+ * the data can be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of the signature key */
+);
+#endif
+
+
+/* C_SignRecover signs data in a single operation, where the
+ * data can be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* the data to sign */
+ CK_ULONG ulDataLen, /* count of bytes to sign */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+
+/* Verifying signatures and MACs */
+
+/* C_VerifyInit initializes a verification operation, where the
+ * signature is an appendix to the data, and plaintext cannot
+ * cannot be recovered from the signature (e.g. DSA).
+ */
+CK_PKCS11_FUNCTION_INFO(C_VerifyInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
+ CK_OBJECT_HANDLE hKey /* verification key */
+);
+#endif
+
+
+/* C_Verify verifies a signature in a single-part operation,
+ * where the signature is an appendix to the data, and plaintext
+ * cannot be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_Verify)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* signed data */
+ CK_ULONG ulDataLen, /* length of signed data */
+ CK_BYTE_PTR pSignature, /* signature */
+ CK_ULONG ulSignatureLen /* signature length*/
+);
+#endif
+
+
+/* C_VerifyUpdate continues a multiple-part verification
+ * operation, where the signature is an appendix to the data,
+ * and plaintext cannot be recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* signed data */
+ CK_ULONG ulPartLen /* length of signed data */
+);
+#endif
+
+
+/* C_VerifyFinal finishes a multiple-part verification
+ * operation, checking the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_VerifyFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* signature to verify */
+ CK_ULONG ulSignatureLen /* signature length */
+);
+#endif
+
+
+/* C_VerifyRecoverInit initializes a signature verification
+ * operation, where the data is recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
+ CK_OBJECT_HANDLE hKey /* verification key */
+);
+#endif
+
+
+/* C_VerifyRecover verifies a signature in a single-part
+ * operation, where the data is recovered from the signature.
+ */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* signature to verify */
+ CK_ULONG ulSignatureLen, /* signature length */
+ CK_BYTE_PTR pData, /* gets signed data */
+ CK_ULONG_PTR pulDataLen /* gets signed data len */
+);
+#endif
+
+
+
+/* Dual-function cryptographic operations */
+
+/* C_DigestEncryptUpdate continues a multiple-part digesting
+ * and encryption operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext length */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptDigestUpdate continues a multiple-part decryption and
+ * digesting operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* ciphertext */
+ CK_ULONG ulEncryptedPartLen, /* ciphertext length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* gets plaintext len */
+);
+#endif
+
+
+/* C_SignEncryptUpdate continues a multiple-part signing and
+ * encryption operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext length */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptVerifyUpdate continues a multiple-part decryption and
+ * verify operation.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* ciphertext */
+ CK_ULONG ulEncryptedPartLen, /* ciphertext length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* gets p-text length */
+);
+#endif
+
+
+
+/* Key management */
+
+/* C_GenerateKey generates a secret key, creating a new key
+ * object.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* key generation mech. */
+ CK_ATTRIBUTE_PTR pTemplate, /* template for new key */
+ CK_ULONG ulCount, /* # of attrs in template */
+ CK_OBJECT_HANDLE_PTR phKey /* gets handle of new key */
+);
+#endif
+
+
+/* C_GenerateKeyPair generates a public-key/private-key pair,
+ * creating new key objects.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session handle */
+ CK_MECHANISM_PTR pMechanism, /* key-gen mech. */
+ CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* template for pub. key */
+ CK_ULONG ulPublicKeyAttributeCount, /* # pub. attrs. */
+ CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* template for priv. key */
+ CK_ULONG ulPrivateKeyAttributeCount, /* # priv. attrs. */
+ CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub. key handle */
+ CK_OBJECT_HANDLE_PTR phPrivateKey /* gets priv. key handle */
+);
+#endif
+
+
+/* C_WrapKey wraps (i.e., encrypts) a key. */
+CK_PKCS11_FUNCTION_INFO(C_WrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */
+ CK_OBJECT_HANDLE hWrappingKey, /* wrapping key */
+ CK_OBJECT_HANDLE hKey, /* key to be wrapped */
+ CK_BYTE_PTR pWrappedKey, /* gets wrapped key */
+ CK_ULONG_PTR pulWrappedKeyLen /* gets wrapped key size */
+);
+#endif
+
+
+/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
+ * key object.
+ */
+CK_PKCS11_FUNCTION_INFO(C_UnwrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_MECHANISM_PTR pMechanism, /* unwrapping mech. */
+ CK_OBJECT_HANDLE hUnwrappingKey, /* unwrapping key */
+ CK_BYTE_PTR pWrappedKey, /* the wrapped key */
+ CK_ULONG ulWrappedKeyLen, /* wrapped key len */
+ CK_ATTRIBUTE_PTR pTemplate, /* new key template */
+ CK_ULONG ulAttributeCount, /* template length */
+ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
+);
+#endif
+
+
+/* C_DeriveKey derives a key from a base key, creating a new key
+ * object.
+ */
+CK_PKCS11_FUNCTION_INFO(C_DeriveKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_MECHANISM_PTR pMechanism, /* key deriv. mech. */
+ CK_OBJECT_HANDLE hBaseKey, /* base key */
+ CK_ATTRIBUTE_PTR pTemplate, /* new key template */
+ CK_ULONG ulAttributeCount, /* template length */
+ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
+);
+#endif
+
+
+
+/* Random number generation */
+
+/* C_SeedRandom mixes additional seed material into the token's
+ * random number generator.
+ */
+CK_PKCS11_FUNCTION_INFO(C_SeedRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSeed, /* the seed material */
+ CK_ULONG ulSeedLen /* length of seed material */
+);
+#endif
+
+
+/* C_GenerateRandom generates random data. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR RandomData, /* receives the random data */
+ CK_ULONG ulRandomLen /* # of bytes to generate */
+);
+#endif
+
+
+
+/* Parallel function management */
+
+/* C_GetFunctionStatus is a legacy function; it obtains an
+ * updated status of a function running in parallel with an
+ * application.
+ */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+/* C_CancelFunction is a legacy function; it cancels a function
+ * running in parallel.
+ */
+CK_PKCS11_FUNCTION_INFO(C_CancelFunction)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+/* C_WaitForSlotEvent waits for a slot event (token insertion,
+ * removal, etc.) to occur.
+ */
+CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_FLAGS flags, /* blocking/nonblocking flag */
+ CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */
+ CK_VOID_PTR pRserved /* reserved. Should be NULL_PTR */
+);
+#endif
+
diff --git a/src/lib/prov/pkcs11/pkcs11t.h b/src/lib/prov/pkcs11/pkcs11t.h
new file mode 100644
index 000000000..c183ea974
--- /dev/null
+++ b/src/lib/prov/pkcs11/pkcs11t.h
@@ -0,0 +1,2002 @@
+/*
+ * PKCS #11 Cryptographic Token Interface Base Specification Version 2.40 Errata 01
+ * Committee Specification Draft 01 / Public Review Draft 01
+ * 09 December 2015
+ * Copyright (c) OASIS Open 2015. All Rights Reserved.
+ * Source: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/csprd01/include/pkcs11-v2.40/
+ * Latest version of the specification: http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html
+ * https://www.oasis-open.org/policies-guidelines/ipr
+ */
+
+/* See top of pkcs11.h for information about the macros that
+ * must be defined and the structure-packing conventions that
+ * must be set before including this file.
+ */
+
+#ifndef _PKCS11T_H_
+#define _PKCS11T_H_ 1
+
+#define CRYPTOKI_VERSION_MAJOR 2
+#define CRYPTOKI_VERSION_MINOR 40
+#define CRYPTOKI_VERSION_AMENDMENT 0
+
+#define CK_TRUE 1
+#define CK_FALSE 0
+
+#ifndef CK_DISABLE_TRUE_FALSE
+#ifndef FALSE
+#define FALSE CK_FALSE
+#endif
+#ifndef TRUE
+#define TRUE CK_TRUE
+#endif
+#endif
+
+/* an unsigned 8-bit value */
+typedef unsigned char CK_BYTE;
+
+/* an unsigned 8-bit character */
+typedef CK_BYTE CK_CHAR;
+
+/* an 8-bit UTF-8 character */
+typedef CK_BYTE CK_UTF8CHAR;
+
+/* a BYTE-sized Boolean flag */
+typedef CK_BYTE CK_BBOOL;
+
+/* an unsigned value, at least 32 bits long */
+typedef unsigned long int CK_ULONG;
+
+/* a signed value, the same size as a CK_ULONG */
+typedef long int CK_LONG;
+
+/* at least 32 bits; each bit is a Boolean flag */
+typedef CK_ULONG CK_FLAGS;
+
+
+/* some special values for certain CK_ULONG variables */
+#define CK_UNAVAILABLE_INFORMATION (~0UL)
+#define CK_EFFECTIVELY_INFINITE 0UL
+
+
+typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+typedef CK_CHAR CK_PTR CK_CHAR_PTR;
+typedef CK_UTF8CHAR CK_PTR CK_UTF8CHAR_PTR;
+typedef CK_ULONG CK_PTR CK_ULONG_PTR;
+typedef void CK_PTR CK_VOID_PTR;
+
+/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */
+typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR;
+
+
+/* The following value is always invalid if used as a session
+ * handle or object handle
+ */
+#define CK_INVALID_HANDLE 0UL
+
+
+typedef struct CK_VERSION {
+ CK_BYTE major; /* integer portion of version number */
+ CK_BYTE minor; /* 1/100ths portion of version number */
+} CK_VERSION;
+
+typedef CK_VERSION CK_PTR CK_VERSION_PTR;
+
+
+typedef struct CK_INFO {
+ CK_VERSION cryptokiVersion; /* Cryptoki interface ver */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_FLAGS flags; /* must be zero */
+ CK_UTF8CHAR libraryDescription[32]; /* blank padded */
+ CK_VERSION libraryVersion; /* version of library */
+} CK_INFO;
+
+typedef CK_INFO CK_PTR CK_INFO_PTR;
+
+
+/* CK_NOTIFICATION enumerates the types of notifications that
+ * Cryptoki provides to an application
+ */
+typedef CK_ULONG CK_NOTIFICATION;
+#define CKN_SURRENDER 0UL
+#define CKN_OTP_CHANGED 1UL
+
+typedef CK_ULONG CK_SLOT_ID;
+
+typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR;
+
+
+/* CK_SLOT_INFO provides information about a slot */
+typedef struct CK_SLOT_INFO {
+ CK_UTF8CHAR slotDescription[64]; /* blank padded */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_FLAGS flags;
+
+ CK_VERSION hardwareVersion; /* version of hardware */
+ CK_VERSION firmwareVersion; /* version of firmware */
+} CK_SLOT_INFO;
+
+/* flags: bit flags that provide capabilities of the slot
+ * Bit Flag Mask Meaning
+ */
+#define CKF_TOKEN_PRESENT 0x00000001UL /* a token is there */
+#define CKF_REMOVABLE_DEVICE 0x00000002UL /* removable devices*/
+#define CKF_HW_SLOT 0x00000004UL /* hardware slot */
+
+typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR;
+
+
+/* CK_TOKEN_INFO provides information about a token */
+typedef struct CK_TOKEN_INFO {
+ CK_UTF8CHAR label[32]; /* blank padded */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_UTF8CHAR model[16]; /* blank padded */
+ CK_CHAR serialNumber[16]; /* blank padded */
+ CK_FLAGS flags; /* see below */
+
+ CK_ULONG ulMaxSessionCount; /* max open sessions */
+ CK_ULONG ulSessionCount; /* sess. now open */
+ CK_ULONG ulMaxRwSessionCount; /* max R/W sessions */
+ CK_ULONG ulRwSessionCount; /* R/W sess. now open */
+ CK_ULONG ulMaxPinLen; /* in bytes */
+ CK_ULONG ulMinPinLen; /* in bytes */
+ CK_ULONG ulTotalPublicMemory; /* in bytes */
+ CK_ULONG ulFreePublicMemory; /* in bytes */
+ CK_ULONG ulTotalPrivateMemory; /* in bytes */
+ CK_ULONG ulFreePrivateMemory; /* in bytes */
+ CK_VERSION hardwareVersion; /* version of hardware */
+ CK_VERSION firmwareVersion; /* version of firmware */
+ CK_CHAR utcTime[16]; /* time */
+} CK_TOKEN_INFO;
+
+/* The flags parameter is defined as follows:
+ * Bit Flag Mask Meaning
+ */
+#define CKF_RNG 0x00000001UL /* has random # generator */
+#define CKF_WRITE_PROTECTED 0x00000002UL /* token is write-protected */
+#define CKF_LOGIN_REQUIRED 0x00000004UL /* user must login */
+#define CKF_USER_PIN_INITIALIZED 0x00000008UL /* normal user's PIN is set */
+
+/* CKF_RESTORE_KEY_NOT_NEEDED. If it is set,
+ * that means that *every* time the state of cryptographic
+ * operations of a session is successfully saved, all keys
+ * needed to continue those operations are stored in the state
+ */
+#define CKF_RESTORE_KEY_NOT_NEEDED 0x00000020UL
+
+/* CKF_CLOCK_ON_TOKEN. If it is set, that means
+ * that the token has some sort of clock. The time on that
+ * clock is returned in the token info structure
+ */
+#define CKF_CLOCK_ON_TOKEN 0x00000040UL
+
+/* CKF_PROTECTED_AUTHENTICATION_PATH. If it is
+ * set, that means that there is some way for the user to login
+ * without sending a PIN through the Cryptoki library itself
+ */
+#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100UL
+
+/* CKF_DUAL_CRYPTO_OPERATIONS. If it is true,
+ * that means that a single session with the token can perform
+ * dual simultaneous cryptographic operations (digest and
+ * encrypt; decrypt and digest; sign and encrypt; and decrypt
+ * and sign)
+ */
+#define CKF_DUAL_CRYPTO_OPERATIONS 0x00000200UL
+
+/* CKF_TOKEN_INITIALIZED. If it is true, the
+ * token has been initialized using C_InitializeToken or an
+ * equivalent mechanism outside the scope of PKCS #11.
+ * Calling C_InitializeToken when this flag is set will cause
+ * the token to be reinitialized.
+ */
+#define CKF_TOKEN_INITIALIZED 0x00000400UL
+
+/* CKF_SECONDARY_AUTHENTICATION. If it is
+ * true, the token supports secondary authentication for
+ * private key objects.
+ */
+#define CKF_SECONDARY_AUTHENTICATION 0x00000800UL
+
+/* CKF_USER_PIN_COUNT_LOW. If it is true, an
+ * incorrect user login PIN has been entered at least once
+ * since the last successful authentication.
+ */
+#define CKF_USER_PIN_COUNT_LOW 0x00010000UL
+
+/* CKF_USER_PIN_FINAL_TRY. If it is true,
+ * supplying an incorrect user PIN will it to become locked.
+ */
+#define CKF_USER_PIN_FINAL_TRY 0x00020000UL
+
+/* CKF_USER_PIN_LOCKED. If it is true, the
+ * user PIN has been locked. User login to the token is not
+ * possible.
+ */
+#define CKF_USER_PIN_LOCKED 0x00040000UL
+
+/* CKF_USER_PIN_TO_BE_CHANGED. If it is true,
+ * the user PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card.
+ */
+#define CKF_USER_PIN_TO_BE_CHANGED 0x00080000UL
+
+/* CKF_SO_PIN_COUNT_LOW. If it is true, an
+ * incorrect SO login PIN has been entered at least once since
+ * the last successful authentication.
+ */
+#define CKF_SO_PIN_COUNT_LOW 0x00100000UL
+
+/* CKF_SO_PIN_FINAL_TRY. If it is true,
+ * supplying an incorrect SO PIN will it to become locked.
+ */
+#define CKF_SO_PIN_FINAL_TRY 0x00200000UL
+
+/* CKF_SO_PIN_LOCKED. If it is true, the SO
+ * PIN has been locked. SO login to the token is not possible.
+ */
+#define CKF_SO_PIN_LOCKED 0x00400000UL
+
+/* CKF_SO_PIN_TO_BE_CHANGED. If it is true,
+ * the SO PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card.
+ */
+#define CKF_SO_PIN_TO_BE_CHANGED 0x00800000UL
+
+#define CKF_ERROR_STATE 0x01000000UL
+
+typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR;
+
+
+/* CK_SESSION_HANDLE is a Cryptoki-assigned value that
+ * identifies a session
+ */
+typedef CK_ULONG CK_SESSION_HANDLE;
+
+typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR;
+
+
+/* CK_USER_TYPE enumerates the types of Cryptoki users */
+typedef CK_ULONG CK_USER_TYPE;
+/* Security Officer */
+#define CKU_SO 0UL
+/* Normal user */
+#define CKU_USER 1UL
+/* Context specific */
+#define CKU_CONTEXT_SPECIFIC 2UL
+
+/* CK_STATE enumerates the session states */
+typedef CK_ULONG CK_STATE;
+#define CKS_RO_PUBLIC_SESSION 0UL
+#define CKS_RO_USER_FUNCTIONS 1UL
+#define CKS_RW_PUBLIC_SESSION 2UL
+#define CKS_RW_USER_FUNCTIONS 3UL
+#define CKS_RW_SO_FUNCTIONS 4UL
+
+/* CK_SESSION_INFO provides information about a session */
+typedef struct CK_SESSION_INFO {
+ CK_SLOT_ID slotID;
+ CK_STATE state;
+ CK_FLAGS flags; /* see below */
+ CK_ULONG ulDeviceError; /* device-dependent error code */
+} CK_SESSION_INFO;
+
+/* The flags are defined in the following table:
+ * Bit Flag Mask Meaning
+ */
+#define CKF_RW_SESSION 0x00000002UL /* session is r/w */
+#define CKF_SERIAL_SESSION 0x00000004UL /* no parallel */
+
+typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR;
+
+
+/* CK_OBJECT_HANDLE is a token-specific identifier for an
+ * object
+ */
+typedef CK_ULONG CK_OBJECT_HANDLE;
+
+typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR;
+
+
+/* CK_OBJECT_CLASS is a value that identifies the classes (or
+ * types) of objects that Cryptoki recognizes. It is defined
+ * as follows:
+ */
+typedef CK_ULONG CK_OBJECT_CLASS;
+
+/* The following classes of objects are defined: */
+#define CKO_DATA 0x00000000UL
+#define CKO_CERTIFICATE 0x00000001UL
+#define CKO_PUBLIC_KEY 0x00000002UL
+#define CKO_PRIVATE_KEY 0x00000003UL
+#define CKO_SECRET_KEY 0x00000004UL
+#define CKO_HW_FEATURE 0x00000005UL
+#define CKO_DOMAIN_PARAMETERS 0x00000006UL
+#define CKO_MECHANISM 0x00000007UL
+#define CKO_OTP_KEY 0x00000008UL
+
+#define CKO_VENDOR_DEFINED 0x80000000UL
+
+typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR;
+
+/* CK_HW_FEATURE_TYPE is a value that identifies the hardware feature type
+ * of an object with CK_OBJECT_CLASS equal to CKO_HW_FEATURE.
+ */
+typedef CK_ULONG CK_HW_FEATURE_TYPE;
+
+/* The following hardware feature types are defined */
+#define CKH_MONOTONIC_COUNTER 0x00000001UL
+#define CKH_CLOCK 0x00000002UL
+#define CKH_USER_INTERFACE 0x00000003UL
+#define CKH_VENDOR_DEFINED 0x80000000UL
+
+/* CK_KEY_TYPE is a value that identifies a key type */
+typedef CK_ULONG CK_KEY_TYPE;
+
+/* the following key types are defined: */
+#define CKK_RSA 0x00000000UL
+#define CKK_DSA 0x00000001UL
+#define CKK_DH 0x00000002UL
+#define CKK_ECDSA 0x00000003UL /* Deprecated */
+#define CKK_EC 0x00000003UL
+#define CKK_X9_42_DH 0x00000004UL
+#define CKK_KEA 0x00000005UL
+#define CKK_GENERIC_SECRET 0x00000010UL
+#define CKK_RC2 0x00000011UL
+#define CKK_RC4 0x00000012UL
+#define CKK_DES 0x00000013UL
+#define CKK_DES2 0x00000014UL
+#define CKK_DES3 0x00000015UL
+#define CKK_CAST 0x00000016UL
+#define CKK_CAST3 0x00000017UL
+#define CKK_CAST5 0x00000018UL /* Deprecated */
+#define CKK_CAST128 0x00000018UL
+#define CKK_RC5 0x00000019UL
+#define CKK_IDEA 0x0000001AUL
+#define CKK_SKIPJACK 0x0000001BUL
+#define CKK_BATON 0x0000001CUL
+#define CKK_JUNIPER 0x0000001DUL
+#define CKK_CDMF 0x0000001EUL
+#define CKK_AES 0x0000001FUL
+#define CKK_BLOWFISH 0x00000020UL
+#define CKK_TWOFISH 0x00000021UL
+#define CKK_SECURID 0x00000022UL
+#define CKK_HOTP 0x00000023UL
+#define CKK_ACTI 0x00000024UL
+#define CKK_CAMELLIA 0x00000025UL
+#define CKK_ARIA 0x00000026UL
+
+#define CKK_MD5_HMAC 0x00000027UL
+#define CKK_SHA_1_HMAC 0x00000028UL
+#define CKK_RIPEMD128_HMAC 0x00000029UL
+#define CKK_RIPEMD160_HMAC 0x0000002AUL
+#define CKK_SHA256_HMAC 0x0000002BUL
+#define CKK_SHA384_HMAC 0x0000002CUL
+#define CKK_SHA512_HMAC 0x0000002DUL
+#define CKK_SHA224_HMAC 0x0000002EUL
+
+#define CKK_SEED 0x0000002FUL
+#define CKK_GOSTR3410 0x00000030UL
+#define CKK_GOSTR3411 0x00000031UL
+#define CKK_GOST28147 0x00000032UL
+
+
+
+#define CKK_VENDOR_DEFINED 0x80000000UL
+
+
+/* CK_CERTIFICATE_TYPE is a value that identifies a certificate
+ * type
+ */
+typedef CK_ULONG CK_CERTIFICATE_TYPE;
+
+#define CK_CERTIFICATE_CATEGORY_UNSPECIFIED 0UL
+#define CK_CERTIFICATE_CATEGORY_TOKEN_USER 1UL
+#define CK_CERTIFICATE_CATEGORY_AUTHORITY 2UL
+#define CK_CERTIFICATE_CATEGORY_OTHER_ENTITY 3UL
+
+#define CK_SECURITY_DOMAIN_UNSPECIFIED 0UL
+#define CK_SECURITY_DOMAIN_MANUFACTURER 1UL
+#define CK_SECURITY_DOMAIN_OPERATOR 2UL
+#define CK_SECURITY_DOMAIN_THIRD_PARTY 3UL
+
+
+/* The following certificate types are defined: */
+#define CKC_X_509 0x00000000UL
+#define CKC_X_509_ATTR_CERT 0x00000001UL
+#define CKC_WTLS 0x00000002UL
+#define CKC_VENDOR_DEFINED 0x80000000UL
+
+
+/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute
+ * type
+ */
+typedef CK_ULONG CK_ATTRIBUTE_TYPE;
+
+/* The CKF_ARRAY_ATTRIBUTE flag identifies an attribute which
+ * consists of an array of values.
+ */
+#define CKF_ARRAY_ATTRIBUTE 0x40000000UL
+
+/* The following OTP-related defines relate to the CKA_OTP_FORMAT attribute */
+#define CK_OTP_FORMAT_DECIMAL 0UL
+#define CK_OTP_FORMAT_HEXADECIMAL 1UL
+#define CK_OTP_FORMAT_ALPHANUMERIC 2UL
+#define CK_OTP_FORMAT_BINARY 3UL
+
+/* The following OTP-related defines relate to the CKA_OTP_..._REQUIREMENT
+ * attributes
+ */
+#define CK_OTP_PARAM_IGNORED 0UL
+#define CK_OTP_PARAM_OPTIONAL 1UL
+#define CK_OTP_PARAM_MANDATORY 2UL
+
+/* The following attribute types are defined: */
+#define CKA_CLASS 0x00000000UL
+#define CKA_TOKEN 0x00000001UL
+#define CKA_PRIVATE 0x00000002UL
+#define CKA_LABEL 0x00000003UL
+#define CKA_APPLICATION 0x00000010UL
+#define CKA_VALUE 0x00000011UL
+#define CKA_OBJECT_ID 0x00000012UL
+#define CKA_CERTIFICATE_TYPE 0x00000080UL
+#define CKA_ISSUER 0x00000081UL
+#define CKA_SERIAL_NUMBER 0x00000082UL
+#define CKA_AC_ISSUER 0x00000083UL
+#define CKA_OWNER 0x00000084UL
+#define CKA_ATTR_TYPES 0x00000085UL
+#define CKA_TRUSTED 0x00000086UL
+#define CKA_CERTIFICATE_CATEGORY 0x00000087UL
+#define CKA_JAVA_MIDP_SECURITY_DOMAIN 0x00000088UL
+#define CKA_URL 0x00000089UL
+#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY 0x0000008AUL
+#define CKA_HASH_OF_ISSUER_PUBLIC_KEY 0x0000008BUL
+#define CKA_NAME_HASH_ALGORITHM 0x0000008CUL
+#define CKA_CHECK_VALUE 0x00000090UL
+
+#define CKA_KEY_TYPE 0x00000100UL
+#define CKA_SUBJECT 0x00000101UL
+#define CKA_ID 0x00000102UL
+#define CKA_SENSITIVE 0x00000103UL
+#define CKA_ENCRYPT 0x00000104UL
+#define CKA_DECRYPT 0x00000105UL
+#define CKA_WRAP 0x00000106UL
+#define CKA_UNWRAP 0x00000107UL
+#define CKA_SIGN 0x00000108UL
+#define CKA_SIGN_RECOVER 0x00000109UL
+#define CKA_VERIFY 0x0000010AUL
+#define CKA_VERIFY_RECOVER 0x0000010BUL
+#define CKA_DERIVE 0x0000010CUL
+#define CKA_START_DATE 0x00000110UL
+#define CKA_END_DATE 0x00000111UL
+#define CKA_MODULUS 0x00000120UL
+#define CKA_MODULUS_BITS 0x00000121UL
+#define CKA_PUBLIC_EXPONENT 0x00000122UL
+#define CKA_PRIVATE_EXPONENT 0x00000123UL
+#define CKA_PRIME_1 0x00000124UL
+#define CKA_PRIME_2 0x00000125UL
+#define CKA_EXPONENT_1 0x00000126UL
+#define CKA_EXPONENT_2 0x00000127UL
+#define CKA_COEFFICIENT 0x00000128UL
+#define CKA_PUBLIC_KEY_INFO 0x00000129UL
+#define CKA_PRIME 0x00000130UL
+#define CKA_SUBPRIME 0x00000131UL
+#define CKA_BASE 0x00000132UL
+
+#define CKA_PRIME_BITS 0x00000133UL
+#define CKA_SUBPRIME_BITS 0x00000134UL
+#define CKA_SUB_PRIME_BITS CKA_SUBPRIME_BITS
+
+#define CKA_VALUE_BITS 0x00000160UL
+#define CKA_VALUE_LEN 0x00000161UL
+#define CKA_EXTRACTABLE 0x00000162UL
+#define CKA_LOCAL 0x00000163UL
+#define CKA_NEVER_EXTRACTABLE 0x00000164UL
+#define CKA_ALWAYS_SENSITIVE 0x00000165UL
+#define CKA_KEY_GEN_MECHANISM 0x00000166UL
+
+#define CKA_MODIFIABLE 0x00000170UL
+#define CKA_COPYABLE 0x00000171UL
+
+#define CKA_DESTROYABLE 0x00000172UL
+
+#define CKA_ECDSA_PARAMS 0x00000180UL /* Deprecated */
+#define CKA_EC_PARAMS 0x00000180UL
+
+#define CKA_EC_POINT 0x00000181UL
+
+#define CKA_SECONDARY_AUTH 0x00000200UL /* Deprecated */
+#define CKA_AUTH_PIN_FLAGS 0x00000201UL /* Deprecated */
+
+#define CKA_ALWAYS_AUTHENTICATE 0x00000202UL
+
+#define CKA_WRAP_WITH_TRUSTED 0x00000210UL
+#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000211UL)
+#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000212UL)
+#define CKA_DERIVE_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000213UL)
+
+#define CKA_OTP_FORMAT 0x00000220UL
+#define CKA_OTP_LENGTH 0x00000221UL
+#define CKA_OTP_TIME_INTERVAL 0x00000222UL
+#define CKA_OTP_USER_FRIENDLY_MODE 0x00000223UL
+#define CKA_OTP_CHALLENGE_REQUIREMENT 0x00000224UL
+#define CKA_OTP_TIME_REQUIREMENT 0x00000225UL
+#define CKA_OTP_COUNTER_REQUIREMENT 0x00000226UL
+#define CKA_OTP_PIN_REQUIREMENT 0x00000227UL
+#define CKA_OTP_COUNTER 0x0000022EUL
+#define CKA_OTP_TIME 0x0000022FUL
+#define CKA_OTP_USER_IDENTIFIER 0x0000022AUL
+#define CKA_OTP_SERVICE_IDENTIFIER 0x0000022BUL
+#define CKA_OTP_SERVICE_LOGO 0x0000022CUL
+#define CKA_OTP_SERVICE_LOGO_TYPE 0x0000022DUL
+
+#define CKA_GOSTR3410_PARAMS 0x00000250UL
+#define CKA_GOSTR3411_PARAMS 0x00000251UL
+#define CKA_GOST28147_PARAMS 0x00000252UL
+
+#define CKA_HW_FEATURE_TYPE 0x00000300UL
+#define CKA_RESET_ON_INIT 0x00000301UL
+#define CKA_HAS_RESET 0x00000302UL
+
+#define CKA_PIXEL_X 0x00000400UL
+#define CKA_PIXEL_Y 0x00000401UL
+#define CKA_RESOLUTION 0x00000402UL
+#define CKA_CHAR_ROWS 0x00000403UL
+#define CKA_CHAR_COLUMNS 0x00000404UL
+#define CKA_COLOR 0x00000405UL
+#define CKA_BITS_PER_PIXEL 0x00000406UL
+#define CKA_CHAR_SETS 0x00000480UL
+#define CKA_ENCODING_METHODS 0x00000481UL
+#define CKA_MIME_TYPES 0x00000482UL
+#define CKA_MECHANISM_TYPE 0x00000500UL
+#define CKA_REQUIRED_CMS_ATTRIBUTES 0x00000501UL
+#define CKA_DEFAULT_CMS_ATTRIBUTES 0x00000502UL
+#define CKA_SUPPORTED_CMS_ATTRIBUTES 0x00000503UL
+#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE|0x00000600UL)
+
+#define CKA_VENDOR_DEFINED 0x80000000UL
+
+/* CK_ATTRIBUTE is a structure that includes the type, length
+ * and value of an attribute
+ */
+typedef struct CK_ATTRIBUTE {
+ CK_ATTRIBUTE_TYPE type;
+ CK_VOID_PTR pValue;
+ CK_ULONG ulValueLen; /* in bytes */
+} CK_ATTRIBUTE;
+
+typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR;
+
+/* CK_DATE is a structure that defines a date */
+typedef struct CK_DATE{
+ CK_CHAR year[4]; /* the year ("1900" - "9999") */
+ CK_CHAR month[2]; /* the month ("01" - "12") */
+ CK_CHAR day[2]; /* the day ("01" - "31") */
+} CK_DATE;
+
+
+/* CK_MECHANISM_TYPE is a value that identifies a mechanism
+ * type
+ */
+typedef CK_ULONG CK_MECHANISM_TYPE;
+
+/* the following mechanism types are defined: */
+#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000UL
+#define CKM_RSA_PKCS 0x00000001UL
+#define CKM_RSA_9796 0x00000002UL
+#define CKM_RSA_X_509 0x00000003UL
+
+#define CKM_MD2_RSA_PKCS 0x00000004UL
+#define CKM_MD5_RSA_PKCS 0x00000005UL
+#define CKM_SHA1_RSA_PKCS 0x00000006UL
+
+#define CKM_RIPEMD128_RSA_PKCS 0x00000007UL
+#define CKM_RIPEMD160_RSA_PKCS 0x00000008UL
+#define CKM_RSA_PKCS_OAEP 0x00000009UL
+
+#define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000AUL
+#define CKM_RSA_X9_31 0x0000000BUL
+#define CKM_SHA1_RSA_X9_31 0x0000000CUL
+#define CKM_RSA_PKCS_PSS 0x0000000DUL
+#define CKM_SHA1_RSA_PKCS_PSS 0x0000000EUL
+
+#define CKM_DSA_KEY_PAIR_GEN 0x00000010UL
+#define CKM_DSA 0x00000011UL
+#define CKM_DSA_SHA1 0x00000012UL
+#define CKM_DSA_SHA224 0x00000013UL
+#define CKM_DSA_SHA256 0x00000014UL
+#define CKM_DSA_SHA384 0x00000015UL
+#define CKM_DSA_SHA512 0x00000016UL
+
+#define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020UL
+#define CKM_DH_PKCS_DERIVE 0x00000021UL
+
+#define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030UL
+#define CKM_X9_42_DH_DERIVE 0x00000031UL
+#define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032UL
+#define CKM_X9_42_MQV_DERIVE 0x00000033UL
+
+#define CKM_SHA256_RSA_PKCS 0x00000040UL
+#define CKM_SHA384_RSA_PKCS 0x00000041UL
+#define CKM_SHA512_RSA_PKCS 0x00000042UL
+#define CKM_SHA256_RSA_PKCS_PSS 0x00000043UL
+#define CKM_SHA384_RSA_PKCS_PSS 0x00000044UL
+#define CKM_SHA512_RSA_PKCS_PSS 0x00000045UL
+
+#define CKM_SHA224_RSA_PKCS 0x00000046UL
+#define CKM_SHA224_RSA_PKCS_PSS 0x00000047UL
+
+#define CKM_SHA512_224 0x00000048UL
+#define CKM_SHA512_224_HMAC 0x00000049UL
+#define CKM_SHA512_224_HMAC_GENERAL 0x0000004AUL
+#define CKM_SHA512_224_KEY_DERIVATION 0x0000004BUL
+#define CKM_SHA512_256 0x0000004CUL
+#define CKM_SHA512_256_HMAC 0x0000004DUL
+#define CKM_SHA512_256_HMAC_GENERAL 0x0000004EUL
+#define CKM_SHA512_256_KEY_DERIVATION 0x0000004FUL
+
+#define CKM_SHA512_T 0x00000050UL
+#define CKM_SHA512_T_HMAC 0x00000051UL
+#define CKM_SHA512_T_HMAC_GENERAL 0x00000052UL
+#define CKM_SHA512_T_KEY_DERIVATION 0x00000053UL
+
+#define CKM_RC2_KEY_GEN 0x00000100UL
+#define CKM_RC2_ECB 0x00000101UL
+#define CKM_RC2_CBC 0x00000102UL
+#define CKM_RC2_MAC 0x00000103UL
+
+#define CKM_RC2_MAC_GENERAL 0x00000104UL
+#define CKM_RC2_CBC_PAD 0x00000105UL
+
+#define CKM_RC4_KEY_GEN 0x00000110UL
+#define CKM_RC4 0x00000111UL
+#define CKM_DES_KEY_GEN 0x00000120UL
+#define CKM_DES_ECB 0x00000121UL
+#define CKM_DES_CBC 0x00000122UL
+#define CKM_DES_MAC 0x00000123UL
+
+#define CKM_DES_MAC_GENERAL 0x00000124UL
+#define CKM_DES_CBC_PAD 0x00000125UL
+
+#define CKM_DES2_KEY_GEN 0x00000130UL
+#define CKM_DES3_KEY_GEN 0x00000131UL
+#define CKM_DES3_ECB 0x00000132UL
+#define CKM_DES3_CBC 0x00000133UL
+#define CKM_DES3_MAC 0x00000134UL
+
+#define CKM_DES3_MAC_GENERAL 0x00000135UL
+#define CKM_DES3_CBC_PAD 0x00000136UL
+#define CKM_DES3_CMAC_GENERAL 0x00000137UL
+#define CKM_DES3_CMAC 0x00000138UL
+#define CKM_CDMF_KEY_GEN 0x00000140UL
+#define CKM_CDMF_ECB 0x00000141UL
+#define CKM_CDMF_CBC 0x00000142UL
+#define CKM_CDMF_MAC 0x00000143UL
+#define CKM_CDMF_MAC_GENERAL 0x00000144UL
+#define CKM_CDMF_CBC_PAD 0x00000145UL
+
+#define CKM_DES_OFB64 0x00000150UL
+#define CKM_DES_OFB8 0x00000151UL
+#define CKM_DES_CFB64 0x00000152UL
+#define CKM_DES_CFB8 0x00000153UL
+
+#define CKM_MD2 0x00000200UL
+
+#define CKM_MD2_HMAC 0x00000201UL
+#define CKM_MD2_HMAC_GENERAL 0x00000202UL
+
+#define CKM_MD5 0x00000210UL
+
+#define CKM_MD5_HMAC 0x00000211UL
+#define CKM_MD5_HMAC_GENERAL 0x00000212UL
+
+#define CKM_SHA_1 0x00000220UL
+
+#define CKM_SHA_1_HMAC 0x00000221UL
+#define CKM_SHA_1_HMAC_GENERAL 0x00000222UL
+
+#define CKM_RIPEMD128 0x00000230UL
+#define CKM_RIPEMD128_HMAC 0x00000231UL
+#define CKM_RIPEMD128_HMAC_GENERAL 0x00000232UL
+#define CKM_RIPEMD160 0x00000240UL
+#define CKM_RIPEMD160_HMAC 0x00000241UL
+#define CKM_RIPEMD160_HMAC_GENERAL 0x00000242UL
+
+#define CKM_SHA256 0x00000250UL
+#define CKM_SHA256_HMAC 0x00000251UL
+#define CKM_SHA256_HMAC_GENERAL 0x00000252UL
+#define CKM_SHA224 0x00000255UL
+#define CKM_SHA224_HMAC 0x00000256UL
+#define CKM_SHA224_HMAC_GENERAL 0x00000257UL
+#define CKM_SHA384 0x00000260UL
+#define CKM_SHA384_HMAC 0x00000261UL
+#define CKM_SHA384_HMAC_GENERAL 0x00000262UL
+#define CKM_SHA512 0x00000270UL
+#define CKM_SHA512_HMAC 0x00000271UL
+#define CKM_SHA512_HMAC_GENERAL 0x00000272UL
+#define CKM_SECURID_KEY_GEN 0x00000280UL
+#define CKM_SECURID 0x00000282UL
+#define CKM_HOTP_KEY_GEN 0x00000290UL
+#define CKM_HOTP 0x00000291UL
+#define CKM_ACTI 0x000002A0UL
+#define CKM_ACTI_KEY_GEN 0x000002A1UL
+
+#define CKM_CAST_KEY_GEN 0x00000300UL
+#define CKM_CAST_ECB 0x00000301UL
+#define CKM_CAST_CBC 0x00000302UL
+#define CKM_CAST_MAC 0x00000303UL
+#define CKM_CAST_MAC_GENERAL 0x00000304UL
+#define CKM_CAST_CBC_PAD 0x00000305UL
+#define CKM_CAST3_KEY_GEN 0x00000310UL
+#define CKM_CAST3_ECB 0x00000311UL
+#define CKM_CAST3_CBC 0x00000312UL
+#define CKM_CAST3_MAC 0x00000313UL
+#define CKM_CAST3_MAC_GENERAL 0x00000314UL
+#define CKM_CAST3_CBC_PAD 0x00000315UL
+/* Note that CAST128 and CAST5 are the same algorithm */
+#define CKM_CAST5_KEY_GEN 0x00000320UL
+#define CKM_CAST128_KEY_GEN 0x00000320UL
+#define CKM_CAST5_ECB 0x00000321UL
+#define CKM_CAST128_ECB 0x00000321UL
+#define CKM_CAST5_CBC 0x00000322UL /* Deprecated */
+#define CKM_CAST128_CBC 0x00000322UL
+#define CKM_CAST5_MAC 0x00000323UL /* Deprecated */
+#define CKM_CAST128_MAC 0x00000323UL
+#define CKM_CAST5_MAC_GENERAL 0x00000324UL /* Deprecated */
+#define CKM_CAST128_MAC_GENERAL 0x00000324UL
+#define CKM_CAST5_CBC_PAD 0x00000325UL /* Deprecated */
+#define CKM_CAST128_CBC_PAD 0x00000325UL
+#define CKM_RC5_KEY_GEN 0x00000330UL
+#define CKM_RC5_ECB 0x00000331UL
+#define CKM_RC5_CBC 0x00000332UL
+#define CKM_RC5_MAC 0x00000333UL
+#define CKM_RC5_MAC_GENERAL 0x00000334UL
+#define CKM_RC5_CBC_PAD 0x00000335UL
+#define CKM_IDEA_KEY_GEN 0x00000340UL
+#define CKM_IDEA_ECB 0x00000341UL
+#define CKM_IDEA_CBC 0x00000342UL
+#define CKM_IDEA_MAC 0x00000343UL
+#define CKM_IDEA_MAC_GENERAL 0x00000344UL
+#define CKM_IDEA_CBC_PAD 0x00000345UL
+#define CKM_GENERIC_SECRET_KEY_GEN 0x00000350UL
+#define CKM_CONCATENATE_BASE_AND_KEY 0x00000360UL
+#define CKM_CONCATENATE_BASE_AND_DATA 0x00000362UL
+#define CKM_CONCATENATE_DATA_AND_BASE 0x00000363UL
+#define CKM_XOR_BASE_AND_DATA 0x00000364UL
+#define CKM_EXTRACT_KEY_FROM_KEY 0x00000365UL
+#define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370UL
+#define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371UL
+#define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372UL
+
+#define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373UL
+#define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374UL
+#define CKM_TLS_MASTER_KEY_DERIVE 0x00000375UL
+#define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376UL
+#define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377UL
+
+#define CKM_TLS_PRF 0x00000378UL
+
+#define CKM_SSL3_MD5_MAC 0x00000380UL
+#define CKM_SSL3_SHA1_MAC 0x00000381UL
+#define CKM_MD5_KEY_DERIVATION 0x00000390UL
+#define CKM_MD2_KEY_DERIVATION 0x00000391UL
+#define CKM_SHA1_KEY_DERIVATION 0x00000392UL
+
+#define CKM_SHA256_KEY_DERIVATION 0x00000393UL
+#define CKM_SHA384_KEY_DERIVATION 0x00000394UL
+#define CKM_SHA512_KEY_DERIVATION 0x00000395UL
+#define CKM_SHA224_KEY_DERIVATION 0x00000396UL
+
+#define CKM_PBE_MD2_DES_CBC 0x000003A0UL
+#define CKM_PBE_MD5_DES_CBC 0x000003A1UL
+#define CKM_PBE_MD5_CAST_CBC 0x000003A2UL
+#define CKM_PBE_MD5_CAST3_CBC 0x000003A3UL
+#define CKM_PBE_MD5_CAST5_CBC 0x000003A4UL /* Deprecated */
+#define CKM_PBE_MD5_CAST128_CBC 0x000003A4UL
+#define CKM_PBE_SHA1_CAST5_CBC 0x000003A5UL /* Deprecated */
+#define CKM_PBE_SHA1_CAST128_CBC 0x000003A5UL
+#define CKM_PBE_SHA1_RC4_128 0x000003A6UL
+#define CKM_PBE_SHA1_RC4_40 0x000003A7UL
+#define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003A8UL
+#define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003A9UL
+#define CKM_PBE_SHA1_RC2_128_CBC 0x000003AAUL
+#define CKM_PBE_SHA1_RC2_40_CBC 0x000003ABUL
+
+#define CKM_PKCS5_PBKD2 0x000003B0UL
+
+#define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003C0UL
+
+#define CKM_WTLS_PRE_MASTER_KEY_GEN 0x000003D0UL
+#define CKM_WTLS_MASTER_KEY_DERIVE 0x000003D1UL
+#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC 0x000003D2UL
+#define CKM_WTLS_PRF 0x000003D3UL
+#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE 0x000003D4UL
+#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE 0x000003D5UL
+
+#define CKM_TLS10_MAC_SERVER 0x000003D6UL
+#define CKM_TLS10_MAC_CLIENT 0x000003D7UL
+#define CKM_TLS12_MAC 0x000003D8UL
+#define CKM_TLS12_KDF 0x000003D9UL
+#define CKM_TLS12_MASTER_KEY_DERIVE 0x000003E0UL
+#define CKM_TLS12_KEY_AND_MAC_DERIVE 0x000003E1UL
+#define CKM_TLS12_MASTER_KEY_DERIVE_DH 0x000003E2UL
+#define CKM_TLS12_KEY_SAFE_DERIVE 0x000003E3UL
+#define CKM_TLS_MAC 0x000003E4UL
+#define CKM_TLS_KDF 0x000003E5UL
+
+#define CKM_KEY_WRAP_LYNKS 0x00000400UL
+#define CKM_KEY_WRAP_SET_OAEP 0x00000401UL
+
+#define CKM_CMS_SIG 0x00000500UL
+#define CKM_KIP_DERIVE 0x00000510UL
+#define CKM_KIP_WRAP 0x00000511UL
+#define CKM_KIP_MAC 0x00000512UL
+
+#define CKM_CAMELLIA_KEY_GEN 0x00000550UL
+#define CKM_CAMELLIA_ECB 0x00000551UL
+#define CKM_CAMELLIA_CBC 0x00000552UL
+#define CKM_CAMELLIA_MAC 0x00000553UL
+#define CKM_CAMELLIA_MAC_GENERAL 0x00000554UL
+#define CKM_CAMELLIA_CBC_PAD 0x00000555UL
+#define CKM_CAMELLIA_ECB_ENCRYPT_DATA 0x00000556UL
+#define CKM_CAMELLIA_CBC_ENCRYPT_DATA 0x00000557UL
+#define CKM_CAMELLIA_CTR 0x00000558UL
+
+#define CKM_ARIA_KEY_GEN 0x00000560UL
+#define CKM_ARIA_ECB 0x00000561UL
+#define CKM_ARIA_CBC 0x00000562UL
+#define CKM_ARIA_MAC 0x00000563UL
+#define CKM_ARIA_MAC_GENERAL 0x00000564UL
+#define CKM_ARIA_CBC_PAD 0x00000565UL
+#define CKM_ARIA_ECB_ENCRYPT_DATA 0x00000566UL
+#define CKM_ARIA_CBC_ENCRYPT_DATA 0x00000567UL
+
+#define CKM_SEED_KEY_GEN 0x00000650UL
+#define CKM_SEED_ECB 0x00000651UL
+#define CKM_SEED_CBC 0x00000652UL
+#define CKM_SEED_MAC 0x00000653UL
+#define CKM_SEED_MAC_GENERAL 0x00000654UL
+#define CKM_SEED_CBC_PAD 0x00000655UL
+#define CKM_SEED_ECB_ENCRYPT_DATA 0x00000656UL
+#define CKM_SEED_CBC_ENCRYPT_DATA 0x00000657UL
+
+#define CKM_SKIPJACK_KEY_GEN 0x00001000UL
+#define CKM_SKIPJACK_ECB64 0x00001001UL
+#define CKM_SKIPJACK_CBC64 0x00001002UL
+#define CKM_SKIPJACK_OFB64 0x00001003UL
+#define CKM_SKIPJACK_CFB64 0x00001004UL
+#define CKM_SKIPJACK_CFB32 0x00001005UL
+#define CKM_SKIPJACK_CFB16 0x00001006UL
+#define CKM_SKIPJACK_CFB8 0x00001007UL
+#define CKM_SKIPJACK_WRAP 0x00001008UL
+#define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009UL
+#define CKM_SKIPJACK_RELAYX 0x0000100aUL
+#define CKM_KEA_KEY_PAIR_GEN 0x00001010UL
+#define CKM_KEA_KEY_DERIVE 0x00001011UL
+#define CKM_KEA_DERIVE 0x00001012UL
+#define CKM_FORTEZZA_TIMESTAMP 0x00001020UL
+#define CKM_BATON_KEY_GEN 0x00001030UL
+#define CKM_BATON_ECB128 0x00001031UL
+#define CKM_BATON_ECB96 0x00001032UL
+#define CKM_BATON_CBC128 0x00001033UL
+#define CKM_BATON_COUNTER 0x00001034UL
+#define CKM_BATON_SHUFFLE 0x00001035UL
+#define CKM_BATON_WRAP 0x00001036UL
+
+#define CKM_ECDSA_KEY_PAIR_GEN 0x00001040UL /* Deprecated */
+#define CKM_EC_KEY_PAIR_GEN 0x00001040UL
+
+#define CKM_ECDSA 0x00001041UL
+#define CKM_ECDSA_SHA1 0x00001042UL
+#define CKM_ECDSA_SHA224 0x00001043UL
+#define CKM_ECDSA_SHA256 0x00001044UL
+#define CKM_ECDSA_SHA384 0x00001045UL
+#define CKM_ECDSA_SHA512 0x00001046UL
+
+#define CKM_ECDH1_DERIVE 0x00001050UL
+#define CKM_ECDH1_COFACTOR_DERIVE 0x00001051UL
+#define CKM_ECMQV_DERIVE 0x00001052UL
+
+#define CKM_ECDH_AES_KEY_WRAP 0x00001053UL
+#define CKM_RSA_AES_KEY_WRAP 0x00001054UL
+
+#define CKM_JUNIPER_KEY_GEN 0x00001060UL
+#define CKM_JUNIPER_ECB128 0x00001061UL
+#define CKM_JUNIPER_CBC128 0x00001062UL
+#define CKM_JUNIPER_COUNTER 0x00001063UL
+#define CKM_JUNIPER_SHUFFLE 0x00001064UL
+#define CKM_JUNIPER_WRAP 0x00001065UL
+#define CKM_FASTHASH 0x00001070UL
+
+#define CKM_AES_KEY_GEN 0x00001080UL
+#define CKM_AES_ECB 0x00001081UL
+#define CKM_AES_CBC 0x00001082UL
+#define CKM_AES_MAC 0x00001083UL
+#define CKM_AES_MAC_GENERAL 0x00001084UL
+#define CKM_AES_CBC_PAD 0x00001085UL
+#define CKM_AES_CTR 0x00001086UL
+#define CKM_AES_GCM 0x00001087UL
+#define CKM_AES_CCM 0x00001088UL
+#define CKM_AES_CTS 0x00001089UL
+#define CKM_AES_CMAC 0x0000108AUL
+#define CKM_AES_CMAC_GENERAL 0x0000108BUL
+
+#define CKM_AES_XCBC_MAC 0x0000108CUL
+#define CKM_AES_XCBC_MAC_96 0x0000108DUL
+#define CKM_AES_GMAC 0x0000108EUL
+
+#define CKM_BLOWFISH_KEY_GEN 0x00001090UL
+#define CKM_BLOWFISH_CBC 0x00001091UL
+#define CKM_TWOFISH_KEY_GEN 0x00001092UL
+#define CKM_TWOFISH_CBC 0x00001093UL
+#define CKM_BLOWFISH_CBC_PAD 0x00001094UL
+#define CKM_TWOFISH_CBC_PAD 0x00001095UL
+
+#define CKM_DES_ECB_ENCRYPT_DATA 0x00001100UL
+#define CKM_DES_CBC_ENCRYPT_DATA 0x00001101UL
+#define CKM_DES3_ECB_ENCRYPT_DATA 0x00001102UL
+#define CKM_DES3_CBC_ENCRYPT_DATA 0x00001103UL
+#define CKM_AES_ECB_ENCRYPT_DATA 0x00001104UL
+#define CKM_AES_CBC_ENCRYPT_DATA 0x00001105UL
+
+#define CKM_GOSTR3410_KEY_PAIR_GEN 0x00001200UL
+#define CKM_GOSTR3410 0x00001201UL
+#define CKM_GOSTR3410_WITH_GOSTR3411 0x00001202UL
+#define CKM_GOSTR3410_KEY_WRAP 0x00001203UL
+#define CKM_GOSTR3410_DERIVE 0x00001204UL
+#define CKM_GOSTR3411 0x00001210UL
+#define CKM_GOSTR3411_HMAC 0x00001211UL
+#define CKM_GOST28147_KEY_GEN 0x00001220UL
+#define CKM_GOST28147_ECB 0x00001221UL
+#define CKM_GOST28147 0x00001222UL
+#define CKM_GOST28147_MAC 0x00001223UL
+#define CKM_GOST28147_KEY_WRAP 0x00001224UL
+
+#define CKM_DSA_PARAMETER_GEN 0x00002000UL
+#define CKM_DH_PKCS_PARAMETER_GEN 0x00002001UL
+#define CKM_X9_42_DH_PARAMETER_GEN 0x00002002UL
+#define CKM_DSA_PROBABLISTIC_PARAMETER_GEN 0x00002003UL
+#define CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN 0x00002004UL
+
+#define CKM_AES_OFB 0x00002104UL
+#define CKM_AES_CFB64 0x00002105UL
+#define CKM_AES_CFB8 0x00002106UL
+#define CKM_AES_CFB128 0x00002107UL
+
+#define CKM_AES_CFB1 0x00002108UL
+#define CKM_AES_KEY_WRAP 0x00002109UL /* WAS: 0x00001090 */
+#define CKM_AES_KEY_WRAP_PAD 0x0000210AUL /* WAS: 0x00001091 */
+
+#define CKM_RSA_PKCS_TPM_1_1 0x00004001UL
+#define CKM_RSA_PKCS_OAEP_TPM_1_1 0x00004002UL
+
+#define CKM_VENDOR_DEFINED 0x80000000UL
+
+typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
+
+
+/* CK_MECHANISM is a structure that specifies a particular
+ * mechanism
+ */
+typedef struct CK_MECHANISM {
+ CK_MECHANISM_TYPE mechanism;
+ CK_VOID_PTR pParameter;
+ CK_ULONG ulParameterLen; /* in bytes */
+} CK_MECHANISM;
+
+typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR;
+
+
+/* CK_MECHANISM_INFO provides information about a particular
+ * mechanism
+ */
+typedef struct CK_MECHANISM_INFO {
+ CK_ULONG ulMinKeySize;
+ CK_ULONG ulMaxKeySize;
+ CK_FLAGS flags;
+} CK_MECHANISM_INFO;
+
+/* The flags are defined as follows:
+ * Bit Flag Mask Meaning */
+#define CKF_HW 0x00000001UL /* performed by HW */
+
+/* Specify whether or not a mechanism can be used for a particular task */
+#define CKF_ENCRYPT 0x00000100UL
+#define CKF_DECRYPT 0x00000200UL
+#define CKF_DIGEST 0x00000400UL
+#define CKF_SIGN 0x00000800UL
+#define CKF_SIGN_RECOVER 0x00001000UL
+#define CKF_VERIFY 0x00002000UL
+#define CKF_VERIFY_RECOVER 0x00004000UL
+#define CKF_GENERATE 0x00008000UL
+#define CKF_GENERATE_KEY_PAIR 0x00010000UL
+#define CKF_WRAP 0x00020000UL
+#define CKF_UNWRAP 0x00040000UL
+#define CKF_DERIVE 0x00080000UL
+
+/* Describe a token's EC capabilities not available in mechanism
+ * information.
+ */
+#define CKF_EC_F_P 0x00100000UL
+#define CKF_EC_F_2M 0x00200000UL
+#define CKF_EC_ECPARAMETERS 0x00400000UL
+#define CKF_EC_NAMEDCURVE 0x00800000UL
+#define CKF_EC_UNCOMPRESS 0x01000000UL
+#define CKF_EC_COMPRESS 0x02000000UL
+
+#define CKF_EXTENSION 0x80000000UL
+
+typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR;
+
+/* CK_RV is a value that identifies the return value of a
+ * Cryptoki function
+ */
+typedef CK_ULONG CK_RV;
+
+#define CKR_OK 0x00000000UL
+#define CKR_CANCEL 0x00000001UL
+#define CKR_HOST_MEMORY 0x00000002UL
+#define CKR_SLOT_ID_INVALID 0x00000003UL
+
+#define CKR_GENERAL_ERROR 0x00000005UL
+#define CKR_FUNCTION_FAILED 0x00000006UL
+
+#define CKR_ARGUMENTS_BAD 0x00000007UL
+#define CKR_NO_EVENT 0x00000008UL
+#define CKR_NEED_TO_CREATE_THREADS 0x00000009UL
+#define CKR_CANT_LOCK 0x0000000AUL
+
+#define CKR_ATTRIBUTE_READ_ONLY 0x00000010UL
+#define CKR_ATTRIBUTE_SENSITIVE 0x00000011UL
+#define CKR_ATTRIBUTE_TYPE_INVALID 0x00000012UL
+#define CKR_ATTRIBUTE_VALUE_INVALID 0x00000013UL
+
+#define CKR_ACTION_PROHIBITED 0x0000001BUL
+
+#define CKR_DATA_INVALID 0x00000020UL
+#define CKR_DATA_LEN_RANGE 0x00000021UL
+#define CKR_DEVICE_ERROR 0x00000030UL
+#define CKR_DEVICE_MEMORY 0x00000031UL
+#define CKR_DEVICE_REMOVED 0x00000032UL
+#define CKR_ENCRYPTED_DATA_INVALID 0x00000040UL
+#define CKR_ENCRYPTED_DATA_LEN_RANGE 0x00000041UL
+#define CKR_FUNCTION_CANCELED 0x00000050UL
+#define CKR_FUNCTION_NOT_PARALLEL 0x00000051UL
+
+#define CKR_FUNCTION_NOT_SUPPORTED 0x00000054UL
+
+#define CKR_KEY_HANDLE_INVALID 0x00000060UL
+
+#define CKR_KEY_SIZE_RANGE 0x00000062UL
+#define CKR_KEY_TYPE_INCONSISTENT 0x00000063UL
+
+#define CKR_KEY_NOT_NEEDED 0x00000064UL
+#define CKR_KEY_CHANGED 0x00000065UL
+#define CKR_KEY_NEEDED 0x00000066UL
+#define CKR_KEY_INDIGESTIBLE 0x00000067UL
+#define CKR_KEY_FUNCTION_NOT_PERMITTED 0x00000068UL
+#define CKR_KEY_NOT_WRAPPABLE 0x00000069UL
+#define CKR_KEY_UNEXTRACTABLE 0x0000006AUL
+
+#define CKR_MECHANISM_INVALID 0x00000070UL
+#define CKR_MECHANISM_PARAM_INVALID 0x00000071UL
+
+#define CKR_OBJECT_HANDLE_INVALID 0x00000082UL
+#define CKR_OPERATION_ACTIVE 0x00000090UL
+#define CKR_OPERATION_NOT_INITIALIZED 0x00000091UL
+#define CKR_PIN_INCORRECT 0x000000A0UL
+#define CKR_PIN_INVALID 0x000000A1UL
+#define CKR_PIN_LEN_RANGE 0x000000A2UL
+
+#define CKR_PIN_EXPIRED 0x000000A3UL
+#define CKR_PIN_LOCKED 0x000000A4UL
+
+#define CKR_SESSION_CLOSED 0x000000B0UL
+#define CKR_SESSION_COUNT 0x000000B1UL
+#define CKR_SESSION_HANDLE_INVALID 0x000000B3UL
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED 0x000000B4UL
+#define CKR_SESSION_READ_ONLY 0x000000B5UL
+#define CKR_SESSION_EXISTS 0x000000B6UL
+
+#define CKR_SESSION_READ_ONLY_EXISTS 0x000000B7UL
+#define CKR_SESSION_READ_WRITE_SO_EXISTS 0x000000B8UL
+
+#define CKR_SIGNATURE_INVALID 0x000000C0UL
+#define CKR_SIGNATURE_LEN_RANGE 0x000000C1UL
+#define CKR_TEMPLATE_INCOMPLETE 0x000000D0UL
+#define CKR_TEMPLATE_INCONSISTENT 0x000000D1UL
+#define CKR_TOKEN_NOT_PRESENT 0x000000E0UL
+#define CKR_TOKEN_NOT_RECOGNIZED 0x000000E1UL
+#define CKR_TOKEN_WRITE_PROTECTED 0x000000E2UL
+#define CKR_UNWRAPPING_KEY_HANDLE_INVALID 0x000000F0UL
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE 0x000000F1UL
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x000000F2UL
+#define CKR_USER_ALREADY_LOGGED_IN 0x00000100UL
+#define CKR_USER_NOT_LOGGED_IN 0x00000101UL
+#define CKR_USER_PIN_NOT_INITIALIZED 0x00000102UL
+#define CKR_USER_TYPE_INVALID 0x00000103UL
+
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000104UL
+#define CKR_USER_TOO_MANY_TYPES 0x00000105UL
+
+#define CKR_WRAPPED_KEY_INVALID 0x00000110UL
+#define CKR_WRAPPED_KEY_LEN_RANGE 0x00000112UL
+#define CKR_WRAPPING_KEY_HANDLE_INVALID 0x00000113UL
+#define CKR_WRAPPING_KEY_SIZE_RANGE 0x00000114UL
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT 0x00000115UL
+#define CKR_RANDOM_SEED_NOT_SUPPORTED 0x00000120UL
+
+#define CKR_RANDOM_NO_RNG 0x00000121UL
+
+#define CKR_DOMAIN_PARAMS_INVALID 0x00000130UL
+
+#define CKR_CURVE_NOT_SUPPORTED 0x00000140UL
+
+#define CKR_BUFFER_TOO_SMALL 0x00000150UL
+#define CKR_SAVED_STATE_INVALID 0x00000160UL
+#define CKR_INFORMATION_SENSITIVE 0x00000170UL
+#define CKR_STATE_UNSAVEABLE 0x00000180UL
+
+#define CKR_CRYPTOKI_NOT_INITIALIZED 0x00000190UL
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191UL
+#define CKR_MUTEX_BAD 0x000001A0UL
+#define CKR_MUTEX_NOT_LOCKED 0x000001A1UL
+
+#define CKR_NEW_PIN_MODE 0x000001B0UL
+#define CKR_NEXT_OTP 0x000001B1UL
+
+#define CKR_EXCEEDED_MAX_ITERATIONS 0x000001B5UL
+#define CKR_FIPS_SELF_TEST_FAILED 0x000001B6UL
+#define CKR_LIBRARY_LOAD_FAILED 0x000001B7UL
+#define CKR_PIN_TOO_WEAK 0x000001B8UL
+#define CKR_PUBLIC_KEY_INVALID 0x000001B9UL
+
+#define CKR_FUNCTION_REJECTED 0x00000200UL
+
+#define CKR_VENDOR_DEFINED 0x80000000UL
+
+
+/* CK_NOTIFY is an application callback that processes events */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_NOTIFICATION event,
+ CK_VOID_PTR pApplication /* passed to C_OpenSession */
+);
+
+
+/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec
+ * version and pointers of appropriate types to all the
+ * Cryptoki functions
+ */
+typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST;
+
+typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR;
+
+typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR;
+
+
+/* CK_CREATEMUTEX is an application callback for creating a
+ * mutex object
+ */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)(
+ CK_VOID_PTR_PTR ppMutex /* location to receive ptr to mutex */
+);
+
+
+/* CK_DESTROYMUTEX is an application callback for destroying a
+ * mutex object
+ */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_LOCKMUTEX is an application callback for locking a mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_UNLOCKMUTEX is an application callback for unlocking a
+ * mutex
+ */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_C_INITIALIZE_ARGS provides the optional arguments to
+ * C_Initialize
+ */
+typedef struct CK_C_INITIALIZE_ARGS {
+ CK_CREATEMUTEX CreateMutex;
+ CK_DESTROYMUTEX DestroyMutex;
+ CK_LOCKMUTEX LockMutex;
+ CK_UNLOCKMUTEX UnlockMutex;
+ CK_FLAGS flags;
+ CK_VOID_PTR pReserved;
+} CK_C_INITIALIZE_ARGS;
+
+/* flags: bit flags that provide capabilities of the slot
+ * Bit Flag Mask Meaning
+ */
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001UL
+#define CKF_OS_LOCKING_OK 0x00000002UL
+
+typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR;
+
+
+/* additional flags for parameters to functions */
+
+/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */
+#define CKF_DONT_BLOCK 1
+
+/* CK_RSA_PKCS_MGF_TYPE is used to indicate the Message
+ * Generation Function (MGF) applied to a message block when
+ * formatting a message block for the PKCS #1 OAEP encryption
+ * scheme.
+ */
+typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE;
+
+typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
+
+/* The following MGFs are defined */
+#define CKG_MGF1_SHA1 0x00000001UL
+#define CKG_MGF1_SHA256 0x00000002UL
+#define CKG_MGF1_SHA384 0x00000003UL
+#define CKG_MGF1_SHA512 0x00000004UL
+#define CKG_MGF1_SHA224 0x00000005UL
+
+/* CK_RSA_PKCS_OAEP_SOURCE_TYPE is used to indicate the source
+ * of the encoding parameter when formatting a message block
+ * for the PKCS #1 OAEP encryption scheme.
+ */
+typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE;
+
+typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR;
+
+/* The following encoding parameter sources are defined */
+#define CKZ_DATA_SPECIFIED 0x00000001UL
+
+/* CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_OAEP mechanism.
+ */
+typedef struct CK_RSA_PKCS_OAEP_PARAMS {
+ CK_MECHANISM_TYPE hashAlg;
+ CK_RSA_PKCS_MGF_TYPE mgf;
+ CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
+ CK_VOID_PTR pSourceData;
+ CK_ULONG ulSourceDataLen;
+} CK_RSA_PKCS_OAEP_PARAMS;
+
+typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR;
+
+/* CK_RSA_PKCS_PSS_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_PSS mechanism(s).
+ */
+typedef struct CK_RSA_PKCS_PSS_PARAMS {
+ CK_MECHANISM_TYPE hashAlg;
+ CK_RSA_PKCS_MGF_TYPE mgf;
+ CK_ULONG sLen;
+} CK_RSA_PKCS_PSS_PARAMS;
+
+typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR;
+
+typedef CK_ULONG CK_EC_KDF_TYPE;
+
+/* The following EC Key Derivation Functions are defined */
+#define CKD_NULL 0x00000001UL
+#define CKD_SHA1_KDF 0x00000002UL
+
+/* The following X9.42 DH key derivation functions are defined */
+#define CKD_SHA1_KDF_ASN1 0x00000003UL
+#define CKD_SHA1_KDF_CONCATENATE 0x00000004UL
+#define CKD_SHA224_KDF 0x00000005UL
+#define CKD_SHA256_KDF 0x00000006UL
+#define CKD_SHA384_KDF 0x00000007UL
+#define CKD_SHA512_KDF 0x00000008UL
+#define CKD_CPDIVERSIFY_KDF 0x00000009UL
+
+
+/* CK_ECDH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms,
+ * where each party contributes one key pair.
+ */
+typedef struct CK_ECDH1_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_ECDH1_DERIVE_PARAMS;
+
+typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR;
+
+/*
+ * CK_ECDH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs.
+ */
+typedef struct CK_ECDH2_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+} CK_ECDH2_DERIVE_PARAMS;
+
+typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_ECMQV_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+ CK_OBJECT_HANDLE publicKey;
+} CK_ECMQV_DERIVE_PARAMS;
+
+typedef CK_ECMQV_DERIVE_PARAMS CK_PTR CK_ECMQV_DERIVE_PARAMS_PTR;
+
+/* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the
+ * CKM_X9_42_DH_PARAMETER_GEN mechanisms
+ */
+typedef CK_ULONG CK_X9_42_DH_KDF_TYPE;
+typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR;
+
+/* CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party
+ * contributes one key pair
+ */
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_X9_42_DH1_DERIVE_PARAMS;
+
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR;
+
+/* CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation
+ * mechanisms, where each party contributes two key pairs
+ */
+typedef struct CK_X9_42_DH2_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+} CK_X9_42_DH2_DERIVE_PARAMS;
+
+typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_X9_42_MQV_DERIVE_PARAMS {
+ CK_X9_42_DH_KDF_TYPE kdf;
+ CK_ULONG ulOtherInfoLen;
+ CK_BYTE_PTR pOtherInfo;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPrivateDataLen;
+ CK_OBJECT_HANDLE hPrivateData;
+ CK_ULONG ulPublicDataLen2;
+ CK_BYTE_PTR pPublicData2;
+ CK_OBJECT_HANDLE publicKey;
+} CK_X9_42_MQV_DERIVE_PARAMS;
+
+typedef CK_X9_42_MQV_DERIVE_PARAMS CK_PTR CK_X9_42_MQV_DERIVE_PARAMS_PTR;
+
+/* CK_KEA_DERIVE_PARAMS provides the parameters to the
+ * CKM_KEA_DERIVE mechanism
+ */
+typedef struct CK_KEA_DERIVE_PARAMS {
+ CK_BBOOL isSender;
+ CK_ULONG ulRandomLen;
+ CK_BYTE_PTR pRandomA;
+ CK_BYTE_PTR pRandomB;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_KEA_DERIVE_PARAMS;
+
+typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR;
+
+
+/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and
+ * CKM_RC2_MAC mechanisms. An instance of CK_RC2_PARAMS just
+ * holds the effective keysize
+ */
+typedef CK_ULONG CK_RC2_PARAMS;
+
+typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR;
+
+
+/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC
+ * mechanism
+ */
+typedef struct CK_RC2_CBC_PARAMS {
+ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */
+ CK_BYTE iv[8]; /* IV for CBC mode */
+} CK_RC2_CBC_PARAMS;
+
+typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR;
+
+
+/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC2_MAC_GENERAL mechanism
+ */
+typedef struct CK_RC2_MAC_GENERAL_PARAMS {
+ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */
+ CK_ULONG ulMacLength; /* Length of MAC in bytes */
+} CK_RC2_MAC_GENERAL_PARAMS;
+
+typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \
+ CK_RC2_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and
+ * CKM_RC5_MAC mechanisms
+ */
+typedef struct CK_RC5_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+} CK_RC5_PARAMS;
+
+typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR;
+
+
+/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC
+ * mechanism
+ */
+typedef struct CK_RC5_CBC_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+ CK_BYTE_PTR pIv; /* pointer to IV */
+ CK_ULONG ulIvLen; /* length of IV in bytes */
+} CK_RC5_CBC_PARAMS;
+
+typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR;
+
+
+/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC5_MAC_GENERAL mechanism
+ */
+typedef struct CK_RC5_MAC_GENERAL_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+ CK_ULONG ulMacLength; /* Length of MAC in bytes */
+} CK_RC5_MAC_GENERAL_PARAMS;
+
+typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \
+ CK_RC5_MAC_GENERAL_PARAMS_PTR;
+
+/* CK_MAC_GENERAL_PARAMS provides the parameters to most block
+ * ciphers' MAC_GENERAL mechanisms. Its value is the length of
+ * the MAC
+ */
+typedef CK_ULONG CK_MAC_GENERAL_PARAMS;
+
+typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR;
+
+typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[8];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_DES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[16];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_AES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_PRIVATE_WRAP mechanism
+ */
+typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS {
+ CK_ULONG ulPasswordLen;
+ CK_BYTE_PTR pPassword;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPAndGLen;
+ CK_ULONG ulQLen;
+ CK_ULONG ulRandomLen;
+ CK_BYTE_PTR pRandomA;
+ CK_BYTE_PTR pPrimeP;
+ CK_BYTE_PTR pBaseG;
+ CK_BYTE_PTR pSubprimeQ;
+} CK_SKIPJACK_PRIVATE_WRAP_PARAMS;
+
+typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \
+ CK_SKIPJACK_PRIVATE_WRAP_PARAMS_PTR;
+
+
+/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_RELAYX mechanism
+ */
+typedef struct CK_SKIPJACK_RELAYX_PARAMS {
+ CK_ULONG ulOldWrappedXLen;
+ CK_BYTE_PTR pOldWrappedX;
+ CK_ULONG ulOldPasswordLen;
+ CK_BYTE_PTR pOldPassword;
+ CK_ULONG ulOldPublicDataLen;
+ CK_BYTE_PTR pOldPublicData;
+ CK_ULONG ulOldRandomLen;
+ CK_BYTE_PTR pOldRandomA;
+ CK_ULONG ulNewPasswordLen;
+ CK_BYTE_PTR pNewPassword;
+ CK_ULONG ulNewPublicDataLen;
+ CK_BYTE_PTR pNewPublicData;
+ CK_ULONG ulNewRandomLen;
+ CK_BYTE_PTR pNewRandomA;
+} CK_SKIPJACK_RELAYX_PARAMS;
+
+typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \
+ CK_SKIPJACK_RELAYX_PARAMS_PTR;
+
+
+typedef struct CK_PBE_PARAMS {
+ CK_BYTE_PTR pInitVector;
+ CK_UTF8CHAR_PTR pPassword;
+ CK_ULONG ulPasswordLen;
+ CK_BYTE_PTR pSalt;
+ CK_ULONG ulSaltLen;
+ CK_ULONG ulIteration;
+} CK_PBE_PARAMS;
+
+typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR;
+
+
+/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the
+ * CKM_KEY_WRAP_SET_OAEP mechanism
+ */
+typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS {
+ CK_BYTE bBC; /* block contents byte */
+ CK_BYTE_PTR pX; /* extra data */
+ CK_ULONG ulXLen; /* length of extra data in bytes */
+} CK_KEY_WRAP_SET_OAEP_PARAMS;
+
+typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR CK_KEY_WRAP_SET_OAEP_PARAMS_PTR;
+
+typedef struct CK_SSL3_RANDOM_DATA {
+ CK_BYTE_PTR pClientRandom;
+ CK_ULONG ulClientRandomLen;
+ CK_BYTE_PTR pServerRandom;
+ CK_ULONG ulServerRandomLen;
+} CK_SSL3_RANDOM_DATA;
+
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS {
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_VERSION_PTR pVersion;
+} CK_SSL3_MASTER_KEY_DERIVE_PARAMS;
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+ CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+typedef struct CK_SSL3_KEY_MAT_OUT {
+ CK_OBJECT_HANDLE hClientMacSecret;
+ CK_OBJECT_HANDLE hServerMacSecret;
+ CK_OBJECT_HANDLE hClientKey;
+ CK_OBJECT_HANDLE hServerKey;
+ CK_BYTE_PTR pIVClient;
+ CK_BYTE_PTR pIVServer;
+} CK_SSL3_KEY_MAT_OUT;
+
+typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_PARAMS {
+ CK_ULONG ulMacSizeInBits;
+ CK_ULONG ulKeySizeInBits;
+ CK_ULONG ulIVSizeInBits;
+ CK_BBOOL bIsExport;
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_SSL3_KEY_MAT_PARAMS;
+
+typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR;
+
+typedef struct CK_TLS_PRF_PARAMS {
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+ CK_BYTE_PTR pLabel;
+ CK_ULONG ulLabelLen;
+ CK_BYTE_PTR pOutput;
+ CK_ULONG_PTR pulOutputLen;
+} CK_TLS_PRF_PARAMS;
+
+typedef CK_TLS_PRF_PARAMS CK_PTR CK_TLS_PRF_PARAMS_PTR;
+
+typedef struct CK_WTLS_RANDOM_DATA {
+ CK_BYTE_PTR pClientRandom;
+ CK_ULONG ulClientRandomLen;
+ CK_BYTE_PTR pServerRandom;
+ CK_ULONG ulServerRandomLen;
+} CK_WTLS_RANDOM_DATA;
+
+typedef CK_WTLS_RANDOM_DATA CK_PTR CK_WTLS_RANDOM_DATA_PTR;
+
+typedef struct CK_WTLS_MASTER_KEY_DERIVE_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_WTLS_RANDOM_DATA RandomInfo;
+ CK_BYTE_PTR pVersion;
+} CK_WTLS_MASTER_KEY_DERIVE_PARAMS;
+
+typedef CK_WTLS_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+ CK_WTLS_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+typedef struct CK_WTLS_PRF_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+ CK_BYTE_PTR pLabel;
+ CK_ULONG ulLabelLen;
+ CK_BYTE_PTR pOutput;
+ CK_ULONG_PTR pulOutputLen;
+} CK_WTLS_PRF_PARAMS;
+
+typedef CK_WTLS_PRF_PARAMS CK_PTR CK_WTLS_PRF_PARAMS_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_OUT {
+ CK_OBJECT_HANDLE hMacSecret;
+ CK_OBJECT_HANDLE hKey;
+ CK_BYTE_PTR pIV;
+} CK_WTLS_KEY_MAT_OUT;
+
+typedef CK_WTLS_KEY_MAT_OUT CK_PTR CK_WTLS_KEY_MAT_OUT_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_PARAMS {
+ CK_MECHANISM_TYPE DigestMechanism;
+ CK_ULONG ulMacSizeInBits;
+ CK_ULONG ulKeySizeInBits;
+ CK_ULONG ulIVSizeInBits;
+ CK_ULONG ulSequenceNumber;
+ CK_BBOOL bIsExport;
+ CK_WTLS_RANDOM_DATA RandomInfo;
+ CK_WTLS_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_WTLS_KEY_MAT_PARAMS;
+
+typedef CK_WTLS_KEY_MAT_PARAMS CK_PTR CK_WTLS_KEY_MAT_PARAMS_PTR;
+
+typedef struct CK_CMS_SIG_PARAMS {
+ CK_OBJECT_HANDLE certificateHandle;
+ CK_MECHANISM_PTR pSigningMechanism;
+ CK_MECHANISM_PTR pDigestMechanism;
+ CK_UTF8CHAR_PTR pContentType;
+ CK_BYTE_PTR pRequestedAttributes;
+ CK_ULONG ulRequestedAttributesLen;
+ CK_BYTE_PTR pRequiredAttributes;
+ CK_ULONG ulRequiredAttributesLen;
+} CK_CMS_SIG_PARAMS;
+
+typedef CK_CMS_SIG_PARAMS CK_PTR CK_CMS_SIG_PARAMS_PTR;
+
+typedef struct CK_KEY_DERIVATION_STRING_DATA {
+ CK_BYTE_PTR pData;
+ CK_ULONG ulLen;
+} CK_KEY_DERIVATION_STRING_DATA;
+
+typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \
+ CK_KEY_DERIVATION_STRING_DATA_PTR;
+
+
+/* The CK_EXTRACT_PARAMS is used for the
+ * CKM_EXTRACT_KEY_FROM_KEY mechanism. It specifies which bit
+ * of the base key should be used as the first bit of the
+ * derived key
+ */
+typedef CK_ULONG CK_EXTRACT_PARAMS;
+
+typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR;
+
+/* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to
+ * indicate the Pseudo-Random Function (PRF) used to generate
+ * key bits using PKCS #5 PBKDF2.
+ */
+typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE;
+
+typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR \
+ CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR;
+
+#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001UL
+#define CKP_PKCS5_PBKD2_HMAC_GOSTR3411 0x00000002UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA224 0x00000003UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA256 0x00000004UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA384 0x00000005UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA512 0x00000006UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA512_224 0x00000007UL
+#define CKP_PKCS5_PBKD2_HMAC_SHA512_256 0x00000008UL
+
+/* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the
+ * source of the salt value when deriving a key using PKCS #5
+ * PBKDF2.
+ */
+typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE;
+
+typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR \
+ CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR;
+
+/* The following salt value sources are defined in PKCS #5 v2.0. */
+#define CKZ_SALT_SPECIFIED 0x00000001UL
+
+/* CK_PKCS5_PBKD2_PARAMS is a structure that provides the
+ * parameters to the CKM_PKCS5_PBKD2 mechanism.
+ */
+typedef struct CK_PKCS5_PBKD2_PARAMS {
+ CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource;
+ CK_VOID_PTR pSaltSourceData;
+ CK_ULONG ulSaltSourceDataLen;
+ CK_ULONG iterations;
+ CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
+ CK_VOID_PTR pPrfData;
+ CK_ULONG ulPrfDataLen;
+ CK_UTF8CHAR_PTR pPassword;
+ CK_ULONG_PTR ulPasswordLen;
+} CK_PKCS5_PBKD2_PARAMS;
+
+typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR;
+
+/* CK_PKCS5_PBKD2_PARAMS2 is a corrected version of the CK_PKCS5_PBKD2_PARAMS
+ * structure that provides the parameters to the CKM_PKCS5_PBKD2 mechanism
+ * noting that the ulPasswordLen field is a CK_ULONG and not a CK_ULONG_PTR.
+ */
+typedef struct CK_PKCS5_PBKD2_PARAMS2 {
+ CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource;
+ CK_VOID_PTR pSaltSourceData;
+ CK_ULONG ulSaltSourceDataLen;
+ CK_ULONG iterations;
+ CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
+ CK_VOID_PTR pPrfData;
+ CK_ULONG ulPrfDataLen;
+ CK_UTF8CHAR_PTR pPassword;
+ CK_ULONG ulPasswordLen;
+} CK_PKCS5_PBKD2_PARAMS2;
+
+typedef CK_PKCS5_PBKD2_PARAMS2 CK_PTR CK_PKCS5_PBKD2_PARAMS2_PTR;
+
+typedef CK_ULONG CK_OTP_PARAM_TYPE;
+typedef CK_OTP_PARAM_TYPE CK_PARAM_TYPE; /* backward compatibility */
+
+typedef struct CK_OTP_PARAM {
+ CK_OTP_PARAM_TYPE type;
+ CK_VOID_PTR pValue;
+ CK_ULONG ulValueLen;
+} CK_OTP_PARAM;
+
+typedef CK_OTP_PARAM CK_PTR CK_OTP_PARAM_PTR;
+
+typedef struct CK_OTP_PARAMS {
+ CK_OTP_PARAM_PTR pParams;
+ CK_ULONG ulCount;
+} CK_OTP_PARAMS;
+
+typedef CK_OTP_PARAMS CK_PTR CK_OTP_PARAMS_PTR;
+
+typedef struct CK_OTP_SIGNATURE_INFO {
+ CK_OTP_PARAM_PTR pParams;
+ CK_ULONG ulCount;
+} CK_OTP_SIGNATURE_INFO;
+
+typedef CK_OTP_SIGNATURE_INFO CK_PTR CK_OTP_SIGNATURE_INFO_PTR;
+
+#define CK_OTP_VALUE 0UL
+#define CK_OTP_PIN 1UL
+#define CK_OTP_CHALLENGE 2UL
+#define CK_OTP_TIME 3UL
+#define CK_OTP_COUNTER 4UL
+#define CK_OTP_FLAGS 5UL
+#define CK_OTP_OUTPUT_LENGTH 6UL
+#define CK_OTP_OUTPUT_FORMAT 7UL
+
+#define CKF_NEXT_OTP 0x00000001UL
+#define CKF_EXCLUDE_TIME 0x00000002UL
+#define CKF_EXCLUDE_COUNTER 0x00000004UL
+#define CKF_EXCLUDE_CHALLENGE 0x00000008UL
+#define CKF_EXCLUDE_PIN 0x00000010UL
+#define CKF_USER_FRIENDLY_OTP 0x00000020UL
+
+typedef struct CK_KIP_PARAMS {
+ CK_MECHANISM_PTR pMechanism;
+ CK_OBJECT_HANDLE hKey;
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+} CK_KIP_PARAMS;
+
+typedef CK_KIP_PARAMS CK_PTR CK_KIP_PARAMS_PTR;
+
+typedef struct CK_AES_CTR_PARAMS {
+ CK_ULONG ulCounterBits;
+ CK_BYTE cb[16];
+} CK_AES_CTR_PARAMS;
+
+typedef CK_AES_CTR_PARAMS CK_PTR CK_AES_CTR_PARAMS_PTR;
+
+typedef struct CK_GCM_PARAMS {
+ CK_BYTE_PTR pIv;
+ CK_ULONG ulIvLen;
+ CK_ULONG ulIvBits;
+ CK_BYTE_PTR pAAD;
+ CK_ULONG ulAADLen;
+ CK_ULONG ulTagBits;
+} CK_GCM_PARAMS;
+
+typedef CK_GCM_PARAMS CK_PTR CK_GCM_PARAMS_PTR;
+
+typedef struct CK_CCM_PARAMS {
+ CK_ULONG ulDataLen;
+ CK_BYTE_PTR pNonce;
+ CK_ULONG ulNonceLen;
+ CK_BYTE_PTR pAAD;
+ CK_ULONG ulAADLen;
+ CK_ULONG ulMACLen;
+} CK_CCM_PARAMS;
+
+typedef CK_CCM_PARAMS CK_PTR CK_CCM_PARAMS_PTR;
+
+/* Deprecated. Use CK_GCM_PARAMS */
+typedef struct CK_AES_GCM_PARAMS {
+ CK_BYTE_PTR pIv;
+ CK_ULONG ulIvLen;
+ CK_ULONG ulIvBits;
+ CK_BYTE_PTR pAAD;
+ CK_ULONG ulAADLen;
+ CK_ULONG ulTagBits;
+} CK_AES_GCM_PARAMS;
+
+typedef CK_AES_GCM_PARAMS CK_PTR CK_AES_GCM_PARAMS_PTR;
+
+/* Deprecated. Use CK_CCM_PARAMS */
+typedef struct CK_AES_CCM_PARAMS {
+ CK_ULONG ulDataLen;
+ CK_BYTE_PTR pNonce;
+ CK_ULONG ulNonceLen;
+ CK_BYTE_PTR pAAD;
+ CK_ULONG ulAADLen;
+ CK_ULONG ulMACLen;
+} CK_AES_CCM_PARAMS;
+
+typedef CK_AES_CCM_PARAMS CK_PTR CK_AES_CCM_PARAMS_PTR;
+
+typedef struct CK_CAMELLIA_CTR_PARAMS {
+ CK_ULONG ulCounterBits;
+ CK_BYTE cb[16];
+} CK_CAMELLIA_CTR_PARAMS;
+
+typedef CK_CAMELLIA_CTR_PARAMS CK_PTR CK_CAMELLIA_CTR_PARAMS_PTR;
+
+typedef struct CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[16];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS CK_PTR \
+ CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+typedef struct CK_ARIA_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[16];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_ARIA_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_ARIA_CBC_ENCRYPT_DATA_PARAMS CK_PTR \
+ CK_ARIA_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+typedef struct CK_DSA_PARAMETER_GEN_PARAM {
+ CK_MECHANISM_TYPE hash;
+ CK_BYTE_PTR pSeed;
+ CK_ULONG ulSeedLen;
+ CK_ULONG ulIndex;
+} CK_DSA_PARAMETER_GEN_PARAM;
+
+typedef CK_DSA_PARAMETER_GEN_PARAM CK_PTR CK_DSA_PARAMETER_GEN_PARAM_PTR;
+
+typedef struct CK_ECDH_AES_KEY_WRAP_PARAMS {
+ CK_ULONG ulAESKeyBits;
+ CK_EC_KDF_TYPE kdf;
+ CK_ULONG ulSharedDataLen;
+ CK_BYTE_PTR pSharedData;
+} CK_ECDH_AES_KEY_WRAP_PARAMS;
+
+typedef CK_ECDH_AES_KEY_WRAP_PARAMS CK_PTR CK_ECDH_AES_KEY_WRAP_PARAMS_PTR;
+
+typedef CK_ULONG CK_JAVA_MIDP_SECURITY_DOMAIN;
+
+typedef CK_ULONG CK_CERTIFICATE_CATEGORY;
+
+typedef struct CK_RSA_AES_KEY_WRAP_PARAMS {
+ CK_ULONG ulAESKeyBits;
+ CK_RSA_PKCS_OAEP_PARAMS_PTR pOAEPParams;
+} CK_RSA_AES_KEY_WRAP_PARAMS;
+
+typedef CK_RSA_AES_KEY_WRAP_PARAMS CK_PTR CK_RSA_AES_KEY_WRAP_PARAMS_PTR;
+
+typedef struct CK_TLS12_MASTER_KEY_DERIVE_PARAMS {
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_VERSION_PTR pVersion;
+ CK_MECHANISM_TYPE prfHashMechanism;
+} CK_TLS12_MASTER_KEY_DERIVE_PARAMS;
+
+typedef CK_TLS12_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+ CK_TLS12_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+typedef struct CK_TLS12_KEY_MAT_PARAMS {
+ CK_ULONG ulMacSizeInBits;
+ CK_ULONG ulKeySizeInBits;
+ CK_ULONG ulIVSizeInBits;
+ CK_BBOOL bIsExport;
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+ CK_MECHANISM_TYPE prfHashMechanism;
+} CK_TLS12_KEY_MAT_PARAMS;
+
+typedef CK_TLS12_KEY_MAT_PARAMS CK_PTR CK_TLS12_KEY_MAT_PARAMS_PTR;
+
+typedef struct CK_TLS_KDF_PARAMS {
+ CK_MECHANISM_TYPE prfMechanism;
+ CK_BYTE_PTR pLabel;
+ CK_ULONG ulLabelLength;
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_BYTE_PTR pContextData;
+ CK_ULONG ulContextDataLength;
+} CK_TLS_KDF_PARAMS;
+
+typedef CK_TLS_KDF_PARAMS CK_PTR CK_TLS_KDF_PARAMS_PTR;
+
+typedef struct CK_TLS_MAC_PARAMS {
+ CK_MECHANISM_TYPE prfHashMechanism;
+ CK_ULONG ulMacLength;
+ CK_ULONG ulServerOrClient;
+} CK_TLS_MAC_PARAMS;
+
+typedef CK_TLS_MAC_PARAMS CK_PTR CK_TLS_MAC_PARAMS_PTR;
+
+typedef struct CK_GOSTR3410_DERIVE_PARAMS {
+ CK_EC_KDF_TYPE kdf;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pUKM;
+ CK_ULONG ulUKMLen;
+} CK_GOSTR3410_DERIVE_PARAMS;
+
+typedef CK_GOSTR3410_DERIVE_PARAMS CK_PTR CK_GOSTR3410_DERIVE_PARAMS_PTR;
+
+typedef struct CK_GOSTR3410_KEY_WRAP_PARAMS {
+ CK_BYTE_PTR pWrapOID;
+ CK_ULONG ulWrapOIDLen;
+ CK_BYTE_PTR pUKM;
+ CK_ULONG ulUKMLen;
+ CK_OBJECT_HANDLE hKey;
+} CK_GOSTR3410_KEY_WRAP_PARAMS;
+
+typedef CK_GOSTR3410_KEY_WRAP_PARAMS CK_PTR CK_GOSTR3410_KEY_WRAP_PARAMS_PTR;
+
+typedef struct CK_SEED_CBC_ENCRYPT_DATA_PARAMS {
+ CK_BYTE iv[16];
+ CK_BYTE_PTR pData;
+ CK_ULONG length;
+} CK_SEED_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_SEED_CBC_ENCRYPT_DATA_PARAMS CK_PTR \
+ CK_SEED_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+#endif /* _PKCS11T_H_ */
+
diff --git a/src/lib/prov/tpm/tpm.h b/src/lib/prov/tpm/tpm.h
index 4a9dcd3c6..b8093518c 100644
--- a/src/lib/prov/tpm/tpm.h
+++ b/src/lib/prov/tpm/tpm.h
@@ -1,3 +1,4 @@
+
/*
* TPM 1.2 interface
* (C) 2015 Jack Lloyd
@@ -71,34 +72,27 @@ class BOTAN_DLL TPM_Context
TSS_HTPM m_tpm;
};
-class BOTAN_DLL TPM_RNG : public RandomNumberGenerator
+class BOTAN_DLL TPM_RNG : public Hardware_RNG
{
public:
TPM_RNG(TPM_Context& ctx) : m_ctx(ctx) {}
+ void add_entropy(const byte in[], size_t in_len) override
+ {
+ m_ctx.stir_random(in, in_len);
+ }
+
void randomize(byte out[], size_t out_len) override
{
m_ctx.gen_random(out, out_len);
}
- void clear() override {}
-
std::string name() const override { return "TPM_RNG"; }
- size_t reseed_with_sources(Entropy_Sources&,
- size_t,
- std::chrono::milliseconds) override
- {
- // TODO: poll and stir
- return 0;
- }
+ bool is_seeded() const override { return true; }
- void add_entropy(const byte in[], size_t in_len) override
- {
- m_ctx.stir_random(in, in_len);
- }
+ void clear() override {}
- bool is_seeded() const override { return true; }
private:
TPM_Context& m_ctx;
};
diff --git a/src/lib/pubkey/curve25519/donna.cpp b/src/lib/pubkey/curve25519/donna.cpp
index 9b28e412c..a0e4d249f 100644
--- a/src/lib/pubkey/curve25519/donna.cpp
+++ b/src/lib/pubkey/curve25519/donna.cpp
@@ -39,6 +39,26 @@ typedef byte u8;
typedef u64bit limb;
typedef limb felem[5];
+typedef struct
+ {
+ limb* x;
+ limb* z;
+ } fmonty_pair_t;
+
+typedef struct
+ {
+ fmonty_pair_t q;
+ fmonty_pair_t q_dash;
+ const limb* q_minus_q_dash;
+ } fmonty_in_t;
+
+typedef struct
+ {
+ fmonty_pair_t two_q;
+ fmonty_pair_t q_plus_q_dash;
+ } fmonty_out_t;
+
+
#if !defined(BOTAN_TARGET_HAS_NATIVE_UINT128)
typedef donna128 uint128_t;
#endif
@@ -273,44 +293,41 @@ fcontract(u8 *output, const felem input) {
/* Input: Q, Q', Q-Q'
* Output: 2Q, Q+Q'
*
- * x2 z3: long form
- * x3 z3: long form
- * x z: short form, destroyed
- * xprime zprime: short form, destroyed
- * qmqp: short form, preserved
+ * result.two_q (2*Q): long form
+ * result.q_plus_q_dash (Q + Q): long form
+ * in.q: short form, destroyed
+ * in.q_dash: short form, destroyed
+ * in.q_minus_q_dash: short form, preserved
*/
static void
-fmonty(limb *x2, limb *z2, /* output 2Q */
- limb *x3, limb *z3, /* output Q + Q' */
- limb *x, limb *z, /* input Q */
- limb *xprime, limb *zprime, /* input Q' */
- const limb *qmqp /* input Q - Q' */) {
+fmonty(fmonty_out_t& result, fmonty_in_t& in)
+{
limb origx[5], origxprime[5], zzz[5], xx[5], zz[5], xxprime[5],
- zzprime[5], zzzprime[5];
+ zzprime[5], zzzprime[5];
- copy_mem(origx, x, 5);
- fsum(x, z);
- fdifference_backwards(z, origx); // does x - z
+ copy_mem(origx, in.q.x, 5);
+ fsum(in.q.x, in.q.z);
+ fdifference_backwards(in.q.z, origx); // does x - z
- copy_mem(origxprime, xprime, 5);
- fsum(xprime, zprime);
- fdifference_backwards(zprime, origxprime);
- fmul(xxprime, xprime, z);
- fmul(zzprime, x, zprime);
+ copy_mem(origxprime, in.q_dash.x, 5);
+ fsum(in.q_dash.x, in.q_dash.z);
+ fdifference_backwards(in.q_dash.z, origxprime);
+ fmul(xxprime, in.q_dash.x, in.q.z);
+ fmul(zzprime, in.q.x, in.q_dash.z);
copy_mem(origxprime, xxprime, 5);
fsum(xxprime, zzprime);
fdifference_backwards(zzprime, origxprime);
- fsquare_times(x3, xxprime, 1);
+ fsquare_times(result.q_plus_q_dash.x, xxprime, 1);
fsquare_times(zzzprime, zzprime, 1);
- fmul(z3, zzzprime, qmqp);
+ fmul(result.q_plus_q_dash.z, zzzprime, in.q_minus_q_dash);
- fsquare_times(xx, x, 1);
- fsquare_times(zz, z, 1);
- fmul(x2, xx, zz);
+ fsquare_times(xx, in.q.x, 1);
+ fsquare_times(zz, in.q.z, 1);
+ fmul(result.two_q.x, xx, zz);
fdifference_backwards(zz, xx); // does zz = xx - zz
fscalar_product(zzz, zz, 121665);
fsum(zzz, xx);
- fmul(z2, zz, zzz);
+ fmul(result.two_q.z, zz, zzz);
}
// -----------------------------------------------------------------------------
@@ -356,11 +373,10 @@ cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
swap_conditional(nqx, nqpqx, bit);
swap_conditional(nqz, nqpqz, bit);
- fmonty(nqx2, nqz2,
- nqpqx2, nqpqz2,
- nqx, nqz,
- nqpqx, nqpqz,
- q);
+
+ fmonty_out_t result { nqx2, nqz2, nqpqx2, nqpqz2 };
+ fmonty_in_t in { nqx, nqz, nqpqx, nqpqz, q };
+ fmonty(result, in);
swap_conditional(nqx2, nqpqx2, bit);
swap_conditional(nqz2, nqpqz2, bit);
diff --git a/src/lib/pubkey/dh/dh.cpp b/src/lib/pubkey/dh/dh.cpp
index 9eb4e5cd0..8ed79aa3d 100644
--- a/src/lib/pubkey/dh/dh.cpp
+++ b/src/lib/pubkey/dh/dh.cpp
@@ -37,6 +37,7 @@ DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng,
const DL_Group& grp,
const BigInt& x_arg)
{
+ const bool generate = (x_arg == 0) ? true : false;
m_group = grp;
m_x = x_arg;
@@ -47,12 +48,18 @@ DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng,
}
if(m_y == 0)
+ {
m_y = power_mod(group_g(), m_x, group_p());
+ }
- if(m_x == 0)
+ if(generate)
+ {
gen_check(rng);
+ }
else
+ {
load_check(rng);
+ }
}
/*
diff --git a/src/lib/pubkey/dlies/dlies.cpp b/src/lib/pubkey/dlies/dlies.cpp
index 2c98966b0..9666a1c23 100644
--- a/src/lib/pubkey/dlies/dlies.cpp
+++ b/src/lib/pubkey/dlies/dlies.cpp
@@ -1,6 +1,7 @@
/*
* DLIES
* (C) 1999-2007 Jack Lloyd
+* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -10,128 +11,204 @@
namespace Botan {
-/*
-* DLIES_Encryptor Constructor
-*/
-DLIES_Encryptor::DLIES_Encryptor(const PK_Key_Agreement_Key& key,
- KDF* kdf_obj,
- MessageAuthenticationCode* mac_obj,
- size_t mac_kl) :
- m_ka(key, "Raw"),
- m_kdf(kdf_obj),
- m_mac(mac_obj),
- m_mac_keylen(mac_kl)
+DLIES_Encryptor::DLIES_Encryptor(const DH_PrivateKey& own_priv_key,
+ KDF* kdf,
+ MessageAuthenticationCode* mac,
+ size_t mac_key_length) :
+ DLIES_Encryptor(own_priv_key, kdf, nullptr, 0, mac, mac_key_length)
{
- BOTAN_ASSERT_NONNULL(kdf_obj);
- BOTAN_ASSERT_NONNULL(mac_obj);
- m_my_key = key.public_value();
}
-/*
-* DLIES Encryption
-*/
+DLIES_Encryptor::DLIES_Encryptor(const DH_PrivateKey& own_priv_key,
+ KDF* kdf,
+ Cipher_Mode* cipher,
+ size_t cipher_key_len,
+ MessageAuthenticationCode* mac,
+ size_t mac_key_length) :
+ m_other_pub_key(),
+ m_own_pub_key(own_priv_key.public_value()),
+ m_ka(own_priv_key, "Raw"),
+ m_kdf(kdf),
+ m_cipher(cipher),
+ m_cipher_key_len(cipher_key_len),
+ m_mac(mac),
+ m_mac_keylen(mac_key_length),
+ m_iv()
+ {
+ BOTAN_ASSERT_NONNULL(kdf);
+ BOTAN_ASSERT_NONNULL(mac);
+ }
+
std::vector<byte> DLIES_Encryptor::enc(const byte in[], size_t length,
RandomNumberGenerator&) const
{
- if(length > maximum_input_size())
- throw Invalid_Argument("DLIES: Plaintext too large");
- if(m_other_key.empty())
+ if(m_other_pub_key.empty())
+ {
throw Invalid_State("DLIES: The other key was never set");
+ }
- secure_vector<byte> out(m_my_key.size() + length + m_mac->output_length());
- buffer_insert(out, 0, m_my_key);
- buffer_insert(out, m_my_key.size(), in, length);
+ // calculate secret value
+ const SymmetricKey secret_value = m_ka.derive_key(0, m_other_pub_key);
- secure_vector<byte> vz(m_my_key.begin(), m_my_key.end());
- vz += m_ka.derive_key(0, m_other_key).bits_of();
+ // derive secret key from secret value
+ const size_t required_key_length = m_cipher ? m_cipher_key_len + m_mac_keylen : length + m_mac_keylen;
+ const secure_vector<byte> secret_keys = m_kdf->derive_key(required_key_length, secret_value.bits_of());
- const size_t K_LENGTH = length + m_mac_keylen;
- secure_vector<byte> K = m_kdf->derive_key(K_LENGTH, vz);
-
- if(K.size() != K_LENGTH)
+ if(secret_keys.size() != required_key_length)
+ {
throw Encoding_Error("DLIES: KDF did not provide sufficient output");
- byte* C = &out[m_my_key.size()];
-
- m_mac->set_key(K.data(), m_mac_keylen);
- xor_buf(C, &K[m_mac_keylen], length);
-
- m_mac->update(C, length);
- for(size_t j = 0; j != 8; ++j)
- m_mac->update(0);
-
- m_mac->final(C + length);
+ }
+
+ secure_vector<byte> ciphertext(in, in + length);
+ const size_t cipher_key_len = m_cipher ? m_cipher_key_len : length;
+
+ if(m_cipher)
+ {
+ SymmetricKey enc_key(secret_keys.data(), cipher_key_len);
+ m_cipher->set_key(enc_key);
+
+ if(m_iv.size())
+ {
+ m_cipher->start(m_iv.bits_of());
+ }
+
+ m_cipher->finish(ciphertext);
+ }
+ else
+ {
+ xor_buf(ciphertext, secret_keys, cipher_key_len);
+ }
+
+ // calculate MAC
+ m_mac->set_key(secret_keys.data() + cipher_key_len, m_mac_keylen);
+ secure_vector<byte> tag = m_mac->process(ciphertext);
+
+ // out = (ephemeral) public key + ciphertext + tag
+ secure_vector<byte> out(m_own_pub_key.size() + ciphertext.size() + tag.size());
+ buffer_insert(out, 0, m_own_pub_key);
+ buffer_insert(out, 0 + m_own_pub_key.size(), ciphertext);
+ buffer_insert(out, 0 + m_own_pub_key.size() + ciphertext.size(), tag);
return unlock(out);
}
-/*
-* Set the other parties public key
-*/
-void DLIES_Encryptor::set_other_key(const std::vector<byte>& ok)
- {
- m_other_key = ok;
- }
-
-/*
+/**
* Return the max size, in bytes, of a message
+* Not_Implemented if DLIES is used in XOR encryption mode
*/
size_t DLIES_Encryptor::maximum_input_size() const
{
- return 32;
+ if(m_cipher)
+ {
+ // no limit in block cipher mode
+ return std::numeric_limits<size_t>::max();
+ }
+ else
+ {
+ // No way to determine if the KDF will output enough bits for XORing with the plaintext?!
+ throw Not_Implemented("Not implemented for XOR encryption mode");
+ }
}
-/*
-* DLIES_Decryptor Constructor
-*/
-DLIES_Decryptor::DLIES_Decryptor(const PK_Key_Agreement_Key& key,
- KDF* kdf_obj,
- MessageAuthenticationCode* mac_obj,
- size_t mac_kl) :
- m_ka(key, "Raw"),
- m_kdf(kdf_obj),
- m_mac(mac_obj),
- m_mac_keylen(mac_kl)
+DLIES_Decryptor::DLIES_Decryptor(const DH_PrivateKey& own_priv_key,
+ KDF* kdf,
+ Cipher_Mode* cipher,
+ size_t cipher_key_len,
+ MessageAuthenticationCode* mac,
+ size_t mac_key_length) :
+ m_pub_key_size(own_priv_key.public_value().size()),
+ m_ka(own_priv_key, "Raw"),
+ m_kdf(kdf),
+ m_cipher(cipher),
+ m_cipher_key_len(cipher_key_len),
+ m_mac(mac),
+ m_mac_keylen(mac_key_length),
+ m_iv()
{
- m_my_key = key.public_value();
+ BOTAN_ASSERT_NONNULL(kdf);
+ BOTAN_ASSERT_NONNULL(mac);
}
-/*
-* DLIES Decryption
-*/
+DLIES_Decryptor::DLIES_Decryptor(const DH_PrivateKey& own_priv_key,
+ KDF* kdf,
+ MessageAuthenticationCode* mac,
+ size_t mac_key_length) :
+ DLIES_Decryptor(own_priv_key, kdf, nullptr, 0, mac, mac_key_length)
+ {}
+
secure_vector<byte> DLIES_Decryptor::do_decrypt(byte& valid_mask,
- const byte msg[], size_t length) const
+ const byte msg[], size_t length) const
{
- if(length < m_my_key.size() + m_mac->output_length())
+ if(length < m_pub_key_size + m_mac->output_length())
+ {
throw Decoding_Error("DLIES decryption: ciphertext is too short");
+ }
- const size_t CIPHER_LEN = length - m_my_key.size() - m_mac->output_length();
-
- std::vector<byte> v(msg, msg + m_my_key.size());
+ // calculate secret value
+ std::vector<byte> other_pub_key(msg, msg + m_pub_key_size);
+ const SymmetricKey secret_value = m_ka.derive_key(0, other_pub_key);
- secure_vector<byte> C(msg + m_my_key.size(), msg + m_my_key.size() + CIPHER_LEN);
+ const size_t ciphertext_len = length - m_pub_key_size - m_mac->output_length();
+ size_t cipher_key_len = m_cipher ? m_cipher_key_len : ciphertext_len;
- secure_vector<byte> T(msg + m_my_key.size() + CIPHER_LEN,
- msg + m_my_key.size() + CIPHER_LEN + m_mac->output_length());
+ // derive secret key from secret value
+ const size_t required_key_length = cipher_key_len + m_mac_keylen;
+ secure_vector<byte> secret_keys = m_kdf->derive_key(required_key_length, secret_value.bits_of());
- secure_vector<byte> vz(msg, msg + m_my_key.size());
- vz += m_ka.derive_key(0, v).bits_of();
-
- const size_t K_LENGTH = C.size() + m_mac_keylen;
- secure_vector<byte> K = m_kdf->derive_key(K_LENGTH, vz);
- if(K.size() != K_LENGTH)
+ if(secret_keys.size() != required_key_length)
+ {
throw Encoding_Error("DLIES: KDF did not provide sufficient output");
-
- m_mac->set_key(K.data(), m_mac_keylen);
- m_mac->update(C);
- for(size_t j = 0; j != 8; ++j)
- m_mac->update(0);
- secure_vector<byte> T2 = m_mac->final();
-
- valid_mask = CT::expand_mask<byte>(same_mem(T.data(), T2.data(), T.size()));
-
- xor_buf(C, K.data() + m_mac_keylen, C.size());
-
- return C;
+ }
+
+ secure_vector<byte> ciphertext(msg + m_pub_key_size, msg + m_pub_key_size + ciphertext_len);
+
+ // calculate MAC
+ m_mac->set_key(secret_keys.data() + cipher_key_len, m_mac_keylen);
+ secure_vector<byte> calculated_tag = m_mac->process(ciphertext);
+
+ // calculated tag == received tag ?
+ secure_vector<byte> tag(msg + m_pub_key_size + ciphertext_len,
+ msg + m_pub_key_size + ciphertext_len + m_mac->output_length());
+
+ valid_mask = CT::expand_mask<byte>(same_mem(tag.data(), calculated_tag.data(), tag.size()));
+
+ // decrypt
+ if(m_cipher)
+ {
+ if(valid_mask)
+ {
+ SymmetricKey dec_key(secret_keys.data(), cipher_key_len);
+ m_cipher->set_key(dec_key);
+
+ try
+ {
+ // the decryption can fail:
+ // e.g. Integrity_Failure is thrown if GCM is used and the message does not have a valid tag
+
+ if(m_iv.size())
+ {
+ m_cipher->start(m_iv.bits_of());
+ }
+
+ m_cipher->finish(ciphertext);
+ }
+ catch(...)
+ {
+ valid_mask = 0;
+ }
+
+ }
+ else
+ {
+ return secure_vector<byte>();
+ }
+ }
+ else
+ {
+ xor_buf(ciphertext, secret_keys.data(), cipher_key_len);
+ }
+
+ return ciphertext;
}
}
diff --git a/src/lib/pubkey/dlies/dlies.h b/src/lib/pubkey/dlies/dlies.h
index 10471048d..5f7251d03 100644
--- a/src/lib/pubkey/dlies/dlies.h
+++ b/src/lib/pubkey/dlies/dlies.h
@@ -1,6 +1,7 @@
/*
* DLIES
* (C) 1999-2007 Jack Lloyd
+* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -11,6 +12,8 @@
#include <botan/pubkey.h>
#include <botan/mac.h>
#include <botan/kdf.h>
+#include <botan/dh.h>
+#include <botan/cipher_mode.h>
namespace Botan {
@@ -20,24 +23,67 @@ namespace Botan {
class BOTAN_DLL DLIES_Encryptor : public PK_Encryptor
{
public:
- DLIES_Encryptor(const PK_Key_Agreement_Key&,
+ /**
+ * Stream mode: use KDF to provide a stream of bytes to xor with the message
+ *
+ * @param own_priv_key own (ephemeral) DH private key
+ * @param kdf the KDF that should be used
+ * @param mac the MAC function that should be used
+ * @param mac_key_len key length of the MAC function. Default = 20 bytes
+ *
+ * output = (ephemeral) public key + ciphertext + tag
+ */
+ DLIES_Encryptor(const DH_PrivateKey& own_priv_key,
KDF* kdf,
MessageAuthenticationCode* mac,
size_t mac_key_len = 20);
- void set_other_key(const std::vector<byte>&);
+ /**
+ * Block cipher mode
+ *
+ * @param own_priv_key own (ephemeral) DH private key
+ * @param kdf the KDF that should be used
+ * @param cipher the block cipher that should be used
+ * @param cipher_key_len the key length of the block cipher
+ * @param mac the MAC function that should be used
+ * @param mac_key_len key length of the MAC function. Default = 20 bytes
+ *
+ * output = (ephemeral) public key + ciphertext + tag
+ */
+ DLIES_Encryptor(const DH_PrivateKey& own_priv_key,
+ KDF* kdf,
+ Cipher_Mode* cipher,
+ size_t cipher_key_len,
+ MessageAuthenticationCode* mac,
+ size_t mac_key_len = 20);
+
+ // Set the other parties public key
+ inline void set_other_key(const std::vector<byte>& other_pub_key)
+ {
+ m_other_pub_key = other_pub_key;
+ }
+
+ /// Set the initialization vector for the data encryption method
+ inline void set_initialization_vector(const InitializationVector& iv)
+ {
+ m_iv = iv;
+ }
+
private:
std::vector<byte> enc(const byte[], size_t,
RandomNumberGenerator&) const override;
size_t maximum_input_size() const override;
- std::vector<byte> m_other_key, m_my_key;
-
+ std::vector<byte> m_other_pub_key;
+ std::vector<byte> m_own_pub_key;
PK_Key_Agreement m_ka;
std::unique_ptr<KDF> m_kdf;
+ std::unique_ptr<Cipher_Mode> m_cipher;
+ const size_t m_cipher_key_len;
std::unique_ptr<MessageAuthenticationCode> m_mac;
- size_t m_mac_keylen;
+ const size_t m_mac_keylen;
+ InitializationVector m_iv;
};
/**
@@ -46,21 +92,58 @@ class BOTAN_DLL DLIES_Encryptor : public PK_Encryptor
class BOTAN_DLL DLIES_Decryptor : public PK_Decryptor
{
public:
- DLIES_Decryptor(const PK_Key_Agreement_Key&,
+ /**
+ * Stream mode: use KDF to provide a stream of bytes to xor with the message
+ *
+ * @param own_priv_key own (ephemeral) DH private key
+ * @param kdf the KDF that should be used
+ * @param mac the MAC function that should be used
+ * @param mac_key_len key length of the MAC function. Default = 20 bytes
+ *
+ * input = (ephemeral) public key + ciphertext + tag
+ */
+ DLIES_Decryptor(const DH_PrivateKey& own_priv_key,
KDF* kdf,
MessageAuthenticationCode* mac,
size_t mac_key_len = 20);
+ /**
+ * Block cipher mode
+ *
+ * @param own_priv_key own (ephemeral) DH private key
+ * @param kdf the KDF that should be used
+ * @param cipher the block cipher that should be used
+ * @param cipher_key_len the key length of the block cipher
+ * @param mac the MAC function that should be used
+ * @param mac_key_len key length of the MAC function. Default = 20 bytes
+ *
+ * input = (ephemeral) public key + ciphertext + tag
+ */
+ DLIES_Decryptor(const DH_PrivateKey& own_priv_key,
+ KDF* kdf,
+ Cipher_Mode* cipher,
+ size_t cipher_key_len,
+ MessageAuthenticationCode* mac,
+ size_t mac_key_len = 20);
+
+ /// Set the initialization vector for the data decryption method
+ inline void set_initialization_vector(const InitializationVector& iv)
+ {
+ m_iv = iv;
+ }
+
private:
secure_vector<byte> do_decrypt(byte& valid_mask,
const byte in[], size_t in_len) const override;
- std::vector<byte> m_my_key;
-
+ const size_t m_pub_key_size;
PK_Key_Agreement m_ka;
std::unique_ptr<KDF> m_kdf;
+ std::unique_ptr<Cipher_Mode> m_cipher;
+ const size_t m_cipher_key_len;
std::unique_ptr<MessageAuthenticationCode> m_mac;
- size_t m_mac_keylen;
+ const size_t m_mac_keylen;
+ InitializationVector m_iv;
};
}
diff --git a/src/lib/pubkey/dlies/info.txt b/src/lib/pubkey/dlies/info.txt
index ec1bac803..30362ad78 100644
--- a/src/lib/pubkey/dlies/info.txt
+++ b/src/lib/pubkey/dlies/info.txt
@@ -1,6 +1,7 @@
-define DLIES 20131128
+define DLIES 20160713
<requires>
kdf
mac
+block
</requires>
diff --git a/src/lib/pubkey/dsa/dsa.cpp b/src/lib/pubkey/dsa/dsa.cpp
index 471189cd8..399756b1a 100644
--- a/src/lib/pubkey/dsa/dsa.cpp
+++ b/src/lib/pubkey/dsa/dsa.cpp
@@ -1,6 +1,7 @@
/*
* DSA
* (C) 1999-2010,2014 Jack Lloyd
+* (C) 2016 René Korthaus
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -10,7 +11,10 @@
#include <botan/keypair.h>
#include <botan/pow_mod.h>
#include <botan/reducer.h>
-#include <botan/rfc6979.h>
+#if defined(BOTAN_HAS_RFC6979_GENERATOR)
+ #include <botan/rfc6979.h>
+ #include <botan/emsa.h>
+#endif
#include <future>
namespace Botan {
@@ -66,7 +70,7 @@ bool DSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const
if(!strong)
return true;
- return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)");
+ return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)");
}
namespace {
@@ -84,7 +88,7 @@ class DSA_Signature_Operation : public PK_Ops::Signature_with_EMSA
m_x(dsa.get_x()),
m_powermod_g_p(dsa.group_g(), dsa.group_p()),
m_mod_q(dsa.group_q()),
- m_hash(hash_for_deterministic_signature(emsa))
+ m_emsa(emsa)
{
}
@@ -99,19 +103,24 @@ class DSA_Signature_Operation : public PK_Ops::Signature_with_EMSA
const BigInt& m_x;
Fixed_Base_Power_Mod m_powermod_g_p;
Modular_Reducer m_mod_q;
- std::string m_hash;
+ std::string m_emsa;
};
secure_vector<byte>
DSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len,
- RandomNumberGenerator&)
+ RandomNumberGenerator& rng)
{
BigInt i(msg, msg_len);
while(i >= m_q)
i -= m_q;
- const BigInt k = generate_rfc6979_nonce(m_x, m_q, i, m_hash);
+#if defined(BOTAN_HAS_RFC6979_GENERATOR)
+ BOTAN_UNUSED(rng);
+ const BigInt k = generate_rfc6979_nonce(m_x, m_q, i, hash_for_emsa(m_emsa));
+#else
+ const BigInt k = BigInt::random_integer(rng, 1, m_q);
+#endif
auto future_r = std::async(std::launch::async,
[&]() { return m_mod_q.reduce(m_powermod_g_p(k)); });
@@ -124,10 +133,7 @@ DSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len,
BOTAN_ASSERT(s != 0, "invalid s");
BOTAN_ASSERT(r != 0, "invalid r");
- secure_vector<byte> output(2*m_q.bytes());
- r.binary_encode(&output[output.size() / 2 - r.bytes()]);
- s.binary_encode(&output[output.size() - s.bytes()]);
- return output;
+ return BigInt::encode_fixed_length_int_pair(r, s, m_q.bytes());
}
/**
diff --git a/src/lib/pubkey/dsa/info.txt b/src/lib/pubkey/dsa/info.txt
index 6e0259ce2..855363789 100644
--- a/src/lib/pubkey/dsa/info.txt
+++ b/src/lib/pubkey/dsa/info.txt
@@ -5,5 +5,6 @@ dl_algo
dl_group
keypair
numbertheory
-rfc6979
+emsa1
+sha2_32
</requires>
diff --git a/src/lib/pubkey/ec_group/named.cpp b/src/lib/pubkey/ec_group/named.cpp
index 3ee791053..6df8a3169 100644
--- a/src/lib/pubkey/ec_group/named.cpp
+++ b/src/lib/pubkey/ec_group/named.cpp
@@ -255,6 +255,16 @@ const char* EC_Group::PEM_for_named_group(const std::string& name)
"/////////////////////2xhEHCZWtEARYQbCbdhuJMCAQE="
"-----END EC PARAMETERS-----";
+ if(name == "frp256v1")
+ return
+ "-----BEGIN EC PARAMETERS-----"
+ "MIHgAgEBMCwGByqGSM49AQECIQDx/ReMCzrVjxASbejOQkNbOWGtvKvIym3o/PNT"
+ "2G6cAzBEBCDx/ReMCzrVjxASbejOQkNbOWGtvKvIym3o/PNT2G6cAAQg7jU/ylQo"
+ "qTANSrp1SkTAD9/sDJrksaGAMHXtlnt7tz8EQQS2s9TDVsE56zEYPUdJ1COVjCfS"
+ "3K+YtwFkyXot2Y9c/2FC4PfIsgSRH5Jx8PPs74wnAcMH6OTJ4YMRWhVUBiz7AiEA"
+ "8f0XjAs61Y8QEm3ozkJDW1PcZ+FA0r+UH/3UWcbWVeECAQE="
+ "-----END EC PARAMETERS-----";
+
return nullptr;
}
diff --git a/src/lib/pubkey/ecdsa/ecdsa.cpp b/src/lib/pubkey/ecdsa/ecdsa.cpp
index 4a4b0c037..264a36963 100644
--- a/src/lib/pubkey/ecdsa/ecdsa.cpp
+++ b/src/lib/pubkey/ecdsa/ecdsa.cpp
@@ -3,6 +3,7 @@
* (C) 2007 Manuel Hartl, FlexSecure GmbH
* 2007 Falko Strenzke, FlexSecure GmbH
* 2008-2010,2015 Jack Lloyd
+* 2016 René Korthaus
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -10,7 +11,10 @@
#include <botan/internal/pk_utils.h>
#include <botan/ecdsa.h>
#include <botan/keypair.h>
-#include <botan/rfc6979.h>
+#if defined(BOTAN_HAS_RFC6979_GENERATOR)
+ #include <botan/rfc6979.h>
+ #include <botan/emsa.h>
+#endif
namespace Botan {
@@ -23,7 +27,7 @@ bool ECDSA_PrivateKey::check_key(RandomNumberGenerator& rng,
if(!strong)
return true;
- return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)");
+ return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)");
}
namespace {
@@ -43,7 +47,7 @@ class ECDSA_Signature_Operation : public PK_Ops::Signature_with_EMSA
m_base_point(ecdsa.domain().get_base_point(), m_order),
m_x(ecdsa.private_value()),
m_mod_order(m_order),
- m_hash(hash_for_deterministic_signature(emsa))
+ m_emsa(emsa)
{
}
@@ -59,7 +63,7 @@ class ECDSA_Signature_Operation : public PK_Ops::Signature_with_EMSA
Blinded_Point_Multiply m_base_point;
const BigInt& m_x;
Modular_Reducer m_mod_order;
- std::string m_hash;
+ std::string m_emsa;
};
secure_vector<byte>
@@ -68,7 +72,11 @@ ECDSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len,
{
const BigInt m(msg, msg_len);
- const BigInt k = generate_rfc6979_nonce(m_x, m_order, m, m_hash);
+#if defined(BOTAN_HAS_RFC6979_GENERATOR)
+ const BigInt k = generate_rfc6979_nonce(m_x, m_order, m, hash_for_emsa(m_emsa));
+#else
+ const BigInt k = BigInt::random_integer(rng, 1, m_order);
+#endif
const PointGFp k_times_P = m_base_point.blinded_multiply(k, rng);
const BigInt r = m_mod_order.reduce(k_times_P.get_affine_x());
@@ -78,10 +86,7 @@ ECDSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len,
BOTAN_ASSERT(s != 0, "invalid s");
BOTAN_ASSERT(r != 0, "invalid r");
- secure_vector<byte> output(2*m_order.bytes());
- r.binary_encode(&output[output.size() / 2 - r.bytes()]);
- s.binary_encode(&output[output.size() - s.bytes()]);
- return output;
+ return BigInt::encode_fixed_length_int_pair(r, s, m_order.bytes());
}
/**
diff --git a/src/lib/pubkey/ecdsa/info.txt b/src/lib/pubkey/ecdsa/info.txt
index e7941d53d..3b12bff0d 100644
--- a/src/lib/pubkey/ecdsa/info.txt
+++ b/src/lib/pubkey/ecdsa/info.txt
@@ -7,5 +7,6 @@ ecc_key
keypair
numbertheory
rng
-rfc6979
+emsa1
+sha2_32
</requires>
diff --git a/src/lib/pubkey/ecgdsa/ecgdsa.cpp b/src/lib/pubkey/ecgdsa/ecgdsa.cpp
index b28e3fe96..30ea32817 100644
--- a/src/lib/pubkey/ecgdsa/ecgdsa.cpp
+++ b/src/lib/pubkey/ecgdsa/ecgdsa.cpp
@@ -20,7 +20,7 @@ bool ECGDSA_PrivateKey::check_key(RandomNumberGenerator& rng,
if(!strong)
return true;
- return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)");
+ return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)");
}
namespace {
@@ -73,10 +73,7 @@ ECGDSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len,
BOTAN_ASSERT(s != 0, "invalid s");
BOTAN_ASSERT(r != 0, "invalid r");
- secure_vector<byte> output(2*m_order.bytes());
- r.binary_encode(&output[output.size() / 2 - r.bytes()]);
- s.binary_encode(&output[output.size() - s.bytes()]);
- return output;
+ return BigInt::encode_fixed_length_int_pair(r, s, m_order.bytes());
}
/**
diff --git a/src/lib/pubkey/ecgdsa/info.txt b/src/lib/pubkey/ecgdsa/info.txt
index 6c18a1440..79dec3199 100644
--- a/src/lib/pubkey/ecgdsa/info.txt
+++ b/src/lib/pubkey/ecgdsa/info.txt
@@ -8,4 +8,6 @@ ecc_key
keypair
numbertheory
rng
+emsa1
+sha2_32
</requires>
diff --git a/src/lib/pubkey/ecies/ecies.cpp b/src/lib/pubkey/ecies/ecies.cpp
new file mode 100644
index 000000000..d44d14803
--- /dev/null
+++ b/src/lib/pubkey/ecies/ecies.cpp
@@ -0,0 +1,398 @@
+/*
+* ECIES
+* (C) 2016 Philipp Weber
+* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ecies.h>
+#include <botan/cipher_mode.h>
+
+#include <botan/internal/ct_utils.h>
+#include <botan/internal/pk_utils.h>
+
+namespace Botan {
+
+namespace {
+
+/**
+* Private key type for ECIES_ECDH_KA_Operation
+*/
+class ECIES_PrivateKey : public EC_PrivateKey, public PK_Key_Agreement_Key
+ {
+ public:
+ explicit ECIES_PrivateKey(const ECDH_PrivateKey& private_key) :
+ EC_PublicKey(private_key),
+ EC_PrivateKey(private_key),
+ PK_Key_Agreement_Key(),
+ m_key(private_key)
+ {
+ }
+
+ std::vector<byte> public_value() const override
+ {
+ return m_key.public_value();
+ }
+
+ std::string algo_name() const override
+ {
+ return "ECIES";
+ }
+
+ size_t max_input_bits() const override
+ {
+ return m_key.max_input_bits();
+ }
+
+ private:
+ ECDH_PrivateKey m_key;
+ };
+
+/**
+* Implements ECDH key agreement without using the cofactor mode
+*/
+class ECIES_ECDH_KA_Operation : public PK_Ops::Key_Agreement_with_KDF
+ {
+ public:
+ typedef ECIES_PrivateKey Key_Type;
+
+ ECIES_ECDH_KA_Operation(const ECIES_PrivateKey& private_key, const std::string&) :
+ PK_Ops::Key_Agreement_with_KDF("Raw"),
+ m_key(private_key)
+ {
+ }
+
+ secure_vector<byte> raw_agree(const byte w[], size_t w_len) override
+ {
+ const CurveGFp& curve = m_key.domain().get_curve();
+ PointGFp point = OS2ECP(w, w_len, curve);
+ PointGFp S = point * m_key.private_value();
+ BOTAN_ASSERT(S.on_the_curve(), "ECDH agreed value was on the curve");
+ return BigInt::encode_1363(S.get_affine_x(), curve.get_p().bytes());
+ }
+
+ private:
+ ECIES_PrivateKey m_key;
+ };
+
+/**
+* Creates a PK_Key_Agreement instance for the given key and ecies_params
+* Returns either ECIES_ECDH_KA_Operation or the default implementation for the given key,
+* depending on the key and ecies_params
+* @param private_key the private key used for the key agreement
+* @param ecies_params settings for ecies
+* @param for_encryption disable cofactor mode if the secret will be used for encryption
+* (according to ISO 18033 cofactor mode is only used during decryption)
+*/
+PK_Key_Agreement create_key_agreement(const PK_Key_Agreement_Key& private_key, const ECIES_KA_Params& ecies_params,
+ bool for_encryption)
+ {
+ const ECDH_PrivateKey* ecdh_key = dynamic_cast<const ECDH_PrivateKey*>(&private_key);
+
+ if(ecdh_key == nullptr && (ecies_params.cofactor_mode() || ecies_params.old_cofactor_mode()
+ || ecies_params.check_mode()))
+ {
+ // assume we have a private key from an external provider (e.g. pkcs#11):
+ // there is no way to determine or control whether the provider uses cofactor mode or not.
+ // ISO 18033 does not allow cofactor mode in combination with old cofactor mode or check mode
+ // => disable cofactor mode, old cofactor mode and check mode for unknown keys/providers (as a precaution).
+ throw Invalid_Argument("ECIES: cofactor, old cofactor and check mode are only supported for ECDH_PrivateKey");
+ }
+
+ if(ecdh_key && (for_encryption || !ecies_params.cofactor_mode()))
+ {
+ // ECDH_KA_Operation uses cofactor mode: use own key agreement method if cofactor should not be used.
+ return PK_Key_Agreement(ECIES_PrivateKey(*ecdh_key), "Raw");
+ }
+
+ return PK_Key_Agreement(private_key, "Raw"); // use default implementation
+ }
+}
+
+BOTAN_REGISTER_PK_KEY_AGREE_OP("ECIES", ECIES_ECDH_KA_Operation);
+
+ECIES_KA_Operation::ECIES_KA_Operation(const PK_Key_Agreement_Key& private_key, const ECIES_KA_Params& ecies_params,
+ bool for_encryption) :
+ m_ka(create_key_agreement(private_key, ecies_params, for_encryption)),
+ m_params(ecies_params)
+ {
+ }
+
+/**
+* ECIES secret derivation according to ISO 18033-2
+*/
+SymmetricKey ECIES_KA_Operation::derive_secret(const std::vector<byte>& eph_public_key_bin,
+ const PointGFp& other_public_key_point) const
+ {
+ if(other_public_key_point.is_zero())
+ {
+ throw Invalid_Argument("ECIES: other public key point is zero");
+ }
+
+ std::unique_ptr<KDF> kdf = m_params.create_kdf();
+ BOTAN_ASSERT(kdf != nullptr, "KDF is found");
+
+ PointGFp other_point = other_public_key_point;
+
+ // ISO 18033: step b
+ if(m_params.old_cofactor_mode())
+ {
+ other_point *= m_params.domain().get_cofactor();
+ }
+
+ secure_vector<byte> derivation_input;
+
+ // ISO 18033: encryption step e / decryption step g
+ if(!m_params.single_hash_mode())
+ {
+ derivation_input += eph_public_key_bin;
+ }
+
+ // ISO 18033: encryption step f / decryption step h
+ secure_vector<byte> other_public_key_bin = EC2OSP(other_point, static_cast<byte>(m_params.compression_type()));
+ // Note: the argument `m_params.secret_length()` passed for `key_len` will only be used by providers because
+ // "Raw" is passed to the `PK_Key_Agreement` if the implementation of botan is used.
+ const SymmetricKey peh = m_ka.derive_key(m_params.domain().get_order().bytes(), other_public_key_bin.data(), other_public_key_bin.size());
+ derivation_input.insert(derivation_input.end(), peh.begin(), peh.end());
+
+ // ISO 18033: encryption step g / decryption step i
+ return kdf->derive_key(m_params.secret_length(), derivation_input);
+ }
+
+
+ECIES_KA_Params::ECIES_KA_Params(const EC_Group& domain, const std::string& kdf_spec, size_t length,
+ PointGFp::Compression_Type compression_type, ECIES_Flags flags) :
+ m_domain(domain),
+ m_kdf_spec(kdf_spec),
+ m_length(length),
+ m_compression_mode(compression_type),
+ m_flags(flags)
+ {
+ }
+
+std::unique_ptr<KDF> ECIES_KA_Params::create_kdf() const
+ {
+ std::unique_ptr<KDF> kdf = Botan::KDF::create(m_kdf_spec);
+ if(kdf == nullptr)
+ {
+ throw Algorithm_Not_Found(m_kdf_spec);
+ }
+ return kdf;
+ }
+
+
+ECIES_System_Params::ECIES_System_Params(const EC_Group& domain, const std::string& kdf_spec,
+ const std::string& dem_algo_spec, size_t dem_key_len,
+ const std::string& mac_spec, size_t mac_key_len,
+ PointGFp::Compression_Type compression_type, ECIES_Flags flags) :
+ ECIES_KA_Params(domain, kdf_spec, dem_key_len + mac_key_len, compression_type, flags),
+ m_dem_spec(dem_algo_spec),
+ m_dem_keylen(dem_key_len),
+ m_mac_spec(mac_spec),
+ m_mac_keylen(mac_key_len)
+ {
+ // ISO 18033: "At most one of CofactorMode, OldCofactorMode, and CheckMode may be 1."
+ if(cofactor_mode() + old_cofactor_mode() + check_mode() > 1)
+ {
+ throw Invalid_Argument("ECIES: only one of cofactor_mode, old_cofactor_mode and check_mode can be set");
+ }
+ }
+
+ECIES_System_Params::ECIES_System_Params(const EC_Group& domain, const std::string& kdf_spec,
+ const std::string& dem_algo_spec, size_t dem_key_len,
+ const std::string& mac_spec, size_t mac_key_len) :
+ ECIES_System_Params(domain, kdf_spec, dem_algo_spec, dem_key_len, mac_spec, mac_key_len, PointGFp::UNCOMPRESSED,
+ ECIES_Flags::NONE)
+ {
+ }
+
+std::unique_ptr<MessageAuthenticationCode> ECIES_System_Params::create_mac() const
+ {
+ std::unique_ptr<MessageAuthenticationCode> mac = Botan::MessageAuthenticationCode::create(m_mac_spec);
+ if(mac == nullptr)
+ {
+ throw Algorithm_Not_Found(m_mac_spec);
+ }
+ return mac;
+ }
+
+std::unique_ptr<Cipher_Mode> ECIES_System_Params::create_cipher(Botan::Cipher_Dir direction) const
+ {
+ Cipher_Mode* cipher = get_cipher_mode(m_dem_spec, direction);
+ if(cipher == nullptr)
+ {
+ throw Algorithm_Not_Found(m_dem_spec);
+ }
+ return std::unique_ptr<Cipher_Mode>(cipher);
+ }
+
+
+/*
+* ECIES_Encryptor Constructor
+*/
+ECIES_Encryptor::ECIES_Encryptor(const PK_Key_Agreement_Key& private_key, const ECIES_System_Params& ecies_params) :
+ m_ka(private_key, ecies_params, true),
+ m_params(ecies_params),
+ m_eph_public_key_bin(private_key.public_value()), // returns the uncompressed public key, see conversion below
+ m_iv(),
+ m_other_point(),
+ m_label()
+ {
+ if(ecies_params.compression_type() != PointGFp::UNCOMPRESSED)
+ {
+ // ISO 18033: step d
+ // convert only if necessary; m_eph_public_key_bin has been initialized with the uncompressed format
+ m_eph_public_key_bin = unlock(EC2OSP(OS2ECP(m_eph_public_key_bin, m_params.domain().get_curve()),
+ static_cast<byte>(ecies_params.compression_type())));
+ }
+ }
+
+/*
+* ECIES_Encryptor Constructor
+*/
+ECIES_Encryptor::ECIES_Encryptor(RandomNumberGenerator& rng, const ECIES_System_Params& ecies_params) :
+ ECIES_Encryptor(ECDH_PrivateKey(rng, ecies_params.domain()), ecies_params)
+ {
+ }
+
+
+/*
+* ECIES Encryption according to ISO 18033-2
+*/
+std::vector<byte> ECIES_Encryptor::enc(const byte data[], size_t length, RandomNumberGenerator&) const
+ {
+ if(m_other_point.is_zero())
+ {
+ throw Invalid_State("ECIES: the other key is zero");
+ }
+
+ const SymmetricKey secret_key = m_ka.derive_secret(m_eph_public_key_bin, m_other_point);
+
+ // encryption
+ std::unique_ptr<Cipher_Mode> cipher = m_params.create_cipher(ENCRYPTION);
+ BOTAN_ASSERT(cipher != nullptr, "Cipher is found");
+
+ cipher->set_key(SymmetricKey(secret_key.begin(), m_params.dem_keylen()));
+ if(m_iv.size() != 0)
+ {
+ cipher->start(m_iv.bits_of());
+ }
+ secure_vector<byte> encrypted_data(data, data + length);
+ cipher->finish(encrypted_data);
+
+ // concat elements
+ std::unique_ptr<MessageAuthenticationCode> mac = m_params.create_mac();
+ BOTAN_ASSERT(mac != nullptr, "MAC is found");
+
+ secure_vector<byte> out(m_eph_public_key_bin.size() + encrypted_data.size() + mac->output_length());
+ buffer_insert(out, 0, m_eph_public_key_bin);
+ buffer_insert(out, m_eph_public_key_bin.size(), encrypted_data);
+
+ // mac
+ mac->set_key(secret_key.begin() + m_params.dem_keylen(), m_params.mac_keylen());
+ mac->update(encrypted_data);
+ if(!m_label.empty())
+ {
+ mac->update(m_label);
+ }
+ mac->final(out.data() + m_eph_public_key_bin.size() + encrypted_data.size());
+
+ return unlock(out);
+ }
+
+
+ECIES_Decryptor::ECIES_Decryptor(const PK_Key_Agreement_Key& key, const ECIES_System_Params& ecies_params) :
+ m_ka(key, ecies_params, false),
+ m_params(ecies_params),
+ m_iv(),
+ m_label()
+ {
+ // ISO 18033: "If v > 1 and CheckMode = 0, then we must have gcd(u, v) = 1." (v = index, u= order)
+ if(!ecies_params.check_mode())
+ {
+ Botan::BigInt cofactor = m_params.domain().get_cofactor();
+ if(cofactor > 1 && Botan::gcd(cofactor, m_params.domain().get_order()) != 1)
+ {
+ throw Invalid_Argument("ECIES: gcd of cofactor and order must be 1 if check_mode is 0");
+ }
+ }
+ }
+
+/**
+* ECIES Decryption according to ISO 18033-2
+*/
+secure_vector<byte> ECIES_Decryptor::do_decrypt(byte& valid_mask, const byte in[], size_t in_len) const
+ {
+ size_t point_size = m_params.domain().get_curve().get_p().bytes();
+ if(m_params.compression_type() != PointGFp::COMPRESSED)
+ {
+ point_size *= 2; // uncompressed and hybrid contains x AND y
+ }
+ point_size += 1; // format byte
+
+ std::unique_ptr<MessageAuthenticationCode> mac = m_params.create_mac();
+ BOTAN_ASSERT(mac != nullptr, "MAC is found");
+
+ if(in_len < point_size + mac->output_length())
+ {
+ throw Decoding_Error("ECIES decryption: ciphertext is too short");
+ }
+
+ // extract data
+ const std::vector<byte> other_public_key_bin(in, in + point_size); // the received (ephemeral) public key
+ const std::vector<byte> encrypted_data(in + point_size, in + in_len - mac->output_length());
+ const std::vector<byte> mac_data(in + in_len - mac->output_length(), in + in_len);
+
+ // ISO 18033: step a
+ PointGFp other_public_key = OS2ECP(other_public_key_bin, m_params.domain().get_curve());
+
+ // ISO 18033: step b
+ if(m_params.check_mode() && !other_public_key.on_the_curve())
+ {
+ throw Decoding_Error("ECIES decryption: received public key is not on the curve");
+ }
+
+ // ISO 18033: step e (and step f because get_affine_x (called by ECDH_KA_Operation::raw_agree)
+ // throws Illegal_Transformation if the point is zero)
+ const SymmetricKey secret_key = m_ka.derive_secret(other_public_key_bin, other_public_key);
+
+ // validate mac
+ mac->set_key(secret_key.begin() + m_params.dem_keylen(), m_params.mac_keylen());
+ mac->update(encrypted_data);
+ if(!m_label.empty())
+ {
+ mac->update(m_label);
+ }
+ const secure_vector<byte> calculated_mac = mac->final();
+ valid_mask = CT::expand_mask<byte>(same_mem(mac_data.data(), calculated_mac.data(), mac_data.size()));
+
+ if(valid_mask)
+ {
+ // decrypt data
+ std::unique_ptr<Cipher_Mode> cipher = m_params.create_cipher(DECRYPTION);
+ BOTAN_ASSERT(cipher != nullptr, "Cipher is found");
+
+ cipher->set_key(SymmetricKey(secret_key.begin(), m_params.dem_keylen()));
+ if(m_iv.size() != 0)
+ {
+ cipher->start(m_iv.bits_of());
+ }
+
+ try
+ {
+ // the decryption can fail:
+ // e.g. Integrity_Failure is thrown if GCM is used and the message does not have a valid tag
+ secure_vector<byte> decrypted_data(encrypted_data.begin(), encrypted_data.end());
+ cipher->finish(decrypted_data);
+ return decrypted_data;
+ }
+ catch(...)
+ {
+ valid_mask = 0;
+ }
+ }
+ return secure_vector<byte>();
+ }
+
+}
diff --git a/src/lib/pubkey/ecies/ecies.h b/src/lib/pubkey/ecies/ecies.h
new file mode 100644
index 000000000..0bc0bf76e
--- /dev/null
+++ b/src/lib/pubkey/ecies/ecies.h
@@ -0,0 +1,293 @@
+/*
+* ECIES
+* (C) 2016 Philipp Weber
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_ECIES_H__
+#define BOTAN_ECIES_H__
+
+#include <botan/ecdh.h>
+#include <botan/ec_group.h>
+#include <botan/kdf.h>
+#include <botan/cipher_mode.h>
+#include <botan/mac.h>
+#include <botan/point_gfp.h>
+#include <botan/pubkey.h>
+#include <botan/secmem.h>
+#include <botan/symkey.h>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace Botan {
+
+class RandomNumberGenerator;
+
+enum class ECIES_Flags : uint32_t
+ {
+ NONE = 0,
+
+ /// if set: prefix the input of the (ecdh) key agreement with the encoded (ephemeral) public key
+ SINGLE_HASH_MODE = 1,
+
+ /// (decryption only) if set: use cofactor multiplication during (ecdh) key agreement
+ COFACTOR_MODE = 2,
+
+ /// if set: use ecdhc instead of ecdh
+ OLD_COFACTOR_MODE = 4,
+
+ /// (decryption only) if set: test if the (ephemeral) public key is on the curve
+ CHECK_MODE = 8
+ };
+
+inline ECIES_Flags operator |(ECIES_Flags a, ECIES_Flags b)
+ {
+ return static_cast<ECIES_Flags>(static_cast<uint32_t>(a) | static_cast<uint32_t>(b));
+ }
+
+inline ECIES_Flags operator &(ECIES_Flags a, ECIES_Flags b)
+ {
+ return static_cast<ECIES_Flags>(static_cast<uint32_t>(a) & static_cast<uint32_t>(b));
+ }
+
+/**
+* Parameters for ecies secret derivation
+*/
+class BOTAN_DLL ECIES_KA_Params
+ {
+ public:
+ /**
+ * @param domain ec domain parameters of the involved ec keys
+ * @param kdf_spec name of the key derivation function
+ * @param length length of the secret to be derived
+ * @param compression_type format of encoded keys (affects the secret derivation if single_hash_mode is used)
+ * @param flags options, see documentation of ECIES_Flags
+ */
+ ECIES_KA_Params(const EC_Group& domain, const std::string& kdf_spec, size_t length,
+ PointGFp::Compression_Type compression_type, ECIES_Flags flags);
+
+ virtual ~ECIES_KA_Params() = default;
+
+ std::unique_ptr<KDF> create_kdf() const;
+
+ inline const EC_Group& domain() const
+ {
+ return m_domain;
+ }
+
+ inline size_t secret_length() const
+ {
+ return m_length;
+ }
+
+ inline bool single_hash_mode() const
+ {
+ return (m_flags & ECIES_Flags::SINGLE_HASH_MODE) == ECIES_Flags::SINGLE_HASH_MODE;
+ }
+
+ inline bool cofactor_mode() const
+ {
+ return (m_flags & ECIES_Flags::COFACTOR_MODE) == ECIES_Flags::COFACTOR_MODE;
+ }
+
+ inline bool old_cofactor_mode() const
+ {
+ return (m_flags & ECIES_Flags::OLD_COFACTOR_MODE) == ECIES_Flags::OLD_COFACTOR_MODE;
+ }
+
+ inline bool check_mode() const
+ {
+ return (m_flags & ECIES_Flags::CHECK_MODE) == ECIES_Flags::CHECK_MODE;
+ }
+
+ inline PointGFp::Compression_Type compression_type() const
+ {
+ return m_compression_mode;
+ }
+
+ private:
+ const EC_Group m_domain;
+ const std::string m_kdf_spec;
+ const size_t m_length;
+ const PointGFp::Compression_Type m_compression_mode;
+ const ECIES_Flags m_flags;
+ };
+
+
+class BOTAN_DLL ECIES_System_Params : public ECIES_KA_Params
+ {
+ public:
+ /**
+ * @param domain ec domain parameters of the involved ec keys
+ * @param kdf_spec name of the key derivation function
+ * @param dem_algo_spec name of the data encryption method
+ * @param dem_key_len length of the key used for the data encryption method
+ * @param mac_spec name of the message authentication code
+ * @param mac_key_len length of the key used for the message authentication code
+ */
+ ECIES_System_Params(const EC_Group& domain, const std::string& kdf_spec, const std::string& dem_algo_spec,
+ size_t dem_key_len, const std::string& mac_spec, size_t mac_key_len);
+
+ /**
+ * @param domain ec domain parameters of the involved ec keys
+ * @param kdf_spec name of the key derivation function
+ * @param dem_algo_spec name of the data encryption method
+ * @param dem_key_len length of the key used for the data encryption method
+ * @param mac_spec name of the message authentication code
+ * @param mac_key_len length of the key used for the message authentication code
+ * @param compression_type format of encoded keys (affects the secret derivation if single_hash_mode is used)
+ * @param flags options, see documentation of ECIES_Flags
+ */
+ ECIES_System_Params(const EC_Group& domain, const std::string& kdf_spec, const std::string& dem_algo_spec,
+ size_t dem_key_len, const std::string& mac_spec, size_t mac_key_len,
+ PointGFp::Compression_Type compression_type, ECIES_Flags flags);
+
+ virtual ~ECIES_System_Params() = default;
+
+ /// creates an instance of the message authentication code
+ std::unique_ptr<MessageAuthenticationCode> create_mac() const;
+
+ /// creates an instance of the data encryption method
+ std::unique_ptr<Cipher_Mode> create_cipher(Botan::Cipher_Dir direction) const;
+
+ /// returns the length of the key used by the data encryption method
+ inline size_t dem_keylen() const
+ {
+ return m_dem_keylen;
+ }
+
+ /// returns the length of the key used by the message authentication code
+ inline size_t mac_keylen() const
+ {
+ return m_mac_keylen;
+ }
+
+ private:
+ const std::string m_dem_spec;
+ const size_t m_dem_keylen;
+ const std::string m_mac_spec;
+ const size_t m_mac_keylen;
+ };
+
+
+/**
+* ECIES secret derivation according to ISO 18033-2
+*/
+class BOTAN_DLL ECIES_KA_Operation
+ {
+ public:
+ /**
+ * @param private_key the (ephemeral) private key which is used to derive the secret
+ * @param ecies_params settings for ecies
+ * @param for_encryption disable cofactor mode if the secret will be used for encryption
+ * (according to ISO 18033 cofactor mode is only used during decryption)
+ */
+ ECIES_KA_Operation(const PK_Key_Agreement_Key& private_key, const ECIES_KA_Params& ecies_params,
+ bool for_encryption);
+
+ /**
+ * Performs a key agreement with the provided keys and derives the secret from the result
+ * @param eph_public_key_bin the encoded (ephemeral) public key which belongs to the used (ephemeral) private key
+ * @param other_public_key_point public key point of the other party
+ */
+ SymmetricKey derive_secret(const std::vector<byte>& eph_public_key_bin,
+ const PointGFp& other_public_key_point) const;
+
+ private:
+ const PK_Key_Agreement m_ka;
+ const ECIES_KA_Params m_params;
+ };
+
+
+/**
+* ECIES Encryption according to ISO 18033-2
+*/
+class BOTAN_DLL ECIES_Encryptor : public PK_Encryptor
+ {
+ public:
+ /**
+ * @param private_key the (ephemeral) private key which is used for the key agreement
+ * @param ecies_params settings for ecies
+ */
+ ECIES_Encryptor(const PK_Key_Agreement_Key& private_key, const ECIES_System_Params& ecies_params);
+
+ /**
+ * Creates an ephemeral private key which is used for the key agreement
+ * @param rng random generator used during private key generation
+ * @param ecies_params settings for ecies
+ */
+ ECIES_Encryptor(RandomNumberGenerator& rng, const ECIES_System_Params& ecies_params);
+
+ /// Set the public key of the other party
+ inline void set_other_key(const Botan::PointGFp& public_point)
+ {
+ m_other_point = public_point;
+ }
+
+ /// Set the initialization vector for the data encryption method
+ inline void set_initialization_vector(const InitializationVector& iv)
+ {
+ m_iv = iv;
+ }
+
+ /// Set the label which is appended to the input for the message authentication code
+ inline void set_label(const std::string& label)
+ {
+ m_label = std::vector<byte>(label.begin(), label.end());
+ }
+
+ private:
+ std::vector<byte> enc(const byte data[], size_t length, RandomNumberGenerator&) const override;
+
+ inline size_t maximum_input_size() const override
+ {
+ return std::numeric_limits<size_t>::max();
+ }
+
+ const ECIES_KA_Operation m_ka;
+ const ECIES_System_Params m_params;
+ std::vector<byte> m_eph_public_key_bin;
+ InitializationVector m_iv;
+ PointGFp m_other_point;
+ std::vector<byte> m_label;
+ };
+
+
+/**
+* ECIES Decryption according to ISO 18033-2
+*/
+class BOTAN_DLL ECIES_Decryptor : public PK_Decryptor
+ {
+ public:
+ /**
+ * @param private_key the private key which is used for the key agreement
+ * @param ecies_params settings for ecies
+ */
+ ECIES_Decryptor(const PK_Key_Agreement_Key& private_key, const ECIES_System_Params& ecies_params);
+
+ /// Set the initialization vector for the data encryption method
+ inline void set_initialization_vector(const InitializationVector& iv)
+ {
+ m_iv = iv;
+ }
+
+ /// Set the label which is appended to the input for the message authentication code
+ inline void set_label(const std::string& label)
+ {
+ m_label = std::vector<byte>(label.begin(), label.end());
+ }
+
+ private:
+ secure_vector<byte> do_decrypt(byte& valid_mask, const byte in[], size_t in_len) const override;
+
+ const ECIES_KA_Operation m_ka;
+ const ECIES_System_Params m_params;
+ InitializationVector m_iv;
+ std::vector<byte> m_label;
+ };
+
+}
+
+#endif
diff --git a/src/lib/pubkey/ecies/info.txt b/src/lib/pubkey/ecies/info.txt
new file mode 100644
index 000000000..12776f8c2
--- /dev/null
+++ b/src/lib/pubkey/ecies/info.txt
@@ -0,0 +1,8 @@
+define ECIES 20160128
+
+<requires>
+kdf
+mac
+ecdh
+modes
+</requires> \ No newline at end of file
diff --git a/src/lib/pubkey/eckcdsa/eckcdsa.cpp b/src/lib/pubkey/eckcdsa/eckcdsa.cpp
new file mode 100644
index 000000000..5ca89675c
--- /dev/null
+++ b/src/lib/pubkey/eckcdsa/eckcdsa.cpp
@@ -0,0 +1,200 @@
+/*
+* ECKCDSA (ISO/IEC 14888-3:2006/Cor.2:2009)
+* (C) 2016 René Korthaus, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/internal/pk_utils.h>
+#include <botan/eckcdsa.h>
+#include <botan/keypair.h>
+#include <botan/emsa.h>
+#include <botan/hash.h>
+
+namespace Botan {
+
+bool ECKCDSA_PrivateKey::check_key(RandomNumberGenerator& rng,
+ bool strong) const
+ {
+ if(!public_point().on_the_curve())
+ {
+ return false;
+ }
+
+ if(!strong)
+ {
+ return true;
+ }
+
+ return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)");
+ }
+
+namespace {
+
+/**
+* ECKCDSA signature operation
+*/
+class ECKCDSA_Signature_Operation : public PK_Ops::Signature_with_EMSA
+ {
+ public:
+ typedef ECKCDSA_PrivateKey Key_Type;
+
+ ECKCDSA_Signature_Operation(const ECKCDSA_PrivateKey& eckcdsa,
+ const std::string& emsa) :
+ PK_Ops::Signature_with_EMSA(emsa),
+ m_order(eckcdsa.domain().get_order()),
+ m_base_point(eckcdsa.domain().get_base_point(), m_order),
+ m_x(eckcdsa.private_value()),
+ m_mod_order(m_order),
+ m_prefix()
+ {
+ const BigInt public_point_x = eckcdsa.public_point().get_affine_x();
+ const BigInt public_point_y = eckcdsa.public_point().get_affine_y();
+
+ m_prefix.resize(public_point_x.bytes() + public_point_y.bytes());
+ public_point_x.binary_encode(m_prefix.data());
+ public_point_y.binary_encode(&m_prefix[public_point_x.bytes()]);
+ m_prefix.resize(HashFunction::create(hash_for_signature())->hash_block_size()); // use only the "hash input block size" leftmost bits
+ }
+
+ secure_vector<byte> raw_sign(const byte msg[], size_t msg_len,
+ RandomNumberGenerator& rng) override;
+
+ size_t message_parts() const override { return 2; }
+ size_t message_part_size() const override { return m_order.bytes(); }
+ size_t max_input_bits() const override { return m_order.bits(); }
+
+ bool has_prefix() override { return true; }
+ secure_vector<byte> message_prefix() const override { return m_prefix; }
+
+ private:
+ const BigInt& m_order;
+ Blinded_Point_Multiply m_base_point;
+ const BigInt& m_x;
+ Modular_Reducer m_mod_order;
+ secure_vector<byte> m_prefix;
+ };
+
+secure_vector<byte>
+ECKCDSA_Signature_Operation::raw_sign(const byte msg[], size_t,
+ RandomNumberGenerator& rng)
+ {
+ const BigInt k = BigInt::random_integer(rng, 1, m_order);
+ const PointGFp k_times_P = m_base_point.blinded_multiply(k, rng);
+ const BigInt k_times_P_x = k_times_P.get_affine_x();
+
+ secure_vector<byte> to_be_hashed(k_times_P_x.bytes());
+ k_times_P_x.binary_encode(to_be_hashed.data());
+
+ std::unique_ptr<EMSA> emsa(m_emsa->clone());
+ emsa->update(to_be_hashed.data(), to_be_hashed.size());
+ secure_vector<byte> c = emsa->raw_data();
+ c = emsa->encoding_of(c, max_input_bits(), rng);
+
+ const BigInt r(c.data(), c.size());
+
+ xor_buf(c, msg, c.size());
+ BigInt w(c.data(), c.size());
+ w = m_mod_order.reduce(w);
+
+ const BigInt s = m_mod_order.multiply(m_x, k - w);
+ BOTAN_ASSERT(s != 0, "invalid s");
+
+ secure_vector<byte> output = BigInt::encode_1363(r, c.size());
+ output += BigInt::encode_1363(s, m_mod_order.get_modulus().bytes());
+ return output;
+ }
+
+/**
+* ECKCDSA verification operation
+*/
+class ECKCDSA_Verification_Operation : public PK_Ops::Verification_with_EMSA
+ {
+ public:
+ typedef ECKCDSA_PublicKey Key_Type;
+
+ ECKCDSA_Verification_Operation(const ECKCDSA_PublicKey& eckcdsa,
+ const std::string& emsa) :
+ PK_Ops::Verification_with_EMSA(emsa),
+ m_base_point(eckcdsa.domain().get_base_point()),
+ m_public_point(eckcdsa.public_point()),
+ m_order(eckcdsa.domain().get_order()),
+ m_mod_order(m_order),
+ m_prefix()
+ {
+ const BigInt public_point_x = m_public_point.get_affine_x();
+ const BigInt public_point_y = m_public_point.get_affine_y();
+
+ m_prefix.resize(public_point_x.bytes() + public_point_y.bytes());
+ public_point_x.binary_encode(&m_prefix[0]);
+ public_point_y.binary_encode(&m_prefix[public_point_x.bytes()]);
+ m_prefix.resize(HashFunction::create(hash_for_signature())->hash_block_size()); // use only the "hash input block size" leftmost bits
+ }
+
+ bool has_prefix() override { return true; }
+ secure_vector<byte> message_prefix() const override { return m_prefix; }
+
+ size_t message_parts() const override { return 2; }
+ size_t message_part_size() const override { return m_order.bytes(); }
+ size_t max_input_bits() const override { return m_order.bits(); }
+
+ bool with_recovery() const override { return false; }
+
+ bool verify(const byte msg[], size_t msg_len,
+ const byte sig[], size_t sig_len) override;
+ private:
+ const PointGFp& m_base_point;
+ const PointGFp& m_public_point;
+ const BigInt& m_order;
+ // FIXME: should be offered by curve
+ Modular_Reducer m_mod_order;
+ secure_vector<byte> m_prefix;
+ };
+
+bool ECKCDSA_Verification_Operation::verify(const byte msg[], size_t,
+ const byte sig[], size_t sig_len)
+ {
+ // check that bit length of r is equal to output bit length of employed hash function h
+ const std::unique_ptr<HashFunction> hash = HashFunction::create(hash_for_signature());
+
+ // no way to know size of r in sig, so check that we have at least hash->output_length()+1
+ // bytes in sig, enough for r and an arbitrary size s
+ if(sig_len <= hash->output_length())
+ {
+ return false;
+ }
+
+ secure_vector<byte> r(sig, sig + hash->output_length());
+
+ // check that 0 < s < q
+ const BigInt s(sig + hash->output_length(), sig_len - hash->output_length());
+
+ if(s <= 0 || s >= m_order)
+ {
+ return false;
+ }
+
+ secure_vector<byte> r_xor_e(r);
+ xor_buf(r_xor_e, msg, r.size());
+ BigInt w(r_xor_e.data(), r_xor_e.size());
+ w = m_mod_order.reduce(w);
+
+ const PointGFp q = (m_base_point * w) + (m_public_point * s);
+ const BigInt q_x = q.get_affine_x();
+ secure_vector<byte> c(q_x.bytes());
+ q_x.binary_encode(c.data());
+ std::unique_ptr<EMSA> emsa(m_emsa->clone());
+ emsa->update(c.data(), c.size());
+ secure_vector<byte> v = emsa->raw_data();
+ Null_RNG rng;
+ v = emsa->encoding_of(v, max_input_bits(), rng);
+
+ return (v == r);
+ }
+
+BOTAN_REGISTER_PK_SIGNATURE_OP("ECKCDSA", ECKCDSA_Signature_Operation);
+BOTAN_REGISTER_PK_VERIFY_OP("ECKCDSA", ECKCDSA_Verification_Operation);
+
+}
+
+}
diff --git a/src/lib/pubkey/eckcdsa/eckcdsa.h b/src/lib/pubkey/eckcdsa/eckcdsa.h
new file mode 100644
index 000000000..b85c4025e
--- /dev/null
+++ b/src/lib/pubkey/eckcdsa/eckcdsa.h
@@ -0,0 +1,91 @@
+/*
+* ECKCDSA (ISO/IEC 14888-3:2006/Cor.2:2009)
+* (C) 2016 René Korthaus, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_ECKCDSA_KEY_H__
+#define BOTAN_ECKCDSA_KEY_H__
+
+#include <botan/ecc_key.h>
+
+namespace Botan {
+
+/**
+* This class represents ECKCDSA public keys.
+*/
+class BOTAN_DLL ECKCDSA_PublicKey : public virtual EC_PublicKey
+ {
+ public:
+
+ /**
+ * 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
+ */
+ ECKCDSA_PublicKey(const EC_Group& dom_par,
+ const PointGFp& public_point) :
+ EC_PublicKey(dom_par, public_point) {}
+
+ ECKCDSA_PublicKey(const AlgorithmIdentifier& alg_id,
+ const secure_vector<byte>& key_bits) :
+ EC_PublicKey(alg_id, key_bits) {}
+
+ /**
+ * Get this keys algorithm name.
+ * @result this keys algorithm name ("ECGDSA")
+ */
+ std::string algo_name() const override { return "ECKCDSA"; }
+
+ /**
+ * 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
+ */
+ size_t max_input_bits() const override
+ { return domain().get_order().bits(); }
+
+ size_t message_parts() const override { return 2; }
+
+ size_t message_part_size() const override
+ { return domain().get_order().bytes(); }
+
+ protected:
+ ECKCDSA_PublicKey() {}
+ };
+
+/**
+* This class represents ECKCDSA private keys.
+*/
+class BOTAN_DLL ECKCDSA_PrivateKey : public ECKCDSA_PublicKey,
+ public EC_PrivateKey
+ {
+ public:
+
+ /**
+ * Load a private key
+ * @param alg_id the X.509 algorithm identifier
+ * @param key_bits PKCS #8 structure
+ */
+ ECKCDSA_PrivateKey(const AlgorithmIdentifier& alg_id,
+ const secure_vector<byte>& key_bits) :
+ EC_PrivateKey(alg_id, key_bits, true) {}
+
+ /**
+ * Generate a new private key
+ * @param rng a random number generator
+ * @param domain parameters to used for this key
+ * @param x the private key (if zero, generate a new random key)
+ */
+ ECKCDSA_PrivateKey(RandomNumberGenerator& rng,
+ const EC_Group& domain,
+ const BigInt& x = 0) :
+ EC_PrivateKey(rng, domain, x, true) {}
+
+ bool check_key(RandomNumberGenerator& rng, bool) const override;
+ };
+
+}
+
+#endif
diff --git a/src/lib/pubkey/eckcdsa/info.txt b/src/lib/pubkey/eckcdsa/info.txt
new file mode 100644
index 000000000..d3df354b1
--- /dev/null
+++ b/src/lib/pubkey/eckcdsa/info.txt
@@ -0,0 +1,13 @@
+define ECKCDSA 20160413
+
+<requires>
+asn1
+bigint
+ec_group
+ecc_key
+hash
+keypair
+numbertheory
+pk_pad
+rng
+</requires>
diff --git a/src/lib/pubkey/pk_algs.cpp b/src/lib/pubkey/pk_algs.cpp
index d2947b0c0..9dbde28af 100644
--- a/src/lib/pubkey/pk_algs.cpp
+++ b/src/lib/pubkey/pk_algs.cpp
@@ -28,6 +28,10 @@
#include <botan/ecgdsa.h>
#endif
+#if defined(BOTAN_HAS_ECKCDSA)
+ #include <botan/eckcdsa.h>
+#endif
+
#if defined(BOTAN_HAS_GOST_34_10_2001)
#include <botan/gost_3410.h>
#endif
@@ -105,6 +109,11 @@ Public_Key* make_public_key(const AlgorithmIdentifier& alg_id,
return new ECGDSA_PublicKey(alg_id, key_bits);
#endif
+#if defined(BOTAN_HAS_ECKCDSA)
+ if(alg_name == "ECKCDSA")
+ return new ECKCDSA_PublicKey(alg_id, key_bits);
+#endif
+
#if defined(BOTAN_HAS_GOST_34_10_2001)
if(alg_name == "GOST-34.10")
return new GOST_3410_PublicKey(alg_id, key_bits);
@@ -176,6 +185,11 @@ Private_Key* make_private_key(const AlgorithmIdentifier& alg_id,
return new ECGDSA_PrivateKey(alg_id, key_bits);
#endif
+#if defined(BOTAN_HAS_ECKCDSA)
+ if(alg_name == "ECKCDSA")
+ return new ECKCDSA_PrivateKey(alg_id, key_bits);
+#endif
+
#if defined(BOTAN_HAS_GOST_34_10_2001)
if(alg_name == "GOST-34.10")
return new GOST_3410_PrivateKey(alg_id, key_bits);
diff --git a/src/lib/pubkey/pk_ops.cpp b/src/lib/pubkey/pk_ops.cpp
index 654b68255..1017518a7 100644
--- a/src/lib/pubkey/pk_ops.cpp
+++ b/src/lib/pubkey/pk_ops.cpp
@@ -76,9 +76,12 @@ secure_vector<byte> PK_Ops::Key_Agreement_with_KDF::agree(size_t key_len,
return z;
}
-PK_Ops::Signature_with_EMSA::Signature_with_EMSA(const std::string& emsa)
+PK_Ops::Signature_with_EMSA::Signature_with_EMSA(const std::string& emsa) :
+ Signature(),
+ m_emsa(get_emsa(emsa)),
+ m_hash(hash_for_emsa(emsa)),
+ m_prefix_used(false)
{
- m_emsa.reset(get_emsa(emsa));
if(!m_emsa)
throw Algorithm_Not_Found(emsa);
}
@@ -87,19 +90,29 @@ PK_Ops::Signature_with_EMSA::~Signature_with_EMSA() {}
void PK_Ops::Signature_with_EMSA::update(const byte msg[], size_t msg_len)
{
+ if(has_prefix() && !m_prefix_used)
+ {
+ m_prefix_used = true;
+ secure_vector<byte> prefix = message_prefix();
+ m_emsa->update(prefix.data(), prefix.size());
+ }
m_emsa->update(msg, msg_len);
}
secure_vector<byte> PK_Ops::Signature_with_EMSA::sign(RandomNumberGenerator& rng)
{
+ m_prefix_used = false;
const secure_vector<byte> msg = m_emsa->raw_data();
const auto padded = m_emsa->encoding_of(msg, this->max_input_bits(), rng);
return raw_sign(padded.data(), padded.size(), rng);
}
-PK_Ops::Verification_with_EMSA::Verification_with_EMSA(const std::string& emsa)
+PK_Ops::Verification_with_EMSA::Verification_with_EMSA(const std::string& emsa) :
+ Verification(),
+ m_emsa(get_emsa(emsa)),
+ m_hash(hash_for_emsa(emsa)),
+ m_prefix_used(false)
{
- m_emsa.reset(get_emsa(emsa));
if(!m_emsa)
throw Algorithm_Not_Found(emsa);
}
@@ -108,11 +121,18 @@ PK_Ops::Verification_with_EMSA::~Verification_with_EMSA() {}
void PK_Ops::Verification_with_EMSA::update(const byte msg[], size_t msg_len)
{
+ if(has_prefix() && !m_prefix_used)
+ {
+ m_prefix_used = true;
+ secure_vector<byte> prefix = message_prefix();
+ m_emsa->update(prefix.data(), prefix.size());
+ }
m_emsa->update(msg, msg_len);
}
bool PK_Ops::Verification_with_EMSA::is_valid_signature(const byte sig[], size_t sig_len)
{
+ m_prefix_used = false;
const secure_vector<byte> msg = m_emsa->raw_data();
if(with_recovery())
diff --git a/src/lib/pubkey/pk_ops_impl.h b/src/lib/pubkey/pk_ops_impl.h
index 81637a81c..9d02de5e5 100644
--- a/src/lib/pubkey/pk_ops_impl.h
+++ b/src/lib/pubkey/pk_ops_impl.h
@@ -58,12 +58,25 @@ class Verification_with_EMSA : public Verification
bool do_check(const secure_vector<byte>& msg,
const byte sig[], size_t sig_len);
+ std::string hash_for_signature() { return m_hash; }
protected:
explicit Verification_with_EMSA(const std::string& emsa);
~Verification_with_EMSA();
/**
+ * @return boolean specifying if this signature scheme uses
+ * a message prefix returned by message_prefix()
+ */
+ virtual bool has_prefix() { return false; }
+
+ /**
+ * @return the message prefix if this signature scheme uses
+ * a message prefix, signaled via has_prefix()
+ */
+ virtual secure_vector<byte> message_prefix() const { throw Exception( "No prefix" ); }
+
+ /**
* @return boolean specifying if this key type supports message
* recovery and thus if you need to call verify() or verify_mr()
*/
@@ -95,8 +108,11 @@ class Verification_with_EMSA : public Verification
throw Invalid_State("Message recovery not supported");
}
- private:
std::unique_ptr<EMSA> m_emsa;
+
+ private:
+ const std::string m_hash;
+ bool m_prefix_used;
};
class Signature_with_EMSA : public Signature
@@ -108,6 +124,22 @@ class Signature_with_EMSA : public Signature
protected:
explicit Signature_with_EMSA(const std::string& emsa);
~Signature_with_EMSA();
+
+ std::string hash_for_signature() { return m_hash; }
+
+ /**
+ * @return boolean specifying if this signature scheme uses
+ * a message prefix returned by message_prefix()
+ */
+ virtual bool has_prefix() { return false; }
+
+ /**
+ * @return the message prefix if this signature scheme uses
+ * a message prefix, signaled via has_prefix()
+ */
+ virtual secure_vector<byte> message_prefix() const { throw Exception( "No prefix" ); }
+
+ std::unique_ptr<EMSA> m_emsa;
private:
/**
@@ -122,7 +154,8 @@ class Signature_with_EMSA : public Signature
virtual secure_vector<byte> raw_sign(const byte msg[], size_t msg_len,
RandomNumberGenerator& rng) = 0;
- std::unique_ptr<EMSA> m_emsa;
+ const std::string m_hash;
+ bool m_prefix_used;
};
class Key_Agreement_with_KDF : public Key_Agreement
diff --git a/src/lib/pubkey/pubkey.cpp b/src/lib/pubkey/pubkey.cpp
index c0485fec8..8b24ee983 100644
--- a/src/lib/pubkey/pubkey.cpp
+++ b/src/lib/pubkey/pubkey.cpp
@@ -54,7 +54,7 @@ PK_Decryptor::decrypt_or_random(const byte in[],
{
const secure_vector<byte> fake_pms = rng.random_vec(expected_pt_len);
- CT::poison(in, length);
+ //CT::poison(in, length);
byte valid_mask = 0;
secure_vector<byte> decoded = do_decrypt(valid_mask, in, length);
@@ -90,8 +90,8 @@ PK_Decryptor::decrypt_or_random(const byte in[],
/*from1*/fake_pms.data(),
expected_pt_len);
- CT::unpoison(in, length);
- CT::unpoison(decoded.data(), decoded.size());
+ //CT::unpoison(in, length);
+ //CT::unpoison(decoded.data(), decoded.size());
return decoded;
}
diff --git a/src/lib/pubkey/rfc6979/rfc6979.cpp b/src/lib/pubkey/rfc6979/rfc6979.cpp
index f749b039f..94b313c3a 100644
--- a/src/lib/pubkey/rfc6979/rfc6979.cpp
+++ b/src/lib/pubkey/rfc6979/rfc6979.cpp
@@ -8,41 +8,32 @@
#include <botan/rfc6979.h>
#include <botan/hmac_drbg.h>
#include <botan/mac.h>
-#include <botan/scan_name.h>
namespace Botan {
-std::string hash_for_deterministic_signature(const std::string& emsa)
- {
- SCAN_Name emsa_name(emsa);
-
- if(emsa_name.arg_count() > 0)
- {
- const std::string pos_hash = emsa_name.arg(0);
- return pos_hash;
- }
-
- return "SHA-512"; // safe default if nothing we understand
- }
-
RFC6979_Nonce_Generator::RFC6979_Nonce_Generator(const std::string& hash,
const BigInt& order,
const BigInt& x) :
m_order(order),
m_qlen(m_order.bits()),
m_rlen(m_qlen / 8 + (m_qlen % 8 ? 1 : 0)),
- m_hmac_drbg(new HMAC_DRBG(MessageAuthenticationCode::create("HMAC(" + hash + ")").release())),
m_rng_in(m_rlen * 2),
m_rng_out(m_rlen)
{
+ m_hmac_drbg.reset(new HMAC_DRBG(MessageAuthenticationCode::create("HMAC(" + hash + ")")));
BigInt::encode_1363(m_rng_in.data(), m_rlen, x);
}
+RFC6979_Nonce_Generator::~RFC6979_Nonce_Generator()
+ {
+ // for ~unique_ptr
+ }
+
const BigInt& RFC6979_Nonce_Generator::nonce_for(const BigInt& m)
{
BigInt::encode_1363(&m_rng_in[m_rlen], m_rlen, m);
m_hmac_drbg->clear();
- m_hmac_drbg->add_entropy(m_rng_in.data(), m_rng_in.size());
+ m_hmac_drbg->initialize_with(m_rng_in.data(), m_rng_in.size());
do
{
diff --git a/src/lib/pubkey/rfc6979/rfc6979.h b/src/lib/pubkey/rfc6979/rfc6979.h
index 5b3dee8ef..2518535f7 100644
--- a/src/lib/pubkey/rfc6979/rfc6979.h
+++ b/src/lib/pubkey/rfc6979/rfc6979.h
@@ -14,7 +14,7 @@
namespace Botan {
-class RandomNumberGenerator;
+class HMAC_DRBG;
class BOTAN_DLL RFC6979_Nonce_Generator
{
@@ -26,12 +26,14 @@ class BOTAN_DLL RFC6979_Nonce_Generator
const BigInt& order,
const BigInt& x);
+ ~RFC6979_Nonce_Generator();
+
const BigInt& nonce_for(const BigInt& m);
private:
const BigInt& m_order;
BigInt m_k;
size_t m_qlen, m_rlen;
- std::unique_ptr<RandomNumberGenerator> m_hmac_drbg;
+ std::unique_ptr<HMAC_DRBG> m_hmac_drbg;
secure_vector<byte> m_rng_in, m_rng_out;
};
@@ -46,8 +48,6 @@ BigInt BOTAN_DLL generate_rfc6979_nonce(const BigInt& x,
const BigInt& h,
const std::string& hash);
-std::string hash_for_deterministic_signature(const std::string& emsa);
-
}
#endif
diff --git a/src/lib/pubkey/rsa/info.txt b/src/lib/pubkey/rsa/info.txt
index 264ff7c62..91eec565a 100644
--- a/src/lib/pubkey/rsa/info.txt
+++ b/src/lib/pubkey/rsa/info.txt
@@ -4,4 +4,6 @@ define RSA 20131128
if_algo
keypair
numbertheory
+emsa_pssr
+sha2_32
</requires>
diff --git a/src/lib/pubkey/rsa/rsa.cpp b/src/lib/pubkey/rsa/rsa.cpp
index e12586014..6a645ec88 100644
--- a/src/lib/pubkey/rsa/rsa.cpp
+++ b/src/lib/pubkey/rsa/rsa.cpp
@@ -58,7 +58,7 @@ bool RSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const
if((m_e * m_d) % lcm(m_p - 1, m_q - 1) != 1)
return false;
- return KeyPair::signature_consistency_check(rng, *this, "EMSA4(SHA-1)");
+ return KeyPair::signature_consistency_check(rng, *this, "EMSA4(SHA-256)");
}
namespace {
diff --git a/src/lib/rng/auto_rng/auto_rng.cpp b/src/lib/rng/auto_rng/auto_rng.cpp
new file mode 100644
index 000000000..a9da085bc
--- /dev/null
+++ b/src/lib/rng/auto_rng/auto_rng.cpp
@@ -0,0 +1,116 @@
+/*
+* (C) 2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/auto_rng.h>
+#include <botan/entropy_src.h>
+
+#if defined(BOTAN_HAS_HMAC_DRBG)
+ #include <botan/hmac_drbg.h>
+#endif
+
+#if defined(BOTAN_HAS_HMAC_RNG)
+ #include <botan/hmac_rng.h>
+#endif
+
+#if defined(BOTAN_HAS_SYSTEM_RNG)
+ #include <botan/system_rng.h>
+#endif
+
+namespace Botan {
+
+AutoSeeded_RNG::~AutoSeeded_RNG()
+ {
+ // for unique_ptr
+ }
+
+AutoSeeded_RNG::AutoSeeded_RNG(RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval)
+ {
+ m_rng.reset(new BOTAN_AUTO_RNG_DRBG(MessageAuthenticationCode::create(BOTAN_AUTO_RNG_HMAC),
+ underlying_rng,
+ reseed_interval));
+ force_reseed();
+ }
+
+AutoSeeded_RNG::AutoSeeded_RNG(Entropy_Sources& entropy_sources,
+ size_t reseed_interval)
+ {
+ m_rng.reset(new BOTAN_AUTO_RNG_DRBG(MessageAuthenticationCode::create(BOTAN_AUTO_RNG_HMAC),
+ entropy_sources,
+ reseed_interval));
+ force_reseed();
+ }
+
+AutoSeeded_RNG::AutoSeeded_RNG(RandomNumberGenerator& underlying_rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval)
+ {
+ m_rng.reset(new BOTAN_AUTO_RNG_DRBG(MessageAuthenticationCode::create(BOTAN_AUTO_RNG_HMAC),
+ underlying_rng,
+ entropy_sources,
+ reseed_interval));
+ force_reseed();
+ }
+
+AutoSeeded_RNG::AutoSeeded_RNG(size_t reseed_interval) :
+#if defined(BOTAN_HAS_SYSTEM_RNG)
+ AutoSeeded_RNG(system_rng(), reseed_interval)
+#else
+ AutoSeeded_RNG(Entropy_Sources::global_sources(), reseed_interval)
+#endif
+ {
+ }
+
+void AutoSeeded_RNG::force_reseed()
+ {
+ m_rng->force_reseed();
+ m_rng->next_byte();
+
+ if(!m_rng->is_seeded())
+ {
+ throw Exception("AutoSeeded_RNG reseeding failed");
+ }
+ }
+
+bool AutoSeeded_RNG::is_seeded() const
+ {
+ return m_rng->is_seeded();
+ }
+
+void AutoSeeded_RNG::clear()
+ {
+ m_rng->clear();
+ }
+
+std::string AutoSeeded_RNG::name() const
+ {
+ return m_rng->name();
+ }
+
+void AutoSeeded_RNG::add_entropy(const byte in[], size_t len)
+ {
+ m_rng->add_entropy(in, len);
+ }
+
+size_t AutoSeeded_RNG::reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout)
+ {
+ return m_rng->reseed(srcs, poll_bits, poll_timeout);
+ }
+
+void AutoSeeded_RNG::randomize(byte output[], size_t output_len)
+ {
+ randomize_with_ts_input(output, output_len);
+ }
+
+void AutoSeeded_RNG::randomize_with_input(byte output[], size_t output_len,
+ const byte ad[], size_t ad_len)
+ {
+ m_rng->randomize_with_input(output, output_len, ad, ad_len);
+ }
+
+}
diff --git a/src/lib/rng/auto_rng/auto_rng.h b/src/lib/rng/auto_rng/auto_rng.h
index 72ea88d3e..6ef1aa291 100644
--- a/src/lib/rng/auto_rng/auto_rng.h
+++ b/src/lib/rng/auto_rng/auto_rng.h
@@ -1,6 +1,6 @@
/*
* Auto Seeded RNG
-* (C) 2008 Jack Lloyd
+* (C) 2008,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -9,35 +9,57 @@
#define BOTAN_AUTO_SEEDING_RNG_H__
#include <botan/rng.h>
-#include <string>
namespace Botan {
-class AutoSeeded_RNG : public RandomNumberGenerator
+class Stateful_RNG;
+
+/**
+* A userspace PRNG
+*/
+class BOTAN_DLL AutoSeeded_RNG final : public RandomNumberGenerator
{
public:
- void randomize(byte out[], size_t len) override
- { m_rng->randomize(out, len); }
+ void randomize(byte out[], size_t len) override;
+
+ void randomize_with_input(byte output[], size_t output_len,
+ const byte input[], size_t input_len) override;
+
+ bool is_seeded() const override;
+
+ void force_reseed();
+
+ size_t reseed(Entropy_Sources& srcs,
+ size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS,
+ std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT) override;
+
+ void add_entropy(const byte in[], size_t len) override;
+
+ std::string name() const override;
+
+ void clear() override;
- bool is_seeded() const override { return m_rng->is_seeded(); }
+ /**
+ * If no RNG or entropy sources are provided to AutoSeeded_RNG, it uses the system RNG
+ * (if available) or else a default group of entropy sources (all other systems) to
+ * gather seed material.
+ */
+ AutoSeeded_RNG(size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
- void clear() override { m_rng->clear(); }
+ AutoSeeded_RNG(RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
- std::string name() const override { return m_rng->name(); }
+ AutoSeeded_RNG(Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
- size_t reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout) override
- {
- return m_rng->reseed_with_sources(srcs, poll_bits, poll_timeout);
- }
+ AutoSeeded_RNG(RandomNumberGenerator& underlying_rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
- void add_entropy(const byte in[], size_t len) override
- { m_rng->add_entropy(in, len); }
+ ~AutoSeeded_RNG();
- AutoSeeded_RNG() : m_rng(RandomNumberGenerator::make_rng()) {}
private:
- std::unique_ptr<RandomNumberGenerator> m_rng;
+ std::unique_ptr<Stateful_RNG> m_rng;
};
}
diff --git a/src/lib/rng/auto_rng/info.txt b/src/lib/rng/auto_rng/info.txt
index 4f48f484b..b77e6aa54 100644
--- a/src/lib/rng/auto_rng/info.txt
+++ b/src/lib/rng/auto_rng/info.txt
@@ -1,9 +1 @@
-define AUTO_SEEDING_RNG 20131128
-
-<requires>
-hmac_rng
-hmac
-sha2_32
-sha2_64
-#dev_random|cryptoapi_rng|unix_procs|proc_walk
-</requires>
+define AUTO_SEEDING_RNG 20160821
diff --git a/src/lib/rng/hmac_drbg/hmac_drbg.cpp b/src/lib/rng/hmac_drbg/hmac_drbg.cpp
index 67325ee1b..6ea66aa2e 100644
--- a/src/lib/rng/hmac_drbg/hmac_drbg.cpp
+++ b/src/lib/rng/hmac_drbg/hmac_drbg.cpp
@@ -1,6 +1,6 @@
/*
* HMAC_DRBG
-* (C) 2014,2015 Jack Lloyd
+* (C) 2014,2015,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -10,53 +10,116 @@
namespace Botan {
-HMAC_DRBG::HMAC_DRBG(MessageAuthenticationCode* mac,
- RandomNumberGenerator* prng) :
- m_mac(mac),
- m_prng(prng),
- m_V(m_mac->output_length(), 0x01),
- m_reseed_counter(0)
+HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval) :
+ Stateful_RNG(underlying_rng, reseed_interval),
+ m_mac(std::move(prf))
{
- m_mac->set_key(std::vector<byte>(m_mac->output_length(), 0x00));
+ BOTAN_ASSERT_NONNULL(m_mac);
+ clear();
+ }
+
+HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval) :
+ Stateful_RNG(underlying_rng, entropy_sources, reseed_interval),
+ m_mac(std::move(prf))
+ {
+ BOTAN_ASSERT_NONNULL(m_mac);
+ clear();
+ }
+
+HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval) :
+ Stateful_RNG(entropy_sources, reseed_interval),
+ m_mac(std::move(prf))
+ {
+ BOTAN_ASSERT_NONNULL(m_mac);
+ clear();
}
-HMAC_DRBG::HMAC_DRBG(const std::string& mac_name,
- RandomNumberGenerator* prng) :
- m_prng(prng),
- m_reseed_counter(0)
+HMAC_DRBG::HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf) :
+ Stateful_RNG(),
+ m_mac(std::move(prf))
{
- m_mac = MessageAuthenticationCode::create(mac_name);
- if(!m_mac)
- throw Algorithm_Not_Found(mac_name);
- m_V = secure_vector<byte>(m_mac->output_length(), 0x01),
+ BOTAN_ASSERT_NONNULL(m_mac);
+ clear();
+ }
+
+void HMAC_DRBG::clear()
+ {
+ Stateful_RNG::clear();
+
+ m_V.resize(m_mac->output_length());
+ for(size_t i = 0; i != m_V.size(); ++i)
+ m_V[i] = 0x01;
m_mac->set_key(std::vector<byte>(m_mac->output_length(), 0x00));
}
-void HMAC_DRBG::randomize(byte out[], size_t length)
+std::string HMAC_DRBG::name() const
{
- if(!is_seeded() || m_reseed_counter > BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED)
- reseed(m_mac->output_length() * 8);
+ return "HMAC_DRBG(" + m_mac->name() + ")";
+ }
- if(!is_seeded())
- throw PRNG_Unseeded(name());
+void HMAC_DRBG::randomize(byte output[], size_t output_len)
+ {
+ randomize_with_input(output, output_len, nullptr, 0);
+ }
- while(length)
+/*
+* HMAC_DRBG generation
+* See NIST SP800-90A section 10.1.2.5
+*/
+void HMAC_DRBG::randomize_with_input(byte output[], size_t output_len,
+ const byte input[], size_t input_len)
+ {
+ /**
+ * SP 800-90A requires we reject any request for a DRBG output
+ * longer than max_number_of_bits_per_request. This is an
+ * implementation-dependent value, but NIST requires for HMAC_DRBG
+ * that every implementation set a value no more than 2**19 bits
+ * (or 64 KiB).
+ *
+ * To avoid inconveniencing the caller who wants a large output for
+ * whatever reason, instead treat very long output requests as
+ * if multiple maximum-length requests had been made.
+ */
+ const size_t max_number_of_bytes_per_request = 64*1024;
+
+ while(output_len > 0)
{
- const size_t to_copy = std::min(length, m_V.size());
- m_V = m_mac->process(m_V);
- copy_mem(out, m_V.data(), to_copy);
+ size_t this_req = std::min(max_number_of_bytes_per_request, output_len);
+ output_len -= this_req;
- length -= to_copy;
- out += to_copy;
- }
+ reseed_check();
- m_reseed_counter += length;
+ if(input_len > 0)
+ {
+ update(input, input_len);
+ }
+
+ while(this_req)
+ {
+ const size_t to_copy = std::min(this_req, m_V.size());
+ m_mac->update(m_V.data(), m_V.size());
+ m_mac->final(m_V.data());
+ copy_mem(output, m_V.data(), to_copy);
+
+ output += to_copy;
+ this_req -= to_copy;
+ }
+
+ update(input, input_len);
+ }
- update(nullptr, 0); // additional_data is always empty
}
/*
* Reset V and the mac key with new values
+* See NIST SP800-90A section 10.1.2.2
*/
void HMAC_DRBG::update(const byte input[], size_t input_len)
{
@@ -65,66 +128,30 @@ void HMAC_DRBG::update(const byte input[], size_t input_len)
m_mac->update(input, input_len);
m_mac->set_key(m_mac->final());
- m_V = m_mac->process(m_V);
+ m_mac->update(m_V.data(), m_V.size());
+ m_mac->final(m_V.data());
- if(input_len)
+ if(input_len > 0)
{
m_mac->update(m_V);
m_mac->update(0x01);
m_mac->update(input, input_len);
m_mac->set_key(m_mac->final());
- m_V = m_mac->process(m_V);
- }
- }
-
-size_t HMAC_DRBG::reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout)
- {
- if(m_prng)
- {
- size_t bits = m_prng->reseed_with_sources(srcs, poll_bits, poll_timeout);
-
- if(m_prng->is_seeded())
- {
- secure_vector<byte> input = m_prng->random_vec(m_mac->output_length());
- update(input.data(), input.size());
- m_reseed_counter = 1;
- }
-
- return bits;
+ m_mac->update(m_V.data(), m_V.size());
+ m_mac->final(m_V.data());
}
-
- return 0;
}
-void HMAC_DRBG::add_entropy(const byte input[], size_t length)
+void HMAC_DRBG::add_entropy(const byte input[], size_t input_len)
{
- update(input, length);
- m_reseed_counter = 1;
+ update(input, input_len);
}
-bool HMAC_DRBG::is_seeded() const
+size_t HMAC_DRBG::security_level() const
{
- return m_reseed_counter > 0;
- }
-
-void HMAC_DRBG::clear()
- {
- m_reseed_counter = 0;
- for(size_t i = 0; i != m_V.size(); ++i)
- m_V[i] = 0x01;
-
- m_mac->set_key(std::vector<byte>(m_mac->output_length(), 0x00));
-
- if(m_prng)
- m_prng->clear();
- }
-
-std::string HMAC_DRBG::name() const
- {
- return "HMAC_DRBG(" + m_mac->name() + ")";
+ // sqrt of hash size
+ return m_mac->output_length() * 8 / 2;
}
}
diff --git a/src/lib/rng/hmac_drbg/hmac_drbg.h b/src/lib/rng/hmac_drbg/hmac_drbg.h
index bd2d18d47..4f96af816 100644
--- a/src/lib/rng/hmac_drbg/hmac_drbg.h
+++ b/src/lib/rng/hmac_drbg/hmac_drbg.h
@@ -1,6 +1,6 @@
/*
* HMAC_DRBG (SP800-90A)
-* (C) 2014,2015 Jack Lloyd
+* (C) 2014,2015,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -8,46 +8,97 @@
#ifndef BOTAN_HMAC_DRBG_H__
#define BOTAN_HMAC_DRBG_H__
-#include <botan/rng.h>
+#include <botan/stateful_rng.h>
#include <botan/mac.h>
namespace Botan {
+class Entropy_Sources;
+
/**
-* HMAC_DRBG (SP800-90A)
+* HMAC_DRBG from NIST SP800-90A
*/
-class BOTAN_DLL HMAC_DRBG : public RandomNumberGenerator
+class BOTAN_DLL HMAC_DRBG final : public Stateful_RNG
{
public:
- void randomize(byte buf[], size_t buf_len) override;
- bool is_seeded() const override;
- void clear() override;
- std::string name() const override;
+ /**
+ * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC)
+ *
+ * Automatic reseeding is disabled completely, as it as no access to
+ * any source for seed material.
+ *
+ * If a fork is detected, the RNG will be unable to reseed itself
+ * in response. In this case, an exception will be thrown rather
+ * than generating duplicated output.
+ */
+ HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf);
- size_t reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout) override;
+ /**
+ * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC)
+ *
+ * @param underlying_rng is a reference to some RNG which will be used
+ * to perform the periodic reseeding
+ * @param reseed_interval specifies a limit of how many times
+ * the RNG will be called before automatic reseeding is performed.
+ */
+ HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
- void add_entropy(const byte input[], size_t input_len) override;
+ /**
+ * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC)
+ *
+ * @param entropy_sources will be polled to perform reseeding periodically
+ * @param reseed_interval specifies a limit of how many times
+ * the RNG will be called before automatic reseeding is performed.
+ */
+ HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
/**
- * @param mac the underlying mac function (eg HMAC(SHA-512))
- * @param underlying_rng RNG used generating inputs (eg HMAC_RNG)
+ * Initialize an HMAC_DRBG instance with the given MAC as PRF (normally HMAC)
+ *
+ * @param underlying_rng is a reference to some RNG which will be used
+ * to perform the periodic reseeding
+ * @param entropy_sources will be polled to perform reseeding periodically
+ * @param reseed_interval specifies a limit of how many times
+ * the RNG will be called before automatic reseeding is performed.
*/
- HMAC_DRBG(MessageAuthenticationCode* mac,
- RandomNumberGenerator* underlying_rng = nullptr);
+ HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
- HMAC_DRBG(const std::string& mac,
- RandomNumberGenerator* underlying_rng = nullptr);
+ /**
+ * Constructor taking a string for the hash
+ */
+ HMAC_DRBG(const std::string& hmac_hash) : Stateful_RNG()
+ {
+ m_mac = MessageAuthenticationCode::create("HMAC(" + hmac_hash + ")");
+ if(!m_mac)
+ throw Algorithm_Not_Found(hmac_hash);
+ clear();
+ }
+
+ std::string name() const override;
+
+ void clear() override;
+
+ void randomize(byte output[], size_t output_len) override;
+
+ void randomize_with_input(byte output[], size_t output_len,
+ const byte input[], size_t input_len) override;
+
+ void add_entropy(const byte input[], size_t input_len) override;
+
+ size_t security_level() const override;
private:
void update(const byte input[], size_t input_len);
std::unique_ptr<MessageAuthenticationCode> m_mac;
- std::unique_ptr<RandomNumberGenerator> m_prng;
-
secure_vector<byte> m_V;
- size_t m_reseed_counter;
};
}
diff --git a/src/lib/rng/hmac_drbg/info.txt b/src/lib/rng/hmac_drbg/info.txt
index f386db199..7f2c12fd0 100644
--- a/src/lib/rng/hmac_drbg/info.txt
+++ b/src/lib/rng/hmac_drbg/info.txt
@@ -2,4 +2,5 @@ define HMAC_DRBG 20140319
<requires>
hmac
+stateful_rng
</requires>
diff --git a/src/lib/rng/hmac_rng/hmac_rng.cpp b/src/lib/rng/hmac_rng/hmac_rng.cpp
index 7a9e4dbc5..081d8b38a 100644
--- a/src/lib/rng/hmac_rng/hmac_rng.cpp
+++ b/src/lib/rng/hmac_rng/hmac_rng.cpp
@@ -9,31 +9,80 @@
#include <botan/entropy_src.h>
#include <botan/internal/os_utils.h>
#include <algorithm>
-#include <chrono>
namespace Botan {
-/*
-* HMAC_RNG Constructor
-*/
-HMAC_RNG::HMAC_RNG(MessageAuthenticationCode* extractor,
- MessageAuthenticationCode* prf) :
- m_extractor(extractor), m_prf(prf)
+HMAC_RNG::HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval) :
+ Stateful_RNG(underlying_rng, entropy_sources, reseed_interval),
+ m_prf(std::move(prf))
+ {
+ BOTAN_ASSERT_NONNULL(m_prf);
+
+ if(!m_prf->valid_keylength(m_prf->output_length()))
+ {
+ throw Invalid_Argument("HMAC_RNG cannot use " + m_prf->name());
+ }
+
+ m_extractor.reset(m_prf->clone());
+ this->clear();
+ }
+
+HMAC_RNG::HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval) :
+ Stateful_RNG(underlying_rng, reseed_interval),
+ m_prf(std::move(prf))
+ {
+ BOTAN_ASSERT_NONNULL(m_prf);
+
+ if(!m_prf->valid_keylength(m_prf->output_length()))
+ {
+ throw Invalid_Argument("HMAC_RNG cannot use " + m_prf->name());
+ }
+
+ m_extractor.reset(m_prf->clone());
+ this->clear();
+ }
+
+HMAC_RNG::HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval) :
+ Stateful_RNG(entropy_sources, reseed_interval),
+ m_prf(std::move(prf)),
+ m_extractor(m_prf->clone())
{
- if(!m_prf->valid_keylength(m_extractor->output_length()) ||
- !m_extractor->valid_keylength(m_prf->output_length()))
+ BOTAN_ASSERT_NONNULL(m_prf);
+
+ if(!m_prf->valid_keylength(m_prf->output_length()))
{
- throw Invalid_Argument("HMAC_RNG: Bad algo combination " +
- m_extractor->name() + " and " +
- m_prf->name());
+ throw Invalid_Argument("HMAC_RNG cannot use " + m_prf->name());
}
+ m_extractor.reset(m_prf->clone());
+ this->clear();
+ }
+
+HMAC_RNG::HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf) :
+ Stateful_RNG(),
+ m_prf(std::move(prf))
+ {
+ BOTAN_ASSERT_NONNULL(m_prf);
+
+ if(!m_prf->valid_keylength(m_prf->output_length()))
+ {
+ throw Invalid_Argument("HMAC_RNG cannot use " + m_prf->name());
+ }
+
+ m_extractor.reset(m_prf->clone());
this->clear();
}
void HMAC_RNG::clear()
{
- m_collected_entropy_estimate = 0;
+ Stateful_RNG::clear();
m_counter = 0;
// First PRF inputs are all zero, as specified in section 2
@@ -71,7 +120,7 @@ void HMAC_RNG::clear()
void HMAC_RNG::new_K_value(byte label)
{
m_prf->update(m_K);
- m_prf->update_be(m_pid);
+ m_prf->update_be(last_pid());
m_prf->update_be(OS::get_processor_timestamp());
m_prf->update_be(OS::get_system_timestamp_ns());
m_prf->update_be(m_counter++);
@@ -84,76 +133,38 @@ void HMAC_RNG::new_K_value(byte label)
*/
void HMAC_RNG::randomize(byte out[], size_t length)
{
- if(!is_seeded() || m_pid != OS::get_process_id())
- {
- reseed(256);
- if(!is_seeded())
- throw PRNG_Unseeded(name());
- }
-
- const size_t max_per_prf_iter = m_prf->output_length() / 2;
+ reseed_check();
- m_output_since_reseed += length;
-
- if(m_output_since_reseed >= BOTAN_RNG_MAX_OUTPUT_BEFORE_RESEED)
- {
- reseed_with_sources(Entropy_Sources::global_sources(),
- BOTAN_RNG_RESEED_POLL_BITS,
- BOTAN_RNG_AUTO_RESEED_TIMEOUT);
- }
-
- /*
- HMAC KDF as described in E-t-E, using a CTXinfo of "rng"
- */
while(length)
{
new_K_value(Running);
- const size_t copied = std::min<size_t>(length, max_per_prf_iter);
+ const size_t copied = std::min<size_t>(length, m_prf->output_length());
copy_mem(out, m_K.data(), copied);
out += copied;
length -= copied;
}
+
+ new_K_value(BlockFinished);
}
-size_t HMAC_RNG::reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds timeout)
+size_t HMAC_RNG::reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds timeout)
{
+ new_K_value(Reseed);
+ m_extractor->update(m_K); // m_K is the PRF output
+
/*
- Using the terminology of E-t-E, XTR is the MAC function (normally
- HMAC) seeded with XTS (below) and we form SKM, the key material, by
- polling as many sources as we think needed to reach our polling
- goal. We then also include feedback of the current PRK so that
- a bad poll doesn't wipe us out.
+ * This ends up calling add_entropy which provides input to the extractor
*/
-
- typedef std::chrono::system_clock clock;
- auto deadline = clock::now() + timeout;
-
- double bits_collected = 0;
-
- Entropy_Accumulator accum([&](const byte in[], size_t in_len, double entropy_estimate) {
- m_extractor->update(in, in_len);
- bits_collected += entropy_estimate;
- return (bits_collected >= poll_bits || clock::now() > deadline);
- });
-
- srcs.poll(accum);
+ size_t bits_collected = Stateful_RNG::reseed(srcs, poll_bits, timeout);
/*
- * It is necessary to feed forward poll data. Otherwise, a good poll
- * (collecting a large amount of conditional entropy) followed by a
- * bad one (collecting little) would be unsafe. Do this by
- * generating new PRF outputs using the previous key and feeding
- * them into the extractor function.
+ Now derive the new PRK using everything that has been fed into
+ the extractor, and set the PRF key to that
*/
- new_K_value(Reseed);
- m_extractor->update(m_K); // K is the CTXinfo=reseed PRF output
-
- /* Now derive the new PRK using everything that has been fed into
- the extractor, and set the PRF key to that */
m_prf->set_key(m_extractor->final());
// Now generate a new PRF output to use as the XTS extractor salt
@@ -164,32 +175,17 @@ size_t HMAC_RNG::reseed_with_sources(Entropy_Sources& srcs,
zeroise(m_K);
m_counter = 0;
- m_collected_entropy_estimate =
- std::min<size_t>(m_collected_entropy_estimate + static_cast<size_t>(bits_collected),
- m_extractor->output_length() * 8);
-
- m_output_since_reseed = 0;
- m_pid = OS::get_process_id();
-
- return static_cast<size_t>(bits_collected);
- }
-
-bool HMAC_RNG::is_seeded() const
- {
- return (m_collected_entropy_estimate >= 256);
+ return bits_collected;
}
/*
-* Add user-supplied entropy to the extractor input then reseed
-* to incorporate it into the state
+* Add user-supplied entropy to the extractor input then set remaining
+* output length to for a reseed on next use.
*/
void HMAC_RNG::add_entropy(const byte input[], size_t length)
{
m_extractor->update(input, length);
-
- reseed_with_sources(Entropy_Sources::global_sources(),
- BOTAN_RNG_RESEED_POLL_BITS,
- BOTAN_RNG_RESEED_DEFAULT_TIMEOUT);
+ force_reseed();
}
/*
diff --git a/src/lib/rng/hmac_rng/hmac_rng.h b/src/lib/rng/hmac_rng/hmac_rng.h
index 95ae25e39..d6e9b4896 100644
--- a/src/lib/rng/hmac_rng/hmac_rng.h
+++ b/src/lib/rng/hmac_rng/hmac_rng.h
@@ -1,6 +1,6 @@
/*
* HMAC RNG
-* (C) 2008,2013 Jack Lloyd
+* (C) 2008,2013,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -8,9 +8,8 @@
#ifndef BOTAN_HMAC_RNG_H__
#define BOTAN_HMAC_RNG_H__
+#include <botan/stateful_rng.h>
#include <botan/mac.h>
-#include <botan/rng.h>
-#include <vector>
namespace Botan {
@@ -19,48 +18,80 @@ namespace Botan {
* Key Derivation Functions and an HMAC-based KDF" by Hugo Krawczyk
* (henceforce, 'E-t-E')
*
-* However it actually can be parameterized with any two MAC functions,
+* However it actually could be parameterized with any two MAC functions,
* not restricted to HMAC (this variation is also described in
* Krawczyk's paper), for instance one could use HMAC(SHA-512) as the
* extractor and CMAC(AES-256) as the PRF.
*/
-class BOTAN_DLL HMAC_RNG : public RandomNumberGenerator
+class BOTAN_DLL HMAC_RNG final : public Stateful_RNG
{
public:
+ /**
+ * Initialize an HMAC_RNG instance with the given MAC as PRF (normally HMAC)
+ * @param underlying_rng is a reference to some RNG which will be used
+ * to perform the periodic reseeding.
+ * @param entropy_sources will be polled to perform reseeding periodically
+ * @param reseed_interval specifies a limit of how many times
+ * the RNG will be called before automatic reseeding is performed.
+ */
+ HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ /**
+ * Initialize an HMAC_RNG instance with the given MAC as PRF (normally HMAC)
+ * @param underlying_rng is a reference to some RNG which will be used
+ * to perform the periodic reseeding.
+ * @param reseed_interval specifies a limit of how many times
+ * the RNG will be called before automatic reseeding is performed.
+ */
+ HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf,
+ RandomNumberGenerator& underlying_rng,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ /*
+ * Initialize an HMAC_RNG instance with the given MAC as PRF (normally HMAC)
+ * @param entropy_sources will be polled to perform reseeding periodically
+ * @param reseed_interval specifies a limit of how many times
+ * the RNG will be called before automatic reseeding is performed.
+ */
+ HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL);
+
+ /**
+ * Initialize an HMAC_RNG instance with the given MAC as PRF (normally HMAC)
+ * Automatic reseeding is disabled completely.
+ */
+ HMAC_RNG(std::unique_ptr<MessageAuthenticationCode> prf);
+
void randomize(byte buf[], size_t len) override;
- bool is_seeded() const override;
void clear() override;
std::string name() const override;
- size_t reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout) override;
+ size_t reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout) override;
void add_entropy(const byte[], size_t) override;
- /**
- * @param extractor a MAC used for extracting the entropy
- * @param prf a MAC used as a PRF using HKDF construction
- */
- HMAC_RNG(MessageAuthenticationCode* extractor,
- MessageAuthenticationCode* prf);
+ size_t security_level() const override { return m_prf->output_length() * 8 / 2; }
+
private:
- std::unique_ptr<MessageAuthenticationCode> m_extractor;
std::unique_ptr<MessageAuthenticationCode> m_prf;
+ std::unique_ptr<MessageAuthenticationCode> m_extractor;
enum HMAC_PRF_Label {
Running,
+ BlockFinished,
Reseed,
ExtractorSeed,
};
void new_K_value(byte label);
- size_t m_collected_entropy_estimate = 0;
- size_t m_output_since_reseed = 0;
-
secure_vector<byte> m_K;
u32bit m_counter = 0;
- u32bit m_pid = 0;
};
}
diff --git a/src/lib/rng/hmac_rng/info.txt b/src/lib/rng/hmac_rng/info.txt
index 36a8a7a34..2b7f49c8a 100644
--- a/src/lib/rng/hmac_rng/info.txt
+++ b/src/lib/rng/hmac_rng/info.txt
@@ -2,4 +2,5 @@ define HMAC_RNG 20131128
<requires>
mac
+stateful_rng
</requires>
diff --git a/src/lib/rng/info.txt b/src/lib/rng/info.txt
index ba7aa8e6a..655e35fd1 100644
--- a/src/lib/rng/info.txt
+++ b/src/lib/rng/info.txt
@@ -1,5 +1,4 @@
<requires>
entropy
-auto_rng
-hmac_rng
+hmac_drbg
</requires>
diff --git a/src/lib/rng/rdrand_rng/info.txt b/src/lib/rng/rdrand_rng/info.txt
new file mode 100644
index 000000000..2e597ebec
--- /dev/null
+++ b/src/lib/rng/rdrand_rng/info.txt
@@ -0,0 +1,16 @@
+define RDRAND_RNG 20160619
+
+need_isa rdrand
+
+<arch>
+x86_32
+x86_64
+</arch>
+
+<cc>
+gcc
+clang
+icc
+msvc
+</cc>
+
diff --git a/src/lib/rng/rdrand_rng/rdrand_rng.cpp b/src/lib/rng/rdrand_rng/rdrand_rng.cpp
new file mode 100644
index 000000000..4d2e51cf8
--- /dev/null
+++ b/src/lib/rng/rdrand_rng/rdrand_rng.cpp
@@ -0,0 +1,84 @@
+/**
+* RDRAND RNG
+* (C) 2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/rdrand_rng.h>
+#include <botan/loadstor.h>
+#include <botan/cpuid.h>
+
+#if !defined(BOTAN_USE_GCC_INLINE_ASM)
+ #include <immintrin.h>
+#endif
+
+namespace Botan {
+
+RDRAND_RNG::RDRAND_RNG()
+ {
+ if(!CPUID::has_rdrand())
+ throw Exception("Current CPU does not support RDRAND instruction");
+ }
+
+//static
+uint32_t RDRAND_RNG::rdrand()
+ {
+ bool ok = false;
+ uint32_t r = rdrand_status(ok);
+
+ while(!ok)
+ {
+ r = rdrand_status(ok);
+ }
+
+ return r;
+ }
+
+//static
+uint32_t RDRAND_RNG::rdrand_status(bool& ok)
+ {
+ ok = false;
+ uint32_t r = 0;
+
+ for(size_t i = 0; i != BOTAN_ENTROPY_RDRAND_RETRIES; ++i)
+ {
+#if defined(BOTAN_USE_GCC_INLINE_ASM)
+ int cf = 0;
+
+ // Encoding of rdrand %eax
+ asm(".byte 0x0F, 0xC7, 0xF0; adcl $0,%1" :
+ "=a" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc");
+#else
+ int cf = _rdrand32_step(&r);
+#endif
+ if(1 == cf)
+ {
+ ok = true;
+ return r;
+ }
+ }
+
+ return 0;
+ }
+
+void RDRAND_RNG::randomize(uint8_t out[], size_t out_len)
+ {
+ while(out_len >= 4)
+ {
+ uint32_t r = RDRAND_RNG::rdrand();
+
+ store_le(r, out);
+ out += 4;
+ out_len -= 4;
+ }
+
+ if(out_len) // between 1 and 3 trailing bytes
+ {
+ uint32_t r = RDRAND_RNG::rdrand();
+ for(size_t i = 0; i != out_len; ++i)
+ out[i] = get_byte(i, r);
+ }
+ }
+
+}
diff --git a/src/lib/rng/rdrand_rng/rdrand_rng.h b/src/lib/rng/rdrand_rng/rdrand_rng.h
new file mode 100644
index 000000000..fcd54035b
--- /dev/null
+++ b/src/lib/rng/rdrand_rng/rdrand_rng.h
@@ -0,0 +1,60 @@
+/**
+* RDRAND RNG
+* (C) 2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_RNG_RDRAND_H__
+#define BOTAN_RNG_RDRAND_H__
+
+#include <botan/rng.h>
+
+namespace Botan {
+
+class BOTAN_DLL RDRAND_RNG : public Hardware_RNG
+ {
+ public:
+ /**
+ * On correctly working hardware, RDRAND is always supposed to
+ * succeed within a set number of retries. If after that many
+ * retries RDRAND has still not suceeded, sets ok = false and
+ * returns 0.
+ */
+ static uint32_t rdrand_status(bool& ok);
+
+ /*
+ * Calls RDRAND until it succeeds, this could hypothetically
+ * loop forever on broken hardware.
+ */
+ static uint32_t rdrand();
+
+ /**
+ * Constructor will throw if CPU does not have RDRAND bit set
+ */
+ RDRAND_RNG();
+
+ /**
+ * Uses RDRAND to produce output
+ */
+ void randomize(uint8_t out[], size_t out_len) override;
+
+ /*
+ * No way to provide entropy to RDRAND generator, so add_entropy is ignored
+ */
+ void add_entropy(const uint8_t[], size_t) override
+ { /* no op */ }
+
+ size_t reseed(Entropy_Sources&, size_t, std::chrono::milliseconds) override
+ { return 0; /* no op */ }
+
+ std::string name() const override { return "RDRAND"; }
+
+ bool is_seeded() const override { return true; }
+
+ void clear() override {}
+ };
+
+}
+
+#endif
diff --git a/src/lib/rng/rng.cpp b/src/lib/rng/rng.cpp
index c17f23dd0..8c2982312 100644
--- a/src/lib/rng/rng.cpp
+++ b/src/lib/rng/rng.cpp
@@ -1,42 +1,62 @@
/*
-* Random Number Generator
-* (C) 1999-2008 Jack Lloyd
+* (C) 2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/rng.h>
-#include <botan/hmac_rng.h>
-#include <botan/entropy_src.h>
+#include <botan/loadstor.h>
+#include <botan/internal/os_utils.h>
+
+#if defined(BOTAN_HAS_AUTO_SEEDING_RNG)
+ #include <botan/auto_rng.h>
+#endif
namespace Botan {
-size_t RandomNumberGenerator::reseed(size_t bits_to_collect)
+void RandomNumberGenerator::randomize_with_ts_input(byte output[], size_t output_len)
{
- return this->reseed_with_timeout(bits_to_collect,
- BOTAN_RNG_RESEED_DEFAULT_TIMEOUT);
+ /*
+ Form additional input which is provided to the PRNG implementation
+ to paramaterize the KDF output.
+ */
+ byte additional_input[16] = { 0 };
+ store_le(OS::get_system_timestamp_ns(), additional_input);
+ store_le(OS::get_processor_timestamp(), additional_input + 8);
+
+ randomize_with_input(output, output_len, additional_input, sizeof(additional_input));
}
-size_t RandomNumberGenerator::reseed_with_timeout(size_t bits_to_collect,
- std::chrono::milliseconds timeout)
+void RandomNumberGenerator::randomize_with_input(byte output[], size_t output_len,
+ const byte input[], size_t input_len)
{
- return this->reseed_with_sources(Entropy_Sources::global_sources(),
- bits_to_collect,
- timeout);
+ this->add_entropy(input, input_len);
+ this->randomize(output, output_len);
}
-RandomNumberGenerator* RandomNumberGenerator::make_rng()
+size_t RandomNumberGenerator::reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout)
{
- std::unique_ptr<MessageAuthenticationCode> h1(MessageAuthenticationCode::create("HMAC(SHA-512)"));
- std::unique_ptr<MessageAuthenticationCode> h2(MessageAuthenticationCode::create("HMAC(SHA-512)"));
-
- if(!h1 || !h2)
- throw Algorithm_Not_Found("HMAC_RNG HMACs");
- std::unique_ptr<RandomNumberGenerator> rng(new HMAC_RNG(h1.release(), h2.release()));
+ return srcs.poll(*this, poll_bits, poll_timeout);
+ }
- rng->reseed(256);
+void RandomNumberGenerator::reseed_from_rng(RandomNumberGenerator& rng, size_t poll_bits)
+ {
+ secure_vector<byte> buf(poll_bits / 8);
+ rng.randomize(buf.data(), buf.size());
+ this->add_entropy(buf.data(), buf.size());
+ }
- return rng.release();
+RandomNumberGenerator* RandomNumberGenerator::make_rng()
+ {
+#if defined(BOTAN_HAS_AUTO_SEEDING_RNG)
+ return new AutoSeeded_RNG;
+#else
+ throw Exception("make_rng failed, no AutoSeeded_RNG in this build");
+#endif
}
+Serialized_RNG::Serialized_RNG() : m_rng(RandomNumberGenerator::make_rng()) {}
+
}
diff --git a/src/lib/rng/rng.h b/src/lib/rng/rng.h
index 3fd3dcec8..d1cdcfff2 100644
--- a/src/lib/rng/rng.h
+++ b/src/lib/rng/rng.h
@@ -1,6 +1,6 @@
/*
-* RandomNumberGenerator
-* (C) 1999-2009 Jack Lloyd
+* Random Number Generator base classes
+* (C) 1999-2009,2015,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -8,6 +8,7 @@
#ifndef BOTAN_RANDOM_NUMBER_GENERATOR_H__
#define BOTAN_RANDOM_NUMBER_GENERATOR_H__
+#include <botan/entropy_src.h>
#include <botan/secmem.h>
#include <botan/exceptn.h>
#include <chrono>
@@ -19,16 +20,20 @@ namespace Botan {
class Entropy_Sources;
/**
-* This class represents a random number (RNG) generator object.
+* An interface to a cryptographic random number generator
*/
class BOTAN_DLL RandomNumberGenerator
{
public:
- /**
- * Create a seeded and active RNG object for general application use
- * Added in 1.8.0
+ virtual ~RandomNumberGenerator() = default;
+
+ RandomNumberGenerator() = default;
+
+ /*
+ * Never copy a RNG, create a new one
*/
- static RandomNumberGenerator* make_rng();
+ RandomNumberGenerator(const RandomNumberGenerator& rng) = delete;
+ RandomNumberGenerator& operator=(const RandomNumberGenerator& rng) = delete;
/**
* Randomize a byte array.
@@ -38,128 +43,160 @@ class BOTAN_DLL RandomNumberGenerator
virtual void randomize(byte output[], size_t length) = 0;
/**
- * Return a random vector
- * @param bytes number of bytes in the result
- * @return randomized vector of length bytes
- */
- virtual secure_vector<byte> random_vec(size_t bytes)
- {
- secure_vector<byte> output(bytes);
- randomize(output.data(), output.size());
- return output;
- }
-
- /**
- * Only usable with POD types, only useful with integers
- * get_random<u64bit>()
+ * Incorporate some additional data into the RNG state. For
+ * example adding nonces or timestamps from a peer's protocol
+ * message can help hedge against VM state rollback attacks.
+ * A few RNG types do not accept any externally provided input,
+ * in which case this function is a no-op.
+ *
+ * @param inputs a byte array containg the entropy to be added
+ * @param length the length of the byte array in
*/
- template<typename T> T get_random()
- {
- T r;
- this->randomize(reinterpret_cast<byte*>(&r), sizeof(r));
- return r;
- }
+ virtual void add_entropy(const byte input[], size_t length) = 0;
/**
- * Return a random byte
- * @return random byte
+ * Incorporate some additional data into the RNG state.
*/
- byte next_byte() { return get_random<byte>(); }
-
- byte next_nonzero_byte()
+ template<typename T> void add_entropy_T(const T& t)
{
- byte b = next_byte();
- while(b == 0)
- b = next_byte();
- return b;
+ this->add_entropy(reinterpret_cast<const uint8_t*>(&t), sizeof(T));
}
/**
- * Check whether this RNG is seeded.
- * @return true if this RNG was already seeded, false otherwise.
+ * Incorporate entropy into the RNG state then produce output.
+ * Some RNG types implement this using a single operation, default
+ * calls add_entropy + randomize in sequence.
+ *
+ * Use this to further bind the outputs to your current
+ * process/protocol state. For instance if generating a new key
+ * for use in a session, include a session ID or other such
+ * value. See NIST SP 800-90 A, B, C series for more ideas.
*/
- virtual bool is_seeded() const = 0;
+ virtual void randomize_with_input(byte output[], size_t output_len,
+ const byte input[], size_t input_len);
/**
- * Clear all internally held values of this RNG.
+ * This calls `randomize_with_input` using some timestamps as extra input.
+ *
+ * For a stateful RNG using non-random but potentially unique data as the
+ * additional_input can help protect against problems with fork, VM state
+ * rollback, or other cases where somehow an RNG state is duplicated. If
+ * both of the duplicated RNG states later incorporate a timestamp (and the
+ * timestamps don't themselves repeat), their outputs will diverge.
*/
- virtual void clear() = 0;
+ virtual void randomize_with_ts_input(byte output[], size_t output_len);
/**
- * Return the name of this object
+ * Return the name of this RNG type
*/
virtual std::string name() const = 0;
/**
- * Seed this RNG using the global entropy sources and default timeout
- * @param bits_to_collect is the number of bits of entropy to
- attempt to gather from the entropy sources
+ * Clear all internally held values of this RNG
+ * @post is_seeded() == false
*/
- size_t reseed(size_t bits_to_collect);
+ virtual void clear() = 0;
/**
- * Seed this RNG using the global entropy sources
- * @param bits_to_collect is the number of bits of entropy to
- attempt to gather from the entropy sources
- * @param poll_timeout try not to run longer than this, no matter what
+ * Check whether this RNG is seeded.
+ * @return true if this RNG was already seeded, false otherwise.
*/
- size_t reseed_with_timeout(size_t bits_to_collect,
- std::chrono::milliseconds poll_timeout);
+ virtual bool is_seeded() const = 0;
/**
* Poll provided sources for up to poll_bits bits of entropy
* or until the timeout expires. Returns estimate of the number
* of bits collected.
*/
- virtual size_t reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout) = 0;
+ virtual size_t reseed(Entropy_Sources& srcs,
+ size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS,
+ std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT);
/**
- * Add entropy to this RNG.
- * @param in a byte array containg the entropy to be added
- * @param length the length of the byte array in
+ * Reseed by reading specified bits from the RNG
*/
- virtual void add_entropy(const byte in[], size_t length) = 0;
+ virtual void reseed_from_rng(RandomNumberGenerator& rng,
+ size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS);
- /*
- * Never copy a RNG, create a new one
+ // Some utility functions built on the interface above:
+
+ /**
+ * Return a random vector
+ * @param bytes number of bytes in the result
+ * @return randomized vector of length bytes
*/
- RandomNumberGenerator(const RandomNumberGenerator& rng) = delete;
- RandomNumberGenerator& operator=(const RandomNumberGenerator& rng) = delete;
+ secure_vector<byte> random_vec(size_t bytes)
+ {
+ secure_vector<byte> output(bytes);
+ this->randomize(output.data(), output.size());
+ return output;
+ }
+
+ /**
+ * Return a random byte
+ * @return random byte
+ */
+ byte next_byte()
+ {
+ byte b;
+ this->randomize(&b, 1);
+ return b;
+ }
+
+ byte next_nonzero_byte()
+ {
+ byte b = this->next_byte();
+ while(b == 0)
+ b = this->next_byte();
+ return b;
+ }
- RandomNumberGenerator() {}
- virtual ~RandomNumberGenerator() {}
+ /**
+ * Create a seeded and active RNG object for general application use
+ * Added in 1.8.0
+ * Use AutoSeeded_RNG instead
+ */
+ BOTAN_DEPRECATED("Use AutoSeeded_RNG")
+ static RandomNumberGenerator* make_rng();
};
+/**
+* Convenience typedef
+*/
typedef RandomNumberGenerator RNG;
/**
+* Hardware RNG has no members but exists to tag hardware RNG types
+*/
+class BOTAN_DLL Hardware_RNG : public RandomNumberGenerator
+ {
+ };
+
+/**
* Null/stub RNG - fails if you try to use it for anything
+* This is not generally useful except for in certain tests
*/
-class BOTAN_DLL Null_RNG : public RandomNumberGenerator
+class BOTAN_DLL Null_RNG final : public RandomNumberGenerator
{
public:
- void randomize(byte[], size_t) override { throw PRNG_Unseeded("Null_RNG"); }
+ bool is_seeded() const override { return false; }
void clear() override {}
- std::string name() const override { return "Null_RNG"; }
-
- size_t reseed_with_sources(Entropy_Sources&, size_t,
- std::chrono::milliseconds) override
+ void randomize(byte[], size_t) override
{
- return 0;
+ throw Exception("Null_RNG called");
}
- bool is_seeded() const override { return false; }
void add_entropy(const byte[], size_t) override {}
+
+ std::string name() const override { return "Null_RNG"; }
};
/**
* Wraps access to a RNG in a mutex
*/
-class BOTAN_DLL Serialized_RNG : public RandomNumberGenerator
+class BOTAN_DLL Serialized_RNG final : public RandomNumberGenerator
{
public:
void randomize(byte out[], size_t len) override
@@ -186,12 +223,12 @@ class BOTAN_DLL Serialized_RNG : public RandomNumberGenerator
return m_rng->name();
}
- size_t reseed_with_sources(Entropy_Sources& src,
- size_t bits,
- std::chrono::milliseconds msec) override
+ size_t reseed(Entropy_Sources& src,
+ size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS,
+ std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT) override
{
std::lock_guard<std::mutex> lock(m_mutex);
- return m_rng->reseed_with_sources(src, bits, msec);
+ return m_rng->reseed(src, poll_bits, poll_timeout);
}
void add_entropy(const byte in[], size_t len) override
@@ -200,7 +237,8 @@ class BOTAN_DLL Serialized_RNG : public RandomNumberGenerator
m_rng->add_entropy(in, len);
}
- Serialized_RNG() : m_rng(RandomNumberGenerator::make_rng()) {}
+ BOTAN_DEPRECATED("Create an AutoSeeded_RNG for other constructor") Serialized_RNG();
+
explicit Serialized_RNG(RandomNumberGenerator* rng) : m_rng(rng) {}
private:
mutable std::mutex m_mutex;
diff --git a/src/lib/rng/stateful_rng/info.txt b/src/lib/rng/stateful_rng/info.txt
new file mode 100644
index 000000000..b4dcedf4a
--- /dev/null
+++ b/src/lib/rng/stateful_rng/info.txt
@@ -0,0 +1,2 @@
+define STATEFUL_RNG 20160819
+
diff --git a/src/lib/rng/stateful_rng/stateful_rng.cpp b/src/lib/rng/stateful_rng/stateful_rng.cpp
new file mode 100644
index 000000000..1349c1208
--- /dev/null
+++ b/src/lib/rng/stateful_rng/stateful_rng.cpp
@@ -0,0 +1,112 @@
+/*
+* (C) 2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/stateful_rng.h>
+#include <botan/internal/os_utils.h>
+#include <botan/loadstor.h>
+
+namespace Botan {
+
+void Stateful_RNG::clear()
+ {
+ m_reseed_counter = 0;
+ m_last_pid = 0;
+ }
+
+void Stateful_RNG::force_reseed()
+ {
+ m_reseed_counter = 0;
+ }
+
+bool Stateful_RNG::is_seeded() const
+ {
+ return m_reseed_counter > 0;
+ }
+
+void Stateful_RNG::initialize_with(const byte input[], size_t len)
+ {
+ add_entropy(input, len);
+
+ if(8*len >= security_level())
+ {
+ m_reseed_counter = 1;
+ }
+ }
+
+void Stateful_RNG::randomize_with_ts_input(byte output[], size_t output_len)
+ {
+ byte additional_input[24] = { 0 };
+ store_le(OS::get_system_timestamp_ns(), additional_input);
+ store_le(OS::get_processor_timestamp(), additional_input + 8);
+ store_le(m_last_pid, additional_input + 16);
+ store_le(static_cast<uint32_t>(m_reseed_counter), additional_input + 20);
+
+ randomize_with_input(output, output_len, additional_input, sizeof(additional_input));
+ }
+
+size_t Stateful_RNG::reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout)
+ {
+ size_t bits_collected = RandomNumberGenerator::reseed(srcs, poll_bits, poll_timeout);
+
+ if(bits_collected >= security_level())
+ {
+ m_reseed_counter = 1;
+ }
+
+ return bits_collected;
+ }
+
+void Stateful_RNG::reseed_from_rng(RandomNumberGenerator& rng, size_t poll_bits)
+ {
+ RandomNumberGenerator::reseed_from_rng(rng, poll_bits);
+
+ if(poll_bits >= security_level())
+ {
+ m_reseed_counter = 1;
+ }
+ }
+
+void Stateful_RNG::reseed_check()
+ {
+ const uint32_t cur_pid = OS::get_process_id();
+
+ const bool fork_detected = (m_last_pid > 0) && (cur_pid != m_last_pid);
+
+ if(is_seeded() == false ||
+ fork_detected ||
+ (m_reseed_interval > 0 && m_reseed_counter >= m_reseed_interval))
+ {
+ m_reseed_counter = 0;
+ m_last_pid = cur_pid;
+
+ if(m_underlying_rng)
+ {
+ reseed_from_rng(*m_underlying_rng, security_level());
+ }
+
+ if(m_entropy_sources)
+ {
+ reseed(*m_entropy_sources, security_level());
+ }
+
+ if(!is_seeded())
+ {
+ if(fork_detected)
+ throw Exception("Detected use of fork but cannot reseed DRBG");
+ else
+ throw PRNG_Unseeded(name());
+ }
+ }
+ else
+ {
+ BOTAN_ASSERT(m_reseed_counter != 0, "RNG is seeded");
+ m_reseed_counter += 1;
+ }
+ }
+
+}
diff --git a/src/lib/rng/stateful_rng/stateful_rng.h b/src/lib/rng/stateful_rng/stateful_rng.h
new file mode 100644
index 000000000..11f0c7e3d
--- /dev/null
+++ b/src/lib/rng/stateful_rng/stateful_rng.h
@@ -0,0 +1,118 @@
+/*
+* (C) 2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_STATEFUL_RNG_H__
+#define BOTAN_STATEFUL_RNG_H__
+
+#include <botan/rng.h>
+
+namespace Botan {
+
+/**
+* Inherited by RNGs which maintain in-process state, like HMAC_DRBG.
+* On Unix these RNGs are vulnerable to problems with fork, where the
+* RNG state is duplicated, and the parent and child process RNGs will
+* produce identical output until one of them reseeds. Stateful_RNG
+* reseeds itself whenever a fork is detected, or after a set number of
+* bytes have been output.
+*
+* Not implemented by RNGs which access an external RNG, such as the
+* system PRNG or a hardware RNG.
+*/
+class BOTAN_DLL Stateful_RNG : public RandomNumberGenerator
+ {
+ public:
+ Stateful_RNG(RandomNumberGenerator& rng,
+ Entropy_Sources& entropy_sources,
+ size_t reseed_interval) :
+ m_underlying_rng(&rng),
+ m_entropy_sources(&entropy_sources),
+ m_reseed_interval(reseed_interval)
+ {}
+
+ Stateful_RNG(RandomNumberGenerator& rng, size_t reseed_interval) :
+ m_underlying_rng(&rng),
+ m_reseed_interval(reseed_interval)
+ {}
+
+ Stateful_RNG(Entropy_Sources& entropy_sources, size_t reseed_interval) :
+ m_entropy_sources(&entropy_sources),
+ m_reseed_interval(reseed_interval)
+ {}
+
+ /**
+ * In this case, automatic reseeding is impossible
+ */
+ Stateful_RNG() : m_reseed_interval(0) {}
+
+ /**
+ * Consume this input and mark the RNG as initialized regardless
+ * of the length of the input or the current seeded state of
+ * the RNG.
+ */
+ void initialize_with(const byte input[], size_t length);
+
+ bool is_seeded() const override final;
+
+ /**
+ * Mark state as requiring a reseed on next use
+ */
+ void force_reseed();
+
+ void reseed_from_rng(RandomNumberGenerator& rng,
+ size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS) override final;
+
+ /**
+ * Overrides default implementation and also includes the current
+ * process ID and the reseed counter.
+ */
+ void randomize_with_ts_input(byte output[], size_t output_len) override final;
+
+ /**
+ * Poll provided sources for up to poll_bits bits of entropy
+ * or until the timeout expires. Returns estimate of the number
+ * of bits collected.
+ */
+ size_t reseed(Entropy_Sources& srcs,
+ size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS,
+ std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT) override;
+
+ /**
+ * Return intended security level of this DRBG
+ */
+ virtual size_t security_level() const = 0;
+
+ void clear() override;
+
+ protected:
+ /**
+ * Called with lock held
+ */
+ void reseed_check();
+
+ uint32_t last_pid() const { return m_last_pid; }
+
+ private:
+ // A non-owned and possibly null pointer to shared RNG
+ RandomNumberGenerator* m_underlying_rng = nullptr;
+
+ // A non-owned and possibly null pointer to a shared Entropy_Source
+ Entropy_Sources* m_entropy_sources = nullptr;
+
+ const size_t m_reseed_interval;
+
+ /*
+ * Set to 1 after a sucessful seeding, then incremented. Reset
+ * to 0 by clear() or a fork. This logic is used even if
+ * automatic reseeding is disabled (via m_reseed_interval = 0)
+ */
+ size_t m_reseed_counter = 0;
+ uint32_t m_last_pid = 0;
+ };
+
+}
+
+#endif
diff --git a/src/lib/rng/system_rng/system_rng.cpp b/src/lib/rng/system_rng/system_rng.cpp
index 81e235a8c..135f4fabd 100644
--- a/src/lib/rng/system_rng/system_rng.cpp
+++ b/src/lib/rng/system_rng/system_rng.cpp
@@ -28,32 +28,23 @@ namespace Botan {
namespace {
-class System_RNG_Impl : public RandomNumberGenerator
+class System_RNG_Impl final : public RandomNumberGenerator
{
public:
System_RNG_Impl();
~System_RNG_Impl();
- void randomize(byte buf[], size_t len) override;
-
bool is_seeded() const override { return true; }
+
void clear() override {}
- std::string name() const override { return "system"; }
- size_t reseed_with_sources(Entropy_Sources&,
- size_t /*poll_bits*/,
- std::chrono::milliseconds /*timeout*/) override
- {
- // We ignore it and assert the PRNG is seeded.
- // TODO: could poll and write it to /dev/urandom to help seed it
- return 0;
- }
+ void randomize(uint8_t out[], size_t len) override;
- void add_entropy(const byte[], size_t) override
- {
- }
- private:
+ void add_entropy(const uint8_t in[], size_t length) override;
+
+ std::string name() const override;
+ private:
#if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
HCRYPTPROV m_prov;
#else
@@ -61,6 +52,15 @@ class System_RNG_Impl : public RandomNumberGenerator
#endif
};
+std::string System_RNG_Impl::name() const
+ {
+#if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
+ return "cryptoapi";
+#else
+ return BOTAN_SYSTEM_RNG_DEVICE;
+#endif
+ }
+
System_RNG_Impl::System_RNG_Impl()
{
#if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
@@ -74,7 +74,7 @@ System_RNG_Impl::System_RNG_Impl()
#define O_NOCTTY 0
#endif
- m_fd = ::open(BOTAN_SYSTEM_RNG_DEVICE, O_RDONLY | O_NOCTTY);
+ m_fd = ::open(BOTAN_SYSTEM_RNG_DEVICE, O_RDWR | O_NOCTTY);
if(m_fd < 0)
throw Exception("System_RNG failed to open RNG device");
#endif
@@ -90,7 +90,61 @@ System_RNG_Impl::~System_RNG_Impl()
#endif
}
-void System_RNG_Impl::randomize(byte buf[], size_t len)
+void System_RNG_Impl::add_entropy(const uint8_t input[], size_t len)
+ {
+#if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
+ /*
+ There is no explicit ConsumeRandom, but all values provided in
+ the call are incorporated into the state.
+
+ TODO: figure out a way to avoid this copy. Byte at a time updating
+ seems worse than the allocation.
+
+ for(size_t i = 0; i != len; ++i)
+ {
+ uint8_t b = input[i];
+ ::CryptGenRandom(m_prov, 1, &b);
+ }
+ */
+
+ if(len > 0)
+ {
+ secure_vector<uint8_t> buf(input, input + len);
+ ::CryptGenRandom(m_prov, static_cast<DWORD>(buf.size()), buf.data());
+ }
+#else
+ while(len)
+ {
+ ssize_t got = ::write(m_fd, input, len);
+
+ if(got < 0)
+ {
+ if(errno == EINTR)
+ continue;
+
+ /*
+ * This is seen on OS X CI, despite the fact that the man page
+ * for Darwin urandom explicitly states that writing to it is
+ * supported, and write(2) does not document EPERM at all.
+ * But in any case EPERM seems indicative of a policy decision
+ * by the OS or sysadmin that additional entropy is not wanted
+ * in the system pool, so we accept that and return here,
+ * since there is no corrective action possible.
+ */
+ if(errno == EPERM)
+ return;
+
+ // maybe just ignore any failure here and return?
+ throw Exception("System_RNG write failed error " + std::to_string(errno));
+ }
+
+ input += got;
+ len -= got;
+ }
+#endif
+ }
+
+void System_RNG_Impl::randomize(uint8_t buf[], size_t len)
{
#if defined(BOTAN_TARGET_OS_HAS_CRYPTGENRANDOM)
::CryptGenRandom(m_prov, static_cast<DWORD>(len), buf);
diff --git a/src/lib/rng/system_rng/system_rng.h b/src/lib/rng/system_rng/system_rng.h
index 6290b8769..9cf31e78b 100644
--- a/src/lib/rng/system_rng/system_rng.h
+++ b/src/lib/rng/system_rng/system_rng.h
@@ -22,29 +22,18 @@ BOTAN_DLL RandomNumberGenerator& system_rng();
/*
* Instantiatable reference to the system RNG.
*/
-class BOTAN_DLL System_RNG : public RandomNumberGenerator
+class BOTAN_DLL System_RNG final : public RandomNumberGenerator
{
public:
- System_RNG() : m_rng(system_rng()) {}
+ std::string name() const override { return system_rng().name(); }
- void randomize(Botan::byte out[], size_t len) override { m_rng.randomize(out, len); }
+ void randomize(uint8_t out[], size_t len) override { system_rng().randomize(out, len); }
- bool is_seeded() const override { return m_rng.is_seeded(); }
+ void add_entropy(const uint8_t in[], size_t length) override { system_rng().add_entropy(in, length); }
- void clear() override { m_rng.clear(); }
+ bool is_seeded() const override { return true; }
- std::string name() const override { return m_rng.name(); }
-
- size_t reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout) override
- {
- return m_rng.reseed_with_sources(srcs, poll_bits, poll_timeout);
- }
-
- void add_entropy(const byte in[], size_t len) override { m_rng.add_entropy(in, len); }
- private:
- Botan::RandomNumberGenerator& m_rng;
+ void clear() override {}
};
}
diff --git a/src/lib/rng/x931_rng/info.txt b/src/lib/rng/x931_rng/info.txt
index b61dc7ec9..4a4418083 100644
--- a/src/lib/rng/x931_rng/info.txt
+++ b/src/lib/rng/x931_rng/info.txt
@@ -1 +1,5 @@
define X931_RNG 20131128
+
+<requires>
+stateful_rng
+</requires>
diff --git a/src/lib/rng/x931_rng/x931_rng.cpp b/src/lib/rng/x931_rng/x931_rng.cpp
index 020d9a5a5..ed44dc743 100644
--- a/src/lib/rng/x931_rng/x931_rng.cpp
+++ b/src/lib/rng/x931_rng/x931_rng.cpp
@@ -14,7 +14,7 @@ void ANSI_X931_RNG::randomize(byte out[], size_t length)
{
if(!is_seeded())
{
- reseed(BOTAN_RNG_RESEED_POLL_BITS);
+ rekey();
if(!is_seeded())
throw PRNG_Unseeded(name());
@@ -72,11 +72,11 @@ void ANSI_X931_RNG::rekey()
}
}
-size_t ANSI_X931_RNG::reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout)
+size_t ANSI_X931_RNG::reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout)
{
- size_t bits = m_prng->reseed_with_sources(srcs, poll_bits, poll_timeout);
+ size_t bits = m_prng->reseed(srcs, poll_bits, poll_timeout);
rekey();
return bits;
}
diff --git a/src/lib/rng/x931_rng/x931_rng.h b/src/lib/rng/x931_rng/x931_rng.h
index ed7124a08..861fcffde 100644
--- a/src/lib/rng/x931_rng/x931_rng.h
+++ b/src/lib/rng/x931_rng/x931_rng.h
@@ -16,7 +16,7 @@ namespace Botan {
/**
* ANSI X9.31 RNG
*/
-class BOTAN_DLL ANSI_X931_RNG : public RandomNumberGenerator
+class BOTAN_DLL ANSI_X931_RNG final : public RandomNumberGenerator
{
public:
void randomize(byte[], size_t) override;
@@ -24,9 +24,9 @@ class BOTAN_DLL ANSI_X931_RNG : public RandomNumberGenerator
void clear() override;
std::string name() const override;
- size_t reseed_with_sources(Entropy_Sources& srcs,
- size_t poll_bits,
- std::chrono::milliseconds poll_timeout) override;
+ size_t reseed(Entropy_Sources& srcs,
+ size_t poll_bits,
+ std::chrono::milliseconds poll_timeout) override;
void add_entropy(const byte[], size_t) override;
@@ -35,6 +35,7 @@ class BOTAN_DLL ANSI_X931_RNG : public RandomNumberGenerator
* @param rng the underlying PRNG for generating inputs
* (eg, an HMAC_RNG)
*/
+ BOTAN_DEPRECATED("X9.31 RNG is deprecated and will be removed soon")
ANSI_X931_RNG(BlockCipher* cipher,
RandomNumberGenerator* rng);
diff --git a/src/lib/stream/chacha/chacha.cpp b/src/lib/stream/chacha/chacha.cpp
index ac81fd70d..40da93029 100644
--- a/src/lib/stream/chacha/chacha.cpp
+++ b/src/lib/stream/chacha/chacha.cpp
@@ -12,8 +12,8 @@ namespace Botan {
ChaCha::ChaCha(size_t rounds) : m_rounds(rounds)
{
- if(m_rounds != 12 && m_rounds != 20)
- throw Invalid_Argument("ChaCha only supports 12 or 20 rounds");
+ if(m_rounds != 8 && m_rounds != 12 && m_rounds != 20)
+ throw Invalid_Argument("ChaCha only supports 8, 12 or 20 rounds");
}
namespace {
@@ -67,7 +67,6 @@ void chacha(byte output[64], const u32bit input[16], size_t rounds)
store_le(x14 + input[14], output + 4 * 14);
store_le(x15 + input[15], output + 4 * 15);
}
-
}
/*
@@ -173,4 +172,27 @@ std::string ChaCha::name() const
return "ChaCha(" + std::to_string(m_rounds) + ")";
}
+void ChaCha::seek(u64bit offset)
+ {
+ if (m_state.size() == 0 && m_buffer.size() == 0)
+ {
+ throw Invalid_State("You have to setup the stream cipher (key and iv)");
+ }
+
+ m_position = offset % m_buffer.size();
+
+ u64bit counter = offset / m_buffer.size();
+
+ byte out[8];
+
+ store_le(counter, out);
+
+ m_state[12] = load_le<u32bit>(out, 0);
+ m_state[13] += load_le<u32bit>(out, 1);
+
+ chacha(m_buffer.data(), m_state.data(), m_rounds);
+
+ ++m_state[12];
+ m_state[13] += (m_state[12] == 0);
+ }
}
diff --git a/src/lib/stream/chacha/chacha.h b/src/lib/stream/chacha/chacha.h
index ba93d6260..f8f42e41d 100644
--- a/src/lib/stream/chacha/chacha.h
+++ b/src/lib/stream/chacha/chacha.h
@@ -21,7 +21,7 @@ class BOTAN_DLL ChaCha final : public StreamCipher
StreamCipher* clone() const override { return new ChaCha(m_rounds); }
/**
- * Currently only 12 or 20 rounds are supported, all others
+ * Currently only 8, 12 or 20 rounds are supported, all others
* will throw an exception
*/
ChaCha(size_t rounds);
@@ -42,6 +42,8 @@ class BOTAN_DLL ChaCha final : public StreamCipher
std::string name() const override;
+ void seek(u64bit offset) override;
+
private:
void key_schedule(const byte key[], size_t key_len) override;
diff --git a/src/lib/stream/ctr/ctr.cpp b/src/lib/stream/ctr/ctr.cpp
index 88c7a8d8e..43609ba2d 100644
--- a/src/lib/stream/ctr/ctr.cpp
+++ b/src/lib/stream/ctr/ctr.cpp
@@ -23,10 +23,23 @@ CTR_BE::CTR_BE(BlockCipher* ciph) :
m_cipher(ciph),
m_counter(m_cipher->parallel_bytes()),
m_pad(m_counter.size()),
+ m_ctr_size(m_cipher->block_size()),
m_pad_pos(0)
{
}
+CTR_BE::CTR_BE(BlockCipher* cipher, size_t ctr_size) :
+ m_cipher(cipher),
+ m_counter(m_cipher->parallel_bytes()),
+ m_pad(m_counter.size()),
+ m_ctr_size(ctr_size),
+ m_pad_pos(0)
+ {
+ //BOTAN_CHECK_ARG(m_ctr_size > 0 && m_ctr_size <= cipher->block_size(), "Invalid CTR size");
+ if(m_ctr_size == 0 || m_ctr_size > m_cipher->block_size())
+ throw Invalid_Argument("Invalid CTR-BE counter size");
+ }
+
void CTR_BE::clear()
{
m_cipher->clear();
@@ -79,7 +92,7 @@ void CTR_BE::set_iv(const byte iv[], size_t iv_len)
{
buffer_insert(m_counter, i*bs, &m_counter[(i-1)*bs], bs);
- for(size_t j = 0; j != bs; ++j)
+ for(size_t j = 0; j != m_ctr_size; ++j)
if(++m_counter[i*bs + (bs - 1 - j)])
break;
}
@@ -99,7 +112,7 @@ void CTR_BE::increment_counter()
for(size_t i = 0; i != n_wide; ++i)
{
uint16_t carry = static_cast<uint16_t>(n_wide);
- for(size_t j = 0; carry && j != bs; ++j)
+ for(size_t j = 0; carry && j != m_ctr_size; ++j)
{
const size_t off = i*bs + (bs-1-j);
const uint16_t cnt = static_cast<uint16_t>(m_counter[off]) + carry;
@@ -112,4 +125,8 @@ void CTR_BE::increment_counter()
m_pad_pos = 0;
}
+void CTR_BE::seek(u64bit)
+ {
+ throw Not_Implemented("CTR_BE::seek");
+ }
}
diff --git a/src/lib/stream/ctr/ctr.h b/src/lib/stream/ctr/ctr.h
index 8e931605c..5d5556254 100644
--- a/src/lib/stream/ctr/ctr.h
+++ b/src/lib/stream/ctr/ctr.h
@@ -44,12 +44,17 @@ class BOTAN_DLL CTR_BE final : public StreamCipher
* @param cipher the underlying block cipher to use
*/
explicit CTR_BE(BlockCipher* cipher);
+
+ CTR_BE(BlockCipher* cipher, size_t ctr_size);
+
+ void seek(u64bit offset) override;
private:
void key_schedule(const byte key[], size_t key_len) override;
void increment_counter();
std::unique_ptr<BlockCipher> m_cipher;
secure_vector<byte> m_counter, m_pad;
+ size_t m_ctr_size;
size_t m_pad_pos;
};
diff --git a/src/lib/stream/ofb/ofb.cpp b/src/lib/stream/ofb/ofb.cpp
index e8cb463db..3337a0c14 100644
--- a/src/lib/stream/ofb/ofb.cpp
+++ b/src/lib/stream/ofb/ofb.cpp
@@ -73,4 +73,9 @@ void OFB::set_iv(const byte iv[], size_t iv_len)
m_buf_pos = 0;
}
+
+void OFB::seek(u64bit)
+ {
+ throw Exception("OFB does not support seeking");
+ }
}
diff --git a/src/lib/stream/ofb/ofb.h b/src/lib/stream/ofb/ofb.h
index fecd47d9d..127a06578 100644
--- a/src/lib/stream/ofb/ofb.h
+++ b/src/lib/stream/ofb/ofb.h
@@ -44,6 +44,8 @@ class BOTAN_DLL OFB final : public StreamCipher
* @param cipher the underlying block cipher to use
*/
explicit OFB(BlockCipher* cipher);
+
+ void seek(u64bit offset) override;
private:
void key_schedule(const byte key[], size_t key_len) override;
diff --git a/src/lib/stream/rc4/rc4.cpp b/src/lib/stream/rc4/rc4.cpp
index 895f38091..e5ea2e2b8 100644
--- a/src/lib/stream/rc4/rc4.cpp
+++ b/src/lib/stream/rc4/rc4.cpp
@@ -6,6 +6,7 @@
*/
#include <botan/rc4.h>
+#include <botan/exceptn.h>
namespace Botan {
@@ -35,6 +36,11 @@ void RC4::cipher(const byte in[], byte out[], size_t length)
m_position += length;
}
+void RC4::set_iv(const byte*, size_t)
+ {
+ throw Exception("RC4 does not support an IV");
+ }
+
/*
* Generate cipher stream
*/
@@ -113,4 +119,8 @@ void RC4::clear()
*/
RC4::RC4(size_t s) : m_SKIP(s) {}
+void RC4::seek(u64bit)
+ {
+ throw Exception("RC4 does not support seeking");
+ }
}
diff --git a/src/lib/stream/rc4/rc4.h b/src/lib/stream/rc4/rc4.h
index f166a2772..82dd6097b 100644
--- a/src/lib/stream/rc4/rc4.h
+++ b/src/lib/stream/rc4/rc4.h
@@ -21,6 +21,8 @@ class BOTAN_DLL RC4 final : public StreamCipher
public:
void cipher(const byte in[], byte out[], size_t length) override;
+ void set_iv(const byte iv[], size_t iv_len) override;
+
void clear() override;
std::string name() const override;
@@ -39,6 +41,8 @@ class BOTAN_DLL RC4 final : public StreamCipher
explicit RC4(size_t skip = 0);
~RC4() { clear(); }
+
+ void seek(u64bit offset) override;
private:
void key_schedule(const byte[], size_t) override;
void generate();
diff --git a/src/lib/stream/salsa20/salsa20.cpp b/src/lib/stream/salsa20/salsa20.cpp
index 1d3fe3d28..f11fe5e59 100644
--- a/src/lib/stream/salsa20/salsa20.cpp
+++ b/src/lib/stream/salsa20/salsa20.cpp
@@ -227,4 +227,8 @@ void Salsa20::clear()
m_position = 0;
}
+void Salsa20::seek(u64bit)
+ {
+ throw Not_Implemented("Salsa20::seek");
+ }
}
diff --git a/src/lib/stream/salsa20/salsa20.h b/src/lib/stream/salsa20/salsa20.h
index 7e75470da..8256ea4db 100644
--- a/src/lib/stream/salsa20/salsa20.h
+++ b/src/lib/stream/salsa20/salsa20.h
@@ -33,6 +33,8 @@ class BOTAN_DLL Salsa20 final : public StreamCipher
void clear() override;
std::string name() const override;
StreamCipher* clone() const override { return new Salsa20; }
+
+ void seek(u64bit offset) override;
private:
void key_schedule(const byte key[], size_t key_len) override;
diff --git a/src/lib/stream/stream_cipher.cpp b/src/lib/stream/stream_cipher.cpp
index 6f98df1fb..cd6400d8f 100644
--- a/src/lib/stream/stream_cipher.cpp
+++ b/src/lib/stream/stream_cipher.cpp
@@ -44,12 +44,6 @@ std::vector<std::string> StreamCipher::providers(const std::string& algo_spec)
StreamCipher::StreamCipher() {}
StreamCipher::~StreamCipher() {}
-void StreamCipher::set_iv(const byte[], size_t iv_len)
- {
- if(!valid_iv_length(iv_len))
- throw Invalid_IV_Length(name(), iv_len);
- }
-
#if defined(BOTAN_HAS_CHACHA)
BOTAN_REGISTER_T_1LEN(StreamCipher, ChaCha, 20);
#endif
diff --git a/src/lib/stream/stream_cipher.h b/src/lib/stream/stream_cipher.h
index bff1fd1a6..e08bee0ce 100644
--- a/src/lib/stream/stream_cipher.h
+++ b/src/lib/stream/stream_cipher.h
@@ -67,7 +67,7 @@ class BOTAN_DLL StreamCipher : public SymmetricAlgorithm
* @param iv the initialization vector
* @param iv_len the length of the IV in bytes
*/
- virtual void set_iv(const byte[], size_t iv_len);
+ virtual void set_iv(const byte[], size_t iv_len) = 0;
/**
* @param iv_len the length of the IV in bytes
@@ -80,6 +80,12 @@ class BOTAN_DLL StreamCipher : public SymmetricAlgorithm
*/
virtual StreamCipher* clone() const = 0;
+ /**
+ * Set the offset and the state used later to generate the keystream
+ * @param offset the offset where we begin to generate the keystream
+ */
+ virtual void seek(u64bit offset) = 0;
+
StreamCipher();
virtual ~StreamCipher();
};
diff --git a/src/lib/tls/info.txt b/src/lib/tls/info.txt
index a43d5619a..667726318 100644
--- a/src/lib/tls/info.txt
+++ b/src/lib/tls/info.txt
@@ -6,6 +6,7 @@ load_on auto
credentials_manager.h
tls_alert.h
tls_blocking.h
+tls_callbacks.h
tls_channel.h
tls_ciphersuite.h
tls_client.h
@@ -43,12 +44,12 @@ eme_pkcs1
emsa_pkcs1
gcm
hmac
-kdf2
md5
+par_hash
prf_tls
rng
rsa
-sha1
+sha1_sse2|sha1
sha2_32
x509
</requires>
diff --git a/src/lib/tls/msg_client_hello.cpp b/src/lib/tls/msg_client_hello.cpp
index d2b1a166e..51cba2940 100644
--- a/src/lib/tls/msg_client_hello.cpp
+++ b/src/lib/tls/msg_client_hello.cpp
@@ -1,6 +1,7 @@
/*
* TLS Hello Request and Client Hello Messages
* (C) 2004-2011,2015,2016 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -68,22 +69,20 @@ std::vector<byte> Hello_Request::serialize() const
*/
Client_Hello::Client_Hello(Handshake_IO& io,
Handshake_Hash& hash,
- Protocol_Version version,
const Policy& policy,
RandomNumberGenerator& rng,
const std::vector<byte>& reneg_info,
- const std::vector<std::string>& next_protocols,
- const std::string& hostname,
- const std::string& srp_identifier) :
- m_version(version),
+ const Client_Hello::Settings& client_settings,
+ const std::vector<std::string>& next_protocols) :
+ m_version(client_settings.protocol_version()),
m_random(make_hello_random(rng, policy)),
- m_suites(policy.ciphersuite_list(m_version, (srp_identifier != ""))),
+ m_suites(policy.ciphersuite_list(m_version,
+ client_settings.srp_identifier() != "")),
m_comp_methods(policy.compression())
{
m_extensions.add(new Extended_Master_Secret);
m_extensions.add(new Renegotiation_Extension(reneg_info));
-
- m_extensions.add(new Server_Name_Indicator(hostname));
+ m_extensions.add(new Server_Name_Indicator(client_settings.hostname()));
m_extensions.add(new Session_Ticket());
m_extensions.add(new Supported_Elliptic_Curves(policy.allowed_ecc_curves()));
@@ -101,7 +100,7 @@ Client_Hello::Client_Hello(Handshake_IO& io,
m_extensions.add(new Encrypt_then_MAC);
#if defined(BOTAN_HAS_SRP6)
- m_extensions.add(new SRP_Identifier(srp_identifier));
+ m_extensions.add(new SRP_Identifier(client_settings.srp_identifier()));
#else
if(!srp_identifier.empty())
{
@@ -109,10 +108,10 @@ Client_Hello::Client_Hello(Handshake_IO& io,
}
#endif
- BOTAN_ASSERT(policy.acceptable_protocol_version(version),
+ BOTAN_ASSERT(policy.acceptable_protocol_version(client_settings.protocol_version()),
"Our policy accepts the version we are offering");
- if(policy.send_fallback_scsv(version))
+ if(policy.send_fallback_scsv(client_settings.protocol_version()))
m_suites.push_back(TLS_FALLBACK_SCSV);
hash.update(io.send(*this));
diff --git a/src/lib/tls/msg_finished.cpp b/src/lib/tls/msg_finished.cpp
index 2d6b11995..3a2c88fb1 100644
--- a/src/lib/tls/msg_finished.cpp
+++ b/src/lib/tls/msg_finished.cpp
@@ -31,14 +31,15 @@ std::vector<byte> finished_compute_verify(const Handshake_State& state,
std::unique_ptr<KDF> prf(state.protocol_specific_prf());
std::vector<byte> input;
+ std::vector<byte> label;
if(side == CLIENT)
- input += std::make_pair(TLS_CLIENT_LABEL, sizeof(TLS_CLIENT_LABEL));
+ label += std::make_pair(TLS_CLIENT_LABEL, sizeof(TLS_CLIENT_LABEL));
else
- input += std::make_pair(TLS_SERVER_LABEL, sizeof(TLS_SERVER_LABEL));
+ label += std::make_pair(TLS_SERVER_LABEL, sizeof(TLS_SERVER_LABEL));
input += state.hash().final(state.version(), state.ciphersuite().prf_algo());
- return unlock(prf->derive_key(12, state.session_keys().master_secret(), input));
+ return unlock(prf->derive_key(12, state.session_keys().master_secret(), input, label));
}
}
diff --git a/src/lib/tls/msg_server_hello.cpp b/src/lib/tls/msg_server_hello.cpp
index e309a7c91..ebe8fb085 100644
--- a/src/lib/tls/msg_server_hello.cpp
+++ b/src/lib/tls/msg_server_hello.cpp
@@ -1,6 +1,7 @@
/*
* TLS Server Hello and Server Hello Done
* (C) 2004-2011,2015,2016 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -23,17 +24,13 @@ Server_Hello::Server_Hello(Handshake_IO& io,
RandomNumberGenerator& rng,
const std::vector<byte>& reneg_info,
const Client_Hello& client_hello,
- const std::vector<byte>& new_session_id,
- Protocol_Version new_session_version,
- u16bit ciphersuite,
- byte compression,
- bool offer_session_ticket,
- const std::string& next_protocol) :
- m_version(new_session_version),
- m_session_id(new_session_id),
+ const Server_Hello::Settings& server_settings,
+ const std::string next_protocol) :
+ m_version(server_settings.protocol_version()),
+ m_session_id(server_settings.session_id()),
m_random(make_hello_random(rng, policy)),
- m_ciphersuite(ciphersuite),
- m_comp_method(compression)
+ m_ciphersuite(server_settings.ciphersuite()),
+ m_comp_method(server_settings.compression())
{
if(client_hello.supports_extended_master_secret())
m_extensions.add(new Extended_Master_Secret);
@@ -48,7 +45,7 @@ Server_Hello::Server_Hello(Handshake_IO& io,
if(client_hello.secure_renegotiation())
m_extensions.add(new Renegotiation_Extension(reneg_info));
- if(client_hello.supports_session_ticket() && offer_session_ticket)
+ if(client_hello.supports_session_ticket() && server_settings.offer_session_ticket())
m_extensions.add(new Session_Ticket());
if(!next_protocol.empty() && client_hello.supports_alpn())
diff --git a/src/lib/tls/tls_blocking.cpp b/src/lib/tls/tls_blocking.cpp
index a1867b6b5..9408972fd 100644
--- a/src/lib/tls/tls_blocking.cpp
+++ b/src/lib/tls/tls_blocking.cpp
@@ -1,6 +1,7 @@
/*
* TLS Blocking API
* (C) 2013 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -23,10 +24,13 @@ Blocking_Client::Blocking_Client(read_fn reader,
const Protocol_Version& offer_version,
const std::vector<std::string>& next) :
m_read(reader),
- m_channel(writer,
- std::bind(&Blocking_Client::data_cb, this, _1, _2),
- std::bind(&Blocking_Client::alert_cb, this, _1, _2, _3),
- std::bind(&Blocking_Client::handshake_cb, this, _1),
+ m_callbacks(new TLS::Compat_Callbacks(
+ writer,
+ std::bind(&Blocking_Client::data_cb, this, _1, _2),
+ std::function<void (Alert)>(std::bind(&Blocking_Client::alert_cb, this, _1)),
+ std::bind(&Blocking_Client::handshake_cb, this, _1)
+ )),
+ m_channel(*m_callbacks.get(),
session_manager,
creds,
policy,
@@ -42,7 +46,7 @@ bool Blocking_Client::handshake_cb(const Session& session)
return this->handshake_complete(session);
}
-void Blocking_Client::alert_cb(const Alert& alert, const byte[], size_t)
+void Blocking_Client::alert_cb(const Alert& alert)
{
this->alert_notification(alert);
}
diff --git a/src/lib/tls/tls_blocking.h b/src/lib/tls/tls_blocking.h
index 00e65cbaf..0f2986710 100644
--- a/src/lib/tls/tls_blocking.h
+++ b/src/lib/tls/tls_blocking.h
@@ -1,6 +1,7 @@
/*
* TLS Blocking API
* (C) 2013 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -32,6 +33,7 @@ class BOTAN_DLL Blocking_Client
typedef std::function<size_t (byte[], size_t)> read_fn;
typedef std::function<void (const byte[], size_t)> write_fn;
+ BOTAN_DEPRECATED("Use the regular TLS::Client interface")
Blocking_Client(read_fn reader,
write_fn writer,
Session_Manager& session_manager,
@@ -89,9 +91,10 @@ class BOTAN_DLL Blocking_Client
void data_cb(const byte data[], size_t data_len);
- void alert_cb(const Alert& alert, const byte data[], size_t data_len);
+ void alert_cb(const Alert& alert);
read_fn m_read;
+ std::unique_ptr<Compat_Callbacks> m_callbacks;
TLS::Client m_channel;
secure_vector<byte> m_plaintext;
};
diff --git a/src/lib/tls/tls_callbacks.h b/src/lib/tls/tls_callbacks.h
new file mode 100644
index 000000000..75887c23f
--- /dev/null
+++ b/src/lib/tls/tls_callbacks.h
@@ -0,0 +1,203 @@
+/*
+* TLS Callbacks
+* (C) 2016 Matthias Gierlings
+* 2016 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_TLS_CALLBACKS_H__
+#define BOTAN_TLS_CALLBACKS_H__
+
+#include <botan/tls_session.h>
+#include <botan/tls_alert.h>
+namespace Botan {
+
+namespace TLS {
+
+class Handshake_Message;
+
+/**
+* Encapsulates the callbacks that a TLS channel will make which are due to
+* channel specific operations.
+*/
+class BOTAN_DLL Callbacks
+ {
+ public:
+ virtual ~Callbacks();
+
+ /**
+ * Mandatory callback: output function
+ * The channel will call this with data which needs to be sent to the peer
+ * (eg, over a socket or some other form of IPC). The array will be overwritten
+ * when the function returns so a copy must be made if the data cannot be
+ * sent immediately.
+ *
+ * @param data the vector of data to send
+ *
+ * @param size the number of bytes to send
+ */
+ virtual void tls_emit_data(const uint8_t data[], size_t size) = 0;
+
+ /**
+ * Mandatory callback: process application data
+ * Called when application data record is received from the peer.
+ * Again the array is overwritten immediately after the function returns.
+ *
+ * @param seq_no the underlying TLS/DTLS record sequence number
+ *
+ * @param data the vector containing the received record
+ *
+ * @param size the length of the received record, in bytes
+ */
+ virtual void tls_record_received(u64bit seq_no, const uint8_t data[], size_t size) = 0;
+
+ /**
+ * Mandary callback: alert received
+ * Called when an alert is received from the peer
+ * If fatal, the connection is closing. If not fatal, the connection may
+ * still be closing (depending on the error and the peer).
+ *
+ * @param alert the source of the alert
+ */
+ virtual void tls_alert(Alert alert) = 0;
+
+ /**
+ * Mandatory callback: session established
+ * Called when a session is established. Throw an exception to abort
+ * the connection.
+ *
+ * @param session the session descriptor
+ *
+ * @return return false to prevent the session from being cached,
+ * return true to cache the session in the configured session manager
+ */
+ virtual bool tls_session_established(const Session& session) = 0;
+
+ /**
+ * Optional callback: inspect handshake message
+ * Throw an exception to abort the handshake.
+ * Default simply ignores the message.
+ *
+ * @param message the handshake message
+ */
+ virtual void tls_inspect_handshake_msg(const Handshake_Message& message);
+
+ /**
+ * Optional callback for server: choose ALPN protocol
+ * ALPN (RFC 7301) works by the client sending a list of application
+ * protocols it is willing to negotiate. The server then selects which
+ * protocol to use, which is not necessarily even on the list that
+ * the client sent.
+ *
+ * @param client_protos the vector of protocols the client is willing to negotiate
+ *
+ * @return the protocol selected by the server, which need not be on the
+ * list that the client sent; if this is the empty string, the server ignores the
+ * client ALPN extension. Default return value is empty string.
+ */
+ virtual std::string tls_server_choose_app_protocol(const std::vector<std::string>& client_protos);
+
+ /**
+ * Optional callback: debug logging. (not currently used)
+ */
+ virtual bool tls_log_debug(const char*) { return false; }
+ };
+
+/**
+* TLS::Callbacks using std::function for compatability with the old API signatures.
+* This type is only provided for backward compatibility.
+* New implementations should derive from TLS::Callbacks instead.
+*/
+class BOTAN_DLL Compat_Callbacks final : public Callbacks
+ {
+ public:
+ typedef std::function<void (const byte[], size_t)> output_fn;
+ typedef std::function<void (const byte[], size_t)> data_cb;
+ typedef std::function<void (Alert, const byte[], size_t)> alert_cb;
+ typedef std::function<bool (const Session&)> handshake_cb;
+ typedef std::function<void (const Handshake_Message&)> handshake_msg_cb;
+ typedef std::function<std::string (std::vector<std::string>)> next_protocol_fn;
+
+ /**
+ * @param output_fn is called with data for the outbound socket
+ *
+ * @param app_data_cb is called when new application data is received
+ *
+ * @param alert_cb is called when a TLS alert is received
+ *
+ * @param handshake_cb is called when a handshake is completed
+ */
+ BOTAN_DEPRECATED("Use TLS::Callbacks (virtual interface).")
+ Compat_Callbacks(output_fn out, data_cb app_data_cb, alert_cb alert_cb,
+ handshake_cb hs_cb, handshake_msg_cb hs_msg_cb = nullptr,
+ next_protocol_fn next_proto = nullptr)
+ : m_output_function(out), m_app_data_cb(app_data_cb),
+ m_alert_cb(std::bind(alert_cb, std::placeholders::_1, nullptr, 0)),
+ m_hs_cb(hs_cb), m_hs_msg_cb(hs_msg_cb), m_next_proto(next_proto) {}
+
+ BOTAN_DEPRECATED("Use TLS::Callbacks (virtual interface).")
+ Compat_Callbacks(output_fn out, data_cb app_data_cb,
+ std::function<void (Alert)> alert_cb,
+ handshake_cb hs_cb,
+ handshake_msg_cb hs_msg_cb = nullptr,
+ next_protocol_fn next_proto = nullptr)
+ : m_output_function(out), m_app_data_cb(app_data_cb),
+ m_alert_cb(alert_cb),
+ m_hs_cb(hs_cb), m_hs_msg_cb(hs_msg_cb), m_next_proto(next_proto) {}
+
+ void tls_emit_data(const byte data[], size_t size) override
+ {
+ BOTAN_ASSERT(m_output_function != nullptr,
+ "Invalid TLS output function callback.");
+ m_output_function(data, size);
+ }
+
+ void tls_record_received(u64bit /*seq_no*/, const byte data[], size_t size) override
+ {
+ BOTAN_ASSERT(m_app_data_cb != nullptr,
+ "Invalid TLS app data callback.");
+ m_app_data_cb(data, size);
+ }
+
+ void tls_alert(Alert alert) override
+ {
+ BOTAN_ASSERT(m_alert_cb != nullptr,
+ "Invalid TLS alert callback.");
+ m_alert_cb(alert);
+ }
+
+ bool tls_session_established(const Session& session) override
+ {
+ BOTAN_ASSERT(m_hs_cb != nullptr,
+ "Invalid TLS handshake callback.");
+ return m_hs_cb(session);
+ }
+
+ std::string tls_server_choose_app_protocol(const std::vector<std::string>& client_protos) override
+ {
+ if(m_next_proto != nullptr) { return m_next_proto(client_protos); }
+ return "";
+ }
+
+ void tls_inspect_handshake_msg(const Handshake_Message& hmsg) override
+ {
+ // The handshake message callback is optional so we can
+ // not assume it has been set.
+ if(m_hs_msg_cb != nullptr) { m_hs_msg_cb(hmsg); }
+ }
+
+ private:
+ const output_fn m_output_function;
+ const data_cb m_app_data_cb;
+ const std::function<void (Alert)> m_alert_cb;
+ const handshake_cb m_hs_cb;
+ const handshake_msg_cb m_hs_msg_cb;
+ const next_protocol_fn m_next_proto;
+ };
+
+}
+
+}
+
+#endif
diff --git a/src/lib/tls/tls_channel.cpp b/src/lib/tls/tls_channel.cpp
index 4549470e2..5e9207da7 100644
--- a/src/lib/tls/tls_channel.cpp
+++ b/src/lib/tls/tls_channel.cpp
@@ -1,6 +1,7 @@
/*
* TLS Channels
-* (C) 2011,2012,2014,2015 Jack Lloyd
+* (C) 2011,2012,2014,2015,2016 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -18,32 +19,63 @@ namespace Botan {
namespace TLS {
-Channel::Channel(output_fn output_fn,
- data_cb data_cb,
- alert_cb alert_cb,
- handshake_cb handshake_cb,
- handshake_msg_cb handshake_msg_cb,
+Callbacks::~Callbacks() {}
+
+void Callbacks::tls_inspect_handshake_msg(const Handshake_Message&)
+ {
+ // default is no op
+ }
+
+std::string Callbacks::tls_server_choose_app_protocol(const std::vector<std::string>&)
+ {
+ return "";
+ }
+
+size_t TLS::Channel::IO_BUF_DEFAULT_SIZE = 10*1024;
+
+Channel::Channel(Callbacks& callbacks,
Session_Manager& session_manager,
RandomNumberGenerator& rng,
const Policy& policy,
bool is_datagram,
size_t reserved_io_buffer_size) :
m_is_datagram(is_datagram),
- m_data_cb(data_cb),
- m_alert_cb(alert_cb),
- m_output_fn(output_fn),
- m_handshake_cb(handshake_cb),
- m_handshake_msg_cb(handshake_msg_cb),
+ m_callbacks(callbacks),
m_session_manager(session_manager),
m_policy(policy),
m_rng(rng)
{
+ init(reserved_io_buffer_size);
+ }
+
+Channel::Channel(output_fn out,
+ data_cb app_data_cb,
+ alert_cb alert_cb,
+ handshake_cb hs_cb,
+ handshake_msg_cb hs_msg_cb,
+ Session_Manager& session_manager,
+ RandomNumberGenerator& rng,
+ const Policy& policy,
+ bool is_datagram,
+ size_t io_buf_sz) :
+ m_is_datagram(is_datagram),
+ m_compat_callbacks(new Compat_Callbacks(out, app_data_cb, alert_cb, hs_cb, hs_msg_cb)),
+ m_callbacks(*m_compat_callbacks.get()),
+ m_session_manager(session_manager),
+ m_policy(policy),
+ m_rng(rng)
+ {
+ init(io_buf_sz);
+ }
+
+void Channel::init(size_t io_buf_sz)
+ {
/* epoch 0 is plaintext, thus null cipher state */
m_write_cipher_states[0] = nullptr;
m_read_cipher_states[0] = nullptr;
- m_writebuf.reserve(reserved_io_buffer_size);
- m_readbuf.reserve(reserved_io_buffer_size);
+ m_writebuf.reserve(io_buf_sz);
+ m_readbuf.reserve(io_buf_sz);
}
void Channel::reset_state()
@@ -265,23 +297,19 @@ size_t Channel::received_data(const byte input[], size_t input_size)
{
while(!is_closed() && input_size)
{
- secure_vector<byte> record;
+ secure_vector<byte> record_data;
u64bit record_sequence = 0;
Record_Type record_type = NO_RECORD;
Protocol_Version record_version;
size_t consumed = 0;
+ Record_Raw_Input raw_input(input, input_size, consumed, m_is_datagram);
+ Record record(record_data, &record_sequence, &record_version, &record_type);
const size_t needed =
read_record(m_readbuf,
- input,
- input_size,
- m_is_datagram,
- consumed,
+ raw_input,
record,
- &record_sequence,
- &record_version,
- &record_type,
m_sequence_numbers.get(),
std::bind(&TLS::Channel::read_cipher_state_epoch, this,
std::placeholders::_1));
@@ -300,105 +328,21 @@ size_t Channel::received_data(const byte input[], size_t input_size)
if(input_size == 0 && needed != 0)
return needed; // need more data to complete record
- if(record.size() > MAX_PLAINTEXT_SIZE)
+ if(record_data.size() > MAX_PLAINTEXT_SIZE)
throw TLS_Exception(Alert::RECORD_OVERFLOW,
"TLS plaintext record is larger than allowed maximum");
if(record_type == HANDSHAKE || record_type == CHANGE_CIPHER_SPEC)
{
- if(!m_pending_state)
- {
- // No pending handshake, possibly new:
- if(record_version.is_datagram_protocol())
- {
- if(m_sequence_numbers)
- {
- /*
- * Might be a peer retransmit under epoch - 1 in which
- * case we must retransmit last flight
- */
- sequence_numbers().read_accept(record_sequence);
-
- const u16bit epoch = record_sequence >> 48;
-
- if(epoch == sequence_numbers().current_read_epoch())
- {
- create_handshake_state(record_version);
- }
- else if(epoch == sequence_numbers().current_read_epoch() - 1)
- {
- BOTAN_ASSERT(m_active_state, "Have active state here");
- m_active_state->handshake_io().add_record(unlock(record),
- record_type,
- record_sequence);
- }
- }
- else if(record_sequence == 0)
- {
- create_handshake_state(record_version);
- }
- }
- else
- {
- create_handshake_state(record_version);
- }
- }
-
- // May have been created in above conditional
- if(m_pending_state)
- {
- m_pending_state->handshake_io().add_record(unlock(record),
- record_type,
- record_sequence);
-
- while(auto pending = m_pending_state.get())
- {
- auto msg = pending->get_next_handshake_msg();
-
- if(msg.first == HANDSHAKE_NONE) // no full handshake yet
- break;
-
- process_handshake_msg(active_state(), *pending,
- msg.first, msg.second);
- }
- }
+ process_handshake_ccs(record_data, record_sequence, record_type, record_version);
}
else if(record_type == APPLICATION_DATA)
{
- if(!active_state())
- throw Unexpected_Message("Application data before handshake done");
-
- /*
- * OpenSSL among others sends empty records in versions
- * before TLS v1.1 in order to randomize the IV of the
- * following record. Avoid spurious callbacks.
- */
- if(record.size() > 0)
- m_data_cb(record.data(), record.size());
+ process_application_data(record_sequence, record_data);
}
else if(record_type == ALERT)
{
- Alert alert_msg(record);
-
- if(alert_msg.type() == Alert::NO_RENEGOTIATION)
- m_pending_state.reset();
-
- m_alert_cb(alert_msg, nullptr, 0);
-
- if(alert_msg.is_fatal())
- {
- if(auto active = active_state())
- m_session_manager.remove_entry(active->server_hello()->session_id());
- }
-
- if(alert_msg.type() == Alert::CLOSE_NOTIFY)
- send_warning_alert(Alert::CLOSE_NOTIFY); // reply in kind
-
- if(alert_msg.type() == Alert::CLOSE_NOTIFY || alert_msg.is_fatal())
- {
- reset_state();
- return 0;
- }
+ process_alert(record_data);
}
else if(record_type != NO_RECORD)
throw Unexpected_Message("Unexpected record type " +
@@ -430,6 +374,108 @@ size_t Channel::received_data(const byte input[], size_t input_size)
}
}
+void Channel::process_handshake_ccs(const secure_vector<byte>& record,
+ u64bit record_sequence,
+ Record_Type record_type,
+ Protocol_Version record_version)
+ {
+ if(!m_pending_state)
+ {
+ // No pending handshake, possibly new:
+ if(record_version.is_datagram_protocol())
+ {
+ if(m_sequence_numbers)
+ {
+ /*
+ * Might be a peer retransmit under epoch - 1 in which
+ * case we must retransmit last flight
+ */
+ sequence_numbers().read_accept(record_sequence);
+
+ const u16bit epoch = record_sequence >> 48;
+
+ if(epoch == sequence_numbers().current_read_epoch())
+ {
+ create_handshake_state(record_version);
+ }
+ else if(epoch == sequence_numbers().current_read_epoch() - 1)
+ {
+ BOTAN_ASSERT(m_active_state, "Have active state here");
+ m_active_state->handshake_io().add_record(unlock(record),
+ record_type,
+ record_sequence);
+ }
+ }
+ else if(record_sequence == 0)
+ {
+ create_handshake_state(record_version);
+ }
+ }
+ else
+ {
+ create_handshake_state(record_version);
+ }
+ }
+
+ // May have been created in above conditional
+ if(m_pending_state)
+ {
+ m_pending_state->handshake_io().add_record(unlock(record),
+ record_type,
+ record_sequence);
+
+ while(auto pending = m_pending_state.get())
+ {
+ auto msg = pending->get_next_handshake_msg();
+
+ if(msg.first == HANDSHAKE_NONE) // no full handshake yet
+ break;
+
+ process_handshake_msg(active_state(), *pending,
+ msg.first, msg.second);
+ }
+ }
+ }
+
+void Channel::process_application_data(u64bit seq_no, const secure_vector<byte>& record)
+ {
+ if(!active_state())
+ throw Unexpected_Message("Application data before handshake done");
+
+ /*
+ * OpenSSL among others sends empty records in versions
+ * before TLS v1.1 in order to randomize the IV of the
+ * following record. Avoid spurious callbacks.
+ */
+ if(record.size() > 0)
+ callbacks().tls_record_received(seq_no, record.data(), record.size());
+ }
+
+void Channel::process_alert(const secure_vector<byte>& record)
+ {
+ Alert alert_msg(record);
+
+ if(alert_msg.type() == Alert::NO_RENEGOTIATION)
+ m_pending_state.reset();
+
+ callbacks().tls_alert(alert_msg);
+
+ if(alert_msg.is_fatal())
+ {
+ if(auto active = active_state())
+ m_session_manager.remove_entry(active->server_hello()->session_id());
+ }
+
+ if(alert_msg.type() == Alert::CLOSE_NOTIFY)
+ send_warning_alert(Alert::CLOSE_NOTIFY); // reply in kind
+
+ if(alert_msg.type() == Alert::CLOSE_NOTIFY || alert_msg.is_fatal())
+ {
+ reset_state();
+ }
+ }
+
+
void Channel::write_record(Connection_Cipher_State* cipher_state, u16bit epoch,
byte record_type, const byte input[], size_t length)
{
@@ -438,16 +484,16 @@ void Channel::write_record(Connection_Cipher_State* cipher_state, u16bit epoch,
Protocol_Version record_version =
(m_pending_state) ? (m_pending_state->version()) : (m_active_state->version());
+ Record_Message record_message(record_type, 0, input, length);
+
TLS::write_record(m_writebuf,
- record_type,
- input,
- length,
+ record_message,
record_version,
sequence_numbers().next_write_sequence(epoch),
cipher_state,
m_rng);
- m_output_fn(m_writebuf.data(), m_writebuf.size());
+ callbacks().tls_emit_data(m_writebuf.data(), m_writebuf.size());
}
void Channel::send_record_array(u16bit epoch, byte type, const byte input[], size_t length)
@@ -623,7 +669,6 @@ SymmetricKey Channel::key_material_export(const std::string& label,
active->session_keys().master_secret();
std::vector<byte> salt;
- salt += to_byte_vector(label);
salt += active->client_hello()->random();
salt += active->server_hello()->random();
@@ -637,7 +682,7 @@ SymmetricKey Channel::key_material_export(const std::string& label,
salt += to_byte_vector(context);
}
- return prf->derive_key(length, master_secret, salt);
+ return prf->derive_key(length, master_secret, salt, to_byte_vector(label));
}
else
throw Exception("Channel::key_material_export connection not active");
diff --git a/src/lib/tls/tls_channel.h b/src/lib/tls/tls_channel.h
index e0219c242..073af760f 100644
--- a/src/lib/tls/tls_channel.h
+++ b/src/lib/tls/tls_channel.h
@@ -1,6 +1,7 @@
/*
* TLS Channel
* (C) 2011,2012,2014,2015 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -12,6 +13,7 @@
#include <botan/tls_session.h>
#include <botan/tls_alert.h>
#include <botan/tls_session_manager.h>
+#include <botan/tls_callbacks.h>
#include <botan/x509cert.h>
#include <vector>
#include <string>
@@ -37,7 +39,20 @@ class BOTAN_DLL Channel
typedef std::function<void (Alert, const byte[], size_t)> alert_cb;
typedef std::function<bool (const Session&)> handshake_cb;
typedef std::function<void (const Handshake_Message&)> handshake_msg_cb;
+ static size_t IO_BUF_DEFAULT_SIZE;
+ Channel(Callbacks& callbacks,
+ Session_Manager& session_manager,
+ RandomNumberGenerator& rng,
+ const Policy& policy,
+ bool is_datagram,
+ size_t io_buf_sz = IO_BUF_DEFAULT_SIZE);
+
+ /**
+ * DEPRECATED. This constructor is only provided for backward
+ * compatibility and should not be used in new implementations.
+ */
+ BOTAN_DEPRECATED("Use TLS::Channel(TLS::Callbacks ...)")
Channel(output_fn out,
data_cb app_data_cb,
alert_cb alert_cb,
@@ -47,7 +62,7 @@ class BOTAN_DLL Channel
RandomNumberGenerator& rng,
const Policy& policy,
bool is_datagram,
- size_t io_buf_sz = 16*1024);
+ size_t io_buf_sz = IO_BUF_DEFAULT_SIZE);
Channel(const Channel&) = delete;
@@ -200,10 +215,12 @@ class BOTAN_DLL Channel
const Policy& policy() const { return m_policy; }
- bool save_session(const Session& session) const { return m_handshake_cb(session); }
+ bool save_session(const Session& session) const { return callbacks().tls_session_established(session); }
- handshake_msg_cb get_handshake_msg_cb() const { return m_handshake_msg_cb; }
+ Callbacks& callbacks() const { return m_callbacks; }
private:
+ void init(size_t io_buf_sze);
+
void send_record(byte record_type, const std::vector<byte>& record);
void send_record_under_epoch(u16bit epoch, byte record_type,
@@ -227,14 +244,21 @@ class BOTAN_DLL Channel
const Handshake_State* pending_state() const { return m_pending_state.get(); }
+ /* methods to handle incoming traffic through Channel::receive_data. */
+ void process_handshake_ccs(const secure_vector<byte>& record,
+ u64bit record_sequence,
+ Record_Type record_type,
+ Protocol_Version record_version);
+
+ void process_application_data(u64bit req_no, const secure_vector<byte>& record);
+
+ void process_alert(const secure_vector<byte>& record);
+
bool m_is_datagram;
/* callbacks */
- data_cb m_data_cb;
- alert_cb m_alert_cb;
- output_fn m_output_fn;
- handshake_cb m_handshake_cb;
- handshake_msg_cb m_handshake_msg_cb;
+ std::unique_ptr<Compat_Callbacks> m_compat_callbacks;
+ Callbacks& m_callbacks;
/* external state */
Session_Manager& m_session_manager;
diff --git a/src/lib/tls/tls_ciphersuite.cpp b/src/lib/tls/tls_ciphersuite.cpp
index 0b575a6ca..9a52e0e0e 100644
--- a/src/lib/tls/tls_ciphersuite.cpp
+++ b/src/lib/tls/tls_ciphersuite.cpp
@@ -11,83 +11,18 @@
#include <botan/stream_cipher.h>
#include <botan/hash.h>
#include <botan/mac.h>
-#include <sstream>
+#include <algorithm>
namespace Botan {
namespace TLS {
-namespace {
-
-/*
-* This way all work happens at the constuctor call, and we can
-* rely on that happening only once in C++11.
-*/
-std::vector<Ciphersuite> gather_known_ciphersuites()
- {
- std::vector<Ciphersuite> ciphersuites;
-
- std::vector<u16bit> all_ids = Ciphersuite::all_known_ciphersuite_ids();
-
- for(auto id : all_ids)
- {
- Ciphersuite suite = Ciphersuite::by_id(id);
-
- if(suite.valid())
- ciphersuites.push_back(suite);
- }
-
- return ciphersuites;
- }
-
-}
-
-const std::vector<Ciphersuite>& Ciphersuite::all_known_ciphersuites()
- {
- static std::vector<Ciphersuite> all_ciphersuites(gather_known_ciphersuites());
- return all_ciphersuites;
- }
-
-Ciphersuite Ciphersuite::by_name(const std::string& name)
- {
- for(auto suite : all_known_ciphersuites())
- {
- if(suite.to_string() == name)
- return suite;
- }
-
- return Ciphersuite(); // some unknown ciphersuite
- }
-
bool Ciphersuite::is_scsv(u16bit suite)
{
// TODO: derive from IANA file in script
return (suite == 0x00FF || suite == 0x5600);
}
-Ciphersuite::Ciphersuite(u16bit ciphersuite_code,
- const char* sig_algo,
- const char* kex_algo,
- const char* cipher_algo,
- size_t cipher_keylen,
- size_t nonce_bytes_from_handshake,
- size_t nonce_bytes_from_record,
- const char* mac_algo,
- size_t mac_keylen,
- const char* prf_algo) :
- m_ciphersuite_code(ciphersuite_code),
- m_sig_algo(sig_algo),
- m_kex_algo(kex_algo),
- m_prf_algo(prf_algo),
- m_cipher_algo(cipher_algo),
- m_cipher_keylen(cipher_keylen),
- m_nonce_bytes_from_handshake(nonce_bytes_from_handshake),
- m_nonce_bytes_from_record(nonce_bytes_from_record),
- m_mac_algo(mac_algo),
- m_mac_keylen(mac_keylen)
- {
- }
-
bool Ciphersuite::psk_ciphersuite() const
{
return (kex_algo() == "PSK" ||
@@ -107,6 +42,19 @@ bool Ciphersuite::cbc_ciphersuite() const
cipher_algo() == "Camellia-128" || cipher_algo() == "Camellia-256");
}
+Ciphersuite Ciphersuite::by_id(u16bit suite)
+ {
+ const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites();
+ auto s = std::lower_bound(all_suites.begin(), all_suites.end(), suite);
+
+ if(s->ciphersuite_code() == suite)
+ {
+ return *s;
+ }
+
+ return Ciphersuite(); // some unknown ciphersuite
+ }
+
namespace {
bool have_hash(const std::string& prf)
@@ -122,7 +70,7 @@ bool have_cipher(const std::string& cipher)
}
-bool Ciphersuite::valid() const
+bool Ciphersuite::is_usable() const
{
if(!m_cipher_keylen) // uninitialized object
return false;
@@ -213,73 +161,6 @@ bool Ciphersuite::valid() const
return true;
}
-std::string Ciphersuite::to_string() const
- {
- if(m_cipher_keylen == 0)
- throw Exception("Ciphersuite::to_string - no value set");
-
- std::ostringstream out;
-
- out << "TLS_";
-
- if(kex_algo() != "RSA")
- {
- if(kex_algo() == "DH")
- out << "DHE";
- else if(kex_algo() == "ECDH")
- out << "ECDHE";
- else
- out << kex_algo();
-
- out << '_';
- }
-
- if(sig_algo() == "DSA")
- out << "DSS_";
- else if(sig_algo() != "")
- out << sig_algo() << '_';
-
- out << "WITH_";
-
- if(cipher_algo() == "RC4")
- {
- out << "RC4_128_";
- }
- else if(cipher_algo() == "ChaCha20Poly1305")
- {
- out << "CHACHA20_POLY1305_";
- }
- else
- {
- if(cipher_algo() == "3DES")
- out << "3DES_EDE";
- else if(cipher_algo().find("Camellia") == 0)
- out << "CAMELLIA_" << std::to_string(8*cipher_keylen());
- else
- {
- if(cipher_algo().find("OCB(12)") != std::string::npos)
- out << replace_chars(cipher_algo().substr(0, cipher_algo().size() - 4),
- {'-', '/'}, '_');
- else
- out << replace_chars(cipher_algo(), {'-', '/'}, '_');
- }
-
- if(cipher_algo().find("/") != std::string::npos)
- out << "_"; // some explicit mode already included
- else
- out << "_CBC_";
- }
-
- if(mac_algo() == "SHA-1")
- out << "SHA";
- else if(mac_algo() == "AEAD")
- out << erase_chars(prf_algo(), {'-'});
- else
- out << erase_chars(mac_algo(), {'-'});
-
- return out.str();
- }
-
}
}
diff --git a/src/lib/tls/tls_ciphersuite.h b/src/lib/tls/tls_ciphersuite.h
index 47246ec11..6708e3ca6 100644
--- a/src/lib/tls/tls_ciphersuite.h
+++ b/src/lib/tls/tls_ciphersuite.h
@@ -29,21 +29,12 @@ class BOTAN_DLL Ciphersuite
*/
static Ciphersuite by_id(u16bit suite);
- static std::vector<u16bit> all_known_ciphersuite_ids();
-
/**
* Returns true iff this suite is a known SCSV
*/
static bool is_scsv(u16bit suite);
/**
- * Lookup a ciphersuite by name
- * @param name the name (eg TLS_RSA_WITH_RC4_128_SHA)
- * @return ciphersuite object
- */
- static Ciphersuite by_name(const std::string& name);
-
- /**
* Generate a static list of all known ciphersuites and return it.
*
* @return list of all known ciphersuites
@@ -54,7 +45,7 @@ class BOTAN_DLL Ciphersuite
* Formats the ciphersuite back to an RFC-style ciphersuite string
* @return RFC ciphersuite string identifier
*/
- std::string to_string() const;
+ std::string to_string() const { return m_iana_id; }
/**
* @return ciphersuite number
@@ -79,26 +70,28 @@ class BOTAN_DLL Ciphersuite
/**
* @return key exchange algorithm used by this ciphersuite
*/
- const std::string& kex_algo() const { return m_kex_algo; }
+ std::string kex_algo() const { return m_kex_algo; }
/**
* @return signature algorithm used by this ciphersuite
*/
- const std::string& sig_algo() const { return m_sig_algo; }
+ std::string sig_algo() const { return m_sig_algo; }
/**
* @return symmetric cipher algorithm used by this ciphersuite
*/
- const std::string& cipher_algo() const { return m_cipher_algo; }
+ std::string cipher_algo() const { return m_cipher_algo; }
/**
* @return message authentication algorithm used by this ciphersuite
*/
- const std::string& mac_algo() const { return m_mac_algo; }
+ std::string mac_algo() const { return m_mac_algo; }
- const std::string& prf_algo() const
+ std::string prf_algo() const
{
- return (!m_prf_algo.empty()) ? m_prf_algo : m_mac_algo;
+ if(m_prf_algo && *m_prf_algo)
+ return m_prf_algo;
+ return m_mac_algo;
}
/**
@@ -115,13 +108,19 @@ class BOTAN_DLL Ciphersuite
/**
* @return true if this is a valid/known ciphersuite
*/
- bool valid() const;
+ bool valid() const { return m_usable; }
+
+ bool operator<(const Ciphersuite& o) const { return ciphersuite_code() < o.ciphersuite_code(); }
+ bool operator<(const u16bit c) const { return ciphersuite_code() < c; }
Ciphersuite() {}
private:
+ bool is_usable() const;
+
Ciphersuite(u16bit ciphersuite_code,
+ const char* iana_id,
const char* sig_algo,
const char* kex_algo,
const char* cipher_algo,
@@ -130,21 +129,43 @@ class BOTAN_DLL Ciphersuite
size_t nonce_bytes_from_record,
const char* mac_algo,
size_t mac_keylen,
- const char* prf_algo = "");
+ const char* prf_algo) :
+ m_ciphersuite_code(ciphersuite_code),
+ m_iana_id(iana_id),
+ m_sig_algo(sig_algo),
+ m_kex_algo(kex_algo),
+ m_prf_algo(prf_algo),
+ m_cipher_algo(cipher_algo),
+ m_mac_algo(mac_algo),
+ m_cipher_keylen(cipher_keylen),
+ m_nonce_bytes_from_handshake(nonce_bytes_from_handshake),
+ m_nonce_bytes_from_record(nonce_bytes_from_record),
+ m_mac_keylen(mac_keylen)
+ {
+ m_usable = is_usable();
+ }
u16bit m_ciphersuite_code = 0;
- std::string m_sig_algo;
- std::string m_kex_algo;
- std::string m_prf_algo;
+ /*
+ All of these const char* strings are references to compile time
+ constants in tls_suite_info.cpp
+ */
+ const char* m_iana_id;
+
+ const char* m_sig_algo;
+ const char* m_kex_algo;
+ const char* m_prf_algo;
+
+ const char* m_cipher_algo;
+ const char* m_mac_algo;
- std::string m_cipher_algo;
size_t m_cipher_keylen = 0;
size_t m_nonce_bytes_from_handshake = 0;
size_t m_nonce_bytes_from_record = 0;
-
- std::string m_mac_algo;
size_t m_mac_keylen = 0;
+
+ bool m_usable = false;
};
}
diff --git a/src/lib/tls/tls_client.cpp b/src/lib/tls/tls_client.cpp
index bf7ccdf8c..0e72b9a28 100644
--- a/src/lib/tls/tls_client.cpp
+++ b/src/lib/tls/tls_client.cpp
@@ -1,6 +1,7 @@
/*
* TLS Client
* (C) 2004-2011,2012,2015,2016 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -23,7 +24,7 @@ class Client_Handshake_State : public Handshake_State
public:
// using Handshake_State::Handshake_State;
- Client_Handshake_State(Handshake_IO* io, handshake_msg_cb cb) : Handshake_State(io, cb) {}
+ Client_Handshake_State(Handshake_IO* io, Callbacks& cb) : Handshake_State(io, cb) {}
const Public_Key& get_server_public_Key() const
{
@@ -42,6 +43,23 @@ class Client_Handshake_State : public Handshake_State
/*
* TLS Client Constructor
*/
+Client::Client(Callbacks& callbacks,
+ Session_Manager& session_manager,
+ Credentials_Manager& creds,
+ const Policy& policy,
+ RandomNumberGenerator& rng,
+ const Server_Information& info,
+ const Protocol_Version& offer_version,
+ const std::vector<std::string>& next_protos,
+ size_t io_buf_sz) :
+ Channel(callbacks, session_manager, rng, policy, offer_version.is_datagram_protocol(),
+ io_buf_sz),
+ m_creds(creds),
+ m_info(info)
+ {
+ init(offer_version, next_protos);
+ }
+
Client::Client(output_fn output_fn,
data_cb proc_cb,
alert_cb alert_cb,
@@ -59,10 +77,7 @@ Client::Client(output_fn output_fn,
m_creds(creds),
m_info(info)
{
- const std::string srp_identifier = m_creds.srp_identifier("tls-client", m_info.hostname());
-
- Handshake_State& state = create_handshake_state(offer_version);
- send_client_hello(state, false, offer_version, srp_identifier, next_protos);
+ init(offer_version, next_protos);
}
Client::Client(output_fn output_fn,
@@ -82,15 +97,22 @@ Client::Client(output_fn output_fn,
m_creds(creds),
m_info(info)
{
+ init(offer_version, next_protos);
+ }
+
+void Client::init(const Protocol_Version& protocol_version,
+ const std::vector<std::string>& next_protocols)
+ {
const std::string srp_identifier = m_creds.srp_identifier("tls-client", m_info.hostname());
- Handshake_State& state = create_handshake_state(offer_version);
- send_client_hello(state, false, offer_version, srp_identifier, next_protos);
+ Handshake_State& state = create_handshake_state(protocol_version);
+ send_client_hello(state, false, protocol_version,
+ srp_identifier, next_protocols);
}
Handshake_State* Client::new_handshake_state(Handshake_IO* io)
{
- return new Client_Handshake_State(io, get_handshake_msg_cb());
+ return new Client_Handshake_State(io, callbacks());
}
std::vector<X509_Certificate>
@@ -145,16 +167,15 @@ void Client::send_client_hello(Handshake_State& state_base,
if(!state.client_hello()) // not resuming
{
+ Client_Hello::Settings client_settings(version, m_info.hostname(), srp_identifier);
state.client_hello(new Client_Hello(
state.handshake_io(),
state.hash(),
- version,
policy(),
rng(),
secure_renegotiation_data_for_client_hello(),
- next_protocols,
- m_info.hostname(),
- srp_identifier));
+ client_settings,
+ next_protocols));
}
secure_renegotiation_check(state.client_hello());
@@ -419,11 +440,9 @@ void Client::process_handshake_msg(const Handshake_State* active_state,
"tls-client",
m_info.hostname());
- state.client_certs(
- new Certificate(state.handshake_io(),
- state.hash(),
- client_certs)
- );
+ state.client_certs(new Certificate(state.handshake_io(),
+ state.hash(),
+ client_certs));
}
state.client_kex(
diff --git a/src/lib/tls/tls_client.h b/src/lib/tls/tls_client.h
index 45a741878..09af053af 100644
--- a/src/lib/tls/tls_client.h
+++ b/src/lib/tls/tls_client.h
@@ -1,6 +1,7 @@
/*
* TLS Client
* (C) 2004-2011 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -22,9 +23,49 @@ namespace TLS {
class BOTAN_DLL Client final : public Channel
{
public:
+
/**
* Set up a new TLS client session
*
+ * @param callbacks contains a set of callback function references
+ * required by the TLS client.
+ *
+ * @param session_manager manages session state
+ *
+ * @param creds manages application/user credentials
+ *
+ * @param policy specifies other connection policy information
+ *
+ * @param rng a random number generator
+ *
+ * @param server_info is identifying information about the TLS server
+ *
+ * @param offer_version specifies which version we will offer
+ * to the TLS server.
+ *
+ * @param next_protocols specifies protocols to advertise with ALPN
+ *
+ * @param reserved_io_buffer_size This many bytes of memory will
+ * be preallocated for the read and write buffers. Smaller
+ * values just mean reallocations and copies are more likely.
+ */
+ Client(Callbacks& callbacks,
+ Session_Manager& session_manager,
+ Credentials_Manager& creds,
+ const Policy& policy,
+ RandomNumberGenerator& rng,
+ const Server_Information& server_info = Server_Information(),
+ const Protocol_Version& offer_version = Protocol_Version::latest_tls_version(),
+ const std::vector<std::string>& next_protocols = {},
+ size_t reserved_io_buffer_size = TLS::Client::IO_BUF_DEFAULT_SIZE
+ );
+
+ /**
+ * DEPRECATED. This constructor is only provided for backward
+ * compatibility and should not be used in new code.
+ *
+ * Set up a new TLS client session
+ *
* @param output_fn is called with data for the outbound socket
*
* @param app_data_cb is called when new application data is received
@@ -52,7 +93,7 @@ class BOTAN_DLL Client final : public Channel
* be preallocated for the read and write buffers. Smaller
* values just mean reallocations and copies are more likely.
*/
-
+ BOTAN_DEPRECATED("Use TLS::Client(TLS::Callbacks ...)")
Client(output_fn out,
data_cb app_data_cb,
alert_cb alert_cb,
@@ -64,9 +105,14 @@ class BOTAN_DLL Client final : public Channel
const Server_Information& server_info = Server_Information(),
const Protocol_Version& offer_version = Protocol_Version::latest_tls_version(),
const std::vector<std::string>& next_protocols = {},
- size_t reserved_io_buffer_size = 16*1024
+ size_t reserved_io_buffer_size = TLS::Client::IO_BUF_DEFAULT_SIZE
);
+ /**
+ * DEPRECATED. This constructor is only provided for backward
+ * compatibility and should not be used in new implementations.
+ */
+ BOTAN_DEPRECATED("Use TLS::Client(TLS::Callbacks ...)")
Client(output_fn out,
data_cb app_data_cb,
alert_cb alert_cb,
@@ -83,6 +129,9 @@ class BOTAN_DLL Client final : public Channel
const std::string& application_protocol() const { return m_application_protocol; }
private:
+ void init(const Protocol_Version& protocol_version,
+ const std::vector<std::string>& next_protocols);
+
std::vector<X509_Certificate>
get_peer_cert_chain(const Handshake_State& state) const override;
diff --git a/src/lib/tls/tls_extensions.h b/src/lib/tls/tls_extensions.h
index 28c49f084..dc69eec36 100644
--- a/src/lib/tls/tls_extensions.h
+++ b/src/lib/tls/tls_extensions.h
@@ -2,6 +2,7 @@
* TLS Extensions
* (C) 2011,2012,2016 Jack Lloyd
* 2016 Juraj Somorovsky
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -35,7 +36,6 @@ enum Handshake_Extension_Type {
TLSEXT_SRP_IDENTIFIER = 12,
TLSEXT_SIGNATURE_ALGORITHMS = 13,
TLSEXT_USE_SRTP = 14,
- TLSEXT_HEARTBEAT_SUPPORT = 15,
TLSEXT_ALPN = 16,
TLSEXT_ENCRYPT_THEN_MAC = 22,
diff --git a/src/lib/tls/tls_handshake_hash.cpp b/src/lib/tls/tls_handshake_hash.cpp
index 00b8d744c..4f78bebbc 100644
--- a/src/lib/tls/tls_handshake_hash.cpp
+++ b/src/lib/tls/tls_handshake_hash.cpp
@@ -21,14 +21,19 @@ secure_vector<byte> Handshake_Hash::final(Protocol_Version version,
{
auto choose_hash = [=]() {
if(!version.supports_ciphersuite_specific_prf())
- return "Parallel(MD5,SHA-160)";;
+ return "Parallel(MD5,SHA-160)";
if(mac_algo == "MD5" || mac_algo == "SHA-1")
return "SHA-256";
return mac_algo.c_str();
};
- std::unique_ptr<HashFunction> hash(HashFunction::create(choose_hash()));
+ const std::string hash_algo = choose_hash();
+ std::unique_ptr<HashFunction> hash(HashFunction::create(hash_algo));
+ if(!hash)
+ {
+ throw Algorithm_Not_Found(hash_algo);
+ }
hash->update(m_data);
return hash->final();
}
diff --git a/src/lib/tls/tls_handshake_msg.h b/src/lib/tls/tls_handshake_msg.h
index 7e527abf4..618ae8d76 100644
--- a/src/lib/tls/tls_handshake_msg.h
+++ b/src/lib/tls/tls_handshake_msg.h
@@ -1,6 +1,7 @@
/*
* TLS Handshake Message
* (C) 2012 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -16,6 +17,9 @@ namespace Botan {
namespace TLS {
+class Handshake_IO;
+class Handshake_Hash;
+
/**
* TLS Handshake Message Base Class
*/
diff --git a/src/lib/tls/tls_handshake_state.cpp b/src/lib/tls/tls_handshake_state.cpp
index afc32ba87..71cacdabd 100644
--- a/src/lib/tls/tls_handshake_state.cpp
+++ b/src/lib/tls/tls_handshake_state.cpp
@@ -8,6 +8,7 @@
#include <botan/internal/tls_handshake_state.h>
#include <botan/internal/tls_messages.h>
#include <botan/internal/tls_record.h>
+#include <botan/tls_callbacks.h>
namespace Botan {
@@ -174,8 +175,8 @@ std::string handshake_mask_to_string(u32bit mask)
/*
* Initialize the SSL/TLS Handshake State
*/
-Handshake_State::Handshake_State(Handshake_IO* io, handshake_msg_cb cb) :
- m_msg_callback(cb),
+Handshake_State::Handshake_State(Handshake_IO* io, Callbacks& cb) :
+ m_callbacks(cb),
m_handshake_io(io),
m_version(m_handshake_io->initial_record_version())
{
@@ -183,6 +184,11 @@ Handshake_State::Handshake_State(Handshake_IO* io, handshake_msg_cb cb) :
Handshake_State::~Handshake_State() {}
+void Handshake_State::note_message(const Handshake_Message& msg)
+ {
+ m_callbacks.tls_inspect_handshake_msg(msg);
+ }
+
void Handshake_State::hello_verify_request(const Hello_Verify_Request& hello_verify)
{
note_message(hello_verify);
diff --git a/src/lib/tls/tls_handshake_state.h b/src/lib/tls/tls_handshake_state.h
index 2943a8637..bdec10d14 100644
--- a/src/lib/tls/tls_handshake_state.h
+++ b/src/lib/tls/tls_handshake_state.h
@@ -24,6 +24,7 @@ class KDF;
namespace TLS {
+class Callbacks;
class Policy;
class Hello_Verify_Request;
@@ -45,9 +46,7 @@ class Finished;
class Handshake_State
{
public:
- typedef std::function<void (const Handshake_Message&)> handshake_msg_cb;
-
- Handshake_State(Handshake_IO* io, handshake_msg_cb cb);
+ Handshake_State(Handshake_IO* io, Callbacks& callbacks);
virtual ~Handshake_State();
@@ -164,15 +163,10 @@ class Handshake_State
const Handshake_Hash& hash() const { return m_handshake_hash; }
- void note_message(const Handshake_Message& msg)
- {
- if(m_msg_callback)
- m_msg_callback(msg);
- }
-
+ void note_message(const Handshake_Message& msg);
private:
- handshake_msg_cb m_msg_callback;
+ Callbacks& m_callbacks;
std::unique_ptr<Handshake_IO> m_handshake_io;
diff --git a/src/lib/tls/tls_messages.h b/src/lib/tls/tls_messages.h
index c6a65b658..8ccb2fbff 100644
--- a/src/lib/tls/tls_messages.h
+++ b/src/lib/tls/tls_messages.h
@@ -1,6 +1,7 @@
/*
* TLS Messages
* (C) 2004-2011,2015 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -61,6 +62,26 @@ class Hello_Verify_Request final : public Handshake_Message
class Client_Hello final : public Handshake_Message
{
public:
+ class Settings
+ {
+ public:
+ Settings(const Protocol_Version version,
+ const std::string& hostname = "",
+ const std::string& srp_identifier = "")
+ : m_new_session_version(version),
+ m_hostname(hostname),
+ m_srp_identifier(srp_identifier) {};
+
+ const Protocol_Version protocol_version() const { return m_new_session_version; };
+ const std::string& hostname() const { return m_hostname; };
+ const std::string& srp_identifier() const { return m_srp_identifier; }
+
+ private:
+ const Protocol_Version m_new_session_version;
+ const std::string m_hostname;
+ const std::string m_srp_identifier;
+ };
+
Handshake_Type type() const override { return CLIENT_HELLO; }
Protocol_Version version() const { return m_version; }
@@ -167,13 +188,11 @@ class Client_Hello final : public Handshake_Message
Client_Hello(Handshake_IO& io,
Handshake_Hash& hash,
- Protocol_Version version,
const Policy& policy,
RandomNumberGenerator& rng,
const std::vector<byte>& reneg_info,
- const std::vector<std::string>& next_protocols,
- const std::string& hostname = "",
- const std::string& srp_identifier = "");
+ const Client_Hello::Settings& client_settings,
+ const std::vector<std::string>& next_protocols);
Client_Hello(Handshake_IO& io,
Handshake_Hash& hash,
@@ -204,6 +223,35 @@ class Client_Hello final : public Handshake_Message
class Server_Hello final : public Handshake_Message
{
public:
+ class Settings
+ {
+ public:
+ Settings(const std::vector<byte> new_session_id,
+ Protocol_Version new_session_version,
+ u16bit ciphersuite,
+ byte compression,
+ bool offer_session_ticket)
+ : m_new_session_id(new_session_id),
+ m_new_session_version(new_session_version),
+ m_ciphersuite(ciphersuite),
+ m_compression(compression),
+ m_offer_session_ticket(offer_session_ticket) {};
+
+ const std::vector<byte>& session_id() const { return m_new_session_id; };
+ Protocol_Version protocol_version() const { return m_new_session_version; };
+ u16bit ciphersuite() const { return m_ciphersuite; };
+ byte compression() const { return m_compression; }
+ bool offer_session_ticket() const { return m_offer_session_ticket; }
+
+ private:
+ const std::vector<byte> m_new_session_id;
+ Protocol_Version m_new_session_version;
+ u16bit m_ciphersuite;
+ byte m_compression;
+ bool m_offer_session_ticket;
+ };
+
+
Handshake_Type type() const override { return SERVER_HELLO; }
Protocol_Version version() const { return m_version; }
@@ -272,12 +320,8 @@ class Server_Hello final : public Handshake_Message
RandomNumberGenerator& rng,
const std::vector<byte>& secure_reneg_info,
const Client_Hello& client_hello,
- const std::vector<byte>& new_session_id,
- Protocol_Version new_session_version,
- u16bit ciphersuite,
- byte compression,
- bool offer_session_ticket,
- const std::string& next_protocol);
+ const Server_Hello::Settings& settings,
+ const std::string next_protocol);
Server_Hello(Handshake_IO& io,
Handshake_Hash& hash,
diff --git a/src/lib/tls/tls_record.cpp b/src/lib/tls/tls_record.cpp
index c273a1546..877b81b41 100644
--- a/src/lib/tls/tls_record.cpp
+++ b/src/lib/tls/tls_record.cpp
@@ -1,7 +1,8 @@
/*
* TLS Record Handling
-* (C) 2012,2013,2014,2015 Jack Lloyd
-* (C) 2016 Juraj Somorovsky
+* (C) 2012,2013,2014,2015,2016 Jack Lloyd
+* 2016 Juraj Somorovsky
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -155,7 +156,7 @@ Connection_Cipher_State::format_ad(u64bit msg_sequence,
}
void write_record(secure_vector<byte>& output,
- byte msg_type, const byte msg[], size_t msg_length,
+ Record_Message msg,
Protocol_Version version,
u64bit seq,
Connection_Cipher_State* cs,
@@ -163,7 +164,7 @@ void write_record(secure_vector<byte>& output,
{
output.clear();
- output.push_back(msg_type);
+ output.push_back(msg.get_type());
output.push_back(version.major_version());
output.push_back(version.minor_version());
@@ -175,17 +176,17 @@ void write_record(secure_vector<byte>& output,
if(!cs) // initial unencrypted handshake records
{
- output.push_back(get_byte(0, static_cast<u16bit>(msg_length)));
- output.push_back(get_byte(1, static_cast<u16bit>(msg_length)));
+ output.push_back(get_byte<u16bit>(0, static_cast<u16bit>(msg.get_size())));
+ output.push_back(get_byte<u16bit>(1, static_cast<u16bit>(msg.get_size())));
- output.insert(output.end(), msg, msg + msg_length);
+ output.insert(output.end(), msg.get_data(), msg.get_data() + msg.get_size());
return;
}
if(AEAD_Mode* aead = cs->aead())
{
- const size_t ctext_size = aead->output_length(msg_length);
+ const size_t ctext_size = aead->output_length(msg.get_size());
const std::vector<byte> nonce = cs->aead_nonce(seq);
@@ -196,17 +197,16 @@ void write_record(secure_vector<byte>& output,
output.push_back(get_byte(0, static_cast<u16bit>(rec_size)));
output.push_back(get_byte(1, static_cast<u16bit>(rec_size)));
- aead->set_ad(cs->format_ad(seq, msg_type, version, static_cast<u16bit>(msg_length)));
+ aead->set_ad(cs->format_ad(seq, msg.get_type(), version, static_cast<u16bit>(msg.get_size())));
if(cs->nonce_bytes_from_record() > 0)
{
output += std::make_pair(&nonce[cs->nonce_bytes_from_handshake()], cs->nonce_bytes_from_record());
}
-
BOTAN_ASSERT(aead->start(nonce).empty(), "AEAD doesn't return anything from start");
const size_t offset = output.size();
- output += std::make_pair(msg, msg_length);
+ output += std::make_pair(msg.get_data(), msg.get_size());
aead->finish(output, offset);
BOTAN_ASSERT(output.size() == offset + ctext_size, "Expected size");
@@ -222,11 +222,11 @@ void write_record(secure_vector<byte>& output,
if(!cs->uses_encrypt_then_mac())
{
- cs->mac()->update(cs->format_ad(seq, msg_type, version, static_cast<u16bit>(msg_length)));
- cs->mac()->update(msg, msg_length);
+ cs->mac()->update(cs->format_ad(seq, msg.get_type(), version, static_cast<u16bit>(msg.get_size())));
+ cs->mac()->update(msg.get_data(), msg.get_size());
const size_t buf_size = round_up(
- iv_size + msg_length + mac_size + (block_size ? 1 : 0),
+ iv_size + msg.get_size() + mac_size + (block_size ? 1 : 0),
block_size);
if(buf_size > MAX_CIPHERTEXT_SIZE)
@@ -243,7 +243,7 @@ void write_record(secure_vector<byte>& output,
rng.randomize(&output[output.size() - iv_size], iv_size);
}
- output.insert(output.end(), msg, msg + msg_length);
+ output.insert(output.end(), msg.get_data(), msg.get_data() + msg.get_size());
output.resize(output.size() + mac_size);
cs->mac()->final(&output[output.size() - mac_size]);
@@ -251,7 +251,7 @@ void write_record(secure_vector<byte>& output,
if(block_size)
{
const size_t pad_val =
- buf_size - (iv_size + msg_length + mac_size + 1);
+ buf_size - (iv_size + msg.get_size() + mac_size + 1);
for(size_t i = 0; i != pad_val + 1; ++i)
output.push_back(static_cast<byte>(pad_val));
@@ -294,7 +294,7 @@ void write_record(secure_vector<byte>& output,
else
{
const size_t enc_size = round_up(
- iv_size + msg_length + (block_size ? 1 : 0),
+ iv_size + msg.get_size() + (block_size ? 1 : 0),
block_size);
const size_t buf_size = enc_size + mac_size;
@@ -313,12 +313,12 @@ void write_record(secure_vector<byte>& output,
rng.randomize(&output[output.size() - iv_size], iv_size);
}
- output.insert(output.end(), msg, msg + msg_length);
+ output.insert(output.end(), msg.get_data(), msg.get_data() + msg.get_size());
if(block_size)
{
const size_t pad_val =
- enc_size - (iv_size + msg_length + 1);
+ enc_size - (iv_size + msg.get_size() + 1);
for(size_t i = 0; i != pad_val + 1; ++i)
output.push_back(pad_val);
@@ -347,7 +347,7 @@ void write_record(secure_vector<byte>& output,
cbc_state.assign(&buf[block_size*(blocks-1)],
&buf[block_size*blocks]);
- cs->mac()->update(cs->format_ad(seq, msg_type, version, enc_size));
+ cs->mac()->update(cs->format_ad(seq, msg.get_type(), version, enc_size));
cs->mac()->update(buf, enc_size);
output.resize(output.size() + mac_size);
@@ -575,65 +575,58 @@ void decrypt_record(secure_vector<byte>& output,
}
size_t read_tls_record(secure_vector<byte>& readbuf,
- const byte input[],
- size_t input_sz,
- size_t& consumed,
- secure_vector<byte>& record,
- u64bit* record_sequence,
- Protocol_Version* record_version,
- Record_Type* record_type,
+ Record_Raw_Input& raw_input,
+ Record& rec,
Connection_Sequence_Numbers* sequence_numbers,
get_cipherstate_fn get_cipherstate)
{
- consumed = 0;
-
if(readbuf.size() < TLS_HEADER_SIZE) // header incomplete?
{
if(size_t needed = fill_buffer_to(readbuf,
- input, input_sz, consumed,
+ raw_input.get_data(), raw_input.get_size(), raw_input.get_consumed(),
TLS_HEADER_SIZE))
return needed;
BOTAN_ASSERT_EQUAL(readbuf.size(), TLS_HEADER_SIZE, "Have an entire header");
}
- *record_version = Protocol_Version(readbuf[1], readbuf[2]);
+ *rec.get_protocol_version() = Protocol_Version(readbuf[1], readbuf[2]);
- BOTAN_ASSERT(!record_version->is_datagram_protocol(), "Expected TLS");
+ BOTAN_ASSERT(!rec.get_protocol_version()->is_datagram_protocol(), "Expected TLS");
- const size_t record_len = make_u16bit(readbuf[TLS_HEADER_SIZE-2],
+ const size_t record_size = make_u16bit(readbuf[TLS_HEADER_SIZE-2],
readbuf[TLS_HEADER_SIZE-1]);
- if(record_len > MAX_CIPHERTEXT_SIZE)
+ if(record_size > MAX_CIPHERTEXT_SIZE)
throw TLS_Exception(Alert::RECORD_OVERFLOW,
"Received a record that exceeds maximum size");
- if(record_len == 0)
+ if(record_size == 0)
throw TLS_Exception(Alert::DECODE_ERROR,
"Received a completely empty record");
if(size_t needed = fill_buffer_to(readbuf,
- input, input_sz, consumed,
- TLS_HEADER_SIZE + record_len))
+ raw_input.get_data(), raw_input.get_size(), raw_input.get_consumed(),
+ TLS_HEADER_SIZE + record_size))
return needed;
- BOTAN_ASSERT_EQUAL(static_cast<size_t>(TLS_HEADER_SIZE) + record_len,
+ BOTAN_ASSERT_EQUAL(static_cast<size_t>(TLS_HEADER_SIZE) + record_size,
readbuf.size(),
"Have the full record");
- *record_type = static_cast<Record_Type>(readbuf[0]);
+ *rec.get_type() = static_cast<Record_Type>(readbuf[0]);
u16bit epoch = 0;
if(sequence_numbers)
{
- *record_sequence = sequence_numbers->next_read_sequence();
+ *rec.get_sequence() = sequence_numbers->next_read_sequence();
epoch = sequence_numbers->current_read_epoch();
}
else
{
// server initial handshake case
- *record_sequence = 0;
+ *rec.get_sequence() = 0;
epoch = 0;
}
@@ -641,7 +634,7 @@ size_t read_tls_record(secure_vector<byte>& readbuf,
if(epoch == 0) // Unencrypted initial handshake
{
- record.assign(readbuf.begin() + TLS_HEADER_SIZE, readbuf.begin() + TLS_HEADER_SIZE + record_len);
+ rec.get_data().assign(readbuf.begin() + TLS_HEADER_SIZE, readbuf.begin() + TLS_HEADER_SIZE + record_size);
readbuf.clear();
return 0; // got a full record
}
@@ -651,37 +644,30 @@ size_t read_tls_record(secure_vector<byte>& readbuf,
BOTAN_ASSERT(cs, "Have cipherstate for this epoch");
- decrypt_record(record,
+ decrypt_record(rec.get_data(),
record_contents,
- record_len,
- *record_sequence,
- *record_version,
- *record_type,
+ record_size,
+ *rec.get_sequence(),
+ *rec.get_protocol_version(),
+ *rec.get_type(),
*cs);
if(sequence_numbers)
- sequence_numbers->read_accept(*record_sequence);
+ sequence_numbers->read_accept(*rec.get_sequence());
readbuf.clear();
return 0;
}
size_t read_dtls_record(secure_vector<byte>& readbuf,
- const byte input[],
- size_t input_sz,
- size_t& consumed,
- secure_vector<byte>& record,
- u64bit* record_sequence,
- Protocol_Version* record_version,
- Record_Type* record_type,
+ Record_Raw_Input& raw_input,
+ Record& rec,
Connection_Sequence_Numbers* sequence_numbers,
get_cipherstate_fn get_cipherstate)
{
- consumed = 0;
-
if(readbuf.size() < DTLS_HEADER_SIZE) // header incomplete?
{
- if(fill_buffer_to(readbuf, input, input_sz, consumed, DTLS_HEADER_SIZE))
+ if(fill_buffer_to(readbuf, raw_input.get_data(), raw_input.get_size(), raw_input.get_consumed(), DTLS_HEADER_SIZE))
{
readbuf.clear();
return 0;
@@ -690,38 +676,35 @@ size_t read_dtls_record(secure_vector<byte>& readbuf,
BOTAN_ASSERT_EQUAL(readbuf.size(), DTLS_HEADER_SIZE, "Have an entire header");
}
- *record_version = Protocol_Version(readbuf[1], readbuf[2]);
+ *rec.get_protocol_version() = Protocol_Version(readbuf[1], readbuf[2]);
- BOTAN_ASSERT(record_version->is_datagram_protocol(), "Expected DTLS");
+ BOTAN_ASSERT(rec.get_protocol_version()->is_datagram_protocol(), "Expected DTLS");
- const size_t record_len = make_u16bit(readbuf[DTLS_HEADER_SIZE-2],
- readbuf[DTLS_HEADER_SIZE-1]);
+ const size_t record_size = make_u16bit(readbuf[DTLS_HEADER_SIZE-2],
+ readbuf[DTLS_HEADER_SIZE-1]);
- // Invalid packet:
- if(record_len == 0 || record_len > MAX_CIPHERTEXT_SIZE)
- {
- readbuf.clear();
- return 0;
- }
+ if(record_size > MAX_CIPHERTEXT_SIZE)
+ throw TLS_Exception(Alert::RECORD_OVERFLOW,
+ "Got message that exceeds maximum size");
- if(fill_buffer_to(readbuf, input, input_sz, consumed, DTLS_HEADER_SIZE + record_len))
+ if(fill_buffer_to(readbuf, raw_input.get_data(), raw_input.get_size(), raw_input.get_consumed(), DTLS_HEADER_SIZE + record_size))
{
// Truncated packet?
readbuf.clear();
return 0;
}
- BOTAN_ASSERT_EQUAL(static_cast<size_t>(DTLS_HEADER_SIZE) + record_len, readbuf.size(),
+ BOTAN_ASSERT_EQUAL(static_cast<size_t>(DTLS_HEADER_SIZE) + record_size, readbuf.size(),
"Have the full record");
- *record_type = static_cast<Record_Type>(readbuf[0]);
+ *rec.get_type() = static_cast<Record_Type>(readbuf[0]);
u16bit epoch = 0;
- *record_sequence = load_be<u64bit>(&readbuf[3], 0);
- epoch = (*record_sequence >> 48);
+ *rec.get_sequence() = load_be<u64bit>(&readbuf[3], 0);
+ epoch = (*rec.get_sequence() >> 48);
- if(sequence_numbers && sequence_numbers->already_seen(*record_sequence))
+ if(sequence_numbers && sequence_numbers->already_seen(*rec.get_sequence()))
{
readbuf.clear();
return 0;
@@ -731,7 +714,7 @@ size_t read_dtls_record(secure_vector<byte>& readbuf,
if(epoch == 0) // Unencrypted initial handshake
{
- record.assign(readbuf.begin() + DTLS_HEADER_SIZE, readbuf.begin() + DTLS_HEADER_SIZE + record_len);
+ rec.get_data().assign(readbuf.begin() + DTLS_HEADER_SIZE, readbuf.begin() + DTLS_HEADER_SIZE + record_size);
readbuf.clear();
return 0; // got a full record
}
@@ -743,23 +726,23 @@ size_t read_dtls_record(secure_vector<byte>& readbuf,
BOTAN_ASSERT(cs, "Have cipherstate for this epoch");
- decrypt_record(record,
+ decrypt_record(rec.get_data(),
record_contents,
- record_len,
- *record_sequence,
- *record_version,
- *record_type,
+ record_size,
+ *rec.get_sequence(),
+ *rec.get_protocol_version(),
+ *rec.get_type(),
*cs);
}
catch(std::exception)
{
readbuf.clear();
- *record_type = NO_RECORD;
+ *rec.get_type() = NO_RECORD;
return 0;
}
if(sequence_numbers)
- sequence_numbers->read_accept(*record_sequence);
+ sequence_numbers->read_accept(*rec.get_sequence());
readbuf.clear();
return 0;
@@ -768,24 +751,16 @@ size_t read_dtls_record(secure_vector<byte>& readbuf,
}
size_t read_record(secure_vector<byte>& readbuf,
- const byte input[],
- size_t input_sz,
- bool is_datagram,
- size_t& consumed,
- secure_vector<byte>& record,
- u64bit* record_sequence,
- Protocol_Version* record_version,
- Record_Type* record_type,
+ Record_Raw_Input& raw_input,
+ Record& rec,
Connection_Sequence_Numbers* sequence_numbers,
get_cipherstate_fn get_cipherstate)
{
- if(is_datagram)
- return read_dtls_record(readbuf, input, input_sz, consumed,
- record, record_sequence, record_version, record_type,
+ if(raw_input.is_datagram())
+ return read_dtls_record(readbuf, raw_input, rec,
sequence_numbers, get_cipherstate);
else
- return read_tls_record(readbuf, input, input_sz, consumed,
- record, record_sequence, record_version, record_type,
+ return read_tls_record(readbuf, raw_input, rec,
sequence_numbers, get_cipherstate);
}
diff --git a/src/lib/tls/tls_record.h b/src/lib/tls/tls_record.h
index 9180aa554..4420a9c66 100644
--- a/src/lib/tls/tls_record.h
+++ b/src/lib/tls/tls_record.h
@@ -1,6 +1,7 @@
/*
* TLS Record Handling
* (C) 2004-2012 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -95,6 +96,80 @@ class Connection_Cipher_State
bool m_uses_encrypt_then_mac;
};
+class Record
+ {
+ public:
+ Record(secure_vector<byte>& data,
+ u64bit* sequence,
+ Protocol_Version* protocol_version,
+ Record_Type* type)
+ : m_data(data), m_sequence(sequence), m_protocol_version(protocol_version),
+ m_type(type), m_size(data.size()) {};
+
+ secure_vector<byte>& get_data() { return m_data; }
+
+ Protocol_Version* get_protocol_version() { return m_protocol_version; }
+
+ u64bit* get_sequence() { return m_sequence; }
+
+ Record_Type* get_type() { return m_type; }
+
+ size_t& get_size() { return m_size; }
+
+ private:
+ secure_vector<byte>& m_data;
+ u64bit* m_sequence;
+ Protocol_Version* m_protocol_version;
+ Record_Type* m_type;
+ size_t m_size;
+ };
+
+class Record_Message
+ {
+ public:
+ Record_Message(const byte* data, size_t size)
+ : m_type(0), m_sequence(0), m_data(data), m_size(size) {};
+ Record_Message(byte type, u64bit sequence, const byte* data, size_t size)
+ : m_type(type), m_sequence(sequence), m_data(data),
+ m_size(size) {};
+
+ byte& get_type() { return m_type; };
+ u64bit& get_sequence() { return m_sequence; };
+ const byte* get_data() { return m_data; };
+ size_t& get_size() { return m_size; };
+
+ private:
+ byte m_type;
+ u64bit m_sequence;
+ const byte* m_data;
+ size_t m_size;
+};
+
+class Record_Raw_Input
+ {
+ public:
+ Record_Raw_Input(const byte* data, size_t size, size_t& consumed,
+ bool is_datagram)
+ : m_data(data), m_size(size), m_consumed(consumed),
+ m_is_datagram(is_datagram) {};
+
+ const byte*& get_data() { return m_data; };
+
+ size_t& get_size() { return m_size; };
+
+ size_t& get_consumed() { return m_consumed; };
+ void set_consumed(size_t consumed) { m_consumed = consumed; }
+
+ bool is_datagram() { return m_is_datagram; };
+
+ private:
+ const byte* m_data;
+ size_t m_size;
+ size_t& m_consumed;
+ bool m_is_datagram;
+ };
+
+
/**
* Create a TLS record
* @param write_buffer the output record is placed here
@@ -108,7 +183,7 @@ class Connection_Cipher_State
* @return number of bytes written to write_buffer
*/
void write_record(secure_vector<byte>& write_buffer,
- byte msg_type, const byte msg[], size_t msg_length,
+ Record_Message rec_msg,
Protocol_Version version,
u64bit msg_sequence,
Connection_Cipher_State* cipherstate,
@@ -122,14 +197,8 @@ typedef std::function<std::shared_ptr<Connection_Cipher_State> (u16bit)> get_cip
* @return zero if full message, else number of bytes still needed
*/
size_t read_record(secure_vector<byte>& read_buffer,
- const byte input[],
- size_t input_length,
- bool is_datagram,
- size_t& input_consumed,
- secure_vector<byte>& record,
- u64bit* record_sequence,
- Protocol_Version* record_version,
- Record_Type* record_type,
+ Record_Raw_Input& raw_input,
+ Record& rec,
Connection_Sequence_Numbers* sequence_numbers,
get_cipherstate_fn get_cipherstate);
diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp
index 78c9087e0..40aa18d27 100644
--- a/src/lib/tls/tls_server.cpp
+++ b/src/lib/tls/tls_server.cpp
@@ -1,6 +1,7 @@
/*
* TLS Server
* (C) 2004-2011,2012,2016 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -9,30 +10,41 @@
#include <botan/internal/tls_handshake_state.h>
#include <botan/internal/tls_messages.h>
#include <botan/internal/stl_util.h>
+#include <botan/tls_magic.h>
namespace Botan {
namespace TLS {
-namespace {
-
class Server_Handshake_State : public Handshake_State
{
public:
- // using Handshake_State::Handshake_State;
+ Server_Handshake_State(Handshake_IO* io, Callbacks& cb)
+ : Handshake_State(io, cb) {}
+
+ Private_Key* server_rsa_kex_key() { return m_server_rsa_kex_key; }
+ void set_server_rsa_kex_key(Private_Key* key)
+ { m_server_rsa_kex_key = key; }
+
+ bool allow_session_resumption() const
+ { return m_allow_session_resumption; }
+ void set_allow_session_resumption(bool allow_session_resumption)
+ { m_allow_session_resumption = allow_session_resumption; }
- Server_Handshake_State(Handshake_IO* io, handshake_msg_cb cb) : Handshake_State(io, cb) {}
+ private:
// Used by the server only, in case of RSA key exchange. Not owned
- Private_Key* server_rsa_kex_key = nullptr;
+ Private_Key* m_server_rsa_kex_key = nullptr;
/*
* Used by the server to know if resumption should be allowed on
* a server-initiated renegotiation
*/
- bool allow_session_resumption = true;
+ bool m_allow_session_resumption = true;
};
+namespace {
+
bool check_for_resume(Session& session_info,
Session_Manager& session_manager,
Credentials_Manager& credentials,
@@ -238,6 +250,19 @@ get_server_certs(const std::string& hostname,
/*
* TLS Server Constructor
*/
+Server::Server(Callbacks& callbacks,
+ Session_Manager& session_manager,
+ Credentials_Manager& creds,
+ const Policy& policy,
+ RandomNumberGenerator& rng,
+ bool is_datagram,
+ size_t io_buf_sz) :
+ Channel(callbacks, session_manager, rng, policy,
+ is_datagram, io_buf_sz),
+ m_creds(creds)
+ {
+ }
+
Server::Server(output_fn output,
data_cb data_cb,
alert_cb alert_cb,
@@ -249,13 +274,15 @@ Server::Server(output_fn output,
next_protocol_fn next_proto,
bool is_datagram,
size_t io_buf_sz) :
- Channel(output, data_cb, alert_cb, handshake_cb, Channel::handshake_msg_cb(),
- session_manager, rng, policy, is_datagram, io_buf_sz),
+ Channel(output, data_cb, alert_cb, handshake_cb,
+ Channel::handshake_msg_cb(), session_manager,
+ rng, policy, is_datagram, io_buf_sz),
m_creds(creds),
m_choose_next_protocol(next_proto)
{
}
+
Server::Server(output_fn output,
data_cb data_cb,
alert_cb alert_cb,
@@ -276,8 +303,7 @@ Server::Server(output_fn output,
Handshake_State* Server::new_handshake_state(Handshake_IO* io)
{
- std::unique_ptr<Handshake_State> state(
- new Server_Handshake_State(io, get_handshake_msg_cb()));
+ std::unique_ptr<Handshake_State> state(new Server_Handshake_State(io, callbacks()));
state->set_expected_next(CLIENT_HELLO);
return state.release();
@@ -297,442 +323,516 @@ Server::get_peer_cert_chain(const Handshake_State& state) const
void Server::initiate_handshake(Handshake_State& state,
bool force_full_renegotiation)
{
- dynamic_cast<Server_Handshake_State&>(state).allow_session_resumption =
- !force_full_renegotiation;
+ dynamic_cast<Server_Handshake_State&>(state).
+ set_allow_session_resumption(!force_full_renegotiation);
Hello_Request hello_req(state.handshake_io());
}
/*
-* Process a handshake message
+* Process a CLIENT HELLO Message
*/
-void Server::process_handshake_msg(const Handshake_State* active_state,
- Handshake_State& state_base,
- Handshake_Type type,
- const std::vector<byte>& contents)
- {
- Server_Handshake_State& state = dynamic_cast<Server_Handshake_State&>(state_base);
-
- state.confirm_transition_to(type);
-
- /*
- * The change cipher spec message isn't technically a handshake
- * message so it's not included in the hash. The finished and
- * certificate verify messages are verified based on the current
- * state of the hash *before* this message so we delay adding them
- * to the hash computation until we've processed them below.
- */
- if(type != HANDSHAKE_CCS && type != FINISHED && type != CERTIFICATE_VERIFY)
+void Server::process_client_hello_msg(const Handshake_State* active_state,
+ Server_Handshake_State& pending_state,
+ const std::vector<byte>& contents)
+{
+ const bool initial_handshake = !active_state;
+
+ if(!policy().allow_insecure_renegotiation() &&
+ !(initial_handshake || secure_renegotiation_supported()))
{
- state.hash().update(state.handshake_io().format(contents, type));
+ send_warning_alert(Alert::NO_RENEGOTIATION);
+ return;
}
- if(type == CLIENT_HELLO)
+ pending_state.client_hello(new Client_Hello(contents));
+ const Protocol_Version client_version = pending_state.client_hello()->version();
+
+ Protocol_Version negotiated_version;
+
+ const Protocol_Version latest_supported =
+ policy().latest_supported_version(client_version.is_datagram_protocol());
+
+ if((initial_handshake && client_version.known_version()) ||
+ (!initial_handshake && client_version == active_state->version()))
{
- const bool initial_handshake = !active_state;
+ /*
+ Common cases: new client hello with some known version, or a
+ renegotiation using the same version as previously
+ negotiated.
+ */
- if(!policy().allow_insecure_renegotiation() &&
- !(initial_handshake || secure_renegotiation_supported()))
+ negotiated_version = client_version;
+ }
+ else if(!initial_handshake && (client_version != active_state->version()))
+ {
+ /*
+ * If this is a renegotiation, and the client has offered a
+ * later version than what it initially negotiated, negotiate
+ * the old version. This matches OpenSSL's behavior. If the
+ * client is offering a version earlier than what it initially
+ * negotiated, reject as a probable attack.
+ */
+ if(active_state->version() > client_version)
{
- send_warning_alert(Alert::NO_RENEGOTIATION);
- return;
+ throw TLS_Exception(Alert::PROTOCOL_VERSION,
+ "Client negotiated " +
+ active_state->version().to_string() +
+ " then renegotiated with " +
+ client_version.to_string());
}
+ else
+ negotiated_version = active_state->version();
+ }
+ else
+ {
+ /*
+ New negotiation using a version we don't know. Offer them the
+ best we currently know and support
+ */
+ negotiated_version = latest_supported;
+ }
- state.client_hello(new Client_Hello(contents));
+ if(!policy().acceptable_protocol_version(negotiated_version))
+ {
+ throw TLS_Exception(Alert::PROTOCOL_VERSION,
+ "Client version " + negotiated_version.to_string() +
+ " is unacceptable by policy");
+ }
- const Protocol_Version client_version = state.client_hello()->version();
+ if(pending_state.client_hello()->sent_fallback_scsv())
+ {
+ if(latest_supported > client_version)
+ throw TLS_Exception(Alert::INAPPROPRIATE_FALLBACK,
+ "Client signalled fallback SCSV, possible attack");
+ }
- Protocol_Version negotiated_version;
+ secure_renegotiation_check(pending_state.client_hello());
- const Protocol_Version latest_supported =
- policy().latest_supported_version(client_version.is_datagram_protocol());
+ pending_state.set_version(negotiated_version);
- if((initial_handshake && client_version.known_version()) ||
- (!initial_handshake && client_version == active_state->version()))
- {
- /*
- Common cases: new client hello with some known version, or a
- renegotiation using the same version as previously
- negotiated.
- */
+ Session session_info;
+ const bool resuming =
+ pending_state.allow_session_resumption() &&
+ check_for_resume(session_info,
+ session_manager(),
+ m_creds,
+ pending_state.client_hello(),
+ std::chrono::seconds(policy().session_ticket_lifetime()));
- negotiated_version = client_version;
- }
- else if(!initial_handshake && (client_version != active_state->version()))
- {
- /*
- * If this is a renegotiation, and the client has offered a
- * later version than what it initially negotiated, negotiate
- * the old version. This matches OpenSSL's behavior. If the
- * client is offering a version earlier than what it initially
- * negotiated, reject as a probable attack.
- */
- if(active_state->version() > client_version)
- {
- throw TLS_Exception(Alert::PROTOCOL_VERSION,
- "Client negotiated " +
- active_state->version().to_string() +
- " then renegotiated with " +
- client_version.to_string());
- }
- else
- negotiated_version = active_state->version();
- }
- else
- {
- /*
- New negotiation using a version we don't know. Offer them the
- best we currently know and support
- */
- negotiated_version = latest_supported;
- }
+ bool have_session_ticket_key = false;
- if(!policy().acceptable_protocol_version(negotiated_version))
- {
- throw TLS_Exception(Alert::PROTOCOL_VERSION,
- "Client version " + negotiated_version.to_string() +
- " is unacceptable by policy");
- }
+ try
+ {
+ have_session_ticket_key =
+ m_creds.psk("tls-server", "session-ticket", "").length() > 0;
+ }
+ catch(...) {}
+
+ m_next_protocol = "";
+ if(pending_state.client_hello()->supports_alpn())
+ {
+ m_next_protocol = callbacks().tls_server_choose_app_protocol(pending_state.client_hello()->next_protocols());
- if(state.client_hello()->sent_fallback_scsv())
+ // if the callback return was empty, fall back to the (deprecated) std::function
+ if(m_next_protocol.empty() && m_choose_next_protocol)
{
- if(latest_supported > client_version)
- throw TLS_Exception(Alert::INAPPROPRIATE_FALLBACK,
- "Client signalled fallback SCSV, possible attack");
+ m_next_protocol = m_choose_next_protocol(pending_state.client_hello()->next_protocols());
}
+ }
- secure_renegotiation_check(state.client_hello());
+ if(resuming)
+ {
+ this->session_resume(pending_state, have_session_ticket_key, session_info);
+ }
+ else // new session
+ {
+ this->session_create(pending_state, have_session_ticket_key);
+ }
+}
- state.set_version(negotiated_version);
+void Server::process_certificate_msg(Server_Handshake_State& pending_state,
+ const std::vector<byte>& contents)
+{
+ pending_state.client_certs(new Certificate(contents, policy()));
+ pending_state.set_expected_next(CLIENT_KEX);
+}
- Session session_info;
- const bool resuming =
- state.allow_session_resumption &&
- check_for_resume(session_info,
- session_manager(),
- m_creds,
- state.client_hello(),
- std::chrono::seconds(policy().session_ticket_lifetime()));
+void Server::process_client_key_exchange_msg(Server_Handshake_State& pending_state,
+ const std::vector<byte>& contents)
+{
+ if(pending_state.received_handshake_msg(CERTIFICATE) && !pending_state.client_certs()->empty())
+ pending_state.set_expected_next(CERTIFICATE_VERIFY);
+ else
+ pending_state.set_expected_next(HANDSHAKE_CCS);
- bool have_session_ticket_key = false;
+ pending_state.client_kex(
+ new Client_Key_Exchange(contents, pending_state,
+ pending_state.server_rsa_kex_key(),
+ m_creds, policy(), rng())
+ );
- try
- {
- have_session_ticket_key =
- m_creds.psk("tls-server", "session-ticket", "").length() > 0;
- }
- catch(...) {}
+ pending_state.compute_session_keys();
+}
- m_next_protocol = "";
- if(m_choose_next_protocol && state.client_hello()->supports_alpn())
- m_next_protocol = m_choose_next_protocol(state.client_hello()->next_protocols());
+void Server::process_change_cipher_spec_msg(Server_Handshake_State& pending_state)
+{
+ pending_state.set_expected_next(FINISHED);
+ change_cipher_spec_reader(SERVER);
+}
- if(resuming)
- {
- // Only offer a resuming client a new ticket if they didn't send one this time,
- // ie, resumed via server-side resumption. TODO: also send one if expiring soon?
-
- const bool offer_new_session_ticket =
- (state.client_hello()->supports_session_ticket() &&
- state.client_hello()->session_ticket().empty() &&
- have_session_ticket_key);
-
- state.server_hello(new Server_Hello(
- state.handshake_io(),
- state.hash(),
- policy(),
- rng(),
- secure_renegotiation_data_for_server_hello(),
- *state.client_hello(),
- session_info,
- offer_new_session_ticket,
- m_next_protocol
- ));
-
- secure_renegotiation_check(state.server_hello());
-
- state.compute_session_keys(session_info.master_secret());
-
- if(!save_session(session_info))
- {
- session_manager().remove_entry(session_info.session_id());
-
- if(state.server_hello()->supports_session_ticket()) // send an empty ticket
- {
- state.new_session_ticket(
- new New_Session_Ticket(state.handshake_io(),
- state.hash())
- );
- }
- }
+void Server::process_certificate_verify_msg(Server_Handshake_State& pending_state,
+ Handshake_Type type,
+ const std::vector<byte>& contents)
+{
+ pending_state.client_verify ( new Certificate_Verify ( contents, pending_state.version() ) );
+
+ const std::vector<X509_Certificate>& client_certs =
+ pending_state.client_certs()->cert_chain();
+
+ const bool sig_valid =
+ pending_state.client_verify()->verify ( client_certs[0], pending_state, policy() );
+
+ pending_state.hash().update ( pending_state.handshake_io().format ( contents, type ) );
+
+ /*
+ * Using DECRYPT_ERROR looks weird here, but per RFC 4346 is for
+ * "A handshake cryptographic operation failed, including being
+ * unable to correctly verify a signature, ..."
+ */
+ if ( !sig_valid )
+ throw TLS_Exception ( Alert::DECRYPT_ERROR, "Client cert verify failed" );
+
+ try
+ {
+ m_creds.verify_certificate_chain ( "tls-server", "", client_certs );
+ }
+ catch ( std::exception& e )
+ {
+ throw TLS_Exception ( Alert::BAD_CERTIFICATE, e.what() );
+ }
+
+ pending_state.set_expected_next ( HANDSHAKE_CCS );
+}
- if(state.server_hello()->supports_session_ticket() && !state.new_session_ticket())
- {
- try
- {
- const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", "");
-
- state.new_session_ticket(
- new New_Session_Ticket(state.handshake_io(),
- state.hash(),
- session_info.encrypt(ticket_key, rng()),
- policy().session_ticket_lifetime())
- );
- }
- catch(...) {}
-
- if(!state.new_session_ticket())
- {
- state.new_session_ticket(
- new New_Session_Ticket(state.handshake_io(), state.hash())
- );
- }
- }
+void Server::process_finished_msg(Server_Handshake_State& pending_state,
+ Handshake_Type type,
+ const std::vector<byte>& contents)
+{
+ pending_state.set_expected_next ( HANDSHAKE_NONE );
- state.handshake_io().send(Change_Cipher_Spec());
+ pending_state.client_finished ( new Finished ( contents ) );
- change_cipher_spec_writer(SERVER);
+ if ( !pending_state.client_finished()->verify ( pending_state, CLIENT ) )
+ throw TLS_Exception ( Alert::DECRYPT_ERROR,
+ "Finished message didn't verify" );
- state.server_finished(new Finished(state.handshake_io(), state, SERVER));
- state.set_expected_next(HANDSHAKE_CCS);
- }
- else // new session
- {
- std::map<std::string, std::vector<X509_Certificate> > cert_chains;
+ if ( !pending_state.server_finished() )
+ {
+ // already sent finished if resuming, so this is a new session
- const std::string sni_hostname = state.client_hello()->sni_hostname();
+ pending_state.hash().update ( pending_state.handshake_io().format ( contents, type ) );
- cert_chains = get_server_certs(sni_hostname, m_creds);
+ Session session_info(
+ pending_state.server_hello()->session_id(),
+ pending_state.session_keys().master_secret(),
+ pending_state.server_hello()->version(),
+ pending_state.server_hello()->ciphersuite(),
+ pending_state.server_hello()->compression_method(),
+ SERVER,
+ pending_state.server_hello()->supports_extended_master_secret(),
+ pending_state.server_hello()->supports_encrypt_then_mac(),
+ get_peer_cert_chain ( pending_state ),
+ std::vector<byte>(),
+ Server_Information(pending_state.client_hello()->sni_hostname()),
+ pending_state.srp_identifier(),
+ pending_state.server_hello()->srtp_profile()
+ );
- if(sni_hostname != "" && cert_chains.empty())
+ if ( save_session ( session_info ) )
{
- cert_chains = get_server_certs("", m_creds);
-
- /*
- * Only send the unrecognized_name alert if we couldn't
- * find any certs for the requested name but did find at
- * least one cert to use in general. That avoids sending an
- * unrecognized_name when a server is configured for purely
- * anonymous operation.
- */
- if(!cert_chains.empty())
- send_alert(Alert(Alert::UNRECOGNIZED_NAME));
+ if ( pending_state.server_hello()->supports_session_ticket() )
+ {
+ try
+ {
+ const SymmetricKey ticket_key = m_creds.psk ( "tls-server", "session-ticket", "" );
+
+ pending_state.new_session_ticket (
+ new New_Session_Ticket ( pending_state.handshake_io(),
+ pending_state.hash(),
+ session_info.encrypt ( ticket_key, rng() ),
+ policy().session_ticket_lifetime() )
+ );
+ }
+ catch ( ... ) {}
+ }
+ else
+ session_manager().save ( session_info );
}
- state.server_hello(new Server_Hello(
- state.handshake_io(),
- state.hash(),
- policy(),
- rng(),
- secure_renegotiation_data_for_server_hello(),
- *state.client_hello(),
- make_hello_random(rng(), policy()), // new session ID
- state.version(),
- choose_ciphersuite(policy(), state.version(), m_creds, cert_chains, state.client_hello()),
- choose_compression(policy(), state.client_hello()->compression_methods()),
- have_session_ticket_key,
- m_next_protocol)
+ if ( !pending_state.new_session_ticket() &&
+ pending_state.server_hello()->supports_session_ticket() )
+ {
+ pending_state.new_session_ticket (
+ new New_Session_Ticket ( pending_state.handshake_io(), pending_state.hash() )
);
+ }
- secure_renegotiation_check(state.server_hello());
+ pending_state.handshake_io().send ( Change_Cipher_Spec() );
- const std::string sig_algo = state.ciphersuite().sig_algo();
- const std::string kex_algo = state.ciphersuite().kex_algo();
+ change_cipher_spec_writer ( SERVER );
- if(sig_algo != "")
- {
- BOTAN_ASSERT(!cert_chains[sig_algo].empty(),
- "Attempting to send empty certificate chain");
+ pending_state.server_finished ( new Finished ( pending_state.handshake_io(), pending_state, SERVER ) );
+ }
- state.server_certs(new Certificate(state.handshake_io(),
- state.hash(),
- cert_chains[sig_algo]));
- }
+ activate_session();
- Private_Key* private_key = nullptr;
+}
- if(kex_algo == "RSA" || sig_algo != "")
- {
- private_key = m_creds.private_key_for(
- state.server_certs()->cert_chain()[0],
- "tls-server",
- sni_hostname);
+/*
+* Process a handshake message
+*/
+void Server::process_handshake_msg(const Handshake_State* active_state,
+ Handshake_State& state_base,
+ Handshake_Type type,
+ const std::vector<byte>& contents)
+ {
+ Server_Handshake_State& state = dynamic_cast<Server_Handshake_State&>(state_base);
+ state.confirm_transition_to(type);
- if(!private_key)
- throw Internal_Error("No private key located for associated server cert");
- }
+ /*
+ * The change cipher spec message isn't technically a handshake
+ * message so it's not included in the hash. The finished and
+ * certificate verify messages are verified based on the current
+ * state of the hash *before* this message so we delay adding them
+ * to the hash computation until we've processed them below.
+ */
+ if(type != HANDSHAKE_CCS && type != FINISHED && type != CERTIFICATE_VERIFY)
+ {
+ state.hash().update(state.handshake_io().format(contents, type));
+ }
- if(kex_algo == "RSA")
- {
- state.server_rsa_kex_key = private_key;
- }
- else
- {
- state.server_kex(new Server_Key_Exchange(state.handshake_io(),
- state, policy(),
- m_creds, rng(), private_key));
- }
+ switch(type)
+ {
+ case CLIENT_HELLO:
+ this->process_client_hello_msg(active_state, state, contents);
+ break;
- auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-server", sni_hostname);
+ case CERTIFICATE:
+ this->process_certificate_msg(state, contents);
+ break;
+
+ case CLIENT_KEX:
+ this->process_client_key_exchange_msg(state, contents);
+ break;
+
+ case CERTIFICATE_VERIFY:
+ this->process_certificate_verify_msg(state, type, contents);
+ break;
+
+ case HANDSHAKE_CCS:
+ this->process_change_cipher_spec_msg(state);
+ break;
+
+ case FINISHED:
+ this->process_finished_msg(state, type, contents);
+ break;
+
+ default:
+ throw Unexpected_Message("Unknown handshake message received");
+ break;
+ }
+ }
- std::vector<X509_DN> client_auth_CAs;
+void Server::session_resume(Server_Handshake_State& pending_state,
+ bool have_session_ticket_key,
+ Session& session_info)
+ {
+ // Only offer a resuming client a new ticket if they didn't send one this time,
+ // ie, resumed via server-side resumption. TODO: also send one if expiring soon?
+
+ const bool offer_new_session_ticket =
+ (pending_state.client_hello()->supports_session_ticket() &&
+ pending_state.client_hello()->session_ticket().empty() &&
+ have_session_ticket_key);
+
+ pending_state.server_hello(new Server_Hello(
+ pending_state.handshake_io(),
+ pending_state.hash(),
+ policy(),
+ rng(),
+ secure_renegotiation_data_for_server_hello(),
+ *pending_state.client_hello(),
+ session_info,
+ offer_new_session_ticket,
+ m_next_protocol
+ ));
+
+ secure_renegotiation_check(pending_state.server_hello());
+
+ pending_state.compute_session_keys(session_info.master_secret());
+
+ if(!save_session(session_info))
+ {
+ session_manager().remove_entry(session_info.session_id());
- for(auto store : trusted_CAs)
+ if(pending_state.server_hello()->supports_session_ticket()) // send an empty ticket
{
- auto subjects = store->all_subjects();
- client_auth_CAs.insert(client_auth_CAs.end(), subjects.begin(), subjects.end());
+ pending_state.new_session_ticket(
+ new New_Session_Ticket(pending_state.handshake_io(),
+ pending_state.hash())
+ );
}
+ }
- if(!client_auth_CAs.empty() && state.ciphersuite().sig_algo() != "")
+ if(pending_state.server_hello()->supports_session_ticket() && !pending_state.new_session_ticket())
+ {
+ try
{
- state.cert_req(
- new Certificate_Req(state.handshake_io(), state.hash(),
- policy(), client_auth_CAs, state.version()));
+ const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", "");
- state.set_expected_next(CERTIFICATE);
+ pending_state.new_session_ticket(
+ new New_Session_Ticket(pending_state.handshake_io(),
+ pending_state.hash(),
+ session_info.encrypt(ticket_key, rng()),
+ policy().session_ticket_lifetime())
+ );
}
+ catch(...) {}
- /*
- * If the client doesn't have a cert they want to use they are
- * allowed to send either an empty cert message or proceed
- * directly to the client key exchange, so allow either case.
- */
- state.set_expected_next(CLIENT_KEX);
-
- state.server_hello_done(new Server_Hello_Done(state.handshake_io(), state.hash()));
+ if(!pending_state.new_session_ticket())
+ {
+ pending_state.new_session_ticket(
+ new New_Session_Ticket(pending_state.handshake_io(), pending_state.hash())
+ );
+ }
}
- }
- else if(type == CERTIFICATE)
- {
- state.client_certs(new Certificate(contents, policy()));
- state.set_expected_next(CLIENT_KEX);
- }
- else if(type == CLIENT_KEX)
- {
- if(state.received_handshake_msg(CERTIFICATE) && !state.client_certs()->empty())
- state.set_expected_next(CERTIFICATE_VERIFY);
- else
- state.set_expected_next(HANDSHAKE_CCS);
+ pending_state.handshake_io().send(Change_Cipher_Spec());
- state.client_kex(
- new Client_Key_Exchange(contents, state,
- state.server_rsa_kex_key,
- m_creds, policy(), rng())
- );
+ change_cipher_spec_writer(SERVER);
- state.compute_session_keys();
- }
- else if(type == CERTIFICATE_VERIFY)
- {
- state.client_verify(new Certificate_Verify(contents, state.version()));
+ pending_state.server_finished(new Finished(pending_state.handshake_io(), pending_state, SERVER));
+ pending_state.set_expected_next(HANDSHAKE_CCS);
+ }
+
+void Server::session_create(Server_Handshake_State& pending_state,
+ bool have_session_ticket_key)
+ {
+ std::map<std::string, std::vector<X509_Certificate> > cert_chains;
- const std::vector<X509_Certificate>& client_certs =
- state.client_certs()->cert_chain();
+ const std::string sni_hostname = pending_state.client_hello()->sni_hostname();
- const bool sig_valid =
- state.client_verify()->verify(client_certs[0], state, policy());
+ cert_chains = get_server_certs(sni_hostname, m_creds);
- state.hash().update(state.handshake_io().format(contents, type));
+ if(sni_hostname != "" && cert_chains.empty())
+ {
+ cert_chains = get_server_certs("", m_creds);
/*
- * Using DECRYPT_ERROR looks weird here, but per RFC 4346 is for
- * "A handshake cryptographic operation failed, including being
- * unable to correctly verify a signature, ..."
+ * Only send the unrecognized_name alert if we couldn't
+ * find any certs for the requested name but did find at
+ * least one cert to use in general. That avoids sending an
+ * unrecognized_name when a server is configured for purely
+ * anonymous operation.
*/
- if(!sig_valid)
- throw TLS_Exception(Alert::DECRYPT_ERROR, "Client cert verify failed");
-
- try
- {
- m_creds.verify_certificate_chain("tls-server", "", client_certs);
- }
- catch(std::exception& e)
- {
- throw TLS_Exception(Alert::BAD_CERTIFICATE, e.what());
- }
-
- state.set_expected_next(HANDSHAKE_CCS);
+ if(!cert_chains.empty())
+ send_alert(Alert(Alert::UNRECOGNIZED_NAME));
}
- else if(type == HANDSHAKE_CCS)
- {
- state.set_expected_next(FINISHED);
- change_cipher_spec_reader(SERVER);
- }
- else if(type == FINISHED)
+
+ Server_Hello::Settings srv_settings(
+ make_hello_random(rng(), policy()), // new session ID
+ pending_state.version(),
+ choose_ciphersuite(policy(),
+ pending_state.version(),
+ m_creds,
+ cert_chains,
+ pending_state.client_hello()),
+ choose_compression(policy(),
+ pending_state.client_hello()->compression_methods()),
+ have_session_ticket_key);
+
+ pending_state.server_hello(new Server_Hello(
+ pending_state.handshake_io(),
+ pending_state.hash(),
+ policy(),
+ rng(),
+ secure_renegotiation_data_for_server_hello(),
+ *pending_state.client_hello(),
+ srv_settings,
+ m_next_protocol)
+ );
+
+ secure_renegotiation_check(pending_state.server_hello());
+
+ const std::string sig_algo = pending_state.ciphersuite().sig_algo();
+ const std::string kex_algo = pending_state.ciphersuite().kex_algo();
+
+ if(sig_algo != "")
{
- state.set_expected_next(HANDSHAKE_NONE);
+ BOTAN_ASSERT(!cert_chains[sig_algo].empty(),
+ "Attempting to send empty certificate chain");
- state.client_finished(new Finished(contents));
+ pending_state.server_certs(new Certificate(pending_state.handshake_io(),
+ pending_state.hash(),
+ cert_chains[sig_algo]));
+ }
- if(!state.client_finished()->verify(state, CLIENT))
- throw TLS_Exception(Alert::DECRYPT_ERROR,
- "Finished message didn't verify");
+ Private_Key* private_key = nullptr;
- if(!state.server_finished())
- {
- // already sent finished if resuming, so this is a new session
+ if(kex_algo == "RSA" || sig_algo != "")
+ {
+ private_key = m_creds.private_key_for(
+ pending_state.server_certs()->cert_chain()[0],
+ "tls-server",
+ sni_hostname);
- state.hash().update(state.handshake_io().format(contents, type));
+ if(!private_key)
+ throw Internal_Error("No private key located for associated server cert");
+ }
- Session session_info(
- state.server_hello()->session_id(),
- state.session_keys().master_secret(),
- state.server_hello()->version(),
- state.server_hello()->ciphersuite(),
- state.server_hello()->compression_method(),
- SERVER,
- state.server_hello()->supports_extended_master_secret(),
- state.server_hello()->supports_encrypt_then_mac(),
- get_peer_cert_chain(state),
- std::vector<byte>(),
- Server_Information(state.client_hello()->sni_hostname()),
- state.srp_identifier(),
- state.server_hello()->srtp_profile()
- );
+ if(kex_algo == "RSA")
+ {
+ pending_state.set_server_rsa_kex_key(private_key);
+ }
+ else
+ {
+ pending_state.server_kex(new Server_Key_Exchange(pending_state.handshake_io(),
+ pending_state, policy(),
+ m_creds, rng(), private_key));
+ }
- if(save_session(session_info))
- {
- if(state.server_hello()->supports_session_ticket())
- {
- try
- {
- const SymmetricKey ticket_key = m_creds.psk("tls-server", "session-ticket", "");
-
- state.new_session_ticket(
- new New_Session_Ticket(state.handshake_io(),
- state.hash(),
- session_info.encrypt(ticket_key, rng()),
- policy().session_ticket_lifetime())
- );
- }
- catch(...) {}
- }
- else
- session_manager().save(session_info);
- }
+ auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-server", sni_hostname);
- if(!state.new_session_ticket() &&
- state.server_hello()->supports_session_ticket())
- {
- state.new_session_ticket(
- new New_Session_Ticket(state.handshake_io(), state.hash())
- );
- }
+ std::vector<X509_DN> client_auth_CAs;
- state.handshake_io().send(Change_Cipher_Spec());
+ for(auto store : trusted_CAs)
+ {
+ auto subjects = store->all_subjects();
+ client_auth_CAs.insert(client_auth_CAs.end(), subjects.begin(), subjects.end());
+ }
- change_cipher_spec_writer(SERVER);
+ if(!client_auth_CAs.empty() && pending_state.ciphersuite().sig_algo() != "")
+ {
+ pending_state.cert_req(
+ new Certificate_Req(pending_state.handshake_io(),
+ pending_state.hash(),
+ policy(),
+ client_auth_CAs,
+ pending_state.version()));
+
+ pending_state.set_expected_next(CERTIFICATE);
+ }
- state.server_finished(new Finished(state.handshake_io(), state, SERVER));
- }
+ /*
+ * If the client doesn't have a cert they want to use they are
+ * allowed to send either an empty cert message or proceed
+ * directly to the client key exchange, so allow either case.
+ */
+ pending_state.set_expected_next(CLIENT_KEX);
- activate_session();
- }
- else
- throw Unexpected_Message("Unknown handshake message received");
+ pending_state.server_hello_done(new Server_Hello_Done(pending_state.handshake_io(), pending_state.hash()));
}
-
}
}
diff --git a/src/lib/tls/tls_server.h b/src/lib/tls/tls_server.h
index 5ea2a1318..051eda445 100644
--- a/src/lib/tls/tls_server.h
+++ b/src/lib/tls/tls_server.h
@@ -1,6 +1,7 @@
/*
* TLS Server
* (C) 2004-2011 Jack Lloyd
+* 2016 Matthias Gierlings
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -12,10 +13,13 @@
#include <botan/credentials_manager.h>
#include <vector>
+
namespace Botan {
namespace TLS {
+class Server_Handshake_State;
+
/**
* TLS Server
*/
@@ -26,7 +30,39 @@ class BOTAN_DLL Server final : public Channel
/**
* Server initialization
+ *
+ * @param callbacks contains a set of callback function references
+ * required by the TLS client.
+ *
+ * @param session_manager manages session state
+ *
+ * @param creds manages application/user credentials
+ *
+ * @param policy specifies other connection policy information
+ *
+ * @param rng a random number generator
+ *
+ * @param is_datagram set to true if this server should expect DTLS
+ * connections. Otherwise TLS connections are expected.
+ *
+ * @param reserved_io_buffer_size This many bytes of memory will
+ * be preallocated for the read and write buffers. Smaller
+ * values just mean reallocations and copies are more likely.
*/
+ Server(Callbacks& callbacks,
+ Session_Manager& session_manager,
+ Credentials_Manager& creds,
+ const Policy& policy,
+ RandomNumberGenerator& rng,
+ bool is_datagram = false,
+ size_t reserved_io_buffer_size = TLS::Server::IO_BUF_DEFAULT_SIZE
+ );
+
+ /**
+ * DEPRECATED. This constructor is only provided for backward
+ * compatibility and should not be used in new implementations.
+ */
+ BOTAN_DEPRECATED("Use TLS::Server(TLS::Callbacks ...)")
Server(output_fn output,
data_cb data_cb,
alert_cb alert_cb,
@@ -37,9 +73,14 @@ class BOTAN_DLL Server final : public Channel
RandomNumberGenerator& rng,
next_protocol_fn next_proto = next_protocol_fn(),
bool is_datagram = false,
- size_t reserved_io_buffer_size = 16*1024
+ size_t reserved_io_buffer_size = TLS::Server::IO_BUF_DEFAULT_SIZE
);
+ /**
+ * DEPRECATED. This constructor is only provided for backward
+ * compatibility and should not be used in new implementations.
+ */
+ BOTAN_DEPRECATED("Use TLS::Server(TLS::Callbacks ...)")
Server(output_fn output,
data_cb data_cb,
alert_cb alert_cb,
@@ -73,12 +114,40 @@ class BOTAN_DLL Server final : public Channel
Handshake_Type type,
const std::vector<byte>& contents) override;
+ void process_client_hello_msg(const Handshake_State* active_state,
+ Server_Handshake_State& pending_state,
+ const std::vector<byte>& contents);
+
+ void process_certificate_msg(Server_Handshake_State& pending_state,
+ const std::vector<byte>& contents);
+
+ void process_client_key_exchange_msg(Server_Handshake_State& pending_state,
+ const std::vector<byte>& contents);
+
+ void process_change_cipher_spec_msg(Server_Handshake_State& pending_state);
+
+ void process_certificate_verify_msg(Server_Handshake_State& pending_state,
+ Handshake_Type type,
+ const std::vector<byte>& contents);
+
+ void process_finished_msg(Server_Handshake_State& pending_state,
+ Handshake_Type type,
+ const std::vector<byte>& contents);
+
+ void session_resume(Server_Handshake_State& pending_state,
+ bool have_session_ticket_key,
+ Session& session_info);
+
+ void session_create(Server_Handshake_State& pending_state,
+ bool have_session_ticket_key);
+
Handshake_State* new_handshake_state(Handshake_IO* io) override;
Credentials_Manager& m_creds;
+ std::string m_next_protocol;
+ // Set by deprecated constructor, Server calls both this fn and Callbacks version
next_protocol_fn m_choose_next_protocol;
- std::string m_next_protocol;
};
}
diff --git a/src/lib/tls/tls_session_key.cpp b/src/lib/tls/tls_session_key.cpp
index 0e796aa23..193af8d9f 100644
--- a/src/lib/tls/tls_session_key.cpp
+++ b/src/lib/tls/tls_session_key.cpp
@@ -48,28 +48,30 @@ Session_Keys::Session_Keys(const Handshake_State* state,
else
{
secure_vector<byte> salt;
+ secure_vector<byte> label;
if(extended_master_secret)
{
- salt += std::make_pair(EXT_MASTER_SECRET_MAGIC, sizeof(EXT_MASTER_SECRET_MAGIC));
+ label += std::make_pair(EXT_MASTER_SECRET_MAGIC, sizeof(EXT_MASTER_SECRET_MAGIC));
salt += state->hash().final(state->version(),
state->ciphersuite().prf_algo());
}
else
{
- salt += std::make_pair(MASTER_SECRET_MAGIC, sizeof(MASTER_SECRET_MAGIC));
+ label += std::make_pair(MASTER_SECRET_MAGIC, sizeof(MASTER_SECRET_MAGIC));
salt += state->client_hello()->random();
salt += state->server_hello()->random();
}
- m_master_sec = prf->derive_key(48, pre_master_secret, salt);
+ m_master_sec = prf->derive_key(48, pre_master_secret, salt, label);
}
secure_vector<byte> salt;
- salt += std::make_pair(KEY_GEN_MAGIC, sizeof(KEY_GEN_MAGIC));
+ secure_vector<byte> label;
+ label += std::make_pair(KEY_GEN_MAGIC, sizeof(KEY_GEN_MAGIC));
salt += state->server_hello()->random();
salt += state->client_hello()->random();
- SymmetricKey keyblock = prf->derive_key(prf_gen, m_master_sec, salt);
+ SymmetricKey keyblock = prf->derive_key(prf_gen, m_master_sec, salt, label);
const byte* key_data = keyblock.begin();
diff --git a/src/lib/tls/tls_suite_info.cpp b/src/lib/tls/tls_suite_info.cpp
index 0d08710e8..7a2c62d56 100644
--- a/src/lib/tls/tls_suite_info.cpp
+++ b/src/lib/tls/tls_suite_info.cpp
@@ -2,8 +2,8 @@
* TLS cipher suite information
*
* This file was automatically generated from the IANA assignments
-* (tls-parameters.txt hash fe280cb8b13bfdd306a975ab39fda238f77ae3bc)
-* by ./src/scripts/tls_suite_info.py on 2016-04-04
+* (tls-parameters.txt hash 9546b3c8be1a1202e1d4a07c2a9d7d6394ae4a21)
+* by ./src/scripts/tls_suite_info.py on 2016-08-16
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -14,659 +14,174 @@ namespace Botan {
namespace TLS {
-std::vector<u16bit> Ciphersuite::all_known_ciphersuite_ids()
+//static
+const std::vector<Ciphersuite>& Ciphersuite::all_known_ciphersuites()
{
- return std::vector<u16bit>{
- 0x000A,
- 0x0013,
- 0x0016,
- 0x001B,
- 0x002F,
- 0x0032,
- 0x0033,
- 0x0034,
- 0x0035,
- 0x0038,
- 0x0039,
- 0x003A,
- 0x003C,
- 0x003D,
- 0x0040,
- 0x0041,
- 0x0044,
- 0x0045,
- 0x0046,
- 0x0067,
- 0x006A,
- 0x006B,
- 0x006C,
- 0x006D,
- 0x0084,
- 0x0087,
- 0x0088,
- 0x0089,
- 0x008B,
- 0x008C,
- 0x008D,
- 0x008F,
- 0x0090,
- 0x0091,
- 0x0096,
- 0x0099,
- 0x009A,
- 0x009B,
- 0x009C,
- 0x009D,
- 0x009E,
- 0x009F,
- 0x00A2,
- 0x00A3,
- 0x00A6,
- 0x00A7,
- 0x00A8,
- 0x00A9,
- 0x00AA,
- 0x00AB,
- 0x00AE,
- 0x00AF,
- 0x00B2,
- 0x00B3,
- 0x00BA,
- 0x00BD,
- 0x00BE,
- 0x00BF,
- 0x00C0,
- 0x00C3,
- 0x00C4,
- 0x00C5,
- 0xC008,
- 0xC009,
- 0xC00A,
- 0xC012,
- 0xC013,
- 0xC014,
- 0xC017,
- 0xC018,
- 0xC019,
- 0xC01A,
- 0xC01B,
- 0xC01C,
- 0xC01D,
- 0xC01E,
- 0xC01F,
- 0xC020,
- 0xC021,
- 0xC022,
- 0xC023,
- 0xC024,
- 0xC027,
- 0xC028,
- 0xC02B,
- 0xC02C,
- 0xC02F,
- 0xC030,
- 0xC034,
- 0xC035,
- 0xC036,
- 0xC037,
- 0xC038,
- 0xC072,
- 0xC073,
- 0xC076,
- 0xC077,
- 0xC07A,
- 0xC07B,
- 0xC07C,
- 0xC07D,
- 0xC080,
- 0xC081,
- 0xC084,
- 0xC085,
- 0xC086,
- 0xC087,
- 0xC08A,
- 0xC08B,
- 0xC08E,
- 0xC08F,
- 0xC090,
- 0xC091,
- 0xC094,
- 0xC095,
- 0xC096,
- 0xC097,
- 0xC09A,
- 0xC09B,
- 0xC09C,
- 0xC09D,
- 0xC09E,
- 0xC09F,
- 0xC0A0,
- 0xC0A1,
- 0xC0A2,
- 0xC0A3,
- 0xC0A4,
- 0xC0A5,
- 0xC0A6,
- 0xC0A7,
- 0xC0A8,
- 0xC0A9,
- 0xC0AA,
- 0xC0AB,
- 0xC0AC,
- 0xC0AD,
- 0xC0AE,
- 0xC0AF,
- 0xCC13,
- 0xCC14,
- 0xCC15,
- 0xCCA8,
- 0xCCA9,
- 0xCCAA,
- 0xCCAB,
- 0xCCAC,
- 0xCCAD,
- 0xFFC0,
- 0xFFC1,
- 0xFFC2,
- 0xFFC3,
- 0xFFC4,
- 0xFFC5,
- 0xFFC6,
- 0xFFC7,
- 0xFFC8,
- 0xFFC9,
- 0xFFCA,
- 0xFFCB,
- };
-}
-
-Ciphersuite Ciphersuite::by_id(u16bit suite)
- {
- switch(suite)
- {
- case 0x000A: // RSA_WITH_3DES_EDE_CBC_SHA
- return Ciphersuite(0x000A, "RSA", "RSA", "3DES", 24, 8, 0, "SHA-1", 20);
-
- case 0x0013: // DHE_DSS_WITH_3DES_EDE_CBC_SHA
- return Ciphersuite(0x0013, "DSA", "DH", "3DES", 24, 8, 0, "SHA-1", 20);
-
- case 0x0016: // DHE_RSA_WITH_3DES_EDE_CBC_SHA
- return Ciphersuite(0x0016, "RSA", "DH", "3DES", 24, 8, 0, "SHA-1", 20);
-
- case 0x001B: // DH_anon_WITH_3DES_EDE_CBC_SHA
- return Ciphersuite(0x001B, "", "DH", "3DES", 24, 8, 0, "SHA-1", 20);
-
- case 0x002F: // RSA_WITH_AES_128_CBC_SHA
- return Ciphersuite(0x002F, "RSA", "RSA", "AES-128", 16, 16, 0, "SHA-1", 20);
-
- case 0x0032: // DHE_DSS_WITH_AES_128_CBC_SHA
- return Ciphersuite(0x0032, "DSA", "DH", "AES-128", 16, 16, 0, "SHA-1", 20);
-
- case 0x0033: // DHE_RSA_WITH_AES_128_CBC_SHA
- return Ciphersuite(0x0033, "RSA", "DH", "AES-128", 16, 16, 0, "SHA-1", 20);
-
- case 0x0034: // DH_anon_WITH_AES_128_CBC_SHA
- return Ciphersuite(0x0034, "", "DH", "AES-128", 16, 16, 0, "SHA-1", 20);
-
- case 0x0035: // RSA_WITH_AES_256_CBC_SHA
- return Ciphersuite(0x0035, "RSA", "RSA", "AES-256", 32, 16, 0, "SHA-1", 20);
-
- case 0x0038: // DHE_DSS_WITH_AES_256_CBC_SHA
- return Ciphersuite(0x0038, "DSA", "DH", "AES-256", 32, 16, 0, "SHA-1", 20);
-
- case 0x0039: // DHE_RSA_WITH_AES_256_CBC_SHA
- return Ciphersuite(0x0039, "RSA", "DH", "AES-256", 32, 16, 0, "SHA-1", 20);
-
- case 0x003A: // DH_anon_WITH_AES_256_CBC_SHA
- return Ciphersuite(0x003A, "", "DH", "AES-256", 32, 16, 0, "SHA-1", 20);
-
- case 0x003C: // RSA_WITH_AES_128_CBC_SHA256
- return Ciphersuite(0x003C, "RSA", "RSA", "AES-128", 16, 16, 0, "SHA-256", 32);
-
- case 0x003D: // RSA_WITH_AES_256_CBC_SHA256
- return Ciphersuite(0x003D, "RSA", "RSA", "AES-256", 32, 16, 0, "SHA-256", 32);
-
- case 0x0040: // DHE_DSS_WITH_AES_128_CBC_SHA256
- return Ciphersuite(0x0040, "DSA", "DH", "AES-128", 16, 16, 0, "SHA-256", 32);
-
- case 0x0041: // RSA_WITH_CAMELLIA_128_CBC_SHA
- return Ciphersuite(0x0041, "RSA", "RSA", "Camellia-128", 16, 16, 0, "SHA-1", 20);
-
- case 0x0044: // DHE_DSS_WITH_CAMELLIA_128_CBC_SHA
- return Ciphersuite(0x0044, "DSA", "DH", "Camellia-128", 16, 16, 0, "SHA-1", 20);
-
- case 0x0045: // DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
- return Ciphersuite(0x0045, "RSA", "DH", "Camellia-128", 16, 16, 0, "SHA-1", 20);
-
- case 0x0046: // DH_anon_WITH_CAMELLIA_128_CBC_SHA
- return Ciphersuite(0x0046, "", "DH", "Camellia-128", 16, 16, 0, "SHA-1", 20);
-
- case 0x0067: // DHE_RSA_WITH_AES_128_CBC_SHA256
- return Ciphersuite(0x0067, "RSA", "DH", "AES-128", 16, 16, 0, "SHA-256", 32);
-
- case 0x006A: // DHE_DSS_WITH_AES_256_CBC_SHA256
- return Ciphersuite(0x006A, "DSA", "DH", "AES-256", 32, 16, 0, "SHA-256", 32);
-
- case 0x006B: // DHE_RSA_WITH_AES_256_CBC_SHA256
- return Ciphersuite(0x006B, "RSA", "DH", "AES-256", 32, 16, 0, "SHA-256", 32);
-
- case 0x006C: // DH_anon_WITH_AES_128_CBC_SHA256
- return Ciphersuite(0x006C, "", "DH", "AES-128", 16, 16, 0, "SHA-256", 32);
-
- case 0x006D: // DH_anon_WITH_AES_256_CBC_SHA256
- return Ciphersuite(0x006D, "", "DH", "AES-256", 32, 16, 0, "SHA-256", 32);
-
- case 0x0084: // RSA_WITH_CAMELLIA_256_CBC_SHA
- return Ciphersuite(0x0084, "RSA", "RSA", "Camellia-256", 32, 16, 0, "SHA-1", 20);
-
- case 0x0087: // DHE_DSS_WITH_CAMELLIA_256_CBC_SHA
- return Ciphersuite(0x0087, "DSA", "DH", "Camellia-256", 32, 16, 0, "SHA-1", 20);
-
- case 0x0088: // DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
- return Ciphersuite(0x0088, "RSA", "DH", "Camellia-256", 32, 16, 0, "SHA-1", 20);
-
- case 0x0089: // DH_anon_WITH_CAMELLIA_256_CBC_SHA
- return Ciphersuite(0x0089, "", "DH", "Camellia-256", 32, 16, 0, "SHA-1", 20);
-
- case 0x008B: // PSK_WITH_3DES_EDE_CBC_SHA
- return Ciphersuite(0x008B, "", "PSK", "3DES", 24, 8, 0, "SHA-1", 20);
-
- case 0x008C: // PSK_WITH_AES_128_CBC_SHA
- return Ciphersuite(0x008C, "", "PSK", "AES-128", 16, 16, 0, "SHA-1", 20);
-
- case 0x008D: // PSK_WITH_AES_256_CBC_SHA
- return Ciphersuite(0x008D, "", "PSK", "AES-256", 32, 16, 0, "SHA-1", 20);
-
- case 0x008F: // DHE_PSK_WITH_3DES_EDE_CBC_SHA
- return Ciphersuite(0x008F, "", "DHE_PSK", "3DES", 24, 8, 0, "SHA-1", 20);
-
- case 0x0090: // DHE_PSK_WITH_AES_128_CBC_SHA
- return Ciphersuite(0x0090, "", "DHE_PSK", "AES-128", 16, 16, 0, "SHA-1", 20);
-
- case 0x0091: // DHE_PSK_WITH_AES_256_CBC_SHA
- return Ciphersuite(0x0091, "", "DHE_PSK", "AES-256", 32, 16, 0, "SHA-1", 20);
-
- case 0x0096: // RSA_WITH_SEED_CBC_SHA
- return Ciphersuite(0x0096, "RSA", "RSA", "SEED", 16, 16, 0, "SHA-1", 20);
-
- case 0x0099: // DHE_DSS_WITH_SEED_CBC_SHA
- return Ciphersuite(0x0099, "DSA", "DH", "SEED", 16, 16, 0, "SHA-1", 20);
-
- case 0x009A: // DHE_RSA_WITH_SEED_CBC_SHA
- return Ciphersuite(0x009A, "RSA", "DH", "SEED", 16, 16, 0, "SHA-1", 20);
-
- case 0x009B: // DH_anon_WITH_SEED_CBC_SHA
- return Ciphersuite(0x009B, "", "DH", "SEED", 16, 16, 0, "SHA-1", 20);
-
- case 0x009C: // RSA_WITH_AES_128_GCM_SHA256
- return Ciphersuite(0x009C, "RSA", "RSA", "AES-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0x009D: // RSA_WITH_AES_256_GCM_SHA384
- return Ciphersuite(0x009D, "RSA", "RSA", "AES-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384");
-
- case 0x009E: // DHE_RSA_WITH_AES_128_GCM_SHA256
- return Ciphersuite(0x009E, "RSA", "DH", "AES-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0x009F: // DHE_RSA_WITH_AES_256_GCM_SHA384
- return Ciphersuite(0x009F, "RSA", "DH", "AES-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384");
-
- case 0x00A2: // DHE_DSS_WITH_AES_128_GCM_SHA256
- return Ciphersuite(0x00A2, "DSA", "DH", "AES-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0x00A3: // DHE_DSS_WITH_AES_256_GCM_SHA384
- return Ciphersuite(0x00A3, "DSA", "DH", "AES-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384");
-
- case 0x00A6: // DH_anon_WITH_AES_128_GCM_SHA256
- return Ciphersuite(0x00A6, "", "DH", "AES-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0x00A7: // DH_anon_WITH_AES_256_GCM_SHA384
- return Ciphersuite(0x00A7, "", "DH", "AES-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384");
-
- case 0x00A8: // PSK_WITH_AES_128_GCM_SHA256
- return Ciphersuite(0x00A8, "", "PSK", "AES-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0x00A9: // PSK_WITH_AES_256_GCM_SHA384
- return Ciphersuite(0x00A9, "", "PSK", "AES-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384");
-
- case 0x00AA: // DHE_PSK_WITH_AES_128_GCM_SHA256
- return Ciphersuite(0x00AA, "", "DHE_PSK", "AES-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0x00AB: // DHE_PSK_WITH_AES_256_GCM_SHA384
- return Ciphersuite(0x00AB, "", "DHE_PSK", "AES-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384");
-
- case 0x00AE: // PSK_WITH_AES_128_CBC_SHA256
- return Ciphersuite(0x00AE, "", "PSK", "AES-128", 16, 16, 0, "SHA-256", 32);
-
- case 0x00AF: // PSK_WITH_AES_256_CBC_SHA384
- return Ciphersuite(0x00AF, "", "PSK", "AES-256", 32, 16, 0, "SHA-384", 48);
-
- case 0x00B2: // DHE_PSK_WITH_AES_128_CBC_SHA256
- return Ciphersuite(0x00B2, "", "DHE_PSK", "AES-128", 16, 16, 0, "SHA-256", 32);
-
- case 0x00B3: // DHE_PSK_WITH_AES_256_CBC_SHA384
- return Ciphersuite(0x00B3, "", "DHE_PSK", "AES-256", 32, 16, 0, "SHA-384", 48);
-
- case 0x00BA: // RSA_WITH_CAMELLIA_128_CBC_SHA256
- return Ciphersuite(0x00BA, "RSA", "RSA", "Camellia-128", 16, 16, 0, "SHA-256", 32);
-
- case 0x00BD: // DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256
- return Ciphersuite(0x00BD, "DSA", "DH", "Camellia-128", 16, 16, 0, "SHA-256", 32);
-
- case 0x00BE: // DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
- return Ciphersuite(0x00BE, "RSA", "DH", "Camellia-128", 16, 16, 0, "SHA-256", 32);
-
- case 0x00BF: // DH_anon_WITH_CAMELLIA_128_CBC_SHA256
- return Ciphersuite(0x00BF, "", "DH", "Camellia-128", 16, 16, 0, "SHA-256", 32);
-
- case 0x00C0: // RSA_WITH_CAMELLIA_256_CBC_SHA256
- return Ciphersuite(0x00C0, "RSA", "RSA", "Camellia-256", 32, 16, 0, "SHA-256", 32);
-
- case 0x00C3: // DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256
- return Ciphersuite(0x00C3, "DSA", "DH", "Camellia-256", 32, 16, 0, "SHA-256", 32);
-
- case 0x00C4: // DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
- return Ciphersuite(0x00C4, "RSA", "DH", "Camellia-256", 32, 16, 0, "SHA-256", 32);
-
- case 0x00C5: // DH_anon_WITH_CAMELLIA_256_CBC_SHA256
- return Ciphersuite(0x00C5, "", "DH", "Camellia-256", 32, 16, 0, "SHA-256", 32);
-
- case 0xC008: // ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
- return Ciphersuite(0xC008, "ECDSA", "ECDH", "3DES", 24, 8, 0, "SHA-1", 20);
-
- case 0xC009: // ECDHE_ECDSA_WITH_AES_128_CBC_SHA
- return Ciphersuite(0xC009, "ECDSA", "ECDH", "AES-128", 16, 16, 0, "SHA-1", 20);
-
- case 0xC00A: // ECDHE_ECDSA_WITH_AES_256_CBC_SHA
- return Ciphersuite(0xC00A, "ECDSA", "ECDH", "AES-256", 32, 16, 0, "SHA-1", 20);
-
- case 0xC012: // ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
- return Ciphersuite(0xC012, "RSA", "ECDH", "3DES", 24, 8, 0, "SHA-1", 20);
-
- case 0xC013: // ECDHE_RSA_WITH_AES_128_CBC_SHA
- return Ciphersuite(0xC013, "RSA", "ECDH", "AES-128", 16, 16, 0, "SHA-1", 20);
-
- case 0xC014: // ECDHE_RSA_WITH_AES_256_CBC_SHA
- return Ciphersuite(0xC014, "RSA", "ECDH", "AES-256", 32, 16, 0, "SHA-1", 20);
-
- case 0xC017: // ECDH_anon_WITH_3DES_EDE_CBC_SHA
- return Ciphersuite(0xC017, "", "ECDH", "3DES", 24, 8, 0, "SHA-1", 20);
-
- case 0xC018: // ECDH_anon_WITH_AES_128_CBC_SHA
- return Ciphersuite(0xC018, "", "ECDH", "AES-128", 16, 16, 0, "SHA-1", 20);
-
- case 0xC019: // ECDH_anon_WITH_AES_256_CBC_SHA
- return Ciphersuite(0xC019, "", "ECDH", "AES-256", 32, 16, 0, "SHA-1", 20);
-
- case 0xC01A: // SRP_SHA_WITH_3DES_EDE_CBC_SHA
- return Ciphersuite(0xC01A, "", "SRP_SHA", "3DES", 24, 8, 0, "SHA-1", 20);
-
- case 0xC01B: // SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA
- return Ciphersuite(0xC01B, "RSA", "SRP_SHA", "3DES", 24, 8, 0, "SHA-1", 20);
-
- case 0xC01C: // SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA
- return Ciphersuite(0xC01C, "DSA", "SRP_SHA", "3DES", 24, 8, 0, "SHA-1", 20);
-
- case 0xC01D: // SRP_SHA_WITH_AES_128_CBC_SHA
- return Ciphersuite(0xC01D, "", "SRP_SHA", "AES-128", 16, 16, 0, "SHA-1", 20);
-
- case 0xC01E: // SRP_SHA_RSA_WITH_AES_128_CBC_SHA
- return Ciphersuite(0xC01E, "RSA", "SRP_SHA", "AES-128", 16, 16, 0, "SHA-1", 20);
-
- case 0xC01F: // SRP_SHA_DSS_WITH_AES_128_CBC_SHA
- return Ciphersuite(0xC01F, "DSA", "SRP_SHA", "AES-128", 16, 16, 0, "SHA-1", 20);
-
- case 0xC020: // SRP_SHA_WITH_AES_256_CBC_SHA
- return Ciphersuite(0xC020, "", "SRP_SHA", "AES-256", 32, 16, 0, "SHA-1", 20);
-
- case 0xC021: // SRP_SHA_RSA_WITH_AES_256_CBC_SHA
- return Ciphersuite(0xC021, "RSA", "SRP_SHA", "AES-256", 32, 16, 0, "SHA-1", 20);
-
- case 0xC022: // SRP_SHA_DSS_WITH_AES_256_CBC_SHA
- return Ciphersuite(0xC022, "DSA", "SRP_SHA", "AES-256", 32, 16, 0, "SHA-1", 20);
-
- case 0xC023: // ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
- return Ciphersuite(0xC023, "ECDSA", "ECDH", "AES-128", 16, 16, 0, "SHA-256", 32);
-
- case 0xC024: // ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
- return Ciphersuite(0xC024, "ECDSA", "ECDH", "AES-256", 32, 16, 0, "SHA-384", 48);
-
- case 0xC027: // ECDHE_RSA_WITH_AES_128_CBC_SHA256
- return Ciphersuite(0xC027, "RSA", "ECDH", "AES-128", 16, 16, 0, "SHA-256", 32);
-
- case 0xC028: // ECDHE_RSA_WITH_AES_256_CBC_SHA384
- return Ciphersuite(0xC028, "RSA", "ECDH", "AES-256", 32, 16, 0, "SHA-384", 48);
-
- case 0xC02B: // ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- return Ciphersuite(0xC02B, "ECDSA", "ECDH", "AES-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC02C: // ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- return Ciphersuite(0xC02C, "ECDSA", "ECDH", "AES-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384");
-
- case 0xC02F: // ECDHE_RSA_WITH_AES_128_GCM_SHA256
- return Ciphersuite(0xC02F, "RSA", "ECDH", "AES-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC030: // ECDHE_RSA_WITH_AES_256_GCM_SHA384
- return Ciphersuite(0xC030, "RSA", "ECDH", "AES-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384");
-
- case 0xC034: // ECDHE_PSK_WITH_3DES_EDE_CBC_SHA
- return Ciphersuite(0xC034, "", "ECDHE_PSK", "3DES", 24, 8, 0, "SHA-1", 20);
-
- case 0xC035: // ECDHE_PSK_WITH_AES_128_CBC_SHA
- return Ciphersuite(0xC035, "", "ECDHE_PSK", "AES-128", 16, 16, 0, "SHA-1", 20);
-
- case 0xC036: // ECDHE_PSK_WITH_AES_256_CBC_SHA
- return Ciphersuite(0xC036, "", "ECDHE_PSK", "AES-256", 32, 16, 0, "SHA-1", 20);
-
- case 0xC037: // ECDHE_PSK_WITH_AES_128_CBC_SHA256
- return Ciphersuite(0xC037, "", "ECDHE_PSK", "AES-128", 16, 16, 0, "SHA-256", 32);
-
- case 0xC038: // ECDHE_PSK_WITH_AES_256_CBC_SHA384
- return Ciphersuite(0xC038, "", "ECDHE_PSK", "AES-256", 32, 16, 0, "SHA-384", 48);
-
- case 0xC072: // ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
- return Ciphersuite(0xC072, "ECDSA", "ECDH", "Camellia-128", 16, 16, 0, "SHA-256", 32);
-
- case 0xC073: // ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
- return Ciphersuite(0xC073, "ECDSA", "ECDH", "Camellia-256", 32, 16, 0, "SHA-384", 48);
-
- case 0xC076: // ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
- return Ciphersuite(0xC076, "RSA", "ECDH", "Camellia-128", 16, 16, 0, "SHA-256", 32);
-
- case 0xC077: // ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384
- return Ciphersuite(0xC077, "RSA", "ECDH", "Camellia-256", 32, 16, 0, "SHA-384", 48);
-
- case 0xC07A: // RSA_WITH_CAMELLIA_128_GCM_SHA256
- return Ciphersuite(0xC07A, "RSA", "RSA", "Camellia-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC07B: // RSA_WITH_CAMELLIA_256_GCM_SHA384
- return Ciphersuite(0xC07B, "RSA", "RSA", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384");
-
- case 0xC07C: // DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256
- return Ciphersuite(0xC07C, "RSA", "DH", "Camellia-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC07D: // DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384
- return Ciphersuite(0xC07D, "RSA", "DH", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384");
-
- case 0xC080: // DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256
- return Ciphersuite(0xC080, "DSA", "DH", "Camellia-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC081: // DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384
- return Ciphersuite(0xC081, "DSA", "DH", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384");
-
- case 0xC084: // DH_anon_WITH_CAMELLIA_128_GCM_SHA256
- return Ciphersuite(0xC084, "", "DH", "Camellia-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC085: // DH_anon_WITH_CAMELLIA_256_GCM_SHA384
- return Ciphersuite(0xC085, "", "DH", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384");
-
- case 0xC086: // ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256
- return Ciphersuite(0xC086, "ECDSA", "ECDH", "Camellia-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC087: // ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384
- return Ciphersuite(0xC087, "ECDSA", "ECDH", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384");
-
- case 0xC08A: // ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256
- return Ciphersuite(0xC08A, "RSA", "ECDH", "Camellia-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC08B: // ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384
- return Ciphersuite(0xC08B, "RSA", "ECDH", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384");
-
- case 0xC08E: // PSK_WITH_CAMELLIA_128_GCM_SHA256
- return Ciphersuite(0xC08E, "", "PSK", "Camellia-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC08F: // PSK_WITH_CAMELLIA_256_GCM_SHA384
- return Ciphersuite(0xC08F, "", "PSK", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384");
-
- case 0xC090: // DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256
- return Ciphersuite(0xC090, "", "DHE_PSK", "Camellia-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC091: // DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384
- return Ciphersuite(0xC091, "", "DHE_PSK", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384");
-
- case 0xC094: // PSK_WITH_CAMELLIA_128_CBC_SHA256
- return Ciphersuite(0xC094, "", "PSK", "Camellia-128", 16, 16, 0, "SHA-256", 32);
-
- case 0xC095: // PSK_WITH_CAMELLIA_256_CBC_SHA384
- return Ciphersuite(0xC095, "", "PSK", "Camellia-256", 32, 16, 0, "SHA-384", 48);
-
- case 0xC096: // DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
- return Ciphersuite(0xC096, "", "DHE_PSK", "Camellia-128", 16, 16, 0, "SHA-256", 32);
-
- case 0xC097: // DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
- return Ciphersuite(0xC097, "", "DHE_PSK", "Camellia-256", 32, 16, 0, "SHA-384", 48);
-
- case 0xC09A: // ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256
- return Ciphersuite(0xC09A, "", "ECDHE_PSK", "Camellia-128", 16, 16, 0, "SHA-256", 32);
-
- case 0xC09B: // ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384
- return Ciphersuite(0xC09B, "", "ECDHE_PSK", "Camellia-256", 32, 16, 0, "SHA-384", 48);
-
- case 0xC09C: // RSA_WITH_AES_128_CCM
- return Ciphersuite(0xC09C, "RSA", "RSA", "AES-128/CCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC09D: // RSA_WITH_AES_256_CCM
- return Ciphersuite(0xC09D, "RSA", "RSA", "AES-256/CCM", 32, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC09E: // DHE_RSA_WITH_AES_128_CCM
- return Ciphersuite(0xC09E, "RSA", "DH", "AES-128/CCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC09F: // DHE_RSA_WITH_AES_256_CCM
- return Ciphersuite(0xC09F, "RSA", "DH", "AES-256/CCM", 32, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC0A0: // RSA_WITH_AES_128_CCM_8
- return Ciphersuite(0xC0A0, "RSA", "RSA", "AES-128/CCM(8)", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC0A1: // RSA_WITH_AES_256_CCM_8
- return Ciphersuite(0xC0A1, "RSA", "RSA", "AES-256/CCM(8)", 32, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC0A2: // DHE_RSA_WITH_AES_128_CCM_8
- return Ciphersuite(0xC0A2, "RSA", "DH", "AES-128/CCM(8)", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC0A3: // DHE_RSA_WITH_AES_256_CCM_8
- return Ciphersuite(0xC0A3, "RSA", "DH", "AES-256/CCM(8)", 32, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC0A4: // PSK_WITH_AES_128_CCM
- return Ciphersuite(0xC0A4, "", "PSK", "AES-128/CCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC0A5: // PSK_WITH_AES_256_CCM
- return Ciphersuite(0xC0A5, "", "PSK", "AES-256/CCM", 32, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC0A6: // DHE_PSK_WITH_AES_128_CCM
- return Ciphersuite(0xC0A6, "", "DHE_PSK", "AES-128/CCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC0A7: // DHE_PSK_WITH_AES_256_CCM
- return Ciphersuite(0xC0A7, "", "DHE_PSK", "AES-256/CCM", 32, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC0A8: // PSK_WITH_AES_128_CCM_8
- return Ciphersuite(0xC0A8, "", "PSK", "AES-128/CCM(8)", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC0A9: // PSK_WITH_AES_256_CCM_8
- return Ciphersuite(0xC0A9, "", "PSK", "AES-256/CCM(8)", 32, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC0AA: // PSK_DHE_WITH_AES_128_CCM_8
- return Ciphersuite(0xC0AA, "", "DHE_PSK", "AES-128/CCM(8)", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC0AB: // PSK_DHE_WITH_AES_256_CCM_8
- return Ciphersuite(0xC0AB, "", "DHE_PSK", "AES-256/CCM(8)", 32, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC0AC: // ECDHE_ECDSA_WITH_AES_128_CCM
- return Ciphersuite(0xC0AC, "ECDSA", "ECDH", "AES-128/CCM", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC0AD: // ECDHE_ECDSA_WITH_AES_256_CCM
- return Ciphersuite(0xC0AD, "ECDSA", "ECDH", "AES-256/CCM", 32, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC0AE: // ECDHE_ECDSA_WITH_AES_128_CCM_8
- return Ciphersuite(0xC0AE, "ECDSA", "ECDH", "AES-128/CCM(8)", 16, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xC0AF: // ECDHE_ECDSA_WITH_AES_256_CCM_8
- return Ciphersuite(0xC0AF, "ECDSA", "ECDH", "AES-256/CCM(8)", 32, 4, 8, "AEAD", 0, "SHA-256");
-
- case 0xCC13: // ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
- return Ciphersuite(0xCC13, "RSA", "ECDH", "ChaCha20Poly1305", 32, 0, 0, "AEAD", 0, "SHA-256");
-
- case 0xCC14: // ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
- return Ciphersuite(0xCC14, "ECDSA", "ECDH", "ChaCha20Poly1305", 32, 0, 0, "AEAD", 0, "SHA-256");
-
- case 0xCC15: // DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
- return Ciphersuite(0xCC15, "RSA", "DH", "ChaCha20Poly1305", 32, 0, 0, "AEAD", 0, "SHA-256");
-
- case 0xCCA8: // ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
- return Ciphersuite(0xCCA8, "RSA", "ECDH", "ChaCha20Poly1305", 32, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xCCA9: // ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
- return Ciphersuite(0xCCA9, "ECDSA", "ECDH", "ChaCha20Poly1305", 32, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xCCAA: // DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
- return Ciphersuite(0xCCAA, "RSA", "DH", "ChaCha20Poly1305", 32, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xCCAB: // PSK_WITH_CHACHA20_POLY1305_SHA256
- return Ciphersuite(0xCCAB, "", "PSK", "ChaCha20Poly1305", 32, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xCCAC: // ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256
- return Ciphersuite(0xCCAC, "", "ECDHE_PSK", "ChaCha20Poly1305", 32, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xCCAD: // DHE_PSK_WITH_CHACHA20_POLY1305_SHA256
- return Ciphersuite(0xCCAD, "", "DHE_PSK", "ChaCha20Poly1305", 32, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xFFC0: // DHE_RSA_WITH_AES_128_OCB_SHA256
- return Ciphersuite(0xFFC0, "RSA", "DH", "AES-128/OCB(12)", 16, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xFFC1: // DHE_RSA_WITH_AES_256_OCB_SHA256
- return Ciphersuite(0xFFC1, "RSA", "DH", "AES-256/OCB(12)", 32, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xFFC2: // ECDHE_RSA_WITH_AES_128_OCB_SHA256
- return Ciphersuite(0xFFC2, "RSA", "ECDH", "AES-128/OCB(12)", 16, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xFFC3: // ECDHE_RSA_WITH_AES_256_OCB_SHA256
- return Ciphersuite(0xFFC3, "RSA", "ECDH", "AES-256/OCB(12)", 32, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xFFC4: // ECDHE_ECDSA_WITH_AES_128_OCB_SHA256
- return Ciphersuite(0xFFC4, "ECDSA", "ECDH", "AES-128/OCB(12)", 16, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xFFC5: // ECDHE_ECDSA_WITH_AES_256_OCB_SHA256
- return Ciphersuite(0xFFC5, "ECDSA", "ECDH", "AES-256/OCB(12)", 32, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xFFC6: // PSK_WITH_AES_128_OCB_SHA256
- return Ciphersuite(0xFFC6, "", "PSK", "AES-128/OCB(12)", 16, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xFFC7: // PSK_WITH_AES_256_OCB_SHA256
- return Ciphersuite(0xFFC7, "", "PSK", "AES-256/OCB(12)", 32, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xFFC8: // DHE_PSK_WITH_AES_128_OCB_SHA256
- return Ciphersuite(0xFFC8, "", "DHE_PSK", "AES-128/OCB(12)", 16, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xFFC9: // DHE_PSK_WITH_AES_256_OCB_SHA256
- return Ciphersuite(0xFFC9, "", "DHE_PSK", "AES-256/OCB(12)", 32, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xFFCA: // ECDHE_PSK_WITH_AES_128_OCB_SHA256
- return Ciphersuite(0xFFCA, "", "ECDHE_PSK", "AES-128/OCB(12)", 16, 12, 0, "AEAD", 0, "SHA-256");
-
- case 0xFFCB: // ECDHE_PSK_WITH_AES_256_OCB_SHA256
- return Ciphersuite(0xFFCB, "", "ECDHE_PSK", "AES-256/OCB(12)", 32, 12, 0, "AEAD", 0, "SHA-256");
-
- }
-
- return Ciphersuite(); // some unknown ciphersuite
+ // Note that this list of ciphersuites is ordered by id!
+ static const std::vector<Ciphersuite> g_ciphersuite_list = {
+ Ciphersuite(0x000A, "RSA_WITH_3DES_EDE_CBC_SHA", "RSA", "RSA", "3DES", 24, 8, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0013, "DHE_DSS_WITH_3DES_EDE_CBC_SHA", "DSA", "DH", "3DES", 24, 8, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0016, "DHE_RSA_WITH_3DES_EDE_CBC_SHA", "RSA", "DH", "3DES", 24, 8, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x001B, "DH_anon_WITH_3DES_EDE_CBC_SHA", "", "DH", "3DES", 24, 8, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x002F, "RSA_WITH_AES_128_CBC_SHA", "RSA", "RSA", "AES-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0032, "DHE_DSS_WITH_AES_128_CBC_SHA", "DSA", "DH", "AES-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0033, "DHE_RSA_WITH_AES_128_CBC_SHA", "RSA", "DH", "AES-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0034, "DH_anon_WITH_AES_128_CBC_SHA", "", "DH", "AES-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0035, "RSA_WITH_AES_256_CBC_SHA", "RSA", "RSA", "AES-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0038, "DHE_DSS_WITH_AES_256_CBC_SHA", "DSA", "DH", "AES-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0039, "DHE_RSA_WITH_AES_256_CBC_SHA", "RSA", "DH", "AES-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x003A, "DH_anon_WITH_AES_256_CBC_SHA", "", "DH", "AES-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x003C, "RSA_WITH_AES_128_CBC_SHA256", "RSA", "RSA", "AES-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x003D, "RSA_WITH_AES_256_CBC_SHA256", "RSA", "RSA", "AES-256", 32, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x0040, "DHE_DSS_WITH_AES_128_CBC_SHA256", "DSA", "DH", "AES-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x0041, "RSA_WITH_CAMELLIA_128_CBC_SHA", "RSA", "RSA", "Camellia-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0044, "DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", "DSA", "DH", "Camellia-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0045, "DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", "RSA", "DH", "Camellia-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0046, "DH_anon_WITH_CAMELLIA_128_CBC_SHA", "", "DH", "Camellia-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0067, "DHE_RSA_WITH_AES_128_CBC_SHA256", "RSA", "DH", "AES-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x006A, "DHE_DSS_WITH_AES_256_CBC_SHA256", "DSA", "DH", "AES-256", 32, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x006B, "DHE_RSA_WITH_AES_256_CBC_SHA256", "RSA", "DH", "AES-256", 32, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x006C, "DH_anon_WITH_AES_128_CBC_SHA256", "", "DH", "AES-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x006D, "DH_anon_WITH_AES_256_CBC_SHA256", "", "DH", "AES-256", 32, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x0084, "RSA_WITH_CAMELLIA_256_CBC_SHA", "RSA", "RSA", "Camellia-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0087, "DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", "DSA", "DH", "Camellia-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0088, "DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", "RSA", "DH", "Camellia-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0089, "DH_anon_WITH_CAMELLIA_256_CBC_SHA", "", "DH", "Camellia-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x008B, "PSK_WITH_3DES_EDE_CBC_SHA", "", "PSK", "3DES", 24, 8, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x008C, "PSK_WITH_AES_128_CBC_SHA", "", "PSK", "AES-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x008D, "PSK_WITH_AES_256_CBC_SHA", "", "PSK", "AES-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x008F, "DHE_PSK_WITH_3DES_EDE_CBC_SHA", "", "DHE_PSK", "3DES", 24, 8, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0090, "DHE_PSK_WITH_AES_128_CBC_SHA", "", "DHE_PSK", "AES-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0091, "DHE_PSK_WITH_AES_256_CBC_SHA", "", "DHE_PSK", "AES-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0096, "RSA_WITH_SEED_CBC_SHA", "RSA", "RSA", "SEED", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x0099, "DHE_DSS_WITH_SEED_CBC_SHA", "DSA", "DH", "SEED", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x009A, "DHE_RSA_WITH_SEED_CBC_SHA", "RSA", "DH", "SEED", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x009B, "DH_anon_WITH_SEED_CBC_SHA", "", "DH", "SEED", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0x009C, "RSA_WITH_AES_128_GCM_SHA256", "RSA", "RSA", "AES-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0x009D, "RSA_WITH_AES_256_GCM_SHA384", "RSA", "RSA", "AES-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"),
+ Ciphersuite(0x009E, "DHE_RSA_WITH_AES_128_GCM_SHA256", "RSA", "DH", "AES-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0x009F, "DHE_RSA_WITH_AES_256_GCM_SHA384", "RSA", "DH", "AES-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"),
+ Ciphersuite(0x00A2, "DHE_DSS_WITH_AES_128_GCM_SHA256", "DSA", "DH", "AES-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0x00A3, "DHE_DSS_WITH_AES_256_GCM_SHA384", "DSA", "DH", "AES-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"),
+ Ciphersuite(0x00A6, "DH_anon_WITH_AES_128_GCM_SHA256", "", "DH", "AES-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0x00A7, "DH_anon_WITH_AES_256_GCM_SHA384", "", "DH", "AES-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"),
+ Ciphersuite(0x00A8, "PSK_WITH_AES_128_GCM_SHA256", "", "PSK", "AES-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0x00A9, "PSK_WITH_AES_256_GCM_SHA384", "", "PSK", "AES-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"),
+ Ciphersuite(0x00AA, "DHE_PSK_WITH_AES_128_GCM_SHA256", "", "DHE_PSK", "AES-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0x00AB, "DHE_PSK_WITH_AES_256_GCM_SHA384", "", "DHE_PSK", "AES-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"),
+ Ciphersuite(0x00AE, "PSK_WITH_AES_128_CBC_SHA256", "", "PSK", "AES-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x00AF, "PSK_WITH_AES_256_CBC_SHA384", "", "PSK", "AES-256", 32, 16, 0, "SHA-384", 48, ""),
+ Ciphersuite(0x00B2, "DHE_PSK_WITH_AES_128_CBC_SHA256", "", "DHE_PSK", "AES-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x00B3, "DHE_PSK_WITH_AES_256_CBC_SHA384", "", "DHE_PSK", "AES-256", 32, 16, 0, "SHA-384", 48, ""),
+ Ciphersuite(0x00BA, "RSA_WITH_CAMELLIA_128_CBC_SHA256", "RSA", "RSA", "Camellia-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x00BD, "DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", "DSA", "DH", "Camellia-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x00BE, "DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", "RSA", "DH", "Camellia-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x00BF, "DH_anon_WITH_CAMELLIA_128_CBC_SHA256", "", "DH", "Camellia-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x00C0, "RSA_WITH_CAMELLIA_256_CBC_SHA256", "RSA", "RSA", "Camellia-256", 32, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x00C3, "DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", "DSA", "DH", "Camellia-256", 32, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x00C4, "DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", "RSA", "DH", "Camellia-256", 32, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0x00C5, "DH_anon_WITH_CAMELLIA_256_CBC_SHA256", "", "DH", "Camellia-256", 32, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0xC008, "ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "ECDSA", "ECDH", "3DES", 24, 8, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC009, "ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "ECDSA", "ECDH", "AES-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC00A, "ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "ECDSA", "ECDH", "AES-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC012, "ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "RSA", "ECDH", "3DES", 24, 8, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC013, "ECDHE_RSA_WITH_AES_128_CBC_SHA", "RSA", "ECDH", "AES-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC014, "ECDHE_RSA_WITH_AES_256_CBC_SHA", "RSA", "ECDH", "AES-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC017, "ECDH_anon_WITH_3DES_EDE_CBC_SHA", "", "ECDH", "3DES", 24, 8, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC018, "ECDH_anon_WITH_AES_128_CBC_SHA", "", "ECDH", "AES-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC019, "ECDH_anon_WITH_AES_256_CBC_SHA", "", "ECDH", "AES-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC01A, "SRP_SHA_WITH_3DES_EDE_CBC_SHA", "", "SRP_SHA", "3DES", 24, 8, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC01B, "SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", "RSA", "SRP_SHA", "3DES", 24, 8, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC01C, "SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", "DSA", "SRP_SHA", "3DES", 24, 8, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC01D, "SRP_SHA_WITH_AES_128_CBC_SHA", "", "SRP_SHA", "AES-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC01E, "SRP_SHA_RSA_WITH_AES_128_CBC_SHA", "RSA", "SRP_SHA", "AES-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC01F, "SRP_SHA_DSS_WITH_AES_128_CBC_SHA", "DSA", "SRP_SHA", "AES-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC020, "SRP_SHA_WITH_AES_256_CBC_SHA", "", "SRP_SHA", "AES-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC021, "SRP_SHA_RSA_WITH_AES_256_CBC_SHA", "RSA", "SRP_SHA", "AES-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC022, "SRP_SHA_DSS_WITH_AES_256_CBC_SHA", "DSA", "SRP_SHA", "AES-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC023, "ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "ECDSA", "ECDH", "AES-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0xC024, "ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "ECDSA", "ECDH", "AES-256", 32, 16, 0, "SHA-384", 48, ""),
+ Ciphersuite(0xC027, "ECDHE_RSA_WITH_AES_128_CBC_SHA256", "RSA", "ECDH", "AES-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0xC028, "ECDHE_RSA_WITH_AES_256_CBC_SHA384", "RSA", "ECDH", "AES-256", 32, 16, 0, "SHA-384", 48, ""),
+ Ciphersuite(0xC02B, "ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "ECDSA", "ECDH", "AES-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC02C, "ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "ECDSA", "ECDH", "AES-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"),
+ Ciphersuite(0xC02F, "ECDHE_RSA_WITH_AES_128_GCM_SHA256", "RSA", "ECDH", "AES-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC030, "ECDHE_RSA_WITH_AES_256_GCM_SHA384", "RSA", "ECDH", "AES-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"),
+ Ciphersuite(0xC034, "ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", "", "ECDHE_PSK", "3DES", 24, 8, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC035, "ECDHE_PSK_WITH_AES_128_CBC_SHA", "", "ECDHE_PSK", "AES-128", 16, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC036, "ECDHE_PSK_WITH_AES_256_CBC_SHA", "", "ECDHE_PSK", "AES-256", 32, 16, 0, "SHA-1", 20, ""),
+ Ciphersuite(0xC037, "ECDHE_PSK_WITH_AES_128_CBC_SHA256", "", "ECDHE_PSK", "AES-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0xC038, "ECDHE_PSK_WITH_AES_256_CBC_SHA384", "", "ECDHE_PSK", "AES-256", 32, 16, 0, "SHA-384", 48, ""),
+ Ciphersuite(0xC072, "ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", "ECDSA", "ECDH", "Camellia-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0xC073, "ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", "ECDSA", "ECDH", "Camellia-256", 32, 16, 0, "SHA-384", 48, ""),
+ Ciphersuite(0xC076, "ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", "RSA", "ECDH", "Camellia-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0xC077, "ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", "RSA", "ECDH", "Camellia-256", 32, 16, 0, "SHA-384", 48, ""),
+ Ciphersuite(0xC07A, "RSA_WITH_CAMELLIA_128_GCM_SHA256", "RSA", "RSA", "Camellia-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC07B, "RSA_WITH_CAMELLIA_256_GCM_SHA384", "RSA", "RSA", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"),
+ Ciphersuite(0xC07C, "DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", "RSA", "DH", "Camellia-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC07D, "DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", "RSA", "DH", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"),
+ Ciphersuite(0xC080, "DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256", "DSA", "DH", "Camellia-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC081, "DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384", "DSA", "DH", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"),
+ Ciphersuite(0xC084, "DH_anon_WITH_CAMELLIA_128_GCM_SHA256", "", "DH", "Camellia-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC085, "DH_anon_WITH_CAMELLIA_256_GCM_SHA384", "", "DH", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"),
+ Ciphersuite(0xC086, "ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", "ECDSA", "ECDH", "Camellia-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC087, "ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", "ECDSA", "ECDH", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"),
+ Ciphersuite(0xC08A, "ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", "RSA", "ECDH", "Camellia-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC08B, "ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", "RSA", "ECDH", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"),
+ Ciphersuite(0xC08E, "PSK_WITH_CAMELLIA_128_GCM_SHA256", "", "PSK", "Camellia-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC08F, "PSK_WITH_CAMELLIA_256_GCM_SHA384", "", "PSK", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"),
+ Ciphersuite(0xC090, "DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256", "", "DHE_PSK", "Camellia-128/GCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC091, "DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384", "", "DHE_PSK", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"),
+ Ciphersuite(0xC094, "PSK_WITH_CAMELLIA_128_CBC_SHA256", "", "PSK", "Camellia-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0xC095, "PSK_WITH_CAMELLIA_256_CBC_SHA384", "", "PSK", "Camellia-256", 32, 16, 0, "SHA-384", 48, ""),
+ Ciphersuite(0xC096, "DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", "", "DHE_PSK", "Camellia-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0xC097, "DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", "", "DHE_PSK", "Camellia-256", 32, 16, 0, "SHA-384", 48, ""),
+ Ciphersuite(0xC09A, "ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", "", "ECDHE_PSK", "Camellia-128", 16, 16, 0, "SHA-256", 32, ""),
+ Ciphersuite(0xC09B, "ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", "", "ECDHE_PSK", "Camellia-256", 32, 16, 0, "SHA-384", 48, ""),
+ Ciphersuite(0xC09C, "RSA_WITH_AES_128_CCM", "RSA", "RSA", "AES-128/CCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC09D, "RSA_WITH_AES_256_CCM", "RSA", "RSA", "AES-256/CCM", 32, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC09E, "DHE_RSA_WITH_AES_128_CCM", "RSA", "DH", "AES-128/CCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC09F, "DHE_RSA_WITH_AES_256_CCM", "RSA", "DH", "AES-256/CCM", 32, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC0A0, "RSA_WITH_AES_128_CCM_8", "RSA", "RSA", "AES-128/CCM(8)", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC0A1, "RSA_WITH_AES_256_CCM_8", "RSA", "RSA", "AES-256/CCM(8)", 32, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC0A2, "DHE_RSA_WITH_AES_128_CCM_8", "RSA", "DH", "AES-128/CCM(8)", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC0A3, "DHE_RSA_WITH_AES_256_CCM_8", "RSA", "DH", "AES-256/CCM(8)", 32, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC0A4, "PSK_WITH_AES_128_CCM", "", "PSK", "AES-128/CCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC0A5, "PSK_WITH_AES_256_CCM", "", "PSK", "AES-256/CCM", 32, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC0A6, "DHE_PSK_WITH_AES_128_CCM", "", "DHE_PSK", "AES-128/CCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC0A7, "DHE_PSK_WITH_AES_256_CCM", "", "DHE_PSK", "AES-256/CCM", 32, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC0A8, "PSK_WITH_AES_128_CCM_8", "", "PSK", "AES-128/CCM(8)", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC0A9, "PSK_WITH_AES_256_CCM_8", "", "PSK", "AES-256/CCM(8)", 32, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC0AA, "PSK_DHE_WITH_AES_128_CCM_8", "", "DHE_PSK", "AES-128/CCM(8)", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC0AB, "PSK_DHE_WITH_AES_256_CCM_8", "", "DHE_PSK", "AES-256/CCM(8)", 32, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC0AC, "ECDHE_ECDSA_WITH_AES_128_CCM", "ECDSA", "ECDH", "AES-128/CCM", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC0AD, "ECDHE_ECDSA_WITH_AES_256_CCM", "ECDSA", "ECDH", "AES-256/CCM", 32, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC0AE, "ECDHE_ECDSA_WITH_AES_128_CCM_8", "ECDSA", "ECDH", "AES-128/CCM(8)", 16, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xC0AF, "ECDHE_ECDSA_WITH_AES_256_CCM_8", "ECDSA", "ECDH", "AES-256/CCM(8)", 32, 4, 8, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xCC13, "ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "RSA", "ECDH", "ChaCha20Poly1305", 32, 0, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xCC14, "ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "ECDSA", "ECDH", "ChaCha20Poly1305", 32, 0, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xCC15, "DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "RSA", "DH", "ChaCha20Poly1305", 32, 0, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xCCA8, "ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "RSA", "ECDH", "ChaCha20Poly1305", 32, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xCCA9, "ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "ECDSA", "ECDH", "ChaCha20Poly1305", 32, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xCCAA, "DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "RSA", "DH", "ChaCha20Poly1305", 32, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xCCAB, "PSK_WITH_CHACHA20_POLY1305_SHA256", "", "PSK", "ChaCha20Poly1305", 32, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xCCAC, "ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", "", "ECDHE_PSK", "ChaCha20Poly1305", 32, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xCCAD, "DHE_PSK_WITH_CHACHA20_POLY1305_SHA256", "", "DHE_PSK", "ChaCha20Poly1305", 32, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xFFC0, "DHE_RSA_WITH_AES_128_OCB_SHA256", "RSA", "DH", "AES-128/OCB(12)", 16, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xFFC1, "DHE_RSA_WITH_AES_256_OCB_SHA256", "RSA", "DH", "AES-256/OCB(12)", 32, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xFFC2, "ECDHE_RSA_WITH_AES_128_OCB_SHA256", "RSA", "ECDH", "AES-128/OCB(12)", 16, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xFFC3, "ECDHE_RSA_WITH_AES_256_OCB_SHA256", "RSA", "ECDH", "AES-256/OCB(12)", 32, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xFFC4, "ECDHE_ECDSA_WITH_AES_128_OCB_SHA256", "ECDSA", "ECDH", "AES-128/OCB(12)", 16, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xFFC5, "ECDHE_ECDSA_WITH_AES_256_OCB_SHA256", "ECDSA", "ECDH", "AES-256/OCB(12)", 32, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xFFC6, "PSK_WITH_AES_128_OCB_SHA256", "", "PSK", "AES-128/OCB(12)", 16, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xFFC7, "PSK_WITH_AES_256_OCB_SHA256", "", "PSK", "AES-256/OCB(12)", 32, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xFFC8, "DHE_PSK_WITH_AES_128_OCB_SHA256", "", "DHE_PSK", "AES-128/OCB(12)", 16, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xFFC9, "DHE_PSK_WITH_AES_256_OCB_SHA256", "", "DHE_PSK", "AES-256/OCB(12)", 32, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xFFCA, "ECDHE_PSK_WITH_AES_128_OCB_SHA256", "", "ECDHE_PSK", "AES-128/OCB(12)", 16, 12, 0, "AEAD", 0, "SHA-256"),
+ Ciphersuite(0xFFCB, "ECDHE_PSK_WITH_AES_256_OCB_SHA256", "", "ECDHE_PSK", "AES-256/OCB(12)", 32, 12, 0, "AEAD", 0, "SHA-256"),
+ };
+
+ return g_ciphersuite_list;
}
}
diff --git a/src/lib/utils/calendar.cpp b/src/lib/utils/calendar.cpp
index 73602d634..2ed90486a 100644
--- a/src/lib/utils/calendar.cpp
+++ b/src/lib/utils/calendar.cpp
@@ -12,6 +12,7 @@
#include <sstream>
#include <iomanip>
#include <mutex>
+#include <stdlib.h>
#if defined(BOTAN_HAS_BOOST_DATETIME)
#include <boost/date_time/posix_time/posix_time_types.hpp>
@@ -39,7 +40,7 @@ std::tm do_gmtime(std::time_t time_val)
return tm;
}
-#if !defined(BOTAN_TARGET_OS_HAS_TIMEGM) && !defined(BOTAN_TARGET_OS_HAS_MKGMTIME)
+#if !defined(BOTAN_TARGET_OS_HAS_TIMEGM) && !(defined(BOTAN_TARGET_OS_HAS_MKGMTIME) && defined(BOTAN_BUILD_COMPILER_IS_MSVC))
#if defined(BOTAN_HAS_BOOST_DATETIME)
@@ -67,7 +68,7 @@ std::time_t boost_timegm(std::tm *tm)
return out;
}
-#else
+#elif defined(BOTAN_OS_TYPE_IS_UNIX)
#pragma message "Caution! A fallback version of timegm() is used which is not thread-safe"
@@ -138,13 +139,15 @@ std::chrono::system_clock::time_point calendar_point::to_std_timepoint() const
// Define a function alias `botan_timegm`
#if defined(BOTAN_TARGET_OS_HAS_TIMEGM)
std::time_t (&botan_timegm)(std::tm *tm) = timegm;
- #elif defined(BOTAN_TARGET_OS_HAS_MKGMTIME)
+ #elif defined(BOTAN_TARGET_OS_HAS_MKGMTIME) && defined(BOTAN_BUILD_COMPILER_IS_MSVC)
// http://stackoverflow.com/questions/16647819/timegm-cross-platform
std::time_t (&botan_timegm)(std::tm *tm) = _mkgmtime;
#elif defined(BOTAN_HAS_BOOST_DATETIME)
std::time_t (&botan_timegm)(std::tm *tm) = boost_timegm;
- #else
+ #elif defined(BOTAN_OS_TYPE_IS_UNIX)
std::time_t (&botan_timegm)(std::tm *tm) = fallback_timegm;
+ #else
+ std::time_t (&botan_timegm)(std::tm *tm) = mktime; // localtime instead...
#endif
// Convert std::tm to std::time_t
diff --git a/src/lib/utils/cpuid.cpp b/src/lib/utils/cpuid.cpp
index 695a28550..d3def91ed 100644
--- a/src/lib/utils/cpuid.cpp
+++ b/src/lib/utils/cpuid.cpp
@@ -159,14 +159,12 @@ bool altivec_check_pvr_emul()
bool CPUID::has_simd_32()
{
-#if defined(BOTAN_HAS_SIMD_SSE2)
+#if defined(BOTAN_TARGET_SUPPORTS_SSE2)
return CPUID::has_sse2();
-#elif defined(BOTAN_HAS_SIMD_ALTIVEC)
+#elif defined(BOTAN_TARGET_SUPPORTS_ALTIVEC)
return CPUID::has_altivec();
-#elif defined(BOTAN_HAS_SIMD_SCALAR)
- return true;
#else
- return false;
+ return true;
#endif
}
diff --git a/src/lib/utils/donna128.h b/src/lib/utils/donna128.h
index c2a3e0d2e..2a2d1e339 100644
--- a/src/lib/utils/donna128.h
+++ b/src/lib/utils/donna128.h
@@ -23,18 +23,24 @@ class donna128
friend donna128 operator>>(const donna128& x, size_t shift)
{
donna128 z = x;
- const u64bit carry = z.h << (64 - shift);
- z.h = (z.h >> shift);
- z.l = (z.l >> shift) | carry;
+ if(shift > 0)
+ {
+ const u64bit carry = z.h << (64 - shift);
+ z.h = (z.h >> shift);
+ z.l = (z.l >> shift) | carry;
+ }
return z;
}
friend donna128 operator<<(const donna128& x, size_t shift)
{
donna128 z = x;
- const u64bit carry = z.l >> (64 - shift);
- z.l = (z.l << shift);
- z.h = (z.h << shift) | carry;
+ if(shift > 0)
+ {
+ const u64bit carry = z.l >> (64 - shift);
+ z.l = (z.l << shift);
+ z.h = (z.h << shift) | carry;
+ }
return z;
}
diff --git a/src/lib/utils/dyn_load/dyn_load.cpp b/src/lib/utils/dyn_load/dyn_load.cpp
index c0795942b..ce6b61a1d 100644
--- a/src/lib/utils/dyn_load/dyn_load.cpp
+++ b/src/lib/utils/dyn_load/dyn_load.cpp
@@ -5,7 +5,7 @@
* Botan is released under the Simplified BSD License (see license.txt)
*/
-#include <botan/internal/dyn_load.h>
+#include <botan/dyn_load.h>
#include <botan/build.h>
#include <botan/exceptn.h>
diff --git a/src/lib/utils/dyn_load/dyn_load.h b/src/lib/utils/dyn_load/dyn_load.h
index 7a9f4a83c..3a155f3de 100644
--- a/src/lib/utils/dyn_load/dyn_load.h
+++ b/src/lib/utils/dyn_load/dyn_load.h
@@ -9,13 +9,14 @@
#define BOTAN_DYNAMIC_LOADER_H__
#include <string>
+#include <botan/build.h>
namespace Botan {
/**
* Represents a DLL or shared object
*/
-class Dynamically_Loaded_Library
+class BOTAN_DLL Dynamically_Loaded_Library
{
public:
/**
diff --git a/src/lib/utils/dyn_load/info.txt b/src/lib/utils/dyn_load/info.txt
index 0cc4e4e73..22a79be43 100644
--- a/src/lib/utils/dyn_load/info.txt
+++ b/src/lib/utils/dyn_load/info.txt
@@ -1,4 +1,4 @@
-define DYNAMIC_LOADER 20131128
+define DYNAMIC_LOADER 20160310
load_on dep
@@ -11,18 +11,12 @@ openbsd
qnx
solaris
windows
+darwin
</os>
<libs>
android -> dl
linux -> dl
solaris -> dl
+darwin -> dl
</libs>
-
-<source>
-dyn_load.cpp
-</source>
-
-<header:internal>
-dyn_load.h
-</header:internal>
diff --git a/src/lib/utils/exceptn.h b/src/lib/utils/exceptn.h
index b6797f0f6..193d78ce9 100644
--- a/src/lib/utils/exceptn.h
+++ b/src/lib/utils/exceptn.h
@@ -215,6 +215,16 @@ struct BOTAN_DLL Self_Test_Failure : public Internal_Error
{}
};
+/**
+* Not Implemented Exception
+*/
+struct BOTAN_DLL Not_Implemented : public Exception
+ {
+ explicit Not_Implemented(const std::string& err) :
+ Exception("Not implemented", err)
+ {}
+ };
+
}
#endif
diff --git a/src/lib/utils/filesystem.cpp b/src/lib/utils/filesystem.cpp
index 8d51e64bd..c67668288 100644
--- a/src/lib/utils/filesystem.cpp
+++ b/src/lib/utils/filesystem.cpp
@@ -90,7 +90,7 @@ std::vector<std::string> impl_readdir(const std::string& dir_path)
struct stat stat_buf;
- if(::lstat(full_path.c_str(), &stat_buf) == -1)
+ if(::stat(full_path.c_str(), &stat_buf) == -1)
continue;
if(S_ISDIR(stat_buf.st_mode))
diff --git a/src/lib/utils/mul128.h b/src/lib/utils/mul128.h
index bcf5fa7ef..fe533c720 100644
--- a/src/lib/utils/mul128.h
+++ b/src/lib/utils/mul128.h
@@ -12,13 +12,15 @@
namespace Botan {
-// Prefer TI mode over __int128 as GCC rejects the latter in pendantic mode
-#if (BOTAN_GCC_VERSION > 440) && defined(BOTAN_TARGET_CPU_HAS_NATIVE_64BIT)
+#if defined(__SIZEOF_INT128__) && defined(BOTAN_TARGET_CPU_HAS_NATIVE_64BIT)
#define BOTAN_TARGET_HAS_NATIVE_UINT128
- typedef unsigned int uint128_t __attribute__((mode(TI)));
-#elif defined(__SIZEOF_INT128__)
- #define BOTAN_TARGET_HAS_NATIVE_UINT128
- typedef unsigned __int128 uint128_t;
+
+ // Prefer TI mode over __int128 as GCC rejects the latter in pendantic mode
+ #if defined(__GNUG__)
+ typedef unsigned int uint128_t __attribute__((mode(TI)));
+ #else
+ typedef unsigned __int128 uint128_t;
+ #endif
#endif
}
diff --git a/src/lib/utils/os_utils.cpp b/src/lib/utils/os_utils.cpp
index 86776bdd0..eab509984 100644
--- a/src/lib/utils/os_utils.cpp
+++ b/src/lib/utils/os_utils.cpp
@@ -19,7 +19,7 @@
#include <unistd.h>
#endif
-#if defined(BOTAN_TARGET_OS_TYPE_IS_WINDOWS)
+#if defined(BOTAN_TARGET_OS_IS_WINDOWS) || defined(BOTAN_TARGET_OS_IS_MINGW)
#include <windows.h>
#endif
@@ -29,12 +29,12 @@ namespace OS {
uint32_t get_process_id()
{
-#if defined(BOTAN_TARGET_OS_IS_UNIX)
+#if defined(BOTAN_TARGET_OS_TYPE_IS_UNIX)
return ::getpid();
-#elif defined(BOTAN_TARGET_OS_IS_WINDOWS)
+#elif defined(BOTAN_TARGET_OS_IS_WINDOWS) || defined(BOTAN_TARGET_OS_IS_MINGW)
return ::GetCurrentProcessId();
#else
- return 0;
+ throw Exception("get_process_id not supported");
#endif
}
@@ -141,7 +141,7 @@ size_t get_memory_locking_limit()
return std::min<size_t>(limits.rlim_cur, mlock_requested * 1024);
}
-#elif defined BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK
+#elif defined(BOTAN_TARGET_OS_HAS_VIRTUAL_LOCK) && defined(BOTAN_BUILD_COMPILER_IS_MSVC)
SIZE_T working_min = 0, working_max = 0;
DWORD working_flags = 0;
if(!::GetProcessWorkingSetSizeEx(::GetCurrentProcess(), &working_min, &working_max, &working_flags))
diff --git a/src/lib/utils/os_utils.h b/src/lib/utils/os_utils.h
index 3335463f7..590ed4ae7 100644
--- a/src/lib/utils/os_utils.h
+++ b/src/lib/utils/os_utils.h
@@ -15,7 +15,7 @@ namespace Botan {
namespace OS {
/**
-* Returns the OS assigned process ID, if available. Otherwise returns 0.
+* Returns the OS assigned process ID, if available. Otherwise throws.
*/
uint32_t get_process_id();
diff --git a/src/lib/utils/simd/info.txt b/src/lib/utils/simd/info.txt
index 35620c940..6b9e381fa 100644
--- a/src/lib/utils/simd/info.txt
+++ b/src/lib/utils/simd/info.txt
@@ -3,7 +3,3 @@ define SIMD_32 20131128
<header:internal>
simd_32.h
</header:internal>
-
-<requires>
-simd_sse2|simd_altivec|simd_scalar
-</requires>
diff --git a/src/lib/utils/simd/simd_32.h b/src/lib/utils/simd/simd_32.h
index 265e347a9..c29c55c7a 100644
--- a/src/lib/utils/simd/simd_32.h
+++ b/src/lib/utils/simd/simd_32.h
@@ -1,6 +1,6 @@
/*
* Lightweight wrappers for SIMD operations
-* (C) 2009,2011 Jack Lloyd
+* (C) 2009,2011,2016 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -9,22 +9,478 @@
#define BOTAN_SIMD_32_H__
#include <botan/types.h>
+#include <botan/loadstor.h>
+#include <botan/bswap.h>
-#if defined(BOTAN_HAS_SIMD_SSE2)
- #include <botan/internal/simd_sse2.h>
- namespace Botan { typedef SIMD_SSE2 SIMD_32; }
+#if defined(BOTAN_TARGET_SUPPORTS_SSE2)
+ #include <emmintrin.h>
+ #define BOTAN_SIMD_USE_SSE2
-#elif defined(BOTAN_HAS_SIMD_ALTIVEC)
- #include <botan/internal/simd_altivec.h>
- namespace Botan { typedef SIMD_Altivec SIMD_32; }
+#elif defined(BOTAN_TARGET_SUPPORTS_ALTIVEC)
+ #include <altivec.h>
+ #undef vector
+ #undef bool
+ #define BOTAN_SIMD_USE_ALTIVEC
+#endif
+
+// TODO: NEON support
+
+namespace Botan {
+
+/**
+* This class is not a general purpose SIMD type, and only offers
+* instructions needed for evaluation of specific crypto primitives.
+* For example it does not currently have equality operators of any
+* kind.
+*/
+class SIMD_4x32
+ {
+ public:
+
+ SIMD_4x32() // zero initialized
+ {
+#if defined(BOTAN_SIMD_USE_SSE2) || defined(BOTAN_SIMD_USE_ALTIVEC)
+ ::memset(&m_reg, 0, sizeof(m_reg));
+#else
+ ::memset(m_reg, 0, sizeof(m_reg));
+#endif
+ }
+
+ explicit SIMD_4x32(const u32bit B[4])
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ m_reg = _mm_loadu_si128(reinterpret_cast<const __m128i*>(B));
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ m_reg = (__vector unsigned int){B[0], B[1], B[2], B[3]};
+#else
+ m_reg[0] = B[0];
+ m_reg[1] = B[1];
+ m_reg[2] = B[2];
+ m_reg[3] = B[3];
+#endif
+ }
+
+ SIMD_4x32(u32bit B0, u32bit B1, u32bit B2, u32bit B3)
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ m_reg = _mm_set_epi32(B0, B1, B2, B3);
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ m_reg = (__vector unsigned int){B0, B1, B2, B3};
+#else
+ m_reg[0] = B0;
+ m_reg[1] = B1;
+ m_reg[2] = B2;
+ m_reg[3] = B3;
+#endif
+ }
+
+ explicit SIMD_4x32(u32bit B)
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ m_reg = _mm_set1_epi32(B);
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ m_reg = (__vector unsigned int){B, B, B, B};
+#else
+ m_reg[0] = B;
+ m_reg[1] = B;
+ m_reg[2] = B;
+ m_reg[3] = B;
+#endif
+ }
+
+ static SIMD_4x32 load_le(const void* in)
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ return SIMD_4x32(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in)));
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ const u32bit* in_32 = static_cast<const u32bit*>(in);
+
+ __vector unsigned int R0 = vec_ld(0, in_32);
+ __vector unsigned int R1 = vec_ld(12, in_32);
-#elif defined(BOTAN_HAS_SIMD_SCALAR)
- #include <botan/internal/simd_scalar.h>
- namespace Botan { typedef SIMD_Scalar<u32bit,4> SIMD_32; }
+ __vector unsigned char perm = vec_lvsl(0, in_32);
+#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
+ perm = vec_xor(perm, vec_splat_u8(3)); // bswap vector
+#endif
+
+ R0 = vec_perm(R0, R1, perm);
+
+ return SIMD_4x32(R0);
#else
- #error "No SIMD module defined"
+ SIMD_4x32 out;
+ Botan::load_le(out.m_reg, static_cast<const uint8_t*>(in), 4);
+ return out;
+#endif
+ }
+ static SIMD_4x32 load_be(const void* in)
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ return load_le(in).bswap();
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ const u32bit* in_32 = static_cast<const u32bit*>(in);
+
+ __vector unsigned int R0 = vec_ld(0, in_32);
+ __vector unsigned int R1 = vec_ld(12, in_32);
+
+ __vector unsigned char perm = vec_lvsl(0, in_32);
+
+#if defined(BOTAN_TARGET_CPU_IS_LITTLE_ENDIAN)
+ perm = vec_xor(perm, vec_splat_u8(3)); // bswap vector
#endif
+ R0 = vec_perm(R0, R1, perm);
+
+ return SIMD_4x32(R0);
+
+#else
+ SIMD_4x32 out;
+ Botan::load_be(out.m_reg, static_cast<const uint8_t*>(in), 4);
+ return out;
+#endif
+ }
+
+ void store_le(uint8_t out[]) const
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(out), m_reg);
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ __vector unsigned char perm = vec_lvsl(0, static_cast<u32bit*>(nullptr));
+
+#if defined(BOTAN_TARGET_CPU_IS_BIG_ENDIAN)
+ perm = vec_xor(perm, vec_splat_u8(3)); // bswap vector
+#endif
+
+ union {
+ __vector unsigned int V;
+ u32bit R[4];
+ } vec;
+
+ vec.V = vec_perm(m_reg, m_reg, perm);
+
+ Botan::store_be(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]);
+#else
+ Botan::store_le(out, m_reg[0], m_reg[1], m_reg[2], m_reg[3]);
+#endif
+ }
+
+ void store_be(uint8_t out[]) const
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ bswap().store_le(out);
+
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+
+ union {
+ __vector unsigned int V;
+ u32bit R[4];
+ } vec;
+
+ vec.V = m_reg;
+
+ Botan::store_be(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]);
+#else
+ Botan::store_be(out, m_reg[0], m_reg[1], m_reg[2], m_reg[3]);
+#endif
+ }
+
+ void rotate_left(size_t rot)
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ m_reg = _mm_or_si128(_mm_slli_epi32(m_reg, static_cast<int>(rot)),
+ _mm_srli_epi32(m_reg, static_cast<int>(32-rot)));
+
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ const unsigned int r = static_cast<unsigned int>(rot);
+ m_reg = vec_rl(m_reg, (__vector unsigned int){r, r, r, r});
+
+#else
+ m_reg[0] = Botan::rotate_left(m_reg[0], rot);
+ m_reg[1] = Botan::rotate_left(m_reg[1], rot);
+ m_reg[2] = Botan::rotate_left(m_reg[2], rot);
+ m_reg[3] = Botan::rotate_left(m_reg[3], rot);
+#endif
+ }
+
+ void rotate_right(size_t rot)
+ {
+ rotate_left(32 - rot);
+ }
+
+ void operator+=(const SIMD_4x32& other)
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ m_reg = _mm_add_epi32(m_reg, other.m_reg);
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ m_reg = vec_add(m_reg, other.m_reg);
+#else
+ m_reg[0] += other.m_reg[0];
+ m_reg[1] += other.m_reg[1];
+ m_reg[2] += other.m_reg[2];
+ m_reg[3] += other.m_reg[3];
+#endif
+ }
+
+ SIMD_4x32 operator+(const SIMD_4x32& other) const
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ return SIMD_4x32(_mm_add_epi32(m_reg, other.m_reg));
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ return SIMD_4x32(vec_add(m_reg, other.m_reg));
+#else
+ return SIMD_4x32(m_reg[0] + other.m_reg[0],
+ m_reg[1] + other.m_reg[1],
+ m_reg[2] + other.m_reg[2],
+ m_reg[3] + other.m_reg[3]);
+#endif
+ }
+
+ void operator-=(const SIMD_4x32& other)
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ m_reg = _mm_sub_epi32(m_reg, other.m_reg);
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ m_reg = vec_sub(m_reg, other.m_reg);
+#else
+ m_reg[0] -= other.m_reg[0];
+ m_reg[1] -= other.m_reg[1];
+ m_reg[2] -= other.m_reg[2];
+ m_reg[3] -= other.m_reg[3];
+#endif
+ }
+
+ SIMD_4x32 operator-(const SIMD_4x32& other) const
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ return SIMD_4x32(_mm_sub_epi32(m_reg, other.m_reg));
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ return SIMD_4x32(vec_sub(m_reg, other.m_reg));
+#else
+ return SIMD_4x32(m_reg[0] - other.m_reg[0],
+ m_reg[1] - other.m_reg[1],
+ m_reg[2] - other.m_reg[2],
+ m_reg[3] - other.m_reg[3]);
+#endif
+ }
+
+ void operator^=(const SIMD_4x32& other)
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ m_reg = _mm_xor_si128(m_reg, other.m_reg);
+
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ m_reg = vec_xor(m_reg, other.m_reg);
+#else
+ m_reg[0] ^= other.m_reg[0];
+ m_reg[1] ^= other.m_reg[1];
+ m_reg[2] ^= other.m_reg[2];
+ m_reg[3] ^= other.m_reg[3];
+#endif
+ }
+
+ SIMD_4x32 operator^(const SIMD_4x32& other) const
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ return SIMD_4x32(_mm_xor_si128(m_reg, other.m_reg));
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ return SIMD_4x32(vec_xor(m_reg, other.m_reg));
+#else
+ return SIMD_4x32(m_reg[0] ^ other.m_reg[0],
+ m_reg[1] ^ other.m_reg[1],
+ m_reg[2] ^ other.m_reg[2],
+ m_reg[3] ^ other.m_reg[3]);
+#endif
+ }
+
+ void operator|=(const SIMD_4x32& other)
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ m_reg = _mm_or_si128(m_reg, other.m_reg);
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ m_reg = vec_or(m_reg, other.m_reg);
+#else
+ m_reg[0] |= other.m_reg[0];
+ m_reg[1] |= other.m_reg[1];
+ m_reg[2] |= other.m_reg[2];
+ m_reg[3] |= other.m_reg[3];
+#endif
+ }
+
+ SIMD_4x32 operator&(const SIMD_4x32& other)
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ return SIMD_4x32(_mm_and_si128(m_reg, other.m_reg));
+
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ return SIMD_4x32(vec_and(m_reg, other.m_reg));
+#else
+ return SIMD_4x32(m_reg[0] & other.m_reg[0],
+ m_reg[1] & other.m_reg[1],
+ m_reg[2] & other.m_reg[2],
+ m_reg[3] & other.m_reg[3]);
+#endif
+ }
+
+ void operator&=(const SIMD_4x32& other)
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ m_reg = _mm_and_si128(m_reg, other.m_reg);
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ m_reg = vec_and(m_reg, other.m_reg);
+#else
+ m_reg[0] &= other.m_reg[0];
+ m_reg[1] &= other.m_reg[1];
+ m_reg[2] &= other.m_reg[2];
+ m_reg[3] &= other.m_reg[3];
+#endif
+ }
+
+ SIMD_4x32 operator<<(size_t shift) const
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ return SIMD_4x32(_mm_slli_epi32(m_reg, static_cast<int>(shift)));
+
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ const unsigned int s = static_cast<unsigned int>(shift);
+ return SIMD_4x32(vec_sl(m_reg, (__vector unsigned int){s, s, s, s}));
+#else
+ return SIMD_4x32(m_reg[0] << shift,
+ m_reg[1] << shift,
+ m_reg[2] << shift,
+ m_reg[3] << shift);
+#endif
+ }
+
+ SIMD_4x32 operator>>(size_t shift) const
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ return SIMD_4x32(_mm_srli_epi32(m_reg, static_cast<int>(shift)));
+
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ const unsigned int s = static_cast<unsigned int>(shift);
+ return SIMD_4x32(vec_sr(m_reg, (__vector unsigned int){s, s, s, s}));
+#else
+ return SIMD_4x32(m_reg[0] >> shift,
+ m_reg[1] >> shift,
+ m_reg[2] >> shift,
+ m_reg[3] >> shift);
+
+#endif
+ }
+
+ SIMD_4x32 operator~() const
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ return SIMD_4x32(_mm_xor_si128(m_reg, _mm_set1_epi32(0xFFFFFFFF)));
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ return SIMD_4x32(vec_nor(m_reg, m_reg));
+#else
+ return SIMD_4x32(~m_reg[0],
+ ~m_reg[1],
+ ~m_reg[2],
+ ~m_reg[3]);
+#endif
+ }
+
+ // (~reg) & other
+ SIMD_4x32 andc(const SIMD_4x32& other)
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ return SIMD_4x32(_mm_andnot_si128(m_reg, other.m_reg));
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ /*
+ AltiVec does arg1 & ~arg2 rather than SSE's ~arg1 & arg2
+ so swap the arguments
+ */
+ return SIMD_4x32(vec_andc(other.m_reg, m_reg));
+#else
+ return SIMD_4x32((~m_reg[0]) & other.m_reg[0],
+ (~m_reg[1]) & other.m_reg[1],
+ (~m_reg[2]) & other.m_reg[2],
+ (~m_reg[3]) & other.m_reg[3]);
+#endif
+ }
+
+ SIMD_4x32 bswap() const
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ __m128i T = m_reg;
+
+ T = _mm_shufflehi_epi16(T, _MM_SHUFFLE(2, 3, 0, 1));
+ T = _mm_shufflelo_epi16(T, _MM_SHUFFLE(2, 3, 0, 1));
+
+ return SIMD_4x32(_mm_or_si128(_mm_srli_epi16(T, 8),
+ _mm_slli_epi16(T, 8)));
+
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+
+ __vector unsigned char perm = vec_lvsl(0, static_cast<u32bit*>(nullptr));
+
+ perm = vec_xor(perm, vec_splat_u8(3));
+
+ return SIMD_4x32(vec_perm(m_reg, m_reg, perm));
+#else
+ return SIMD_4x32(reverse_bytes(m_reg[0]),
+ reverse_bytes(m_reg[1]),
+ reverse_bytes(m_reg[2]),
+ reverse_bytes(m_reg[3]));
+#endif
+ }
+
+ static void transpose(SIMD_4x32& B0, SIMD_4x32& B1,
+ SIMD_4x32& B2, SIMD_4x32& B3)
+ {
+#if defined(BOTAN_SIMD_USE_SSE2)
+ __m128i T0 = _mm_unpacklo_epi32(B0.m_reg, B1.m_reg);
+ __m128i T1 = _mm_unpacklo_epi32(B2.m_reg, B3.m_reg);
+ __m128i T2 = _mm_unpackhi_epi32(B0.m_reg, B1.m_reg);
+ __m128i T3 = _mm_unpackhi_epi32(B2.m_reg, B3.m_reg);
+ B0.m_reg = _mm_unpacklo_epi64(T0, T1);
+ B1.m_reg = _mm_unpackhi_epi64(T0, T1);
+ B2.m_reg = _mm_unpacklo_epi64(T2, T3);
+ B3.m_reg = _mm_unpackhi_epi64(T2, T3);
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ __vector unsigned int T0 = vec_mergeh(B0.m_reg, B2.m_reg);
+ __vector unsigned int T1 = vec_mergel(B0.m_reg, B2.m_reg);
+ __vector unsigned int T2 = vec_mergeh(B1.m_reg, B3.m_reg);
+ __vector unsigned int T3 = vec_mergel(B1.m_reg, B3.m_reg);
+
+ B0.m_reg = vec_mergeh(T0, T2);
+ B1.m_reg = vec_mergel(T0, T2);
+ B2.m_reg = vec_mergeh(T1, T3);
+ B3.m_reg = vec_mergel(T1, T3);
+#else
+ SIMD_4x32 T0(B0.m_reg[0], B1.m_reg[0], B2.m_reg[0], B3.m_reg[0]);
+ SIMD_4x32 T1(B0.m_reg[1], B1.m_reg[1], B2.m_reg[1], B3.m_reg[1]);
+ SIMD_4x32 T2(B0.m_reg[2], B1.m_reg[2], B2.m_reg[2], B3.m_reg[2]);
+ SIMD_4x32 T3(B0.m_reg[3], B1.m_reg[3], B2.m_reg[3], B3.m_reg[3]);
+
+ B0 = T0;
+ B1 = T1;
+ B2 = T2;
+ B3 = T3;
+#endif
+ }
+
+ private:
+#if defined(BOTAN_SIMD_USE_SSE2)
+ explicit SIMD_4x32(__m128i in) { m_reg = in; }
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ explicit SIMD_4x32(__vector unsigned int input) { m_reg = input; }
+#endif
+
+#if defined(BOTAN_SIMD_USE_SSE2)
+ __m128i m_reg;
+#elif defined(BOTAN_SIMD_USE_ALTIVEC)
+ __vector unsigned int m_reg;
+#else
+ uint32_t m_reg[4];
+#endif
+ };
+
+typedef SIMD_4x32 SIMD_32;
+
+}
+
#endif
diff --git a/src/lib/utils/simd/simd_altivec/info.txt b/src/lib/utils/simd/simd_altivec/info.txt
deleted file mode 100644
index 19168a928..000000000
--- a/src/lib/utils/simd/simd_altivec/info.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-define SIMD_ALTIVEC 20131128
-
-need_isa altivec
-
-load_on dep
-
-<header:internal>
-simd_altivec.h
-</header:internal>
diff --git a/src/lib/utils/simd/simd_altivec/simd_altivec.h b/src/lib/utils/simd/simd_altivec/simd_altivec.h
deleted file mode 100644
index 3963f2817..000000000
--- a/src/lib/utils/simd/simd_altivec/simd_altivec.h
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
-* Lightweight wrappers around AltiVec for 32-bit operations
-* (C) 2009 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_SIMD_ALTIVEC_H__
-#define BOTAN_SIMD_ALTIVEC_H__
-
-#if defined(BOTAN_TARGET_SUPPORTS_ALTIVEC)
-
-#include <botan/loadstor.h>
-#include <botan/cpuid.h>
-
-#include <altivec.h>
-#undef vector
-#undef bool
-
-namespace Botan {
-
-class SIMD_Altivec
- {
- public:
- SIMD_Altivec(const u32bit B[4])
- {
- m_reg = (__vector unsigned int){B[0], B[1], B[2], B[3]};
- }
-
- SIMD_Altivec(u32bit B0, u32bit B1, u32bit B2, u32bit B3)
- {
- m_reg = (__vector unsigned int){B0, B1, B2, B3};
- }
-
- SIMD_Altivec(u32bit B)
- {
- m_reg = (__vector unsigned int){B, B, B, B};
- }
-
- static SIMD_Altivec load_le(const void* in)
- {
- const u32bit* in_32 = static_cast<const u32bit*>(in);
-
- __vector unsigned int R0 = vec_ld(0, in_32);
- __vector unsigned int R1 = vec_ld(12, in_32);
-
- __vector unsigned char perm = vec_lvsl(0, in_32);
-
- perm = vec_xor(perm, vec_splat_u8(3));
-
- R0 = vec_perm(R0, R1, perm);
-
- return SIMD_Altivec(R0);
- }
-
- static SIMD_Altivec load_be(const void* in)
- {
- const u32bit* in_32 = static_cast<const u32bit*>(in);
-
- __vector unsigned int R0 = vec_ld(0, in_32);
- __vector unsigned int R1 = vec_ld(12, in_32);
-
- __vector unsigned char perm = vec_lvsl(0, in_32);
-
- R0 = vec_perm(R0, R1, perm);
-
- return SIMD_Altivec(R0);
- }
-
- void store_le(byte out[]) const
- {
- __vector unsigned char perm = vec_lvsl(0, static_cast<u32bit*>(nullptr));
-
- perm = vec_xor(perm, vec_splat_u8(3));
-
- union {
- __vector unsigned int V;
- u32bit R[4];
- } vec;
-
- vec.V = vec_perm(m_reg, m_reg, perm);
-
- Botan::store_be(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]);
- }
-
- void store_be(byte out[]) const
- {
- union {
- __vector unsigned int V;
- u32bit R[4];
- } vec;
-
- vec.V = m_reg;
-
- Botan::store_be(out, vec.R[0], vec.R[1], vec.R[2], vec.R[3]);
- }
-
- void rotate_left(size_t rot)
- {
- const unsigned int r = static_cast<unsigned int>(rot);
- m_reg = vec_rl(m_reg, (__vector unsigned int){r, r, r, r});
- }
-
- void rotate_right(size_t rot)
- {
- rotate_left(32 - rot);
- }
-
- void operator+=(const SIMD_Altivec& other)
- {
- m_reg = vec_add(m_reg, other.m_reg);
- }
-
- SIMD_Altivec operator+(const SIMD_Altivec& other) const
- {
- return vec_add(m_reg, other.m_reg);
- }
-
- void operator-=(const SIMD_Altivec& other)
- {
- m_reg = vec_sub(m_reg, other.m_reg);
- }
-
- SIMD_Altivec operator-(const SIMD_Altivec& other) const
- {
- return vec_sub(m_reg, other.m_reg);
- }
-
- void operator^=(const SIMD_Altivec& other)
- {
- m_reg = vec_xor(m_reg, other.m_reg);
- }
-
- SIMD_Altivec operator^(const SIMD_Altivec& other) const
- {
- return vec_xor(m_reg, other.m_reg);
- }
-
- void operator|=(const SIMD_Altivec& other)
- {
- m_reg = vec_or(m_reg, other.m_reg);
- }
-
- SIMD_Altivec operator&(const SIMD_Altivec& other)
- {
- return vec_and(m_reg, other.m_reg);
- }
-
- void operator&=(const SIMD_Altivec& other)
- {
- m_reg = vec_and(m_reg, other.m_reg);
- }
-
- SIMD_Altivec operator<<(size_t shift) const
- {
- const unsigned int s = static_cast<unsigned int>(shift);
- return vec_sl(m_reg, (__vector unsigned int){s, s, s, s});
- }
-
- SIMD_Altivec operator>>(size_t shift) const
- {
- const unsigned int s = static_cast<unsigned int>(shift);
- return vec_sr(m_reg, (__vector unsigned int){s, s, s, s});
- }
-
- SIMD_Altivec operator~() const
- {
- return vec_nor(m_reg, m_reg);
- }
-
- SIMD_Altivec andc(const SIMD_Altivec& other)
- {
- /*
- AltiVec does arg1 & ~arg2 rather than SSE's ~arg1 & arg2
- so swap the arguments
- */
- return vec_andc(other.m_reg, m_reg);
- }
-
- SIMD_Altivec bswap() const
- {
- __vector unsigned char perm = vec_lvsl(0, static_cast<u32bit*>(nullptr));
-
- perm = vec_xor(perm, vec_splat_u8(3));
-
- return SIMD_Altivec(vec_perm(m_reg, m_reg, perm));
- }
-
- static void transpose(SIMD_Altivec& B0, SIMD_Altivec& B1,
- SIMD_Altivec& B2, SIMD_Altivec& B3)
- {
- __vector unsigned int T0 = vec_mergeh(B0.m_reg, B2.m_reg);
- __vector unsigned int T1 = vec_mergel(B0.m_reg, B2.m_reg);
- __vector unsigned int T2 = vec_mergeh(B1.m_reg, B3.m_reg);
- __vector unsigned int T3 = vec_mergel(B1.m_reg, B3.m_reg);
-
- B0.m_reg = vec_mergeh(T0, T2);
- B1.m_reg = vec_mergel(T0, T2);
- B2.m_reg = vec_mergeh(T1, T3);
- B3.m_reg = vec_mergel(T1, T3);
- }
-
- private:
- SIMD_Altivec(__vector unsigned int input) { m_reg = input; }
-
- __vector unsigned int m_reg;
- };
-
-}
-
-#endif
-
-#endif
diff --git a/src/lib/utils/simd/simd_scalar/info.txt b/src/lib/utils/simd/simd_scalar/info.txt
deleted file mode 100644
index 26a9fbfee..000000000
--- a/src/lib/utils/simd/simd_scalar/info.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-define SIMD_SCALAR 20131128
-
-load_on dep
-
-<header:internal>
-simd_scalar.h
-</header:internal>
diff --git a/src/lib/utils/simd/simd_scalar/simd_scalar.h b/src/lib/utils/simd/simd_scalar/simd_scalar.h
deleted file mode 100644
index 28d72c615..000000000
--- a/src/lib/utils/simd/simd_scalar/simd_scalar.h
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
-* Scalar emulation of SIMD
-* (C) 2009,2013 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_SIMD_SCALAR_H__
-#define BOTAN_SIMD_SCALAR_H__
-
-#include <botan/loadstor.h>
-#include <botan/bswap.h>
-
-namespace Botan {
-
-/**
-* Fake SIMD, using plain scalar operations
-* Often still faster than iterative on superscalar machines
-*/
-template<typename T, size_t N>
-class SIMD_Scalar
- {
- public:
- static size_t size() { return N; }
-
- SIMD_Scalar() { /* uninitialized */ }
-
- SIMD_Scalar(const T B[N])
- {
- for(size_t i = 0; i != size(); ++i)
- m_v[i] = B[i];
- }
-
- SIMD_Scalar(T B)
- {
- for(size_t i = 0; i != size(); ++i)
- m_v[i] = B;
- }
-
- static SIMD_Scalar<T,N> load_le(const void* in)
- {
- SIMD_Scalar<T,N> out;
- const byte* in_b = static_cast<const byte*>(in);
-
- for(size_t i = 0; i != size(); ++i)
- out.m_v[i] = Botan::load_le<T>(in_b, i);
-
- return out;
- }
-
- static SIMD_Scalar<T,N> load_be(const void* in)
- {
- SIMD_Scalar<T,N> out;
- const byte* in_b = static_cast<const byte*>(in);
-
- for(size_t i = 0; i != size(); ++i)
- out.m_v[i] = Botan::load_be<T>(in_b, i);
-
- return out;
- }
-
- void store_le(byte out[]) const
- {
- for(size_t i = 0; i != size(); ++i)
- Botan::store_le(m_v[i], out + i*sizeof(T));
- }
-
- void store_be(byte out[]) const
- {
- for(size_t i = 0; i != size(); ++i)
- Botan::store_be(m_v[i], out + i*sizeof(T));
- }
-
- void rotate_left(size_t rot)
- {
- for(size_t i = 0; i != size(); ++i)
- m_v[i] = Botan::rotate_left(m_v[i], rot);
- }
-
- void rotate_right(size_t rot)
- {
- for(size_t i = 0; i != size(); ++i)
- m_v[i] = Botan::rotate_right(m_v[i], rot);
- }
-
- void operator+=(const SIMD_Scalar<T,N>& other)
- {
- for(size_t i = 0; i != size(); ++i)
- m_v[i] += other.m_v[i];
- }
-
- void operator-=(const SIMD_Scalar<T,N>& other)
- {
- for(size_t i = 0; i != size(); ++i)
- m_v[i] -= other.m_v[i];
- }
-
- SIMD_Scalar<T,N> operator+(const SIMD_Scalar<T,N>& other) const
- {
- SIMD_Scalar<T,N> out = *this;
- out += other;
- return out;
- }
-
- SIMD_Scalar<T,N> operator-(const SIMD_Scalar<T,N>& other) const
- {
- SIMD_Scalar<T,N> out = *this;
- out -= other;
- return out;
- }
-
- void operator^=(const SIMD_Scalar<T,N>& other)
- {
- for(size_t i = 0; i != size(); ++i)
- m_v[i] ^= other.m_v[i];
- }
-
- SIMD_Scalar<T,N> operator^(const SIMD_Scalar<T,N>& other) const
- {
- SIMD_Scalar<T,N> out = *this;
- out ^= other;
- return out;
- }
-
- void operator|=(const SIMD_Scalar<T,N>& other)
- {
- for(size_t i = 0; i != size(); ++i)
- m_v[i] |= other.m_v[i];
- }
-
- void operator&=(const SIMD_Scalar<T,N>& other)
- {
- for(size_t i = 0; i != size(); ++i)
- m_v[i] &= other.m_v[i];
- }
-
- SIMD_Scalar<T,N> operator&(const SIMD_Scalar<T,N>& other)
- {
- SIMD_Scalar<T,N> out = *this;
- out &= other;
- return out;
- }
-
- SIMD_Scalar<T,N> operator<<(size_t shift) const
- {
- SIMD_Scalar<T,N> out = *this;
- for(size_t i = 0; i != size(); ++i)
- out.m_v[i] <<= shift;
- return out;
- }
-
- SIMD_Scalar<T,N> operator>>(size_t shift) const
- {
- SIMD_Scalar<T,N> out = *this;
- for(size_t i = 0; i != size(); ++i)
- out.m_v[i] >>= shift;
- return out;
- }
-
- SIMD_Scalar<T,N> operator~() const
- {
- SIMD_Scalar<T,N> out = *this;
- for(size_t i = 0; i != size(); ++i)
- out.m_v[i] = ~out.m_v[i];
- return out;
- }
-
- // (~reg) & other
- SIMD_Scalar<T,N> andc(const SIMD_Scalar<T,N>& other)
- {
- SIMD_Scalar<T,N> out;
- for(size_t i = 0; i != size(); ++i)
- out.m_v[i] = (~m_v[i]) & other.m_v[i];
- return out;
- }
-
- SIMD_Scalar<T,N> bswap() const
- {
- SIMD_Scalar<T,N> out;
- for(size_t i = 0; i != size(); ++i)
- out.m_v[i] = reverse_bytes(m_v[i]);
- return out;
- }
-
- static void transpose(SIMD_Scalar<T,N>& B0, SIMD_Scalar<T,N>& B1,
- SIMD_Scalar<T,N>& B2, SIMD_Scalar<T,N>& B3)
- {
- static_assert(N == 4, "4x4 transpose");
- SIMD_Scalar<T,N> T0({B0.m_v[0], B1.m_v[0], B2.m_v[0], B3.m_v[0]});
- SIMD_Scalar<T,N> T1({B0.m_v[1], B1.m_v[1], B2.m_v[1], B3.m_v[1]});
- SIMD_Scalar<T,N> T2({B0.m_v[2], B1.m_v[2], B2.m_v[2], B3.m_v[2]});
- SIMD_Scalar<T,N> T3({B0.m_v[3], B1.m_v[3], B2.m_v[3], B3.m_v[3]});
-
- B0 = T0;
- B1 = T1;
- B2 = T2;
- B3 = T3;
- }
-
- private:
- SIMD_Scalar(std::initializer_list<T> B)
- {
- size_t i = 0;
- for(auto v = B.begin(); v != B.end(); ++v)
- m_v[i++] = *v;
- }
-
- T m_v[N];
- };
-
-}
-
-#endif
diff --git a/src/lib/utils/simd/simd_sse2/info.txt b/src/lib/utils/simd/simd_sse2/info.txt
deleted file mode 100644
index bd9e430cb..000000000
--- a/src/lib/utils/simd/simd_sse2/info.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-define SIMD_SSE2 20131128
-
-need_isa sse2
-
-load_on dep
-
-<header:internal>
-simd_sse2.h
-</header:internal>
diff --git a/src/lib/utils/simd/simd_sse2/simd_sse2.h b/src/lib/utils/simd/simd_sse2/simd_sse2.h
deleted file mode 100644
index 551e9189c..000000000
--- a/src/lib/utils/simd/simd_sse2/simd_sse2.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
-* Lightweight wrappers for SSE2 intrinsics for 32-bit operations
-* (C) 2009 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_SIMD_SSE_H__
-#define BOTAN_SIMD_SSE_H__
-
-#if defined(BOTAN_TARGET_SUPPORTS_SSE2)
-
-#include <botan/cpuid.h>
-#include <emmintrin.h>
-
-namespace Botan {
-
-class SIMD_SSE2
- {
- public:
- explicit SIMD_SSE2(const u32bit B[4])
- {
- m_reg = _mm_loadu_si128(reinterpret_cast<const __m128i*>(B));
- }
-
- SIMD_SSE2(u32bit B0, u32bit B1, u32bit B2, u32bit B3)
- {
- m_reg = _mm_set_epi32(B0, B1, B2, B3);
- }
-
- explicit SIMD_SSE2(u32bit B)
- {
- m_reg = _mm_set1_epi32(B);
- }
-
- static SIMD_SSE2 load_le(const void* in)
- {
- return SIMD_SSE2(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in)));
- }
-
- static SIMD_SSE2 load_be(const void* in)
- {
- return load_le(in).bswap();
- }
-
- void store_le(byte out[]) const
- {
- _mm_storeu_si128(reinterpret_cast<__m128i*>(out), m_reg);
- }
-
- void store_be(byte out[]) const
- {
- bswap().store_le(out);
- }
-
- void rotate_left(size_t rot)
- {
- m_reg = _mm_or_si128(_mm_slli_epi32(m_reg, static_cast<int>(rot)),
- _mm_srli_epi32(m_reg, static_cast<int>(32-rot)));
- }
-
- void rotate_right(size_t rot)
- {
- rotate_left(32 - rot);
- }
-
- void operator+=(const SIMD_SSE2& other)
- {
- m_reg = _mm_add_epi32(m_reg, other.m_reg);
- }
-
- SIMD_SSE2 operator+(const SIMD_SSE2& other) const
- {
- return SIMD_SSE2(_mm_add_epi32(m_reg, other.m_reg));
- }
-
- void operator-=(const SIMD_SSE2& other)
- {
- m_reg = _mm_sub_epi32(m_reg, other.m_reg);
- }
-
- SIMD_SSE2 operator-(const SIMD_SSE2& other) const
- {
- return SIMD_SSE2(_mm_sub_epi32(m_reg, other.m_reg));
- }
-
- void operator^=(const SIMD_SSE2& other)
- {
- m_reg = _mm_xor_si128(m_reg, other.m_reg);
- }
-
- SIMD_SSE2 operator^(const SIMD_SSE2& other) const
- {
- return SIMD_SSE2(_mm_xor_si128(m_reg, other.m_reg));
- }
-
- void operator|=(const SIMD_SSE2& other)
- {
- m_reg = _mm_or_si128(m_reg, other.m_reg);
- }
-
- SIMD_SSE2 operator&(const SIMD_SSE2& other)
- {
- return SIMD_SSE2(_mm_and_si128(m_reg, other.m_reg));
- }
-
- void operator&=(const SIMD_SSE2& other)
- {
- m_reg = _mm_and_si128(m_reg, other.m_reg);
- }
-
- SIMD_SSE2 operator<<(size_t shift) const
- {
- return SIMD_SSE2(_mm_slli_epi32(m_reg, static_cast<int>(shift)));
- }
-
- SIMD_SSE2 operator>>(size_t shift) const
- {
- return SIMD_SSE2(_mm_srli_epi32(m_reg, static_cast<int>(shift)));
- }
-
- SIMD_SSE2 operator~() const
- {
- return SIMD_SSE2(_mm_xor_si128(m_reg, _mm_set1_epi32(0xFFFFFFFF)));
- }
-
- // (~reg) & other
- SIMD_SSE2 andc(const SIMD_SSE2& other)
- {
- return SIMD_SSE2(_mm_andnot_si128(m_reg, other.m_reg));
- }
-
- SIMD_SSE2 bswap() const
- {
- __m128i T = m_reg;
-
- T = _mm_shufflehi_epi16(T, _MM_SHUFFLE(2, 3, 0, 1));
- T = _mm_shufflelo_epi16(T, _MM_SHUFFLE(2, 3, 0, 1));
-
- return SIMD_SSE2(_mm_or_si128(_mm_srli_epi16(T, 8),
- _mm_slli_epi16(T, 8)));
- }
-
- static void transpose(SIMD_SSE2& B0, SIMD_SSE2& B1,
- SIMD_SSE2& B2, SIMD_SSE2& B3)
- {
- __m128i T0 = _mm_unpacklo_epi32(B0.m_reg, B1.m_reg);
- __m128i T1 = _mm_unpacklo_epi32(B2.m_reg, B3.m_reg);
- __m128i T2 = _mm_unpackhi_epi32(B0.m_reg, B1.m_reg);
- __m128i T3 = _mm_unpackhi_epi32(B2.m_reg, B3.m_reg);
- B0.m_reg = _mm_unpacklo_epi64(T0, T1);
- B1.m_reg = _mm_unpackhi_epi64(T0, T1);
- B2.m_reg = _mm_unpacklo_epi64(T2, T3);
- B3.m_reg = _mm_unpackhi_epi64(T2, T3);
- }
-
- private:
- explicit SIMD_SSE2(__m128i in) { m_reg = in; }
-
- __m128i m_reg;
- };
-
-}
-
-#endif
-
-#endif
diff --git a/src/lib/utils/zero_mem.cpp b/src/lib/utils/zero_mem.cpp
index 371c434ca..df195048a 100644
--- a/src/lib/utils/zero_mem.cpp
+++ b/src/lib/utils/zero_mem.cpp
@@ -18,6 +18,13 @@ void zero_mem(void* ptr, size_t n)
#if defined(BOTAN_TARGET_OS_HAS_RTLSECUREZEROMEMORY)
::RtlSecureZeroMemory(ptr, n);
#elif defined(BOTAN_USE_VOLATILE_MEMSET_FOR_ZERO) && (BOTAN_USE_VOLATILE_MEMSET_FOR_ZERO == 1)
+ /*
+ Call memset through a static volatile pointer, which the compiler
+ should not elide. This construct should be safe in conforming
+ compilers, but who knows. I did confirm that on x86-64 GCC 6.1 and
+ Clang 3.8 both create code that saves the memset address in the
+ data segment and uncondtionally loads and jumps to that address.
+ */
static void* (*const volatile memset_ptr)(void*, int, size_t) = std::memset;
(memset_ptr)(ptr, 0, n);
#else