diff --git a/.gitignore b/.gitignore index 3b7327250..08debe1de 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,671 @@ libs/ffi/*.cm* src/tls/krml_output/*.c src/tls/krml_output/*.h +apps/cmitls/benchmark.sh +apps/quicMinusNet/quic_common.c +apps/QuicWin/ffi2lib.bat +apps/QuicWin/QuicWin.sln +apps/QuicWin/QuicWin/QuicWin.cpp +apps/QuicWin/QuicWin/QuicWin.vcxproj +apps/QuicWin/QuicWin/QuicWin.vcxproj.filters +scripts/vsbin.sh +src/pki/win/mipkiwin.c +src/tls/extract/cstubs/log_to_choice.h +src/tls/extract/cstubs/RegionAllocator.c +src/tls/extract/cstubs/RegionAllocator.h +src/tls/hints/AEAD_GCM.fst.hints +src/tls/hints/AEADProvider.fst.hints +src/tls/hints/C.Endianness.fst.hints +src/tls/hints/CommonDH.fst.hints +src/tls/hints/DebugFlags.fst.hints +src/tls/hints/HandshakeLog.fst.hints +src/tls/hints/LHAEPlain.fst.hints +src/tls/hints/List.Helpers.fst.hints +src/tls/hints/Negotiation.fst.hints +src/tls/hints/Old.KeySchedule.fst.hints +src/tls/hints/Record.fst.hints +src/tls/hints/StreamAE.fst.hints +src/tls/hints/TLS.fst.hints +src/tls/renamings.sh +src/windows/bin/libcrypto-1_1-x64.dll +src/windows/bin/libevercrypt.dll +src/windows/bin/libmitls.dll +src/windows/bin/libquiccrypto.dll +src/windows/evercrypt/AEAD.c +src/windows/evercrypt/AEAD.h +src/windows/evercrypt/AEAD_Poly1305_64.c +src/windows/evercrypt/AEAD_Poly1305_64.h +src/windows/evercrypt/AEAD_Poly1305_64.obj +src/windows/evercrypt/aes-x86_64.obj +src/windows/evercrypt/aes.h +src/windows/evercrypt/aesgcm-x86_64.obj +src/windows/evercrypt/amd64/aes-x86_64.asm +src/windows/evercrypt/amd64/aesgcm-x86_64.asm +src/windows/evercrypt/amd64/sha256-x86_64.asm +src/windows/evercrypt/benchmark-aesgcm.c +src/windows/evercrypt/C.c +src/windows/evercrypt/C.h +src/windows/evercrypt/C.obj +src/windows/evercrypt/C_Endianness.c +src/windows/evercrypt/C_Endianness.h +src/windows/evercrypt/C_Endianness.obj +src/windows/evercrypt/C_Failure.c +src/windows/evercrypt/C_Failure.h +src/windows/evercrypt/C_Failure.obj +src/windows/evercrypt/C_Loops.c +src/windows/evercrypt/C_Loops.h +src/windows/evercrypt/C_Loops.obj +src/windows/evercrypt/C_String.c +src/windows/evercrypt/C_String.h +src/windows/evercrypt/C_String.obj +src/windows/evercrypt/Crypto_Symmetric_AES.c +src/windows/evercrypt/Crypto_Symmetric_AES.h +src/windows/evercrypt/Crypto_Symmetric_AES.obj +src/windows/evercrypt/Crypto_Symmetric_AES128.c +src/windows/evercrypt/Crypto_Symmetric_AES128.h +src/windows/evercrypt/Crypto_Symmetric_AES128.obj +src/windows/evercrypt/DafnyLib.h +src/windows/evercrypt/dllmain.obj +src/windows/evercrypt/EverCrypt.c +src/windows/evercrypt/EverCrypt.h +src/windows/evercrypt/EverCrypt.obj +src/windows/evercrypt/EverCrypt_AutoConfig.c +src/windows/evercrypt/EverCrypt_AutoConfig.h +src/windows/evercrypt/EverCrypt_AutoConfig.obj +src/windows/evercrypt/EverCrypt_BCrypt.c +src/windows/evercrypt/EverCrypt_BCrypt.h +src/windows/evercrypt/EverCrypt_BCrypt.obj +src/windows/evercrypt/EverCrypt_Bytes.c +src/windows/evercrypt/EverCrypt_Bytes.h +src/windows/evercrypt/EverCrypt_Bytes.obj +src/windows/evercrypt/EverCrypt_Hacl.c +src/windows/evercrypt/EverCrypt_Hacl.h +src/windows/evercrypt/EverCrypt_Hacl.obj +src/windows/evercrypt/EverCrypt_Hash.c +src/windows/evercrypt/EverCrypt_Hash.h +src/windows/evercrypt/EverCrypt_Hash.obj +src/windows/evercrypt/EverCrypt_Helpers.c +src/windows/evercrypt/EverCrypt_Helpers.h +src/windows/evercrypt/EverCrypt_Helpers.obj +src/windows/evercrypt/EverCrypt_HKDF.c +src/windows/evercrypt/EverCrypt_HKDF.h +src/windows/evercrypt/EverCrypt_HMAC.c +src/windows/evercrypt/EverCrypt_HMAC.h +src/windows/evercrypt/EverCrypt_OpenSSL.c +src/windows/evercrypt/EverCrypt_OpenSSL.h +src/windows/evercrypt/EverCrypt_Spec_SHA2_256.c +src/windows/evercrypt/EverCrypt_Spec_SHA2_256.h +src/windows/evercrypt/EverCrypt_Spec_SHA2_384.c +src/windows/evercrypt/EverCrypt_Spec_SHA2_384.h +src/windows/evercrypt/EverCrypt_Specs.c +src/windows/evercrypt/EverCrypt_Specs.h +src/windows/evercrypt/EverCrypt_Specs.obj +src/windows/evercrypt/EverCrypt_StaticConfig.c +src/windows/evercrypt/EverCrypt_StaticConfig.h +src/windows/evercrypt/EverCrypt_StaticConfig.obj +src/windows/evercrypt/EverCrypt_Vale.c +src/windows/evercrypt/EverCrypt_Vale.h +src/windows/evercrypt/EverCrypt_Vale.obj +src/windows/evercrypt/evercrypt_vale_stubs.c +src/windows/evercrypt/evercrypt_vale_stubs.obj +src/windows/evercrypt/EverCrypt_ValeGlue.c +src/windows/evercrypt/EverCrypt_ValeGlue.h +src/windows/evercrypt/EverCrypt_ValeGlue.obj +src/windows/evercrypt/Flag.c +src/windows/evercrypt/Flag.h +src/windows/evercrypt/FStar.c +src/windows/evercrypt/FStar.h +src/windows/evercrypt/FStar.obj +src/windows/evercrypt/Hacl.c +src/windows/evercrypt/Hacl.h +src/windows/evercrypt/Hacl_Chacha20.c +src/windows/evercrypt/Hacl_Chacha20.h +src/windows/evercrypt/Hacl_Chacha20.obj +src/windows/evercrypt/Hacl_Chacha20Poly1305.c +src/windows/evercrypt/Hacl_Chacha20Poly1305.h +src/windows/evercrypt/Hacl_Chacha20Poly1305.obj +src/windows/evercrypt/Hacl_Curve25519.c +src/windows/evercrypt/Hacl_Curve25519.h +src/windows/evercrypt/Hacl_Curve25519.obj +src/windows/evercrypt/Hacl_Ed25519.c +src/windows/evercrypt/Hacl_Ed25519.h +src/windows/evercrypt/Hacl_Ed25519.obj +src/windows/evercrypt/Hacl_HMAC_SHA2_256.c +src/windows/evercrypt/Hacl_HMAC_SHA2_256.h +src/windows/evercrypt/Hacl_HMAC_SHA2_256.obj +src/windows/evercrypt/Hacl_Policies.c +src/windows/evercrypt/Hacl_Policies.h +src/windows/evercrypt/Hacl_Policies.obj +src/windows/evercrypt/Hacl_Poly1305_64.c +src/windows/evercrypt/Hacl_Poly1305_64.h +src/windows/evercrypt/Hacl_Poly1305_64.obj +src/windows/evercrypt/Hacl_Salsa20.c +src/windows/evercrypt/Hacl_Salsa20.h +src/windows/evercrypt/Hacl_Salsa20.obj +src/windows/evercrypt/Hacl_SHA2_256.c +src/windows/evercrypt/Hacl_SHA2_256.h +src/windows/evercrypt/Hacl_SHA2_256.obj +src/windows/evercrypt/Hacl_SHA2_384.c +src/windows/evercrypt/Hacl_SHA2_384.h +src/windows/evercrypt/Hacl_SHA2_384.obj +src/windows/evercrypt/Hacl_SHA2_512.c +src/windows/evercrypt/Hacl_SHA2_512.h +src/windows/evercrypt/Hacl_SHA2_512.obj +src/windows/evercrypt/Hacl_Spe.c +src/windows/evercrypt/Hacl_Spe.h +src/windows/evercrypt/Hacl_Spec.c +src/windows/evercrypt/Hacl_Spec.h +src/windows/evercrypt/i386/aes-i686.asm +src/windows/evercrypt/libevercrypt.dll +src/windows/evercrypt/libevercrypt.exp +src/windows/evercrypt/libevercrypt.lib +src/windows/evercrypt/libevercrypt.pdb +src/windows/evercrypt/libevercrypt_code.lib +src/windows/evercrypt/LowStar.c +src/windows/evercrypt/LowStar.h +src/windows/evercrypt/LowStar.obj +src/windows/evercrypt/Prims.c +src/windows/evercrypt/Prims.h +src/windows/evercrypt/Prims.obj +src/windows/evercrypt/Seq_Create.c +src/windows/evercrypt/Seq_Create.h +src/windows/evercrypt/sha256-x86_64.obj +src/windows/evercrypt/sha256_main_i.c +src/windows/evercrypt/sha256_main_i.h +src/windows/evercrypt/sha256_main_i.obj +src/windows/evercrypt/Spec.c +src/windows/evercrypt/Spec.h +src/windows/evercrypt/testsha256.c +src/windows/evercrypt/vale_aes_glue.c +src/windows/evercrypt/vale_aes_glue.obj +src/windows/evercrypt/Vale_Hash_SHA2_256.c +src/windows/evercrypt/Vale_Hash_SHA2_256.h +src/windows/evercrypt/Vale_Hash_SHA2_256.obj +src/windows/evercrypt/vc140.pdb +src/windows/evercrypt/WasmSupport.h +src/windows/hashes.sh +src/windows/include/EverCrypt.h +src/windows/include/kremlib.h +src/windows/include/kremlin/c_endianness.h +src/windows/include/kremlin/internal/builtin.h +src/windows/include/kremlin/internal/callconv.h +src/windows/include/kremlin/internal/compat.h +src/windows/include/kremlin/internal/debug.h +src/windows/include/kremlin/internal/target.h +src/windows/include/kremlin/internal/types.h +src/windows/include/kremlin/internal/wasmsupport.h +src/windows/include/mitlsffi.h +src/windows/include/quic_provider.h +src/windows/include/RegionAllocator.h +src/windows/kremlib/c.c +src/windows/kremlib/C.h +src/windows/kremlib/c.obj +src/windows/kremlib/C_Endianness.h +src/windows/kremlib/C_Failure.h +src/windows/kremlib/C_Loops.h +src/windows/kremlib/c_string.c +src/windows/kremlib/C_String.h +src/windows/kremlib/c_string.obj +src/windows/kremlib/dllmain.obj +src/windows/kremlib/FStar_All.h +src/windows/kremlib/FStar_BitVector.h +src/windows/kremlib/fstar_bytes.c +src/windows/kremlib/FStar_Bytes.h +src/windows/kremlib/fstar_bytes.obj +src/windows/kremlib/fstar_char.c +src/windows/kremlib/FStar_Char.h +src/windows/kremlib/fstar_char.obj +src/windows/kremlib/FStar_Classical.h +src/windows/kremlib/fstar_date.c +src/windows/kremlib/FStar_Date.h +src/windows/kremlib/fstar_date.obj +src/windows/kremlib/fstar_dyn.c +src/windows/kremlib/FStar_Dyn.h +src/windows/kremlib/fstar_dyn.obj +src/windows/kremlib/FStar_ErasedLogic.h +src/windows/kremlib/FStar_Exn.h +src/windows/kremlib/FStar_Float.h +src/windows/kremlib/FStar_FunctionalExtensionality.h +src/windows/kremlib/FStar_Ghost.h +src/windows/kremlib/FStar_GSet.h +src/windows/kremlib/FStar_Heap.h +src/windows/kremlib/FStar_HyperStack.h +src/windows/kremlib/FStar_HyperStack_All.h +src/windows/kremlib/fstar_hyperstack_io.c +src/windows/kremlib/FStar_HyperStack_IO.h +src/windows/kremlib/fstar_hyperstack_io.obj +src/windows/kremlib/FStar_HyperStack_ST.h +src/windows/kremlib/FStar_Int.h +src/windows/kremlib/fstar_int16.c +src/windows/kremlib/FStar_Int16.h +src/windows/kremlib/fstar_int16.obj +src/windows/kremlib/fstar_int32.c +src/windows/kremlib/FStar_Int32.h +src/windows/kremlib/fstar_int32.obj +src/windows/kremlib/FStar_Int63.h +src/windows/kremlib/fstar_int64.c +src/windows/kremlib/FStar_Int64.h +src/windows/kremlib/fstar_int64.obj +src/windows/kremlib/fstar_int8.c +src/windows/kremlib/FStar_Int8.h +src/windows/kremlib/fstar_int8.obj +src/windows/kremlib/FStar_Int_Cast.h +src/windows/kremlib/FStar_Int_Cast_Full.h +src/windows/kremlib/fstar_io.c +src/windows/kremlib/FStar_IO.h +src/windows/kremlib/fstar_io.obj +src/windows/kremlib/FStar_Kremlin_Endianness.h +src/windows/kremlib/FStar_List.h +src/windows/kremlib/FStar_List_Tot.h +src/windows/kremlib/FStar_List_Tot_Base.h +src/windows/kremlib/FStar_List_Tot_Properties.h +src/windows/kremlib/FStar_Map.h +src/windows/kremlib/FStar_Math_Lemmas.h +src/windows/kremlib/FStar_Math_Lib.h +src/windows/kremlib/FStar_ModifiesGen.h +src/windows/kremlib/FStar_Monotonic_Heap.h +src/windows/kremlib/FStar_Monotonic_HyperHeap.h +src/windows/kremlib/FStar_Monotonic_HyperStack.h +src/windows/kremlib/FStar_Monotonic_Witnessed.h +src/windows/kremlib/FStar_Mul.h +src/windows/kremlib/FStar_Pervasives.h +src/windows/kremlib/FStar_Pervasives_Native.h +src/windows/kremlib/FStar_PredicateExtensionality.h +src/windows/kremlib/FStar_Preorder.h +src/windows/kremlib/FStar_PropositionalExtensionality.h +src/windows/kremlib/FStar_Seq.h +src/windows/kremlib/FStar_Seq_Base.h +src/windows/kremlib/FStar_Seq_Properties.h +src/windows/kremlib/FStar_Set.h +src/windows/kremlib/FStar_Squash.h +src/windows/kremlib/FStar_ST.h +src/windows/kremlib/fstar_string.c +src/windows/kremlib/FStar_String.h +src/windows/kremlib/fstar_string.obj +src/windows/kremlib/FStar_StrongExcludedMiddle.h +src/windows/kremlib/FStar_TSet.h +src/windows/kremlib/FStar_UInt.h +src/windows/kremlib/fstar_uint128.c +src/windows/kremlib/FStar_UInt128.h +src/windows/kremlib/fstar_uint128_msvc.c +src/windows/kremlib/fstar_uint128_msvc.obj +src/windows/kremlib/fstar_uint16.c +src/windows/kremlib/FStar_UInt16.h +src/windows/kremlib/fstar_uint16.obj +src/windows/kremlib/fstar_uint32.c +src/windows/kremlib/FStar_UInt32.h +src/windows/kremlib/fstar_uint32.obj +src/windows/kremlib/FStar_UInt63.h +src/windows/kremlib/fstar_uint64.c +src/windows/kremlib/FStar_UInt64.h +src/windows/kremlib/fstar_uint64.obj +src/windows/kremlib/fstar_uint8.c +src/windows/kremlib/FStar_UInt8.h +src/windows/kremlib/fstar_uint8.obj +src/windows/kremlib/FStar_Universe.h +src/windows/kremlib/kremlinit.h +src/windows/kremlib/libkremlib.dll +src/windows/kremlib/libkremlib.exp +src/windows/kremlib/libkremlib.lib +src/windows/kremlib/libkremlib.pdb +src/windows/kremlib/libkremlib_code.lib +src/windows/kremlib/LowStar_Buffer.h +src/windows/kremlib/LowStar_BufferOps.h +src/windows/kremlib/LowStar_Modifies.h +src/windows/kremlib/prims.c +src/windows/kremlib/Prims.h +src/windows/kremlib/prims.obj +src/windows/kremlib/RegionAllocator.c +src/windows/kremlib/RegionAllocator.obj +src/windows/kremlib/Spec_Loops.h +src/windows/kremlib/testlib.c +src/windows/kremlib/TestLib.h +src/windows/kremlib/testlib.obj +src/windows/kremlib/vc140.pdb +src/windows/mitls/AEAD_GCM.c +src/windows/mitls/AEAD_GCM.h +src/windows/mitls/AEAD_GCM.obj +src/windows/mitls/AEADOpenssl.c +src/windows/mitls/AEADOpenssl.h +src/windows/mitls/AEADOpenssl.obj +src/windows/mitls/AEADProvider.c +src/windows/mitls/AEADProvider.h +src/windows/mitls/AEADProvider.obj +src/windows/mitls/Alert.c +src/windows/mitls/Alert.h +src/windows/mitls/Alert.obj +src/windows/mitls/buffer_bytes.c +src/windows/mitls/buffer_bytes.obj +src/windows/mitls/Buffer_Utils.c +src/windows/mitls/Buffer_Utils.h +src/windows/mitls/Buffer_Utils.obj +src/windows/mitls/BufferBytes.c +src/windows/mitls/BufferBytes.h +src/windows/mitls/BufferBytes.obj +src/windows/mitls/C.c +src/windows/mitls/C.h +src/windows/mitls/C_Endianness.c +src/windows/mitls/C_Endianness.h +src/windows/mitls/C_Loops_Spec_Loops.c +src/windows/mitls/C_Loops_Spec_Loops.h +src/windows/mitls/C_Loops_Spec_Loops.obj +src/windows/mitls/Cert.c +src/windows/mitls/Cert.h +src/windows/mitls/Cert.obj +src/windows/mitls/CommonDH.c +src/windows/mitls/CommonDH.h +src/windows/mitls/CommonDH.obj +src/windows/mitls/Connection.c +src/windows/mitls/Connection.h +src/windows/mitls/Connection.obj +src/windows/mitls/Content.c +src/windows/mitls/Content.h +src/windows/mitls/Content.obj +src/windows/mitls/core_crypto.c +src/windows/mitls/core_crypto.obj +src/windows/mitls/CoreCrypto.c +src/windows/mitls/CoreCrypto.h +src/windows/mitls/CoreCrypto.obj +src/windows/mitls/Crypto_AEAD_Main.c +src/windows/mitls/Crypto_AEAD_Main.h +src/windows/mitls/Crypto_AEAD_Main.obj +src/windows/mitls/Crypto_HKDF_Crypto_HMAC.c +src/windows/mitls/Crypto_HKDF_Crypto_HMAC.h +src/windows/mitls/Crypto_HKDF_Crypto_HMAC.obj +src/windows/mitls/Crypto_Indexing.c +src/windows/mitls/Crypto_Indexing.h +src/windows/mitls/Crypto_Indexing.obj +src/windows/mitls/Crypto_Plain.c +src/windows/mitls/Crypto_Plain.h +src/windows/mitls/Crypto_Plain.obj +src/windows/mitls/Crypto_Symmetric_Bytes.c +src/windows/mitls/Crypto_Symmetric_Bytes.h +src/windows/mitls/Crypto_Symmetric_Bytes.obj +src/windows/mitls/CryptoTypes.c +src/windows/mitls/CryptoTypes.h +src/windows/mitls/CryptoTypes.obj +src/windows/mitls/DataStream.c +src/windows/mitls/DataStream.h +src/windows/mitls/DataStream.obj +src/windows/mitls/DebugFlags.c +src/windows/mitls/DebugFlags.h +src/windows/mitls/DHGroup.c +src/windows/mitls/DHGroup.h +src/windows/mitls/DHGroup.obj +src/windows/mitls/dllmain.obj +src/windows/mitls/ECGroup.c +src/windows/mitls/ECGroup.h +src/windows/mitls/ECGroup.obj +src/windows/mitls/EverCrypt_Bytes.c +src/windows/mitls/EverCrypt_Bytes.h +src/windows/mitls/Extensions.c +src/windows/mitls/Extensions.h +src/windows/mitls/Extensions.obj +src/windows/mitls/FFI.c +src/windows/mitls/FFI.h +src/windows/mitls/FFI.obj +src/windows/mitls/FFICallbacks.c +src/windows/mitls/FFICallbacks.h +src/windows/mitls/FFICallbacks.obj +src/windows/mitls/Flag.c +src/windows/mitls/Flag.h +src/windows/mitls/Flag.obj +src/windows/mitls/Flags.c +src/windows/mitls/Flags.h +src/windows/mitls/Flags.obj +src/windows/mitls/Format.c +src/windows/mitls/Format.h +src/windows/mitls/Format.obj +src/windows/mitls/FStar.c +src/windows/mitls/FStar.h +src/windows/mitls/FStar.obj +src/windows/mitls/hacks.h +src/windows/mitls/hacl_glue.h +src/windows/mitls/hacl_provider.c +src/windows/mitls/hacl_provider.obj +src/windows/mitls/HaclProvider.c +src/windows/mitls/HaclProvider.h +src/windows/mitls/HaclProvider.obj +src/windows/mitls/HandshakeLog.c +src/windows/mitls/HandshakeLog.h +src/windows/mitls/HandshakeLog.obj +src/windows/mitls/HandshakeMessages.c +src/windows/mitls/HandshakeMessages.h +src/windows/mitls/HandshakeMessages.obj +src/windows/mitls/Hashing.c +src/windows/mitls/Hashing.h +src/windows/mitls/Hashing.obj +src/windows/mitls/Hashing_CRF.c +src/windows/mitls/Hashing_CRF.h +src/windows/mitls/Hashing_CRF.obj +src/windows/mitls/Hashing_OpenSSL.c +src/windows/mitls/Hashing_OpenSSL.h +src/windows/mitls/Hashing_OpenSSL.obj +src/windows/mitls/Hashing_Spec.c +src/windows/mitls/Hashing_Spec.h +src/windows/mitls/Hashing_Spec.obj +src/windows/mitls/HMAC.c +src/windows/mitls/HMAC.h +src/windows/mitls/HMAC.obj +src/windows/mitls/kremlinit.c +src/windows/mitls/kremlinit.h +src/windows/mitls/kremlinit.obj +src/windows/mitls/LHAEPlain.c +src/windows/mitls/LHAEPlain.h +src/windows/mitls/LHAEPlain.obj +src/windows/mitls/libmitls.dll +src/windows/mitls/libmitls.exp +src/windows/mitls/libmitls.lib +src/windows/mitls/libmitls.pdb +src/windows/mitls/libmitls_code.lib +src/windows/mitls/List_Helpers.c +src/windows/mitls/List_Helpers.h +src/windows/mitls/log_to_choice.h +src/windows/mitls/LowCProvider.c +src/windows/mitls/LowCProvider.h +src/windows/mitls/LowCProvider.obj +src/windows/mitls/LowParse.c +src/windows/mitls/LowParse.h +src/windows/mitls/LowParse.obj +src/windows/mitls/LowParseWrappers.c +src/windows/mitls/LowParseWrappers.h +src/windows/mitls/LowParseWrappers.obj +src/windows/mitls/LowStar.c +src/windows/mitls/LowStar.h +src/windows/mitls/Mem.c +src/windows/mitls/Mem.h +src/windows/mitls/mitlsffi.c +src/windows/mitls/mitlsffi.obj +src/windows/mitls/Negotiation.c +src/windows/mitls/Negotiation.h +src/windows/mitls/Negotiation.obj +src/windows/mitls/Nonce.c +src/windows/mitls/Nonce.h +src/windows/mitls/Nonce.obj +src/windows/mitls/Old_Epochs.c +src/windows/mitls/Old_Epochs.h +src/windows/mitls/Old_Epochs.obj +src/windows/mitls/Old_Handshake.c +src/windows/mitls/Old_Handshake.h +src/windows/mitls/Old_Handshake.obj +src/windows/mitls/Old_HKDF.c +src/windows/mitls/Old_HKDF.h +src/windows/mitls/Old_HKDF.obj +src/windows/mitls/Old_HMAC_UFCMA.c +src/windows/mitls/Old_HMAC_UFCMA.h +src/windows/mitls/Old_HMAC_UFCMA.obj +src/windows/mitls/Old_KeySchedule.c +src/windows/mitls/Old_KeySchedule.h +src/windows/mitls/Old_KeySchedule.obj +src/windows/mitls/Parse.c +src/windows/mitls/Parse.h +src/windows/mitls/Parse.obj +src/windows/mitls/PMS.c +src/windows/mitls/PMS.h +src/windows/mitls/PMS.obj +src/windows/mitls/Prims.c +src/windows/mitls/Prims.h +src/windows/mitls/Prims.obj +src/windows/mitls/PSK.c +src/windows/mitls/PSK.h +src/windows/mitls/PSK.obj +src/windows/mitls/QUIC.c +src/windows/mitls/QUIC.h +src/windows/mitls/QUIC.obj +src/windows/mitls/Range.c +src/windows/mitls/Range.h +src/windows/mitls/Range.obj +src/windows/mitls/Record.c +src/windows/mitls/Record.h +src/windows/mitls/Record.obj +src/windows/mitls/regions.h +src/windows/mitls/RSAKey.c +src/windows/mitls/RSAKey.h +src/windows/mitls/RSAKey.obj +src/windows/mitls/Specializations_Providers_AEAD.c +src/windows/mitls/Specializations_Providers_AEAD.h +src/windows/mitls/Specializations_Providers_AEAD.obj +src/windows/mitls/StAE.c +src/windows/mitls/StAE.h +src/windows/mitls/StAE.obj +src/windows/mitls/StatefulLHAE.c +src/windows/mitls/StatefulLHAE.h +src/windows/mitls/StatefulLHAE.obj +src/windows/mitls/StatefulPlain.c +src/windows/mitls/StatefulPlain.h +src/windows/mitls/StatefulPlain.obj +src/windows/mitls/StreamAE.c +src/windows/mitls/StreamAE.h +src/windows/mitls/StreamAE.obj +src/windows/mitls/StreamDeltas.c +src/windows/mitls/StreamDeltas.h +src/windows/mitls/StreamDeltas.obj +src/windows/mitls/StreamPlain.c +src/windows/mitls/StreamPlain.h +src/windows/mitls/StreamPlain.obj +src/windows/mitls/Ticket.c +src/windows/mitls/Ticket.h +src/windows/mitls/Ticket.obj +src/windows/mitls/TLS.c +src/windows/mitls/TLS.h +src/windows/mitls/TLS.obj +src/windows/mitls/TLS_Curve25519.c +src/windows/mitls/TLS_Curve25519.h +src/windows/mitls/TLS_Curve25519.obj +src/windows/mitls/TLSConstants.c +src/windows/mitls/TLSConstants.h +src/windows/mitls/TLSConstants.obj +src/windows/mitls/TLSError.c +src/windows/mitls/TLSError.h +src/windows/mitls/TLSError.obj +src/windows/mitls/TLSInfo.c +src/windows/mitls/TLSInfo.h +src/windows/mitls/TLSInfo.obj +src/windows/mitls/TLSInfoFlags.c +src/windows/mitls/TLSInfoFlags.h +src/windows/mitls/TLSInfoFlags.obj +src/windows/mitls/TLSPRF.c +src/windows/mitls/TLSPRF.h +src/windows/mitls/TLSPRF.obj +src/windows/mitls/Transport.c +src/windows/mitls/Transport.h +src/windows/mitls/Transport.obj +src/windows/mitls/vc140.pdb +src/windows/quiccrypto/Crypto_HKDF_Crypto_HMAC.c +src/windows/quiccrypto/Crypto_HKDF_Crypto_HMAC.h +src/windows/quiccrypto/Crypto_HKDF_Crypto_HMAC.obj +src/windows/quiccrypto/dllmain.obj +src/windows/quiccrypto/libquiccrypto.dll +src/windows/quiccrypto/libquiccrypto.exp +src/windows/quiccrypto/libquiccrypto.lib +src/windows/quiccrypto/libquiccrypto.pdb +src/windows/quiccrypto/libquiccrypto_code.lib +src/windows/quiccrypto/quic_provider.c +src/windows/quiccrypto/quic_provider.obj +src/windows/quiccrypto/test.c +src/windows/quiccrypto/test.exe +src/windows/quiccrypto/test.obj +src/windows/quiccrypto/test.pdb +src/windows/quiccrypto/vc140.pdb +apps/cmitls/benchmark.sh +apps/quicMinusNet/quic_common.c +apps/QuicWin/ffi2lib.bat +apps/QuicWin/QuicWin.sln +apps/QuicWin/QuicWin/QuicWin.cpp +apps/QuicWin/QuicWin/QuicWin.vcxproj +apps/QuicWin/QuicWin/QuicWin.vcxproj.filters +scripts/vsbin.sh +src/pki/win/mipkiwin.c +src/tls/extract/cstubs/log_to_choice.h +src/tls/extract/cstubs/RegionAllocator.c +src/tls/extract/cstubs/RegionAllocator.h +src/tls/hints/AEAD_GCM.fst.hints +src/tls/hints/AEADProvider.fst.hints +src/tls/hints/C.Endianness.fst.hints +src/tls/hints/CommonDH.fst.hints +src/tls/hints/DebugFlags.fst.hints +src/tls/hints/HandshakeLog.fst.hints +src/tls/hints/LHAEPlain.fst.hints +src/tls/hints/List.Helpers.fst.hints +src/tls/hints/Negotiation.fst.hints +src/tls/hints/Old.KeySchedule.fst.hints +src/tls/hints/Record.fst.hints +src/tls/hints/StreamAE.fst.hints +src/tls/hints/TLS.fst.hints +src/tls/renamings.sh +src/tls/hints/StreamAE.fst.hints +src/tls/hints/Record.fst.hints +src/tls/hints/Old.KeySchedule.fst.hints +src/tls/hints/Negotiation.fst.hints +src/tls/hints/List.Helpers.fst.hints +src/tls/hints/LHAEPlain.fst.hints +src/tls/hints/HandshakeLog.fst.hints +src/tls/hints/DebugFlags.fst.hints +src/tls/hints/CommonDH.fst.hints +src/tls/hints/C.Endianness.fst.hints +src/tls/hints/AEADProvider.fst.hints +src/tls/hints/AEAD_GCM.fst.hints +src/tls/extract/cstubs/RegionAllocator.h +src/tls/extract/cstubs/RegionAllocator.c +src/tls/extract/cstubs/log_to_choice.h +src/pki/win/mipkiwin.c +scripts/vsbin.sh +apps/QuicWin/QuicWin/QuicWin.vcxproj.filters +apps/QuicWin/QuicWin/QuicWin.vcxproj +apps/QuicWin/QuicWin/QuicWin.cpp +apps/QuicWin/QuicWin.sln +apps/QuicWin/ffi2lib.bat +apps/quicMinusNet/quic_common.c +apps/cmitls/benchmark.sh +src/tls/hints/TLS.fst.hints +src/tls/renamings.sh +apps/cmitls/benchmark.sh +apps/quicMinusNet/quic_common.c +apps/QuicWin/ffi2lib.bat +apps/QuicWin/QuicWin.sln +apps/QuicWin/QuicWin/QuicWin.cpp +apps/QuicWin/QuicWin/QuicWin.vcxproj +apps/QuicWin/QuicWin/QuicWin.vcxproj.filters +scripts/vsbin.sh +src/pki/win/mipkiwin.c +src/tls/extract/cstubs/log_to_choice.h +src/tls/extract/cstubs/RegionAllocator.c +src/tls/extract/cstubs/RegionAllocator.h +src/tls/hints/AEAD_GCM.fst.hints +src/tls/hints/AEADProvider.fst.hints +src/tls/hints/C.Endianness.fst.hints +src/tls/hints/CommonDH.fst.hints +src/tls/hints/DebugFlags.fst.hints +src/tls/hints/HandshakeLog.fst.hints +src/tls/hints/LHAEPlain.fst.hints +src/tls/hints/List.Helpers.fst.hints +src/tls/hints/Negotiation.fst.hints +src/tls/hints/Old.KeySchedule.fst.hints +src/tls/hints/Record.fst.hints +src/tls/hints/StreamAE.fst.hints +src/tls/hints/TLS.fst.hints +src/tls/renamings.sh +tests/Tester/Tester/Tester.user +tests/Tester/Tester/Tester.vcxproj +tests/Tester/Tester/Tester.vcxproj.filters +tests/Tester/Tester/packages.config diff --git a/apps/QuicWin/QuicWin.sln b/apps/QuicWin/QuicWin.sln old mode 100755 new mode 100644 diff --git a/apps/QuicWin/QuicWin/QuicWin.cpp b/apps/QuicWin/QuicWin/QuicWin.cpp old mode 100755 new mode 100644 diff --git a/apps/QuicWin/QuicWin/QuicWin.vcxproj b/apps/QuicWin/QuicWin/QuicWin.vcxproj old mode 100755 new mode 100644 diff --git a/apps/QuicWin/QuicWin/QuicWin.vcxproj.filters b/apps/QuicWin/QuicWin/QuicWin.vcxproj.filters old mode 100755 new mode 100644 diff --git a/apps/QuicWin/ffi2lib.bat b/apps/QuicWin/ffi2lib.bat old mode 100755 new mode 100644 diff --git a/apps/cmitls/benchmark.sh b/apps/cmitls/benchmark.sh old mode 100755 new mode 100644 diff --git a/apps/quicMinusNet/quic_common.c b/apps/quicMinusNet/quic_common.c old mode 100755 new mode 100644 diff --git a/scripts/vsbin.sh b/scripts/vsbin.sh old mode 100755 new mode 100644 diff --git a/src/pki/win/mipkiwin.c b/src/pki/win/mipkiwin.c old mode 100755 new mode 100644 diff --git a/src/tls/extract/cstubs/RegionAllocator.c b/src/tls/extract/cstubs/RegionAllocator.c old mode 100755 new mode 100644 diff --git a/src/tls/extract/cstubs/RegionAllocator.h b/src/tls/extract/cstubs/RegionAllocator.h old mode 100755 new mode 100644 diff --git a/src/tls/extract/cstubs/log_to_choice.h b/src/tls/extract/cstubs/log_to_choice.h old mode 100755 new mode 100644 diff --git a/src/tls/hints/AEADProvider.fst.hints b/src/tls/hints/AEADProvider.fst.hints index e8808b44e..393e771f1 100644 --- a/src/tls/hints/AEADProvider.fst.hints +++ b/src/tls/hints/AEADProvider.fst.hints @@ -22,11 +22,12 @@ 2, 1, [ - "@query", "equation_DebugFlags.debug", - "equation_DebugFlags.debug_AEP" + "@query", "equation_FStar.HyperStack.ST.equal_stack_domains", + "equation_FStar.Monotonic.Heap.equal_dom", + "lemma_FStar.HyperStack.ST.lemma_same_refs_in_stack_regions_intro" ], 0, - "aa16157c6c5d52cd0a09025ff3f96e1e" + "fe945fed7520bb18180c8b21c3da950d" ], [ "AEADProvider.prov", diff --git a/src/tls/hints/AEAD_GCM.fst.hints b/src/tls/hints/AEAD_GCM.fst.hints index 59fc1161f..45367c3b1 100644 --- a/src/tls/hints/AEAD_GCM.fst.hints +++ b/src/tls/hints/AEAD_GCM.fst.hints @@ -1441,7 +1441,7 @@ "typing_tok_TLSError.AD_close_notify@tok" ], 0, - "a747ccf952cad5d346e3b104d0bd1e6a" + "62b88cf98ed69215eb652bfc9c32bef1" ] ] ] \ No newline at end of file diff --git a/src/tls/hints/C.Endianness.fst.hints b/src/tls/hints/C.Endianness.fst.hints old mode 100755 new mode 100644 diff --git a/src/tls/hints/CommonDH.fst.hints b/src/tls/hints/CommonDH.fst.hints index 10d737019..f92dfc8ab 100644 --- a/src/tls/hints/CommonDH.fst.hints +++ b/src/tls/hints/CommonDH.fst.hints @@ -29,11 +29,12 @@ 2, 1, [ - "@query", "equation_DebugFlags.debug", - "equation_DebugFlags.debug_CDH" + "@query", "equation_FStar.HyperStack.ST.equal_stack_domains", + "equation_FStar.Monotonic.Heap.equal_dom", + "lemma_FStar.HyperStack.ST.lemma_same_refs_in_stack_regions_intro" ], 0, - "4b029046e1d126898bf65f34ac46d3de" + "0e20d2f78d2486c6e0888e4dcc7cdc09" ], [ "CommonDH.group'", @@ -465,7 +466,7 @@ "token_correspondence_CommonDH.pre_share" ], 0, - "d5af2b9ddb033cc555a699dfb5fb7b73" + "ad9172bd372508966af04b9410e6649b" ], [ "CommonDH.ilog", @@ -488,7 +489,7 @@ "token_correspondence_CommonDH.pre_share", "unit_typing" ], 0, - "6bdf89d756102a1b33864ce64b93b035" + "f920e274f59d90ba77983ffd436dea72" ], [ "CommonDH.registered_dhi", @@ -509,7 +510,7 @@ "token_correspondence_CommonDH.pre_share" ], 0, - "f08b66c551a2a7741cd2c695707a9c82" + "5855f6079660c1391cfe473e2c898eb5" ], [ "CommonDH.fresh_dhi", @@ -530,7 +531,7 @@ "token_correspondence_CommonDH.pre_share" ], 0, - "c37fa039d43d48402328eeef544d85de" + "9165cd04372449480b096f8d764259a5" ], [ "CommonDH.honest_dhi_st", @@ -550,7 +551,7 @@ "token_correspondence_CommonDH.pre_share" ], 0, - "5feba040983f45896fd5a5055c91a7cb" + "34026b9b8856862122b00de64cbd9e2b" ], [ "CommonDH.lemma_honest_dhi_stable", @@ -570,7 +571,7 @@ "token_correspondence_CommonDH.pre_share" ], 0, - "840c0ec6e088df3a2e0e31f2035238ac" + "75fa48527342f31c6f096730341a53f2" ], [ "CommonDH.honest_dhi", @@ -602,7 +603,7 @@ "token_correspondence_CommonDH.pre_share" ], 0, - "5b889a32a9e08728330192b877825461" + "6f7cd6bed5d0bf93e85f2a42ac840486" ], [ "CommonDH.lemma_corrupt_dhi_stable", @@ -622,7 +623,7 @@ "token_correspondence_CommonDH.pre_share" ], 0, - "c9fb103ff7df5e2965ddca95e112108e" + "5183e33b23f33f26f8ac02529a87bba6" ], [ "CommonDH.corrupt_dhi", @@ -648,7 +649,7 @@ "FStar.Monotonic.DependentMap_interpretation_Tm_arrow_f23bd32e4d56f2eb45951698864a8758", "Prims_interpretation_Tm_arrow_e06752ba152f81447b312efcdf8f0e23", "assumption_CommonDH.group___uu___haseq", - "assumption_Prims.dtuple2__uu___haseq", "bool_typing", + "assumption_Prims.dtuple2__uu___haseq", "bool_inversion", "data_elim_Prims.Mkdtuple2", "disc_equation_CommonDH.Corrupt", "disc_equation_CommonDH.Honest", "disc_equation_FStar.Pervasives.Native.Some", @@ -659,9 +660,11 @@ "equation_CommonDH.registered_dhi", "equation_DebugFlags.debug", "equation_FStar.HyperStack.ST.equal_stack_domains", "equation_FStar.HyperStack.ST.erid", + "equation_FStar.HyperStack.ST.is_eternal_region", "equation_FStar.Monotonic.DependentMap.contains", "equation_FStar.Monotonic.DependentMap.value_of", "equation_FStar.Monotonic.Heap.equal_dom", + "equation_FStar.Monotonic.HyperStack.is_eternal_color", "equation_FStar.Monotonic.HyperStack.mem", "equation_Mem.rgn", "equation_Prims.eqtype", "equation_Prims.l_True", "false_interp", "fuel_guarded_inversion_CommonDH.ilog_entry", @@ -682,10 +685,12 @@ "token_correspondence_CommonDH.ilog_entry@tok", "token_correspondence_CommonDH.pre_share", "true_interp", "typing_CommonDH_Tm_abs_64faaf4084c89a3727c800ef9f2c1b85", - "typing_FStar.Monotonic.DependentMap.value_of" + "typing_FStar.Monotonic.DependentMap.value_of", + "typing_FStar.Monotonic.HyperHeap.color", + "typing_FStar.Monotonic.HyperStack.is_eternal_color" ], 0, - "c61c890782ab783515d0ff93d59b42d3" + "29ea12bded42219d66ae0401ae5efd7b" ], [ "CommonDH.ipubshare", @@ -723,7 +728,7 @@ "token_correspondence_CommonDH.pre_share" ], 0, - "04e230db8e161135c8cd63b83e2e225f" + "d74e86b514928a91210497db52a9bb53" ], [ "CommonDH.registered_dhr", @@ -761,7 +766,7 @@ "token_correspondence_CommonDH.pre_share" ], 0, - "d25dd8cd19c99b7fa07ad3b6e9c1e337" + "828cd49b792356545f400c2ba1a20236" ], [ "CommonDH.honest_dhr_st", @@ -787,7 +792,7 @@ "token_correspondence_CommonDH.pre_share" ], 0, - "679a537e9f38b21e839a9669c17d03b3" + "9aa4c6d830b69b13d8e047003c6283f1" ], [ "CommonDH.honest_dhr", @@ -825,7 +830,7 @@ "token_correspondence_CommonDH.pre_share" ], 0, - "009932075a12419d294444f36e0e0d9d" + "8da5564af59663c03b3a4993f16a4937" ], [ "CommonDH.corrupt_dhr", @@ -853,7 +858,7 @@ "Prims_pretyping_f537159ed795b314b4e58c260361ae86", "assumption_CommonDH.group___uu___haseq", "assumption_Prims.dtuple2__uu___haseq", "b2t_def", "bool_inversion", - "bool_typing", "constructor_distinct_CommonDH.Corrupt", + "constructor_distinct_CommonDH.Corrupt", "data_elim_FStar.Pervasives.Native.Some", "data_elim_Prims.Mkdtuple2", "disc_equation_CommonDH.Honest", "disc_equation_FStar.Pervasives.Native.Some", @@ -867,10 +872,12 @@ "equation_CommonDH.registered_dhr_st", "equation_DebugFlags.debug", "equation_FStar.HyperStack.ST.equal_stack_domains", "equation_FStar.HyperStack.ST.erid", + "equation_FStar.HyperStack.ST.is_eternal_region", "equation_FStar.Monotonic.DependentMap.contains", "equation_FStar.Monotonic.DependentMap.defined", "equation_FStar.Monotonic.DependentMap.value_of", "equation_FStar.Monotonic.Heap.equal_dom", + "equation_FStar.Monotonic.HyperStack.is_eternal_color", "equation_FStar.Monotonic.HyperStack.mem", "equation_FStar.Pervasives.dfst", "equation_Mem.rgn", "equation_Prims.eqtype", "equation_Prims.l_True", "false_interp", @@ -900,10 +907,12 @@ "token_correspondence_CommonDH.pre_share", "true_interp", "typing_CommonDH.uu___is_Corrupt", "typing_CommonDH_Tm_abs_64faaf4084c89a3727c800ef9f2c1b85", - "typing_FStar.Monotonic.DependentMap.value_of" + "typing_FStar.Monotonic.DependentMap.value_of", + "typing_FStar.Monotonic.HyperHeap.color", + "typing_FStar.Monotonic.HyperStack.is_eternal_color" ], 0, - "27386f9164d2ec4d6668ce078057bb64" + "804c2e4c3c53e3c7ffbcb994cd4c2278" ], [ "CommonDH.rshare", @@ -1108,11 +1117,13 @@ "equation_CommonDH.registered_dhr", "equation_CommonDH.registered_dhr_st", "equation_CommonDH.rshare", "equation_CommonDH.secret", "equation_FStar.HyperStack.ST.erid", + "equation_FStar.HyperStack.ST.is_eternal_region", "equation_FStar.Monotonic.DependentMap.contains", "equation_FStar.Monotonic.DependentMap.value_of", "equation_FStar.Monotonic.HyperHeap.hmap", "equation_FStar.Monotonic.HyperHeap.modifies_just", "equation_FStar.Monotonic.HyperHeap.modifies_one", + "equation_FStar.Monotonic.HyperStack.is_eternal_color", "equation_FStar.Monotonic.HyperStack.mem", "equation_FStar.Monotonic.HyperStack.modifies", "equation_FStar.Monotonic.HyperStack.modifies_one", @@ -1154,11 +1165,13 @@ "typing_FStar.Map.concat", "typing_FStar.Map.contains", "typing_FStar.Map.restrict", "typing_FStar.Monotonic.DependentMap.value_of", + "typing_FStar.Monotonic.HyperHeap.color", "typing_FStar.Monotonic.HyperStack.get_hmap", + "typing_FStar.Monotonic.HyperStack.is_eternal_color", "typing_FStar.Set.complement", "typing_FStar.Set.singleton" ], 0, - "da3e85eef97361db6f7bca2d5538ee1a" + "9a4674b1714c468325539387b2bdcd05" ], [ "CommonDH.register_dhi", @@ -1184,6 +1197,7 @@ "equation_CommonDH.ishare_table", "equation_CommonDH.pre_dhi", "equation_CommonDH.registered_dhi", "equation_FStar.HyperStack.ST.equal_stack_domains", + "equation_FStar.HyperStack.ST.is_eternal_region", "equation_FStar.HyperStack.ST.m_rref", "equation_FStar.HyperStack.ST.mref", "equation_FStar.Monotonic.DependentMap.contains", @@ -1196,6 +1210,7 @@ "equation_FStar.Monotonic.HyperHeap.hmap", "equation_FStar.Monotonic.HyperHeap.modifies_just", "equation_FStar.Monotonic.HyperHeap.modifies_one", + "equation_FStar.Monotonic.HyperStack.is_eternal_color", "equation_FStar.Monotonic.HyperStack.mem", "equation_FStar.Monotonic.HyperStack.modifies", "equation_FStar.Monotonic.HyperStack.modifies_one", @@ -1248,12 +1263,14 @@ "typing_FStar.Monotonic.DependentMap.repr", "typing_FStar.Monotonic.DependentMap.sel", "typing_FStar.Monotonic.DependentMap.upd", + "typing_FStar.Monotonic.HyperHeap.color", "typing_FStar.Monotonic.HyperStack.get_hmap", + "typing_FStar.Monotonic.HyperStack.is_eternal_color", "typing_FStar.Monotonic.HyperStack.sel", "typing_FStar.Set.complement", "typing_FStar.Set.singleton" ], 0, - "8551fea4664c93fa6924035673d8a58e" + "1906a2e0f94d3d05d69af6010682282e" ], [ "CommonDH.register_dhr", @@ -1316,7 +1333,7 @@ "typing_FStar.Set.complement", "typing_FStar.Set.singleton" ], 0, - "2a0bf030073727d06a5913170941a078" + "dd35e05efdf9d1350ca1a34598b6b907" ], [ "CommonDH.parse", @@ -1941,7 +1958,7 @@ "well-founded-ordering-on-nat" ], 0, - "85ae012e65fc8fdbdaa5fff75a22b6c7" + "f5a6be7c758c26f0876dae6036783b28" ], [ "CommonDH.parseKeyShareEntries", diff --git a/src/tls/hints/DebugFlags.fst.hints b/src/tls/hints/DebugFlags.fst.hints index 7cd61d050..a726bc726 100644 --- a/src/tls/hints/DebugFlags.fst.hints +++ b/src/tls/hints/DebugFlags.fst.hints @@ -1 +1 @@ -[ "\u001aqmg@\u000bl(}?", [] ] \ No newline at end of file +[ "P\u0001.\u0016aA\u0015>$", [] ] \ No newline at end of file diff --git a/src/tls/hints/HandshakeLog.fst.hints b/src/tls/hints/HandshakeLog.fst.hints index c8f12ef85..c64a96a21 100644 --- a/src/tls/hints/HandshakeLog.fst.hints +++ b/src/tls/hints/HandshakeLog.fst.hints @@ -48,11 +48,12 @@ 2, 1, [ - "@query", "equation_DebugFlags.debug", - "equation_DebugFlags.debug_HSL" + "@query", "equation_FStar.HyperStack.ST.equal_stack_domains", + "equation_FStar.Monotonic.Heap.equal_dom", + "lemma_FStar.HyperStack.ST.lemma_same_refs_in_stack_regions_intro" ], 0, - "bbbc3568ed55d38bca0526cb4fc971c8" + "9e0d9166bef6db226aa97ab8fcc9e68a" ], [ "HandshakeLog.elift1_def", diff --git a/src/tls/hints/LHAEPlain.fst.hints b/src/tls/hints/LHAEPlain.fst.hints index c9916e7e8..3f95370fc 100644 --- a/src/tls/hints/LHAEPlain.fst.hints +++ b/src/tls/hints/LHAEPlain.fst.hints @@ -77,7 +77,7 @@ "typing_FStar.Pervasives.Native.fst" ], 0, - "ca4818ae11c8563f00c231aec6dce520" + "68b8d5ca8a17e65739846a35544768f5" ], [ "LHAEPlain.lemma_makeAD_seqN", diff --git a/src/tls/hints/List.Helpers.fst.hints b/src/tls/hints/List.Helpers.fst.hints index d546d59d9..887d473ab 100644 --- a/src/tls/hints/List.Helpers.fst.hints +++ b/src/tls/hints/List.Helpers.fst.hints @@ -38,7 +38,7 @@ "subterm_ordering_Prims.Cons", "true_interp", "unit_typing" ], 0, - "fe5c6304cb4bd8ac6ca1ef5ceae1d6a1" + "d5cd6beefb5cd98bab3a8c60981202b3" ], [ "List.Helpers.find_aux", diff --git a/src/tls/hints/Negotiation.fst.hints b/src/tls/hints/Negotiation.fst.hints index 67ff70057..49235e472 100644 --- a/src/tls/hints/Negotiation.fst.hints +++ b/src/tls/hints/Negotiation.fst.hints @@ -22,11 +22,12 @@ 2, 1, [ - "@query", "equation_DebugFlags.debug", - "equation_DebugFlags.debug_NGO" + "@query", "equation_FStar.HyperStack.ST.equal_stack_domains", + "equation_FStar.Monotonic.Heap.equal_dom", + "lemma_FStar.HyperStack.ST.lemma_same_refs_in_stack_regions_intro" ], 0, - "533a2ccd956c1cb48a55456ec785d1b1" + "a3b2e1a58b5971ad0b67b8a2f43723b7" ], [ "Negotiation.string_of_option_extensions", @@ -244,7 +245,7 @@ "typing_Negotiation.find_client_extension" ], 0, - "a0f86924a640f930237084d2060776df" + "f2dc7b01a5544dbab4c376b8c0db6e22" ], [ "Negotiation.find_signature_algorithms", @@ -270,7 +271,7 @@ "typing_Negotiation.find_client_extension" ], 0, - "d9d9f922cbdabf8b89e0bb55b576d403" + "3b3ab9439e38098ee36c93d55b7ee69a" ], [ "Negotiation.find_signature_algorithms_cert", @@ -296,7 +297,7 @@ "typing_Negotiation.find_client_extension" ], 0, - "11650171bdb898f20dad7ab5777812ed" + "f047b0b0a27fd1e4919b2b82fbe40318" ], [ "Negotiation.find_cookie", @@ -322,7 +323,7 @@ "typing_Negotiation.find_client_extension" ], 0, - "77c94813dfcb26ed402ba85e79ed7357" + "56cd2238708c639c78951b44236446bc" ], [ "Negotiation.find_sessionTicket", @@ -348,7 +349,7 @@ "typing_Negotiation.find_client_extension" ], 0, - "c12fa412c9160562304d7eb84a8ced9a" + "0e01f383d09b0079c4ffc53ec7cafd5c" ], [ "Negotiation.find_clientPske", @@ -377,7 +378,7 @@ "typing_Negotiation.find_client_extension" ], 0, - "c03a0c8ee8203713267bae5ca2d9a519" + "d508064107ce15ff9dc14ceecad6686f" ], [ "Negotiation.find_serverPske", @@ -455,7 +456,7 @@ "typing_Negotiation.find_client_extension" ], 0, - "c72716f79f1d02f4ab550f3eeeea1f18" + "589312850958fb83c35697181366fe8b" ], [ "Negotiation.list_of_ClientKeyShare", @@ -519,7 +520,7 @@ "typing_Negotiation.find_client_extension" ], 0, - "a02232d9a6fe3797940aa69a9cdf55b5" + "00cfaf0f4449fc1587e8ba26a8f990dd" ], [ "Negotiation.__proj__Mode__item__n_hrr", diff --git a/src/tls/hints/Old.KeySchedule.fst.hints b/src/tls/hints/Old.KeySchedule.fst.hints index aa24af544..33e8556ae 100644 --- a/src/tls/hints/Old.KeySchedule.fst.hints +++ b/src/tls/hints/Old.KeySchedule.fst.hints @@ -22,10 +22,12 @@ 2, 1, [ - "@query", "equation_DebugFlags.debug", "equation_DebugFlags.debug_KS" + "@query", "equation_FStar.HyperStack.ST.equal_stack_domains", + "equation_FStar.Monotonic.Heap.equal_dom", + "lemma_FStar.HyperStack.ST.lemma_same_refs_in_stack_regions_intro" ], 0, - "8d68771e8f553adb6ed5b428cc36ed3f" + "5e16441bd47e4ad82c3c77beb28943cb" ] ] ] \ No newline at end of file diff --git a/src/tls/hints/Record.fst.hints b/src/tls/hints/Record.fst.hints index af5a1f3c4..9930f7d15 100644 --- a/src/tls/hints/Record.fst.hints +++ b/src/tls/hints/Record.fst.hints @@ -22,11 +22,12 @@ 2, 1, [ - "@query", "equation_DebugFlags.debug", - "equation_DebugFlags.debug_Record" + "@query", "equation_FStar.HyperStack.ST.equal_stack_domains", + "equation_FStar.Monotonic.Heap.equal_dom", + "lemma_FStar.HyperStack.ST.lemma_same_refs_in_stack_regions_intro" ], 0, - "bc206922c1a9324b4a8b18808e1685d1" + "9d1c7fd5c885a62647ea889bb99eba4e" ], [ "Record.p_of_f", diff --git a/src/tls/hints/StreamAE.fst.hints b/src/tls/hints/StreamAE.fst.hints old mode 100755 new mode 100644 diff --git a/src/tls/hints/TLS.fst.hints b/src/tls/hints/TLS.fst.hints index 7d15fa438..83338d3e8 100644 --- a/src/tls/hints/TLS.fst.hints +++ b/src/tls/hints/TLS.fst.hints @@ -22,11 +22,12 @@ 2, 1, [ - "@query", "equation_DebugFlags.debug", - "equation_DebugFlags.debug_TLS" + "@query", "equation_FStar.HyperStack.ST.equal_stack_domains", + "equation_FStar.Monotonic.Heap.equal_dom", + "lemma_FStar.HyperStack.ST.lemma_same_refs_in_stack_regions_intro" ], 0, - "aa524d0c268bc58a024bb43407b90fd5" + "62b4881a306fcc37e7823a8e855b0ac0" ] ] ] \ No newline at end of file diff --git a/src/tls/renamings.sh b/src/tls/renamings.sh old mode 100755 new mode 100644 diff --git a/tests/Tester/PerformanceTester-draftA3.pdf b/tests/Tester/PerformanceTester-draftA3.pdf new file mode 100644 index 000000000..b030eddaf Binary files /dev/null and b/tests/Tester/PerformanceTester-draftA3.pdf differ diff --git a/tests/Tester/Readme.md b/tests/Tester/Readme.md new file mode 100644 index 000000000..a7d9f83dc --- /dev/null +++ b/tests/Tester/Readme.md @@ -0,0 +1,50 @@ +

Building

+ +Until the tester is incorporated into the everest build system, it will require manual building. To build the tester, open the Tester.sln file, found in the root of the solution directory, with Visual Studio 2017. The solution requires three library files, libmitls.lib, libmipki.lib and libquiccrypo.lib which should all be present in the \Tester subdirectory. These libraries are built using the everest script:- + + ./everest -j XX -windows -opt make drop qbuild + +By default Visual studio will create the final executable in an "\X64\Debug" subdirectory in the solution. + +

Running

+ +To run the tester, there are a number of run-time dependencies:- + + 1) The tester expects to find the dll files, "libmitls.dll", "libmipki.dll", "libcrypto-1_1-x64.dll" and "libquiccrypto.dll" either in the "\Tester" subdirectory or in the path. + + 2) The certificate files should either be copied to the "\Tester" subdirectory or the tester can be invoked from the "everest\mitls-fstar\data" directory. Three certificate files are used by default, "CAFile.pem" is the certificate authority file. "server-ecdsa.crt" is the security certificate file and "server-ecdsa.key" is the certificate key file. + +Then type tester.exe to run the tester. + +When running Tester.exe with no arguments, it will generate the help text:- +
+           TLS/DTLS Tester
+            Version 0.0.2
+(c) Microsoft Research 21st August 2018
+
+Usage: Tester.exe [Arguments...]
+
+  -v              Be verbose in console output (otherwise no console output except errors)
+  -d              Turn on console debugging output
+  -f:filename     Use file to specify server names (otherwise tester uses google.com)
+  -c              Do libmitls as client TLS and DTLS tests
+  -s              Do libmitls as client & server TLS and DTLS tests
+  -i              Do libmitls as client interoperability TLS and DTLS tests
+  -x              Do libmitls as server interoperability TLS and DTLS tests
+  -t              Do TLS part of any tests
+  -q              Do QUIC part of any tests
+  -l:tlsversion   Specify TLS version number to support (default is '1.3')
+  -p:port number  Specify port number to use (default is 443)
+  -o:hostname     Specify host name to use (default is 'google.com')
+  -r:certfilename Use specified Server Certificate filename (default is 'server-ecdsa.crt')
+  -k:keyfilename  Use specified Server certificate key filename (default is 'server-ecdsa.key')
+  -a:authfilename Use specified Certificate Authority Chain filename (default is 'CAFile.pem')
+
+All the options except for "i", "-x" are currently supported. The Component DLL currently produces copious amounts of debug output, but this is gathered into a file. If you want to see this output then choose the "-v" flag which makes the tester more verbose. + +If no other arguments are given, the tester does not perform any tests. You have to enable the tests you want to run by using the "-c", "-s" and "-t" flags. There are no interoperability tests as yet, so the "i" and "-x" flags have no effect. + +The tester has a built in TLS Decoder which can be enabled with the "-d" flag. The QUIC tests do not currently run correcly. + +

Output

+The tester generates several output files in the "\Tester" directory but the main one is the "ComponentStatistics.csv" file which is a summary of the test results. More details of the measurements are stored in the "RecordedMeasurements.csv" file. The file whose name starts with "RedirectedStandardOutput" is the DLL debug output for the test run. diff --git a/tests/Tester/Tester.sln b/tests/Tester/Tester.sln new file mode 100644 index 000000000..48aaec7e1 --- /dev/null +++ b/tests/Tester/Tester.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2036 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tester", "Tester\Tester.vcxproj", "{CA0F3E1D-5DCD-4A24-A7E6-687502B7BE17}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3C16E5F0-3E50-4E4C-BB62-EF6AC2055A66}" + ProjectSection(SolutionItems) = preProject + ..\..\..\..\cygwin\home\caroline\everest\mitls-fstar\apps\cmitls\cmitls.c = ..\..\..\..\cygwin\home\caroline\everest\mitls-fstar\apps\cmitls\cmitls.c + Tester\ComponentStatistics.csv = Tester\ComponentStatistics.csv + Tester\ConsoleCopyFile.txt = Tester\ConsoleCopyFile.txt + Tester\everest_install_instructions.txt = Tester\everest_install_instructions.txt + Tester\hostfilelist.txt = Tester\hostfilelist.txt + ..\..\..\..\cygwin\home\caroline\everest\mitls-fstar\tests\bench\openssl-client.c = ..\..\..\..\cygwin\home\caroline\everest\mitls-fstar\tests\bench\openssl-client.c + ..\..\..\..\cygwin\home\caroline\everest\mitls-fstar\tests\bench\openssl-server.c = ..\..\..\..\cygwin\home\caroline\everest\mitls-fstar\tests\bench\openssl-server.c + ..\..\..\..\cygwin\home\caroline\everest\mitls-fstar\apps\QuicWin\QuicWin\QuicWin.cpp = ..\..\..\..\cygwin\home\caroline\everest\mitls-fstar\apps\QuicWin\QuicWin\QuicWin.cpp + Tester\RecordedMeasurements.csv = Tester\RecordedMeasurements.csv + Tester\test.png = Tester\test.png + Tester\TesterDebug.log = Tester\TesterDebug.log + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CA0F3E1D-5DCD-4A24-A7E6-687502B7BE17}.Debug|x64.ActiveCfg = Debug|x64 + {CA0F3E1D-5DCD-4A24-A7E6-687502B7BE17}.Debug|x64.Build.0 = Debug|x64 + {CA0F3E1D-5DCD-4A24-A7E6-687502B7BE17}.Debug|x86.ActiveCfg = Debug|x64 + {CA0F3E1D-5DCD-4A24-A7E6-687502B7BE17}.Debug|x86.Build.0 = Debug|x64 + {CA0F3E1D-5DCD-4A24-A7E6-687502B7BE17}.Release|x64.ActiveCfg = Release|x64 + {CA0F3E1D-5DCD-4A24-A7E6-687502B7BE17}.Release|x64.Build.0 = Release|x64 + {CA0F3E1D-5DCD-4A24-A7E6-687502B7BE17}.Release|x86.ActiveCfg = Release|Win32 + {CA0F3E1D-5DCD-4A24-A7E6-687502B7BE17}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D07A203A-3092-4BA9-873E-4C6DAAA6CB0E} + EndGlobalSection +EndGlobal diff --git a/tests/Tester/Tester/Component.cpp b/tests/Tester/Tester/Component.cpp new file mode 100644 index 000000000..a774401b7 --- /dev/null +++ b/tests/Tester/Tester/Component.cpp @@ -0,0 +1,2908 @@ + +//********************************************************************************************************************************** +// +// Purpose: Component, Library and Measurement implementation source code file +// +// Project: Everest +// +// Filename: Component.cpp +// +// Authors: Caroline.M.Mathieson (CMM) +// +//********************************************************************************************************************************** +// +// Description +// ----------- +// +//! \file Component.cpp +//! \brief Contains the complete implementation of the COMPONENT Object. +//! +//! The COMPONENT object encapsulates two dlls, the "libmitls.dll" which provides the TLS/QUIC handshake, and the "libmipki.dll" +//! which provides certificate handling. The two have to be used in conjunction and they communicate with each other. In fact these +//! two dlls require the presence of the libquiccrypto.dll as well. The performance of each DLL will impact the others, so each must +//! be instrumented and measured. In addition, each DLL uses callbacks and these callbacks must be instrumented and measured as well +//! to measure and eliminate the time spent in the tester code. +//! +//********************************************************************************************************************************** + +#include "Tester.h" // pulls in everything else + +//********************************************************************************************************************************** + +extern class TLSTESTER *Tester; // to give access to the component instance(s) for callbacks!! + +//********************************************************************************************************************************** + +static unsigned char LargeTransmitBuffer [ 65536 ]; // almost the maximum packet the network will transmit in one go +static unsigned char LargeReceiveBuffer [ 65536 ]; // almost the maximum packet the network will receive in one go + +static unsigned int LargeTransmitBufferReadIndex = 0; +static unsigned int LargeReceiveBufferReadIndex = 0; + +static int AmountTransmitted = 0; +static int AmountReceived = 0; + +static bool IncompleteTransmission = FALSE; +static bool IncompleteTransfer = FALSE; + +static unsigned int ExpectedRecordLength = 0; + +static TRANSFER_BUFFER SendBuffer; +static TRANSFER_BUFFER ReceiveBuffer; + +//********************************************************************************************************************************** + +const char *MeasurementTypeNames [] = // must be in the same order as the enumerated types +{ + "TLS Client Measurements", // TLS_CLIENT_MEASUREMENTS, + "QUIC Client Measurements", // QUIC_CLIENT_MEASUREMENTS, + "TLS Server Measurements", // TLS_SERVER_MEASUREMENTS, + "QUIC Server Measurements", // QUIC_SERVER_MEASUREMENTS, + "OPENSSL Server Measurements", // OPENSSL_SERVER_MEASUREMENTS, + "BORINGSSL Server Measurements", // BORINGSSL_SERVER_MEASUREMENTS, + "MBEDTLS Server Measurements", // MBEDTLS_SERVER_MEASUREMENTS, + "WOLFSSL Server Measurements", // WOLFSSL_SERVER_MEASUREMENTS, + "FIZZ Server Measurements", // FIZZ_SERVER_MEASUREMENTS, + "OPENSSL Client Measurements", // OPENSSL_CLIENT_MEASUREMENTS, + "BORINGSSL Client Measurements", // BORINGSSL_CLIENT_MEASUREMENTS, + "MBEDTLS Client Measurements", // MBEDTLS_CLIENT_MEASUREMENTS, + "WOLFSSL Client Measurements", // WOLFSSL_CLIENT_MEASUREMENTS, + "FIZZ Client Measurements", // FIZZ_CLIENT_MEASUREMENTS, +}; + +const char *FFIMeasurementEntryNames [ MAX_FFI_FUNCTIONS ] = // must be in the same order as the enumerated types +{ + // TLS API functions + + "FFI_mitls_init", // FFI_MITLS_INIT, + "FFI_mitls_configure", // FFI_MITLS_CONFIGURE, + "FFI_mitls_set_ticket_key", // FFI_MITLS_SET_TICKET_KEY, + "FFI_mitls_configure_ticket", // FFI_MITLS_CONFIGURE_TICKET + "FFI_mitls_configure_cipher_suites", // FFI_MITLS_CONFIGURE_CIPHER_SUITES, + "FFI_mitls_configure_signature_algorithms", // FFI_MITLS_CONFIGURE_SIGNATURE_ALGORITHMS, + "FFI_mitls_configure_named_groups", // FFI_MITLS_CONFIGURE_NAMED_GROUPS, + "FFI_mitls_configure_alpn", // FFI_MITLS_CONFIGURE_ALPN, + "FFI_mitls_configure_early_data", // FFI_MITLS_CONFIGURE_EARLY_DATA, + "FFI_mitls_configure_custom_extensions", // FFI_MITLS_CONFIGURE_CUSTOM_EXTENSIONS + "FFI_mitls_configure_ticket_callback", // FFI_MITLS_CONFIGURE_TICKET_CALLBACK, + "FFI_mitls_configure_nego_callback", // FFI_MITLS_CONFIGURE_NEGO_CALLBACK + "FFI_mitls_configure_cert_callbacks", // FFI_MITLS_CONFIGURE_CERT_CALLBACKS, + "FFI_mitls_close", // FFI_MITLS_CLOSE, + "FFI_mitls_connect", // FFI_MITLS_CONNECT, + "FFI_mitls_accept_connected", // FFI_MITLS_ACCEPT_CONNECTED, + "FFI_mitls_get_exporter", // FFI_MITLS_GET_EXPORTER, + "FFI_mitls_get_cert", // FFI_MITLS_GET_CERT, + "FFI_mitls_send", // FFI_MITLS_SEND, + "FFI_mitls_receive", // FFI_MITLS_RECEIVE, + "FFI_mitls_free", // FFI_MITLS_FREE, + "FFI_mitls_cleanup", // FFI_MITLS_CLEANUP, + "FFI_mitls_set_trace_callback", // FFI_MITLS_SET_TRACE_CALLBACK, + + // QUIC API functions + + "FFI_mitls_quic_create", // FFI_MITLS_QUIC_CREATE, + "FFI_mitls_quic_process", // FFI_MITLS_QUIC_PROCESS, + "FFI_mitls_quic_get_exporter", // FFI_MITLS_QUIC_GET_EXPORTER, + "FFI_mitls_quic_close", // FFI_MITLS_QUIC_CLOSE + "FFI_mitls_get_hello_summary", // FFI_MITLS_GET_HELLO_SUMMARY, + "FFI_mitls_find_custom_extension", // FFI_MITLS_FIND_CUSTOM_EXTENSION, + "FFI_mitls_global_free" // FFI_MITLS_GLOBAL_FREE, +}; + +const char *FFICallbackMeasurementEntryNames [ MAX_FFI_CALLBACK_FUNCTIONS ] = // must be in the same order as the enumerated types +{ + // TLS Callback functions + + "FFI_mitls_send_callback", // FFI_MITLS_SEND_CALLBACK + "FFI_mitls_receive_callback", // FFI_MITLS_RECEIVE_CALLBACK + + "FFI_mitls_certificate_select_callback", // FFI_MITLS_CERTIFICATE_SELECT_CALLBACK + "FFI_mitls_certificate_format_callback", // FFI_MITLS_CERTIFICATE_FORMAT_CALLBACK + "FFI_mitls_certificate_sign_callback", // FFI_MITLS_CERTIFICATE_SIGN_CALLBACK + "FFI_mitls_certificate_verify_callback", // FFI_MITLS_CERTIFICATE_VERIFY_CALLBACK + + "FFI_mitls_ticket_callback", // FFI_MITLS_TICKET_CALLBACK + "FFI_mitls_negotiation_callback", // FFI_MITLS_NEGOTIATION_CALLBACK + "FFI_mitls_trace_callback" // FFI_MITLS_TRACE_CALLBACK +}; + +const char *PKIMeasurementEntryNames [ MAX_PKI_FUNCTIONS ] = // must be in the same order as the enumerated types +{ + "mipki_init", // MIPKI_INIT, + "mipki_free", // MIPKI_FREE, + "mipki_add_root_file_or_path", // MIPKI_ADD_ROOT_FILE_OR_PATH, + "mipki_select_certificate", // MIPKI_SELECT_CERTIFICATE, + "mipki_sign_verify", // MIPKI_SIGN_VERFIY, + "mipki_parse_chain", // MIPKI_PARSE_CHAIN, + "mipki_parse_list", // MIPKI_PARSE_LIST, + "mipki_format_chain", // MIPKI_FORMAT_CHAIN, + "mipki_format_alloc", // MIPKI_FORMAT_ALLOC, + "mipki_validate_chain", // MIPKI_VALIDATE_CHAIN, + "mipki_free_chain" // MIPKI_FREE_CHAIN, +}; + +const char *PKICallbackMeasurementEntryNames [ MAX_PKI_CALLBACK_FUNCTIONS ] = // must be in the same order as the enumerated types +{ + "mipki_password_callback", // MIPKI_PASSWORD_CALLBACK + "mipki_alloc_callback" // MIPKI_ALLOC_CALLBACK +}; + +//********************************************************************************************************************************** +// +// Buffer Functions +// +//********************************************************************************************************************************** + +void BufferInitialise ( TRANSFER_BUFFER *TransferBuffer ) +{ +#ifdef WIN32 + InitializeCriticalSection ( &TransferBuffer->CriticalSection ); +#endif + memset ( TransferBuffer->Buffer, 0, TRANSFER_BUFFER_SIZE ); + + TransferBuffer->ReadPointer = TransferBuffer->Buffer; + TransferBuffer->WritePointer = TransferBuffer->Buffer; + + TransferBuffer->ReadIndex = 0; + TransferBuffer->WriteIndex = 0; + + TransferBuffer->TotalAmountWritten = 0; + TransferBuffer->TotalAmountRead = 0; +} + +//********************************************************************************************************************************** + +unsigned long BufferWrite ( TRANSFER_BUFFER *TransferBuffer, unsigned char *Buffer, unsigned long BufferSize ) +{ +#ifdef WIN32 + EnterCriticalSection ( &TransferBuffer->CriticalSection ); +#endif + // write the data into the buffer if there is room + + if ( ( TransferBuffer->WriteIndex + BufferSize ) < TRANSFER_BUFFER_SIZE ) + { + memcpy ( (void *) TransferBuffer->WritePointer, (const void *) Buffer, BufferSize ); + + DumpPacket ( Buffer, BufferSize, 0 , 0, "Buffer Write" ); + + TransferBuffer->WritePointer += BufferSize; + + TransferBuffer->WriteIndex += BufferSize; + + TransferBuffer->TotalAmountWritten += BufferSize; + } + else + { + fprintf ( stderr, "Transfer Buffer is full!\n" ); + + BufferSize = 0; + } + +#ifdef WIN32 + LeaveCriticalSection ( &TransferBuffer->CriticalSection ); +#endif + + return ( BufferSize ); +} + +//********************************************************************************************************************************** + +unsigned long BufferRead ( TRANSFER_BUFFER *TransferBuffer, unsigned char *Buffer, unsigned long BufferSize ) +{ + unsigned int AmountRead = 0; + + // make this a blocking call! + + do + { +#ifdef WIN32 + EnterCriticalSection ( &TransferBuffer->CriticalSection ); +#endif + if ( ( TransferBuffer->WriteIndex - TransferBuffer->ReadIndex ) >= BufferSize ) // is there enough data to read? + { + memcpy ( Buffer, TransferBuffer->ReadPointer, BufferSize ); + + DumpPacket ( Buffer, BufferSize, 0 , 0, "Buffer Read" ); + + TransferBuffer->ReadPointer += BufferSize; + + TransferBuffer->ReadIndex += BufferSize; + + TransferBuffer->TotalAmountRead += BufferSize; + + AmountRead = BufferSize; + + //// if the indices are now the same then reset them + // + //if ( TransferBuffer->WriteIndex == TransferBuffer->ReadIndex ) + //{ + // BufferReset ( TransferBuffer ); + //} + } + +#ifdef WIN32 + LeaveCriticalSection ( &TransferBuffer->CriticalSection ); +#endif + + } while ( AmountRead == 0 ); + + return ( AmountRead ); +} + +//********************************************************************************************************************************** + +void BufferReset ( TRANSFER_BUFFER *TransferBuffer ) +{ + TransferBuffer->WritePointer = TransferBuffer->Buffer; + TransferBuffer->ReadPointer = TransferBuffer->Buffer; + + TransferBuffer->WriteIndex = 0; + TransferBuffer->ReadIndex = 0; +} + +//********************************************************************************************************************************** +// +// FFI Callback Function wrappers +// +//********************************************************************************************************************************** + +CALLBACKMEASUREMENTENTRY *GetFFICallbackMeasurement ( unsigned int CallBackNumber, + COMPONENT **Component ) +{ + CALLBACKMEASUREMENTENTRY *FFICallbackMeasurement = NULL; + + DWORD CurrentThreadId = GetCurrentThreadId (); // which thread is running? + + if ( CurrentThreadId == Tester->ClientTLSTestsThreadIdentifier ) + { + FFICallbackMeasurement = &Tester-> + ClientComponent-> + MeasurementResultsArray [ Tester->ClientComponent->TestRunNumber ]-> + Measurements [ Tester->ClientComponent->MeasurementNumber ]. + FFICallbackMeasurements [ CallBackNumber ]; + + *Component = Tester->ClientComponent; + } + else + { + FFICallbackMeasurement = &Tester-> + ServerComponent-> + MeasurementResultsArray [ Tester->ServerComponent->TestRunNumber ]-> + Measurements [ Tester->ServerComponent->MeasurementNumber ]. + FFICallbackMeasurements [ CallBackNumber ]; + + *Component = Tester->ServerComponent; + } + + return ( FFICallbackMeasurement ); +} + +//********************************************************************************************************************************** + +CALLBACKMEASUREMENTENTRY *GetPKICallbackMeasurement ( unsigned int CallBackNumber, + COMPONENT **Component ) +{ + CALLBACKMEASUREMENTENTRY *PKICallbackMeasurement = NULL; + + DWORD CurrentThreadId = GetCurrentThreadId (); // which thread is running? + + if ( CurrentThreadId == Tester->ClientTLSTestsThreadIdentifier ) + { + PKICallbackMeasurement = &Tester-> + ClientComponent-> + MeasurementResultsArray [ Tester->ClientComponent->TestRunNumber ]-> + Measurements [ Tester->ClientComponent->MeasurementNumber ]. + PKICallbackMeasurements [ CallBackNumber ]; + + *Component = Tester->ClientComponent; + } + else + { + PKICallbackMeasurement = &Tester-> + ServerComponent-> + MeasurementResultsArray [ Tester->ServerComponent->TestRunNumber ]-> + Measurements [ Tester->ServerComponent->MeasurementNumber ]. + PKICallbackMeasurements [ CallBackNumber ]; + + *Component = Tester->ServerComponent; + } + + return ( PKICallbackMeasurement ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV ClientSendCallback ( void *Context, + const unsigned char *Buffer, + size_t BufferSize ) +{ + size_t AmountSent = 0; + COMPONENT *Component = ( COMPONENT * ) Context; + CALLBACKMEASUREMENTENTRY *FFICallbackMeasurement = NULL; + unsigned int CallCount = 0; + + FFICallbackMeasurement = GetFFICallbackMeasurement ( FFI_MITLS_SEND_CALLBACK, &Component ); + + CallCount = FFICallbackMeasurement->NumberOfCalls++; + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->StartTimes [ CallCount ] ); + } + + if ( Tester->ConsoleDebugging ) printf ( "Client Send callback function invoked for %zd octets!\n", BufferSize ); + + // The component sends the records in sections now (Aug 2018) so we have to send this right away + + if ( Tester->ServerTLSTestsThreadIdentifier != 0 ) // if we are running server tests then use buffers + { + AmountSent = BufferWrite ( &ReceiveBuffer, (unsigned char *) Buffer, BufferSize ); + } + else + { + AmountSent = send ( Component->Socket, (char * ) Buffer, (int) BufferSize, 0 ); + } + + // if console debugging is enabled then accumulate the network packets and then decode them + + if ( Tester->ConsoleDebugging ) + { + if ( AmountSent == 0 ) + { + printf ( "Socket Closed!\n" ); + } + else + { + // append to temporary decoder buffer + + memcpy ( (void *) &LargeTransmitBuffer [ LargeTransmitBufferReadIndex ], (const void *) Buffer, BufferSize ); + + LargeTransmitBufferReadIndex += BufferSize; + + AmountTransmitted += BufferSize; + + if ( IncompleteTransmission == FALSE ) + { + if ( AmountSent == 5 ) // just the header was sent first (API change August 2018) + { + // peek into message to get record length if its a TLS handshake record + + TLS_RECORD *TLSRecord = (TLS_RECORD *) Buffer; + + if ( TLSRecord->RecordHeader.ContentType == TLS_CT_HANDSHAKE ) + { + ExpectedRecordLength = ( TLSRecord->RecordHeader.ContentLengthHigh * 256 ) + TLSRecord->RecordHeader.ContentLengthLow; + + IncompleteTransmission = TRUE; // we will need to get the rest before decoding + } + else + { + if ( TLSRecord->RecordHeader.ContentType == TLS_CT_ALERT ) + { + DecodePacket ( (void *) LargeTransmitBuffer, BufferSize, "Packet sent to server" ); + + // reset decoder buffer as we know what this is + + LargeTransmitBufferReadIndex = 0; + + AmountTransmitted = 0; + } + } + } + } + else + { + // do we have enough to decode it yet? + + if ( AmountTransmitted >= ExpectedRecordLength ) + { + DecodePacket ( (void *) LargeTransmitBuffer, BufferSize, "Packet sent to server" ); + + // reset decoder buffer + + LargeTransmitBufferReadIndex = 0; + + AmountTransmitted = 0; + + ExpectedRecordLength = 0; + + IncompleteTransmission = FALSE; + } + } + } + + } // if ConsoleDebugging + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->EndTimes [ CallCount ] ); + } + + return ( (int) AmountSent ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV ServerSendCallback ( void *Context, + const unsigned char *Buffer, + size_t BufferSize ) +{ + size_t AmountSent = 0; + COMPONENT *Component = ( COMPONENT * ) Context; + CALLBACKMEASUREMENTENTRY *FFICallbackMeasurement = NULL; + unsigned int CallCount = 0; + + FFICallbackMeasurement = GetFFICallbackMeasurement ( FFI_MITLS_SEND_CALLBACK, &Component ); + + CallCount = FFICallbackMeasurement->NumberOfCalls++; + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->StartTimes [ CallCount ] ); + } + + if ( Tester->ConsoleDebugging ) printf ( "Server Send callback function invoked for %zd octets!\n", BufferSize ); + + // copy the record into the send buffer if there is room + + AmountSent = BufferWrite ( &SendBuffer, (unsigned char *) Buffer, BufferSize ); + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->EndTimes [ CallCount ] ); + } + + return ( AmountSent ); +} + +//********************************************************************************************************************************** +// PROBLEM: MITLS requests data from the server in sections. It reads the header first and then depending on the fragment length, +// reads that fragment. However this makes debugging very difficult as the whole record is needed for this. The solution +// is to read the complete response from the peer and then return it bit by bit as requested by MITLS. So the call back +// function will read the data from a local buffer rather than from the network buffer. +// + +int MITLS_CALLCONV ClientReceiveCallback ( void *Context, + unsigned char *Buffer, + size_t BufferSize ) +{ + size_t AmountTransferred = 0; + size_t AmountRemaining = 0; + COMPONENT *Component = ( COMPONENT * ) Context; + CALLBACKMEASUREMENTENTRY *FFICallbackMeasurement = NULL; + unsigned int CallCount = 0; + + FFICallbackMeasurement = GetFFICallbackMeasurement ( FFI_MITLS_RECEIVE_CALLBACK, &Component ); + + CallCount = FFICallbackMeasurement->NumberOfCalls++; + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->StartTimes [ CallCount ] ); + } + + // if console debugging is enabled then we need to buffer the network packet to decode it and return only the requested amount. + + if ( Tester->ConsoleDebugging ) + { + printf ( "Client Receive callback function invoked (with room for %zu octets)!\n", BufferSize ); + + // yes, so did the previous call result in an incomplete transfer? + + if ( IncompleteTransfer == FALSE ) + { + // No, so get as much as the network will provide + + LargeReceiveBufferReadIndex = 0; + + AmountReceived = recv ( Component->Socket, (char * ) LargeReceiveBuffer, sizeof ( LargeReceiveBuffer ), 0 ); + + if ( AmountReceived > 0 ) + { + IncompleteTransfer = TRUE; + + // we only decode the packet the first time round and if console debuggin is enabled! + + DecodePacket ( (void *) LargeReceiveBuffer, AmountReceived, "Packet received from server" ); + } + } + + // webservers such as bing.com will go mute when you specify a valid but old cipher suite in the clienthello which means that + // the call to recv() will timeout and an error returned such as "connection reset by peer". So we have to test for this but we + // also need to indicate back to the component that it has happened, so that it finishes the ffi_mitls_connect() call. + + if ( AmountReceived == -1 ) + { + PrintSocketError (); + + return ( AmountReceived ); // let libmitls.dll know what has happened + } + + if ( AmountReceived == 0 ) + { + printf ( "Socket Closed!\n" ); + + IncompleteTransfer = FALSE; + } + else + { + AmountRemaining = AmountReceived - LargeReceiveBufferReadIndex; + + if ( AmountRemaining > BufferSize ) + { + memcpy ( Buffer, &LargeReceiveBuffer [ LargeReceiveBufferReadIndex ], BufferSize ); + + AmountTransferred = BufferSize; + + IncompleteTransfer = TRUE; // still more left so still incomplete + } + else + { + memcpy ( Buffer, &LargeReceiveBuffer [ LargeReceiveBufferReadIndex ], AmountRemaining ); + + AmountTransferred = AmountRemaining; + + IncompleteTransfer = FALSE; // no more left now so transfer complete + } + + LargeReceiveBufferReadIndex += AmountTransferred; + } + } + else + { + // no, so just return the amount requested from the network + + if ( Tester->ServerTLSTestsThreadIdentifier != 0 ) // if we are running server tests then use buffers + { + // read from the send buffer + + AmountTransferred = BufferRead ( &SendBuffer, Buffer, BufferSize ); + } + else + { + // read from the network socket + + AmountTransferred = recv ( Component->Socket, (char * ) Buffer, BufferSize, 0 ); + } + } + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->EndTimes [ CallCount ] ); + } + + return ( AmountTransferred ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV ServerReceiveCallback ( void *Context, + unsigned char *Buffer, + size_t BufferSize ) +{ + size_t AmountTransferred = 0; + size_t AmountRemaining = 0; + COMPONENT *Component = ( COMPONENT * ) Context; + CALLBACKMEASUREMENTENTRY *FFICallbackMeasurement = NULL; + unsigned int CallCount = 0; + + FFICallbackMeasurement = GetFFICallbackMeasurement ( FFI_MITLS_RECEIVE_CALLBACK, &Component ); + + CallCount = FFICallbackMeasurement->NumberOfCalls++; + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->StartTimes [ CallCount ] ); + } + + if ( Tester->ConsoleDebugging ) + { + printf ( "Server Receive callback function invoked (with room for %zu octets)!\n", BufferSize ); + } + + // intended behaviour is that this should be blocking + + do + { + AmountTransferred = BufferRead ( &ReceiveBuffer, (unsigned char *) Buffer, BufferSize ); + + } while ( AmountTransferred == 0 ); + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->EndTimes [ CallCount ] ); + } + + return ( AmountTransferred ); +} + +//********************************************************************************************************************************** + +void MITLS_CALLCONV TicketCallback ( void *cb_state, + const char *sni, + const mitls_ticket *ticket ) +{ + COMPONENT *Component = NULL; + CALLBACKMEASUREMENTENTRY *FFICallbackMeasurement = NULL; + unsigned int CallCount = 0; + + FFICallbackMeasurement = GetFFICallbackMeasurement ( FFI_MITLS_TICKET_CALLBACK, &Component ); + + CallCount = FFICallbackMeasurement->NumberOfCalls++; + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->StartTimes [ CallCount ] ); + } + + printf ( "Ticket callback function invoked!\n" ); + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->EndTimes [ CallCount ] ); + } +} + +//********************************************************************************************************************************** + +mitls_nego_action MITLS_CALLCONV NegotiationCallback ( void *cb_state, + mitls_version ver, + const unsigned char *exts, + size_t exts_len, + mitls_extension **custom_exts, + size_t *custom_exts_len, + unsigned char **cookie, + size_t *cookie_len ) +{ + COMPONENT *Component = NULL; // the component using this dll and callback + CALLBACKMEASUREMENTENTRY *FFICallbackMeasurement = NULL; + unsigned int CallCount = 0; + //unsigned char *TransportParameters = NULL; + //unsigned long TransportParametersLength = 0; + //unsigned int Result = 0; + + FFICallbackMeasurement = GetFFICallbackMeasurement ( FFI_MITLS_NEGOTIATION_CALLBACK, &Component ); + + CallCount = FFICallbackMeasurement->NumberOfCalls++; + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->StartTimes [ CallCount ] ); + } + + printf ( "Negotiation callback function invoked!\n" ); + + // check first if there was an extension for QUIC transport parameters even if this was not a QUIC test + + // Result = Component->FindCustomExtension ( 1, exts, exts_len, TLS_ET_QUIC_TRANSPORT_PARAMETERS, &TransportParameters, &TransportParametersLength ); + + *custom_exts_len = 0; *custom_exts = NULL; + + *cookie = ( unsigned char * ) "Hello TLS World"; *cookie_len = 15; + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->EndTimes [ CallCount ] ); + } + + return ( TLS_nego_accept ); +} + +//********************************************************************************************************************************** + +void MITLS_CALLCONV TraceCallback ( const char *msg ) +{ + DWORD CurrentThreadId = GetCurrentThreadId (); // which thread is running? + + if ( CurrentThreadId == Tester->ClientTLSTestsThreadIdentifier ) + { + printf ( ASES_SET_FOREGROUND_YELLOW "Client Traced: %s" ASES_SET_FOREGROUND_BLACK, msg ); + } + else + { + printf ( ASES_SET_FOREGROUND_YELLOW "Server Traced: %s" ASES_SET_FOREGROUND_BLACK, msg ); + } +} + +//********************************************************************************************************************************** + +void *MITLS_CALLCONV CertificateSelectCallback ( void *State, + mitls_version TLSVersion, // not used below + const unsigned char *ServerNameIndicator, + size_t ServerNameIndicatorLength, + const unsigned char *ApplicationLevelProtocolName, // not used below + size_t ApplicationLevelProtocolNameLength, // not used below + const mitls_signature_scheme *SignatureAlgorithms, + size_t SignatureAlgorithmsLength, + mitls_signature_scheme *SelectedSignature ) +{ + COMPONENT *Component = NULL; // the component using this dll and callback + CALLBACKMEASUREMENTENTRY *FFICallbackMeasurement = NULL; + unsigned int CallCount = 0; + + FFICallbackMeasurement = GetFFICallbackMeasurement ( FFI_MITLS_CERTIFICATE_SELECT_CALLBACK, &Component ); + + CallCount = FFICallbackMeasurement->NumberOfCalls++; + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->StartTimes [ CallCount ] ); + } + + printf ( "Certificate Select Callback function invoked!\n" ); + + mipki_chain Chain = Component->SelectCertificate ( (mipki_state *) State, + ServerNameIndicator, + ServerNameIndicatorLength, + SignatureAlgorithms, + SignatureAlgorithmsLength, + SelectedSignature ); + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->EndTimes [ CallCount ] ); + } + + return ( (void *) Chain ); +} + +//********************************************************************************************************************************** + +size_t MITLS_CALLCONV CertificateFormatCallback ( void *State, + const void *ChainOfTrust, + unsigned char ChainBuffer [ MAX_CHAIN_LEN ] ) +{ + COMPONENT *Component = NULL; // the component using this dll and callback + CALLBACKMEASUREMENTENTRY *FFICallbackMeasurement = NULL; + unsigned int CallCount = 0; + + FFICallbackMeasurement = GetFFICallbackMeasurement ( FFI_MITLS_CERTIFICATE_FORMAT_CALLBACK, &Component ); + + CallCount = FFICallbackMeasurement->NumberOfCalls++; + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->StartTimes [ CallCount ] ); + } + + printf ( "Certificate Format Callback function invoked!\n" ); + + size_t Result = Component->FormatChain ( (mipki_state *) State, + (mipki_chain) ChainOfTrust, + ChainBuffer, + MAX_CHAIN_LEN ); + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->EndTimes [ CallCount ] ); + } + + return ( Result ); +} + +//********************************************************************************************************************************** + +size_t MITLS_CALLCONV CertificateSignCallback ( void *State, + const void *CertificatePointer, + const mitls_signature_scheme SignatureAlgorithm, + const unsigned char *Certificate, + size_t CertificateLength, + unsigned char *Signature ) +{ + COMPONENT *Component = NULL; // the component using this dll and callback + CALLBACKMEASUREMENTENTRY *FFICallbackMeasurement = NULL; + unsigned int CallCount = 0; + size_t VerifiedSignatureLength = MAX_SIGNATURE_LEN; // signal the maximum before signing (was 0) + + FFICallbackMeasurement = GetFFICallbackMeasurement ( FFI_MITLS_CERTIFICATE_SIGN_CALLBACK, &Component ); + + CallCount = FFICallbackMeasurement->NumberOfCalls++; + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->StartTimes [ CallCount ] ); + } + + printf ( "Certificate Sign Callback function invoked!\n" ); + + int Result = Component->SignCertificate ( (mipki_state *) State, + CertificatePointer, + SignatureAlgorithm, + (const char *) Certificate, + CertificateLength, + (char *) Signature, + &VerifiedSignatureLength ); + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->EndTimes [ CallCount ] ); + } + + return ( VerifiedSignatureLength ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV CertificateVerifyCallback ( void *State, + const unsigned char *ChainOfTrust, // the certificate chain of trust + size_t ChainLength, // how many entries are in the chain + const mitls_signature_scheme SignatureAlgorithm, // what signature algorithm was used to sign it + const unsigned char *Certificate, // the certificate to be verified (tbs) + size_t CertificateLength, // how long it is in octets + const unsigned char *Signature, // the signature + size_t SignatureLength ) // how long the signature is in octets +{ + COMPONENT *Component = NULL; // the component using this dll and callback + CALLBACKMEASUREMENTENTRY *FFICallbackMeasurement = NULL; + unsigned int CallCount = 0; + int Result = 0; + size_t VerifiedSignatureLength = SignatureLength; + + FFICallbackMeasurement = GetFFICallbackMeasurement ( FFI_MITLS_CERTIFICATE_VERIFY_CALLBACK, &Component ); + + CallCount = FFICallbackMeasurement->NumberOfCalls++; + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->StartTimes [ CallCount ] ); + } + + if ( Tester->ConsoleDebugging ) printf ( "Certificate Verify Callback function invoked!\n" ); + + //bool Supported = FALSE; + // + //const char *SignatureAlgorithmName = LookupSignatureAlgorithm ( SignatureAlgorithm, &Supported ); + // + //printf ( " State = 0x%08X\n", State ); + //printf ( " ChainOfTrust = 0x%08X\n", ChainOfTrust ); + //printf ( " ChainLength = %zd octets\n", ChainLength ); + // + //printf ( "SignatureAlgorithm = 0x%04X (%s), Supported = %d\n", SignatureAlgorithm, SignatureAlgorithmName, Supported ); + // + //printf ( " Certificate = 0x%08X\n", Certificate ); + //printf ( " CertificateLength = %zd octets\n", CertificateLength ); + //printf ( " Signature = 0x%08X\n", Signature ); + //printf ( " SignatureLength = %zd octets\n", SignatureLength ); + + // verification requires us to first parse the chain of trust. If all is well, then we use the library to verify the certificate + // which is why there are so many parameters to this callback + + int ChainNumber = Component->ParseChain ( (mipki_state *) State, (const char *) ChainOfTrust, ChainLength ); + + if ( Component->CertificateChains [ ChainNumber ] != NULL ) + { + Result = Component->ValidateChain ( Component->CertificateChains [ ChainNumber ] ); + + if ( ! Result ) + { + if ( Tester->ConsoleDebugging ) + { + if ( Tester->ConsoleDebugging ) printf ( "Chain Validation failed!\n" ); // comment on result but otherwise ignore it + } + } + + Result = Component->VerifyCertificate ( (mipki_state *) State, + Component->CertificateChains [ ChainNumber ], + SignatureAlgorithm, + (const char *) Certificate, + CertificateLength, + (char *) Signature, + &VerifiedSignatureLength ); + + if ( ! Result ) + { + if ( Tester->ConsoleDebugging ) printf ( "Certificate Verification failed!\n" ); + } + + // free the chain as we no longer need it + + Component->FreeChain ( Component->CertificateChains [ ChainNumber ] ); + + Component->CertificateChains [ ChainNumber ] = NULL; + } + else + { + if ( Tester->ConsoleDebugging ) printf ( "Certificate Chain Parsing failed!\n" ); + } + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &FFICallbackMeasurement->EndTimes [ CallCount ] ); + } + + return ( Result ); +} + +//********************************************************************************************************************************** +// +// PKI Callback Function wrappers +// +//********************************************************************************************************************************** + +int MITLS_CALLCONV CertificatePasswordCallback ( char *password, + int max_size, + const char *key_file ) +{ + CALLBACKMEASUREMENTENTRY *PKICallbackMeasurement = NULL; + unsigned int CallCount = 0; + + PKICallbackMeasurement = &Tester->ClientComponent->MeasurementResultsArray [ Tester->ClientComponent->TestRunNumber ]->Measurements [ Tester->ClientComponent->MeasurementNumber ].PKICallbackMeasurements [ MIPKI_PASSWORD_CALLBACK ]; + + CallCount = PKICallbackMeasurement->NumberOfCalls++; + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &PKICallbackMeasurement->StartTimes [ CallCount ] ); + } + + printf ( "Certificate Password Callback function invoked!\n" ); + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &PKICallbackMeasurement->EndTimes [ CallCount ] ); + } + + return ( 0 ); +} + +//********************************************************************************************************************************** + +void *MITLS_CALLCONV CertificateAllocationCallback ( void *cur, + size_t len, + char **buf ) +{ + CALLBACKMEASUREMENTENTRY *PKICallbackMeasurement = NULL; + unsigned int CallCount = 0; + + PKICallbackMeasurement = &Tester->ClientComponent->MeasurementResultsArray [ Tester->ClientComponent->TestRunNumber ]->Measurements [ Tester->ClientComponent->MeasurementNumber ].PKICallbackMeasurements [ MIPKI_ALLOC_CALLBACK ]; + + CallCount = PKICallbackMeasurement->NumberOfCalls++; + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &PKICallbackMeasurement->StartTimes [ CallCount ] ); + } + + printf ( "Certificate Allocation Callback function invoked!\n" ); + + if ( CallCount < MAX_CALLBACK_CALLS_PER_MEASUREMENT ) + { + QueryPerformanceCounter ( &PKICallbackMeasurement->EndTimes [ CallCount ] ); + } + + return ( NULL ); +} + +//********************************************************************************************************************************** +// +// Measurement Methods +// +//********************************************************************************************************************************** + +void COMPONENT::InitialiseMeasurementResults ( void ) +{ + int TestRunNumber = 0; + MEASUREMENTRESULTS *MeasurementResult = NULL; + + // initialise all array entries to unallocated + + for ( TestRunNumber = 0; TestRunNumber < MAX_MEASUREMENT_TYPES; TestRunNumber++ ) + { + MeasurementResultsArray [ TestRunNumber ] = NULL; + } + + // Then allocate the measurement results arrays for the selected measurements + + if ( Tester->DoClientTests ) + { + if ( Tester->DoTLSTests ) AllocateMeasurementResult ( TLS_CLIENT_MEASUREMENTS ); + if ( Tester->DoQUICTests ) AllocateMeasurementResult ( QUIC_CLIENT_MEASUREMENTS ); + } + + if ( Tester->DoServerTests ) + { + if ( Tester->DoTLSTests ) AllocateMeasurementResult ( TLS_SERVER_MEASUREMENTS ); + if ( Tester->DoQUICTests ) AllocateMeasurementResult ( QUIC_SERVER_MEASUREMENTS ); + } + + if ( Tester->DoServerInteroperabilityTests ) + { + AllocateMeasurementResult ( OPENSSL_SERVER_MEASUREMENTS ); + AllocateMeasurementResult ( BORINGSSL_SERVER_MEASUREMENTS ); + AllocateMeasurementResult ( MBEDTLS_SERVER_MEASUREMENTS ); + AllocateMeasurementResult ( WOLFSSL_SERVER_MEASUREMENTS ); + AllocateMeasurementResult ( FIZZ_SERVER_MEASUREMENTS ); + } + + if ( Tester->DoClientInteroperabilityTests ) + { + AllocateMeasurementResult ( OPENSSL_CLIENT_MEASUREMENTS ); + AllocateMeasurementResult ( BORINGSSL_CLIENT_MEASUREMENTS ); + AllocateMeasurementResult ( MBEDTLS_CLIENT_MEASUREMENTS ); + AllocateMeasurementResult ( WOLFSSL_CLIENT_MEASUREMENTS ); + AllocateMeasurementResult ( FIZZ_CLIENT_MEASUREMENTS ); + } + + // finally, initialise the allocated measurement results arrays + + for ( TestRunNumber = 0; TestRunNumber < MAX_MEASUREMENT_TYPES; TestRunNumber++ ) + { + if ( MeasurementResultsArray [ TestRunNumber ] != NULL ) // was memory allocated for this measurement? + { + MeasurementResult = MeasurementResultsArray [ TestRunNumber ]; + + MeasurementResult->MeasurementTypeName = MeasurementTypeNames [ TestRunNumber ]; + + InitialiseMeasurementResult ( MeasurementResult ); + } + } +} + +//********************************************************************************************************************************** + +void COMPONENT::AllocateMeasurementResult ( int TestRunNumber ) +{ + MeasurementResultsArray [ TestRunNumber ] = ( MEASUREMENTRESULTS * ) malloc ( sizeof ( MEASUREMENTRESULTS ) ); + + if ( MeasurementResultsArray [ TestRunNumber ] == NULL ) + { + printf ( "Could not allocate memory for measurement type %d. This is a FATAL error!\n", TestRunNumber ); + + exit ( EXIT_FAILURE ); + } +} + +//********************************************************************************************************************************** + +void COMPONENT::FreeMeasurementResults ( void ) +{ + int TestRunNumber = 0; + + for ( TestRunNumber = 0; TestRunNumber < MAX_MEASUREMENT_TYPES; TestRunNumber++ ) + { + if ( MeasurementResultsArray [ TestRunNumber ] != NULL ) // was memory allocated for this measurement? + { + // if so then free it + + free ( MeasurementResultsArray [ TestRunNumber ] ); + + MeasurementResultsArray [ TestRunNumber ] = NULL; + } + } +} + +//********************************************************************************************************************************** + +void COMPONENT::InitialiseMeasurementResult ( MEASUREMENTRESULTS *MeasurementResult ) +{ + COMPONENTMEASUREMENTENTRY *ComponentMeasurementEntry = NULL; + CALLBACKMEASUREMENTENTRY *CallbackMeasurementEntry = NULL; + COMPONENTMEASUREMENT *ComponentMeasurement = NULL; + + MeasurementResult->TestRunStartTime.QuadPart = 0; + MeasurementResult->TestRunEndTime.QuadPart = 0; + + for ( int MeasurementNumber = 0; MeasurementNumber < MAX_MEASUREMENTS; MeasurementNumber++ ) + { + ComponentMeasurement = &MeasurementResult->Measurements [ MeasurementNumber ]; + + ComponentMeasurement->MeasurementStartTime.QuadPart = 0; + ComponentMeasurement->MeasurementEndTime.QuadPart = 0; + + //*********************** + // Component measurements + //*********************** + + for ( int FunctionIndex = 0; FunctionIndex < MAX_FFI_FUNCTIONS; FunctionIndex++ ) + { + ComponentMeasurementEntry = &ComponentMeasurement->FFIMeasurements [ FunctionIndex ]; + + ComponentMeasurementEntry->EntryName = FFIMeasurementEntryNames [ FunctionIndex ]; + + ComponentMeasurementEntry->NumberOfCalls = 0; + + for ( int CallIndex = 0; CallIndex < MAX_COMPONENT_CALLS_PER_MEASUREMENT; CallIndex++ ) + { + ComponentMeasurementEntry->StartTimes [ CallIndex ].QuadPart = 0; + ComponentMeasurementEntry->EndTimes [ CallIndex ].QuadPart = 0; + } + } + + for ( int FunctionIndex = 0; FunctionIndex < MAX_PKI_FUNCTIONS; FunctionIndex++ ) + { + ComponentMeasurementEntry = &ComponentMeasurement->PKIMeasurements [ FunctionIndex ]; + + ComponentMeasurementEntry->EntryName = PKIMeasurementEntryNames [ FunctionIndex ]; + + ComponentMeasurementEntry->NumberOfCalls = 0; + + for ( int CallIndex = 0; CallIndex < MAX_COMPONENT_CALLS_PER_MEASUREMENT; CallIndex++ ) + { + ComponentMeasurementEntry->StartTimes [ CallIndex ].QuadPart = 0; + ComponentMeasurementEntry->EndTimes [ CallIndex ].QuadPart = 0; + } + } + + //********************* + // Library measurements + //********************* + + for ( int FunctionIndex = 0; FunctionIndex < MAX_FFI_CALLBACK_FUNCTIONS; FunctionIndex++ ) + { + CallbackMeasurementEntry = &ComponentMeasurement->FFICallbackMeasurements [ FunctionIndex ]; + + CallbackMeasurementEntry->EntryName = FFICallbackMeasurementEntryNames [ FunctionIndex ]; + + CallbackMeasurementEntry->NumberOfCalls = 0; + + for ( int CallIndex = 0; CallIndex < MAX_CALLBACK_CALLS_PER_MEASUREMENT; CallIndex++ ) + { + CallbackMeasurementEntry->StartTimes [ CallIndex ].QuadPart = 0; + CallbackMeasurementEntry->EndTimes [ CallIndex ].QuadPart = 0; + } + } + + for ( int FunctionIndex = 0; FunctionIndex < MAX_PKI_CALLBACK_FUNCTIONS; FunctionIndex++ ) + { + CallbackMeasurementEntry = &ComponentMeasurement->PKICallbackMeasurements [ FunctionIndex ]; + + CallbackMeasurementEntry->EntryName = PKICallbackMeasurementEntryNames [ FunctionIndex ]; + + CallbackMeasurementEntry->NumberOfCalls = 0; + + for ( int CallIndex = 0; CallIndex < MAX_CALLBACK_CALLS_PER_MEASUREMENT; CallIndex++ ) + { + CallbackMeasurementEntry->StartTimes [ CallIndex ].QuadPart = 0; + CallbackMeasurementEntry->EndTimes [ CallIndex ].QuadPart = 0; + } + } + } +} + +//********************************************************************************************************************************** + +void COMPONENT::PrintMeasurementResults ( FILE *MeasurementsResultFile ) +{ + MEASUREMENTRESULTS *MeasurementResult = NULL; + + // write the measurements to the recorded measurements file + + for ( int TestRunNumber = 0; TestRunNumber < MAX_MEASUREMENT_TYPES; TestRunNumber++ ) + { + MeasurementResult = MeasurementResultsArray [ TestRunNumber ]; + + // only print out the test runs which were actually recorded + + if ( MeasurementResult != NULL ) // was memory allocated? + { + if ( MeasurementResult->TestRunStartTime.QuadPart != 0 ) // did the measurement take place? + { + PrintMeasurementResult ( MeasurementsResultFile, MeasurementResult ); + } + } + } + + PrintMeasurementSummary ( IsServer ); +} + +//********************************************************************************************************************************** + +void COMPONENT::PrintMeasurementResult ( FILE *MeasurementsResultFile, + MEASUREMENTRESULTS *MeasurementResult ) +{ + COMPONENTMEASUREMENTENTRY *ComponentMeasurementEntry = NULL; + CALLBACKMEASUREMENTENTRY *CallbackMeasurementEntry = NULL; + COMPONENTMEASUREMENT *ComponentMeasurement = NULL; + + fprintf ( MeasurementsResultFile, "\n" ); + + fprintf ( MeasurementsResultFile, "Test Run Type Type = %s\n", MeasurementResult->MeasurementTypeName ); + + fprintf ( MeasurementsResultFile, "Test Run StartTime = %I64u\n", MeasurementResult->TestRunStartTime.QuadPart ); + + fprintf ( MeasurementsResultFile, "Test Run EndTime = %I64u\n", MeasurementResult->TestRunEndTime.QuadPart ); + + for ( int MeasurementNumber = 0; MeasurementNumber < MAX_MEASUREMENTS; MeasurementNumber++ ) + { + ComponentMeasurement = &MeasurementResult->Measurements [ MeasurementNumber ]; + + // only print out the measurements which were actually recorded + + if ( ComponentMeasurement->MeasurementStartTime.QuadPart == 0 ) break; + + fprintf ( MeasurementsResultFile, "\nMeasurement Results Entry [ %d ]\n\n", MeasurementNumber ); + + fprintf ( MeasurementsResultFile, "Measurement Start Time = %I64u\n", ComponentMeasurement->MeasurementStartTime.QuadPart ); + fprintf ( MeasurementsResultFile, "Measurement End Time = %I64u\n", ComponentMeasurement->MeasurementEndTime.QuadPart ); + + //*********************** + // Component measurements + //*********************** + + for ( int FunctionIndex = 0; FunctionIndex < MAX_FFI_FUNCTIONS; FunctionIndex++ ) + { + ComponentMeasurementEntry = &ComponentMeasurement->FFIMeasurements [ FunctionIndex ]; + + // only print out the component measurements recorded + + if ( ComponentMeasurementEntry->NumberOfCalls > 0 ) + { + fprintf ( MeasurementsResultFile, " FFI Function Name = %s\n", ComponentMeasurementEntry->EntryName ); + + fprintf ( MeasurementsResultFile, " Number Of Calls = %u\n", ComponentMeasurementEntry->NumberOfCalls ); + + for ( int CallIndex = 0; CallIndex < ComponentMeasurementEntry->NumberOfCalls; CallIndex++ ) + { + fprintf ( MeasurementsResultFile, " Measurement Start Time [%03d] = %I64u\n", CallIndex, ComponentMeasurementEntry->StartTimes [ CallIndex ].QuadPart ); + fprintf ( MeasurementsResultFile, " Measurement End Time [%03d] = %I64u\n", CallIndex, ComponentMeasurementEntry->EndTimes [ CallIndex ].QuadPart ); + } + } + } + + for ( int FunctionIndex = 0; FunctionIndex < MAX_FFI_CALLBACK_FUNCTIONS; FunctionIndex++ ) + { + CallbackMeasurementEntry = &ComponentMeasurement->FFICallbackMeasurements [ FunctionIndex ]; + + // only print out the component callback measurements recorded + + if ( CallbackMeasurementEntry->NumberOfCalls > 0 ) + { + fprintf ( MeasurementsResultFile, " FFI Callback Name = %s\n", CallbackMeasurementEntry->EntryName ); + + fprintf ( MeasurementsResultFile, " Number Of Calls = %u\n", CallbackMeasurementEntry->NumberOfCalls ); + + for ( int CallIndex = 0; CallIndex < CallbackMeasurementEntry->NumberOfCalls; CallIndex++ ) + { + fprintf ( MeasurementsResultFile, " Measurement Start Time [%03d] = %I64u\n", CallIndex, CallbackMeasurementEntry->StartTimes [ CallIndex ].QuadPart ); + fprintf ( MeasurementsResultFile, " Measurement End Time [%03d] = %I64u\n", CallIndex, CallbackMeasurementEntry->EndTimes [ CallIndex ].QuadPart ); + } + } + } + + //********************* + // Library measurements + //********************* + + for ( int FunctionIndex = 0; FunctionIndex < MAX_PKI_FUNCTIONS; FunctionIndex++ ) + { + ComponentMeasurementEntry = &ComponentMeasurement->PKIMeasurements [ FunctionIndex ]; + + // only print the library measurements recorded + + if ( ComponentMeasurementEntry->NumberOfCalls > 0 ) + { + fprintf ( MeasurementsResultFile, " PKI Function Name = %s\n", ComponentMeasurementEntry->EntryName ); + + fprintf ( MeasurementsResultFile, " Number Of Calls = %u\n", ComponentMeasurementEntry->NumberOfCalls ); + + for ( int CallIndex = 0; CallIndex < ComponentMeasurementEntry->NumberOfCalls; CallIndex++ ) + { + fprintf ( MeasurementsResultFile, " Measurement Start Time [%03d] = %I64u\n", CallIndex, ComponentMeasurementEntry->StartTimes [ CallIndex ].QuadPart ); + fprintf ( MeasurementsResultFile, " Measurement End Time [%03d] = %I64u\n", CallIndex, ComponentMeasurementEntry->EndTimes [ CallIndex ].QuadPart ); + } + } + } + + for ( int FunctionIndex = 0; FunctionIndex < MAX_PKI_CALLBACK_FUNCTIONS; FunctionIndex++ ) + { + CallbackMeasurementEntry = &ComponentMeasurement->PKICallbackMeasurements [ FunctionIndex ]; + + // only print the library callback measurements recorded + + if ( CallbackMeasurementEntry->NumberOfCalls > 0 ) + { + fprintf ( MeasurementsResultFile, " PKI Callback Name = %s\n", CallbackMeasurementEntry->EntryName ); + + fprintf ( MeasurementsResultFile, " Number Of Calls = %u\n", CallbackMeasurementEntry->NumberOfCalls ); + + for ( int CallIndex = 0; CallIndex < CallbackMeasurementEntry->NumberOfCalls; CallIndex++ ) + { + fprintf ( MeasurementsResultFile, " Measurement Start Time [%03d] = %I64u\n", CallIndex, CallbackMeasurementEntry->StartTimes [ CallIndex ].QuadPart ); + fprintf ( MeasurementsResultFile, " Measurement End Time [%03d] = %I64u\n", CallIndex, CallbackMeasurementEntry->EndTimes [ CallIndex ].QuadPart ); + } + } + } + } +} + +//********************************************************************************************************************************** + +unsigned long MeasurementSummaryArrayIndex = 0; +unsigned long MaxMeasurementSummaryArrayIndex = ( ( MAX_FFI_FUNCTIONS + MAX_PKI_FUNCTIONS ) * MAX_COMPONENT_CALLS_PER_MEASUREMENT * 2 ) + + ( ( MAX_FFI_CALLBACK_FUNCTIONS + MAX_PKI_CALLBACK_FUNCTIONS ) * MAX_CALLBACK_CALLS_PER_MEASUREMENT * 2 ); + +MEASUREMENT_SUMMARY_ENTRY *MeasurementSummaryArray = NULL; // allocate dynamically + +void COMPONENT::PrintMeasurementSummary ( bool IsServer ) +{ + MEASUREMENTRESULTS *MeasurementResult = NULL; + COMPONENTMEASUREMENTENTRY *ComponentMeasurementEntry = NULL; + CALLBACKMEASUREMENTENTRY *CallbackMeasurementEntry = NULL; + COMPONENTMEASUREMENT *ComponentMeasurement = NULL; + FILE *MeasurementSummaryFile = NULL; + unsigned int TestRunNumber = 0; + unsigned int MeasurementNumber = 0; + unsigned int FunctionIndex = 0; + unsigned int CallIndex = 0; + long StartTime = 0; + long ExecutionTime = 0; // in microseconds + char *ClientMeasurementSummaryFilename = "ClientMeasurementSummary.csv"; + char *ServerMeasurementSummaryFilename = "ServerMeasurementSummary.csv"; + LARGE_INTEGER MeasurementStartTime; + + if ( IsServer ) + { + MeasurementSummaryFile = fopen ( ServerMeasurementSummaryFilename, "wt" ); + } + else + { + MeasurementSummaryFile = fopen ( ClientMeasurementSummaryFilename, "wt" ); + } + + if ( MeasurementSummaryFile != NULL ) // was the file opened successfully? + { + fprintf ( MeasurementSummaryFile, "#\n" ); + fprintf ( MeasurementSummaryFile, "# Measurement Summary (Unsorted)\n" ); + fprintf ( MeasurementSummaryFile, "# ------------------------------\n" ); + fprintf ( MeasurementSummaryFile, "#\n" ); + + // run through each test run + + for ( TestRunNumber = 0; TestRunNumber < MAX_MEASUREMENT_TYPES; TestRunNumber++ ) + { + // get the measurement array for this test run + + MeasurementResult = MeasurementResultsArray [ TestRunNumber ]; + + // only print out the test runs which were actually recorded + + if ( MeasurementResult != NULL ) // was memory allocated for this test run? + { + // run through each measurement for this test run + + for ( MeasurementNumber = 0; MeasurementNumber < MAX_MEASUREMENTS; MeasurementNumber++ ) + { + // allocate empty measurement summary array for maximum number of component measurements and function calls + + MeasurementSummaryArray = (MEASUREMENT_SUMMARY_ENTRY *) calloc ( MaxMeasurementSummaryArrayIndex, sizeof ( MEASUREMENT_SUMMARY_ENTRY ) ); + + if ( MeasurementSummaryArray != NULL ) // was memory allocated for the measurement summary array ? + { + ComponentMeasurement = &MeasurementResult->Measurements [ MeasurementNumber ]; + + MeasurementStartTime = ComponentMeasurement->MeasurementStartTime; + + // only print out the measurements which were actually recorded + + if ( MeasurementStartTime.QuadPart == 0 ) break; + + // work out how long the component measurement took + + ExecutionTime = Tester->CalculateExecutionTime ( MeasurementStartTime, ComponentMeasurement->MeasurementEndTime ); + + fprintf ( MeasurementSummaryFile, + "# Test Run [%d] Component Measurement [ %d ] Total Execution Time %u microseconds\n", TestRunNumber, MeasurementNumber, ExecutionTime ); + + //*********************** + // Component measurements + //*********************** + + for ( FunctionIndex = 0; FunctionIndex < MAX_FFI_FUNCTIONS; FunctionIndex++ ) + { + ComponentMeasurementEntry = &ComponentMeasurement->FFIMeasurements [ FunctionIndex ]; + + // only print out the component measurements recorded + + if ( ComponentMeasurementEntry->NumberOfCalls > 0 ) + { + for ( int CallIndex = 0; CallIndex < ComponentMeasurementEntry->NumberOfCalls; CallIndex++ ) + { + AddMeasurementSummaryEntry ( MeasurementSummaryFile, + MeasurementResult, + ComponentMeasurement, + ComponentMeasurementEntry, + TestRunNumber, + MeasurementNumber, + FunctionIndex, + CallIndex ); + } + } + } + + for ( FunctionIndex = 0; FunctionIndex < MAX_FFI_CALLBACK_FUNCTIONS; FunctionIndex++ ) + { + CallbackMeasurementEntry = &ComponentMeasurement->FFICallbackMeasurements [ FunctionIndex ]; + + // only print out the component callback measurements recorded + + if ( CallbackMeasurementEntry->NumberOfCalls > 0 ) + { + for ( CallIndex = 0; CallIndex < CallbackMeasurementEntry->NumberOfCalls; CallIndex++ ) + { + AddMeasurementSummaryEntry ( MeasurementSummaryFile, + ComponentMeasurement, + CallbackMeasurementEntry, + TestRunNumber, + MeasurementNumber, + CallIndex ); + } + } + } + + //********************* + // Library measurements + //********************* + + for ( FunctionIndex = 0; FunctionIndex < MAX_PKI_FUNCTIONS; FunctionIndex++ ) + { + ComponentMeasurementEntry = &ComponentMeasurement->PKIMeasurements [ FunctionIndex ]; + + // only print the library measurements recorded + + if ( ComponentMeasurementEntry->NumberOfCalls > 0 ) + { + for ( CallIndex = 0; CallIndex < ComponentMeasurementEntry->NumberOfCalls; CallIndex++ ) + { + AddMeasurementSummaryEntry ( MeasurementSummaryFile, + MeasurementResult, + ComponentMeasurement, + ComponentMeasurementEntry, + TestRunNumber, + MeasurementNumber, + FunctionIndex, + CallIndex ); + } + } + } + + for ( FunctionIndex = 0; FunctionIndex < MAX_PKI_CALLBACK_FUNCTIONS; FunctionIndex++ ) + { + CallbackMeasurementEntry = &ComponentMeasurement->PKICallbackMeasurements [ FunctionIndex ]; + + // only print the library callback measurements recorded + + if ( CallbackMeasurementEntry->NumberOfCalls > 0 ) + { + for ( CallIndex = 0; CallIndex < CallbackMeasurementEntry->NumberOfCalls; CallIndex++ ) + { + AddMeasurementSummaryEntry ( MeasurementSummaryFile, + ComponentMeasurement, + CallbackMeasurementEntry, + TestRunNumber, + MeasurementNumber, + CallIndex ); + } + } + } + + // now sort the summary array into chronological order + + qsort ( (void *) MeasurementSummaryArray, + (size_t) MeasurementSummaryArrayIndex, + (size_t) sizeof ( MEASUREMENT_SUMMARY_ENTRY ), + MeasurementSummaryCompare ); + + // and put the resulting array into the summary file + + fprintf ( MeasurementSummaryFile, "\n" ); + fprintf ( MeasurementSummaryFile, "# Measurement Summary (Sorted)\n" ); + fprintf ( MeasurementSummaryFile, "# ----------------------------\n" ); + fprintf ( MeasurementSummaryFile, "\n" ); + + fprintf ( MeasurementSummaryFile, + "Test Run Number, Measurement Number, Call Index, Function Name, StartTime, Duration\n\n" ); + + for ( int Index = 0; Index < MeasurementSummaryArrayIndex; Index++ ) + { + fprintf ( MeasurementSummaryFile, + "%d, %d, %d, %s, %u, %u\n", + MeasurementSummaryArray [ Index ].TestRunNumber, + MeasurementSummaryArray [ Index ].MeasurementNumber, + MeasurementSummaryArray [ Index ].CallNumber, + MeasurementSummaryArray [ Index ].FunctionName, + MeasurementSummaryArray [ Index ].StartTime, + MeasurementSummaryArray [ Index ].Duration ); + } + + if ( Tester->GenerateImageFiles ) CreateMeasurementSummaryImage ( TestRunNumber, MeasurementNumber ); + + // we are finished with the array + + free ( MeasurementSummaryArray ); + + MeasurementSummaryArray = NULL; + + MeasurementSummaryArrayIndex = 0; + } + else + { + printf ( "Cannot allocate memory for measurement array!\n" ); + } + + } // Measurement Number + + } // if ( MeasurementResult != NULL ) + + } // TestRunNumber + + fclose ( MeasurementSummaryFile ); + } + else + { + printf ( "Cannot open measurement summary file!\n", + IsServer ? ClientMeasurementSummaryFilename : ServerMeasurementSummaryFilename ); + } +} + +//********************************************************************************************************************************** + +int MeasurementSummaryCompare ( const void *arg1, const void *arg2 ) +{ + MEASUREMENT_SUMMARY_ENTRY *Entry1 = (MEASUREMENT_SUMMARY_ENTRY *) arg1; + MEASUREMENT_SUMMARY_ENTRY *Entry2 = (MEASUREMENT_SUMMARY_ENTRY *) arg2; + + // Compare only the start times of both entries + + return ( Entry1->StartTime - Entry2->StartTime ); +} + +//********************************************************************************************************************************** + +void COMPONENT::AddMeasurementSummaryEntry ( FILE *MeasurementSummaryFile, + MEASUREMENTRESULTS *MeasurementResult, + COMPONENTMEASUREMENT *ComponentMeasurement, + COMPONENTMEASUREMENTENTRY *ComponentMeasurementEntry, + int TestRunNumber, + int MeasurementNumber, + int FunctionIndex, + int CallIndex ) +{ + long StartTime = 0; + long ExecutionTime = 0; + + // work out the start and execution times + + if ( ( FunctionIndex == FFI_MITLS_INIT ) || // these are all called very early, well before any measurements + ( FunctionIndex == MIPKI_INIT ) || + ( FunctionIndex == MIPKI_FREE ) || + ( FunctionIndex == FFI_MITLS_SET_TRACE_CALLBACK ) || + ( FunctionIndex == MIPKI_ADD_ROOT_FILE_OR_PATH ) || + ( FunctionIndex == FFI_MITLS_CLEANUP ) ) // this is called at the very end + { + // dont record these ones + + return; + + //StartTime = Tester->CalculateExecutionTime ( MeasurementResult->TestRunStartTime, + // ComponentMeasurementEntry->StartTimes [ CallIndex ]); + } + else + { + StartTime = Tester->CalculateExecutionTime ( ComponentMeasurement->MeasurementStartTime, + ComponentMeasurementEntry->StartTimes [ CallIndex ]); + + ExecutionTime = Tester->CalculateExecutionTime ( ComponentMeasurementEntry->StartTimes [ CallIndex ], + ComponentMeasurementEntry->EndTimes [ CallIndex ]); + + // record the measurement summary in the measurement summary file + + fprintf ( MeasurementSummaryFile, + "# %s [%d] Function Start Time %u, Execution Time %u\n", + ComponentMeasurementEntry->EntryName, + CallIndex, + StartTime, + ExecutionTime ); + + // add an entry to the measurement summary array + + MeasurementSummaryArray [ MeasurementSummaryArrayIndex ].IsCallback = FALSE; + MeasurementSummaryArray [ MeasurementSummaryArrayIndex ].FunctionName = ComponentMeasurementEntry->EntryName; + MeasurementSummaryArray [ MeasurementSummaryArrayIndex ].TestRunNumber = TestRunNumber; + MeasurementSummaryArray [ MeasurementSummaryArrayIndex ].MeasurementNumber = MeasurementNumber; + MeasurementSummaryArray [ MeasurementSummaryArrayIndex ].CallNumber = CallIndex; + MeasurementSummaryArray [ MeasurementSummaryArrayIndex ].StartTime = StartTime; + MeasurementSummaryArray [ MeasurementSummaryArrayIndex ].Duration = ExecutionTime; + + MeasurementSummaryArrayIndex++; + } +} + +//********************************************************************************************************************************** + +void COMPONENT::AddMeasurementSummaryEntry ( FILE *MeasurementSummaryFile, + COMPONENTMEASUREMENT *ComponentMeasurement, + CALLBACKMEASUREMENTENTRY *CallbackMeasurementEntry, + int TestRunNumber, + int MeasurementNumber, + int CallIndex ) +{ + // work out the start and execution times + + long StartTime = Tester->CalculateExecutionTime ( ComponentMeasurement->MeasurementStartTime, + CallbackMeasurementEntry->StartTimes [ CallIndex ]); + + long ExecutionTime = Tester->CalculateExecutionTime ( CallbackMeasurementEntry->StartTimes [ CallIndex ], + CallbackMeasurementEntry->EndTimes [ CallIndex ]); + + // record the measurement summary in the measurement summary file + + fprintf ( MeasurementSummaryFile, + "# %s [%d] Callback Execution Time, %u\n", + CallbackMeasurementEntry->EntryName, + CallIndex, + ExecutionTime ); + + // add an entry to the measurement summary array + + MeasurementSummaryArray [ MeasurementSummaryArrayIndex ].IsCallback = TRUE; + MeasurementSummaryArray [ MeasurementSummaryArrayIndex ].FunctionName = CallbackMeasurementEntry->EntryName; + MeasurementSummaryArray [ MeasurementSummaryArrayIndex ].TestRunNumber = TestRunNumber; + MeasurementSummaryArray [ MeasurementSummaryArrayIndex ].MeasurementNumber = MeasurementNumber; + MeasurementSummaryArray [ MeasurementSummaryArrayIndex ].CallNumber = CallIndex; + MeasurementSummaryArray [ MeasurementSummaryArrayIndex ].StartTime = StartTime; + MeasurementSummaryArray [ MeasurementSummaryArrayIndex ].Duration = ExecutionTime; + + MeasurementSummaryArrayIndex++; +} + +//********************************************************************************************************************************** +// +// < --------------------------------------- Image Width --------------------------------------> +// -------------------------------------------------------------------------------------------- ^ +// | Top Border | | +// | -------------------------------------------------------------------------- | | +// | | | | | | +// | Left | | | Right | | Image +// | Border | Text Area | Line Area | Border | | Height +// | | | | | | +// | | | | | | +// | -------------------------------------------------------------------------- | | +// | Bottom Border | | +// -------------------------------------------------------------------------------------------- v +// +// + +void COMPONENT::CreateMeasurementSummaryImage ( int TestRunNumber, + int MeasurementNMumber ) +{ + int FontSize = 20; + int LeftBorder = 100; + int RightBorder = 100; + int TopBorder = 100; + int BottomBorder = 100; + int TextAreaHeight = MeasurementSummaryArrayIndex * ( FontSize + 4); // based in number of lines needed and fontsize + int ImageHeight = TextAreaHeight + TopBorder + BottomBorder; + int ImageWidth = 3000; + int TextStart = 10; // left border within the Text Area + int LineStart = 500; // left border within the Line Area + long FirstStartTime = MeasurementSummaryArray [ 0 ].StartTime; + long LastStartTime = MeasurementSummaryArray [ MeasurementSummaryArrayIndex - 1 ].StartTime; + long MaxDuration = LastStartTime - FirstStartTime; + long Duration = 1; + int PowerOfTen = 1; + int Value = MaxDuration; + int DurationIncrement = 0; + + char TestImageFilename [ MAX_PATH ]; + char TestImageTitle [ 1000 ]; + + char *FontPath = "C:\\Program Files (x86)\\Graphviz2.38\\share\\fonts\\FreeSans.ttf"; + + if ( IsServer ) + { + sprintf ( TestImageFilename, "ServerMeasurementSummaryImage_Run%d_Measurement%d.png", TestRunNumber, MeasurementNMumber ); + } + else + { + sprintf ( TestImageFilename, "ClientMeasurementSummaryImage_Run%d_Measurement%d.png", TestRunNumber, MeasurementNMumber ); + } + + pngwriter TestImage ( ImageWidth, ImageHeight, 65535, TestImageFilename ); // a white image + + sprintf ( TestImageTitle, "Measurement Summary Image for Run %d and Measurement %d", TestRunNumber, MeasurementNMumber ); + + TestImage.settext ( TestImageTitle, + (const char *) "Caroline Mathieson", + (const char *) "gantt chart like image of start time and duration for each function call", + (const char *) "MITLS Tester" ); + + // draw a border round the text and line areas + + TestImage.square ( LeftBorder, BottomBorder, ImageWidth - RightBorder, ImageHeight - TopBorder, 0, 0, 0 ); + + // for each entry in the measurement summary array, draw the function name in black + + for ( int Index = 0; Index < MeasurementSummaryArrayIndex; Index++ ) + { + char *FunctionName = (char *) MeasurementSummaryArray [ Index ].FunctionName; + + TestImage.plot_text_utf8 ( FontPath, + FontSize, + LeftBorder + TextStart, + ImageHeight - TopBorder - FontSize - ( FontSize + 4 ) * Index, // compensate for text height + (double) 0.0, + FunctionName, + 0, + 0, + 0 ); + } + + // find the nearest power of ten + + while ( Value > 0 ) + { + Value = Value / 10; PowerOfTen++; Duration *= 10; + } + + DurationIncrement = Duration / 10; // nearest power of ten above the actual total duration so reduce by 10 to get real increment + + // and calculate a scaling factor given the line area size + + double ScalingFactor = (double) ( ImageWidth - LeftBorder - RightBorder - LineStart - 100 ) / (double) ( MaxDuration ); + + // draw some power of ten grid lines for scale + + for ( long Index = 0; Index < MaxDuration; Index += DurationIncrement ) // x axis + { + for ( int y = BottomBorder; y < ( ImageHeight - TopBorder ); y += 5 ) // y axis + { + int x = LeftBorder + LineStart + ( Index * ScalingFactor ); + + TestImage.filledsquare ( x, y, x + 1, y + 1, 0.0, 1.0, 0.0 ); + } + } + + // for each entry in the measurement array, draw the duration line at the right starting point + + for ( int Index = 0; Index < MeasurementSummaryArrayIndex; Index++) + { + // plot the duration line + + int y = ImageHeight - TopBorder - FontSize - ( FontSize + 4 ) * Index; + + int x = LeftBorder + LineStart + ( MeasurementSummaryArray [ Index ].StartTime - FirstStartTime ) * ScalingFactor; + + int width = 2 + (int) ( MeasurementSummaryArray [ Index ].Duration ) * ScalingFactor; // minimum width of 2 pixels + + int height = FontSize - 2; + + if ( MeasurementSummaryArray [ Index ].IsCallback ) + { + TestImage.filledsquare ( x + 1, y + 1, x + width, y + height, 0.0, 0.0, 1.0 ); // draw it in blue + } + else + { + TestImage.filledsquare ( x + 1, y + 1, x + width, y + height, 1.0, 0.0, 1.0 ); // draw it in magenta + } + + // plot the duration text (in us) + + char DurationText [ 10 ]; + + itoa ( MeasurementSummaryArray [ Index ].Duration, DurationText, 10 ); + + strcat ( DurationText, "us" ); + + TestImage.plot_text_utf8 ( FontPath, + FontSize - 4, + x + width + 15, // offset the text to the right from the line + y + 2, + (double) 0.0, + (char *) DurationText, + 0, + 0, + 0 ); + } + + TestImage.close (); +} + +//********************************************************************************************************************************** + +void COMPONENT::RecordTestRunStartTime ( void ) +{ + QueryPerformanceCounter ( &MeasurementResultsArray [ TestRunNumber ]->TestRunStartTime ); +} + +//********************************************************************************************************************************** + +void COMPONENT::RecordTestRunEndTime ( void ) +{ + QueryPerformanceCounter ( &MeasurementResultsArray [ TestRunNumber ]->TestRunEndTime ); +} + +//********************************************************************************************************************************** + +void COMPONENT::RecordMeasurementStartTime ( void ) +{ + QueryPerformanceCounter ( &MeasurementResultsArray [ TestRunNumber ]->Measurements [ MeasurementNumber ].MeasurementStartTime ); +} + +//********************************************************************************************************************************** + +void COMPONENT::RecordMeasurementEndTime ( void ) +{ + QueryPerformanceCounter ( &MeasurementResultsArray [ TestRunNumber ]->Measurements [ MeasurementNumber ].MeasurementEndTime ); +} + +//********************************************************************************************************************************** +// +// COMPONENT Methods +// +//********************************************************************************************************************************** + +COMPONENT::COMPONENT ( TLSTESTER *Parent, FILE *NewDebugFile, bool IsThisAServer ) +{ + Tester = Parent; + + DebugFile = NewDebugFile; + + IsServer = IsThisAServer; + + Socket = INVALID_SOCKET; + + // initialise component and library internal state variable addresses + + TLSState = NULL; + QUICState = NULL; + PKIState = NULL; + + // set the default values here in case they are not over-ridden by command line arguments + + strcpy ( TLSVersion, "1.3" ); + + strcpy ( HostName, "google.com" ); + + PortNumber = 443; + + strcpy ( ClientCertificateFilename, "server-ecdsa.crt" ); + strcpy ( ClientCertificateKeyFilename, "server-ecdsa.key" ); + strcpy ( ServerCertificateFilename, "server-ecdsa.crt" ); + strcpy ( ServerCertificateKeyFilename, "server-ecdsa.key" ); + + // initialise certificate chain variables + + NumberOfChainsAllocated = 0; // index into CertificateChains + + for ( int ChainNumber = 0; ChainNumber < MAX_CERTIFICATE_CHAINS; ChainNumber++ ) + { + CertificateChains [ ChainNumber ] = NULL; + } + + // initialise measurement results global variables + + TestRunNumber = 0; + + MeasurementNumber = 0; + + NumberOfMeasurementsMade = 0; + + InitialiseMeasurementResults (); + + if ( IsServer ) // initialise the transfer buffers used in server tests + { + BufferInitialise ( &SendBuffer ); + BufferInitialise ( &ReceiveBuffer ); + } + + CurrentComponentMeasurement = &MeasurementResultsArray [ 0 ]->Measurements [ 0 ]; // set to the first test and measurement +} + +//********************************************************************************************************************************** + +COMPONENT::~COMPONENT ( void ) +{ + FreeMeasurementResults (); + + if ( IsServer ) + { + fprintf ( stderr, "Buffer Management, SendBuffer->TotalAmountWritten = %u octets\n", SendBuffer.TotalAmountWritten ); + fprintf ( stderr, "Buffer Management, SendBuffer->TotalAmountRead = %u octets\n", SendBuffer.TotalAmountRead ); + fprintf ( stderr, "Buffer Management, ReceiveBuffer->TotalAmountWritten = %u octets\n", ReceiveBuffer.TotalAmountWritten ); + fprintf ( stderr, "Buffer Management, ReceiveBuffer->TotalAmountRead = %u octets\n", ReceiveBuffer.TotalAmountRead ); + } +} + +//********************************************************************************************************************************** + +void COMPONENT::SetClientCertificateFilename ( char *NewClientCertificateFilename ) +{ + strcpy ( ClientCertificateFilename, NewClientCertificateFilename ); +} + +//********************************************************************************************************************************** + +void COMPONENT::SetClientCertificateKeyFilename ( char *NewClientCertificateKeyFilename ) +{ + strcpy ( ClientCertificateKeyFilename, NewClientCertificateKeyFilename ); +} + +//********************************************************************************************************************************** + +void COMPONENT::SetServerCertificateFilename ( char *NewServerCertificateFilename ) +{ + strcpy ( ServerCertificateFilename, NewServerCertificateFilename ); +} + +//********************************************************************************************************************************** + +void COMPONENT::SetServerCertificateKeyFilename ( char *NewServerCertificateKeyFilename ) +{ + strcpy ( ServerCertificateKeyFilename, NewServerCertificateKeyFilename ); +} + +//********************************************************************************************************************************** + +void COMPONENT::SetVersion ( char *NewVersion ) +{ + strcpy ( TLSVersion, NewVersion ); +} + +//********************************************************************************************************************************** + +void COMPONENT::SetHostName ( char *NewHostName ) +{ + strcpy ( HostName, NewHostName ); +} + +//********************************************************************************************************************************** + +void COMPONENT::SetPortNumber ( int NewPortNumber ) +{ + PortNumber = NewPortNumber; +} + +//********************************************************************************************************************************** + +void COMPONENT::SetTestRunNumber ( int NewTestRunNumber ) +{ + TestRunNumber = NewTestRunNumber; + + // when we change the test run number, the measurements should start at 0 again + + SetMeasurementNumber ( 0 ); +} + +//********************************************************************************************************************************** + +void COMPONENT::SetMeasurementNumber ( int NewMeasurementNumber ) +{ + MeasurementNumber = NewMeasurementNumber; + + CurrentComponentMeasurement = &MeasurementResultsArray [ TestRunNumber ]->Measurements [ MeasurementNumber ]; +} + +//********************************************************************************************************************************** + +void COMPONENT::SetSocket ( SOCKET ServerSocket ) +{ + Socket = ServerSocket; +} + +//********************************************************************************************************************************** + +void COMPONENT::SetNumberOfMeasurementsMade ( int FinalNumberOfMeasurementsMade ) +{ + NumberOfMeasurementsMade = FinalNumberOfMeasurementsMade; +} + +//********************************************************************************************************************************** + +char *COMPONENT::GetHostName ( void ) +{ + return ( (char *) HostName ); +} + +//********************************************************************************************************************************** + +int COMPONENT::GetPortNumber ( void ) +{ + return ( PortNumber ); +} + +//********************************************************************************************************************************** +// +// TLS API Function wrappers +// +//********************************************************************************************************************************** + +int COMPONENT::InitialiseTLS ( void ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_INIT ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_init () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_init (); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +int COMPONENT::Configure ( void ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_CONFIGURE ]; + + int Result = 0; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_configure () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + if ( IsServer ) + { + // don't specify the host name when in server mode + + Result = FFI_mitls_configure ( &TLSState, TLSVersion, "" ); // note that this one requires a state double pointer! + } + else + { + Result = FFI_mitls_configure ( &TLSState, TLSVersion, HostName ); // note that this one requires a state double pointer! + } + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + if ( IsServer ) // reset those transfer buffers for each test that does a configure + { + BufferReset ( &SendBuffer ); + BufferReset ( &ReceiveBuffer ); + } + + return ( Result ); +} + +//********************************************************************************************************************************** + +int COMPONENT::Configure ( char *UseThisHostName ) // configure using the specified host name +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_CONFIGURE ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_configure (%s) called\n", UseThisHostName ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_configure ( &TLSState, TLSVersion, UseThisHostName ); // note that this one requires a state double pointer! + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +int COMPONENT::SetTicketKey ( const char *Algorithm, + const unsigned char *TicketKey, + size_t TicketKeyLength ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_SET_TICKET_KEY ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_set_ticket_key () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_set_ticket_key ( Algorithm, TicketKey, TicketKeyLength ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +int COMPONENT::ConfigureCipherSuites ( const char *CipherSuites ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_CONFIGURE_CIPHER_SUITES ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_configure_cipher_suites () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_configure_cipher_suites ( TLSState, CipherSuites ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +int COMPONENT::ConfigureSignatureAlgorithms ( const char *SignatureAlgorithms ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_CONFIGURE_SIGNATURE_ALGORITHMS ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_configure_signature_algorithms () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_configure_signature_algorithms ( TLSState, SignatureAlgorithms ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +int COMPONENT::ConfigureNamedGroups ( const char *NamedGroups ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_CONFIGURE_NAMED_GROUPS ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_configure_named_groups () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_configure_named_groups ( TLSState, NamedGroups ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +int COMPONENT::ConfigureApplicationLayerProtocolNegotiation ( const char *ApplicationLayerProtocolNegotiation ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_CONFIGURE_ALPN ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_configure_alpn () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_configure_alpn ( TLSState, ApplicationLayerProtocolNegotiation ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +int COMPONENT::ConfigureEarlyData ( uint32_t MaximumEarlyData ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_CONFIGURE_EARLY_DATA ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_configure_early_data () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_configure_early_data ( TLSState, MaximumEarlyData ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +void COMPONENT::ConfigureTraceCallback ( void ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_SET_TRACE_CALLBACK ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_set_trace_callback () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + FFI_mitls_set_trace_callback ( TraceCallback ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); +} + +//********************************************************************************************************************************** + +int COMPONENT::ConfigureTicketCallback ( void *CallbackState, + pfn_FFI_ticket_cb TicketCallback ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_CONFIGURE_TICKET_CALLBACK ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_configure_ticket_callback () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_configure_ticket_callback ( TLSState, CallbackState, TicketCallback ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +int COMPONENT::ConfigureNegotiationCallback ( void ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_CONFIGURE_NEGO_CALLBACK ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_configure_nego_callback () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_configure_nego_callback ( TLSState, NULL, NegotiationCallback ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +int COMPONENT::ConfigureCertificateCallbacks ( void ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_CONFIGURE_CERT_CALLBACKS ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + mitls_cert_cb CertificateCallbacks; + + // setup the callback functions structure with the wrapper functions (so we can do measurements) + + CertificateCallbacks.format = CertificateFormatCallback; + CertificateCallbacks.select = CertificateSelectCallback; + CertificateCallbacks.sign = CertificateSignCallback; + CertificateCallbacks.verify = CertificateVerifyCallback; + + fprintf ( DebugFile, "FFI_mitls_configure_cert_callbacks () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_configure_cert_callbacks ( TLSState, PKIState, &CertificateCallbacks ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +void COMPONENT::Close ( void ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_CLOSE ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_close () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + FFI_mitls_close ( TLSState ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); +} + +//********************************************************************************************************************************** + +int COMPONENT::Connect ( void ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_CONNECT ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_connect () called\n" ); + + Tester->ClientComponent->MeasurementNumber = MeasurementNumber; // record the measurement number used for the connect call for use in callbacks + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_connect ( ( void * ) this, ClientSendCallback, ClientReceiveCallback, TLSState ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +int COMPONENT::AcceptConnected ( void ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_ACCEPT_CONNECTED ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_accept_connected () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_accept_connected ( ( void * ) this, ServerSendCallback, ServerReceiveCallback, TLSState ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +int COMPONENT::GetExporter ( int early, + mitls_secret *secret ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_GET_EXPORTER ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_get_exporter () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_get_exporter ( TLSState, early, secret ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +void *COMPONENT::GetCertificate ( size_t *cert_size ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_GET_CERT ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_get_cert () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + void *Certificate = FFI_mitls_get_cert ( TLSState, cert_size ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Certificate ); +} + +//********************************************************************************************************************************** + +int COMPONENT::Send ( const unsigned char *buffer, + size_t buffer_size ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_SEND ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_send () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_send ( TLSState, buffer, buffer_size ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +void *COMPONENT::Receive ( size_t *packet_size ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_RECEIVE ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_receive () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + void *Packet = FFI_mitls_receive ( TLSState, packet_size ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Packet ); +} + +//********************************************************************************************************************************** + +void COMPONENT::Cleanup ( void ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_CLEANUP ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_cleanup () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + FFI_mitls_cleanup (); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); +} + +//********************************************************************************************************************************** +// +// QUIC API Function wrappers +// +//********************************************************************************************************************************** + +mitls_cert_cb CertificateCallbacks = +{ + CertificateCallbacks.select = CertificateSelectCallback, + CertificateCallbacks.format = CertificateFormatCallback, + CertificateCallbacks.sign = CertificateSignCallback, + CertificateCallbacks.verify = CertificateVerifyCallback, +}; + +mitls_extension QuicClientTransportParameters = +{ + QuicClientTransportParameters.ext_type = (uint16_t) 0x1A, // TLS_ET_QUIC_TRANSPORT_PARAMETERS + QuicClientTransportParameters.ext_data = (const unsigned char*) "\xff\xff\x00\x05\x0a\x0b\x0c\x0d\x0e\x00", + QuicClientTransportParameters.ext_data_len = 9, +}; + +int COMPONENT::QuicCreate ( void ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_QUIC_CREATE ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_quic_create () called\n" ); + + // set the right configuration for this test + + Configuration.callback_state = &QUICState; + Configuration.cert_callbacks = &CertificateCallbacks; + Configuration.nego_callback = &NegotiationCallback; + + Configuration.exts = &QuicClientTransportParameters; + Configuration.exts_count = 1; + + // and call the API with this config + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_quic_create ( &QUICState, &Configuration ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +quic_result COMPONENT::QuicProcess ( const unsigned char *inBuf, + size_t *pInBufLen, + unsigned char *outBuf, + size_t *pOutBufLen ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_QUIC_PROCESS ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_quic_process () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + quic_result Result = FFI_mitls_quic_process ( QUICState, inBuf, pInBufLen, outBuf, pOutBufLen ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +int COMPONENT::QuicGetExporter ( int early, + quic_secret *secret ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_QUIC_GET_EXPORTER ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_quic_get_exporter () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + //int Result = FFI_mitls_quic_get_exporter ( QUICState, early, secret ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( 0 /*Result*/ ); +} + +//********************************************************************************************************************************** + +void COMPONENT::QuicClose ( void ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_QUIC_CLOSE ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_quic_close () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + //FFI_mitls_quic_close ( QUICState ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); +} + +//********************************************************************************************************************************** + +int COMPONENT::GetHelloSummary ( const unsigned char *buffer, + size_t buffer_len, + mitls_hello_summary *summary, + unsigned char **cookie, + size_t *cookie_len ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_GET_HELLO_SUMMARY ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_quic_get_hello_summary () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_get_hello_summary ( buffer, buffer_len, summary, cookie, cookie_len ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +int COMPONENT::FindCustomExtension ( int is_server, + const unsigned char *exts, + size_t exts_len, + uint16_t ext_type, + unsigned char **ext_data, + size_t *ext_data_len ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_FIND_CUSTOM_EXTENSION ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_find_custom_extension () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + int Result = FFI_mitls_find_custom_extension ( is_server, exts, exts_len, ext_type, ext_data, ext_data_len ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +void COMPONENT::GlobalFree ( void *pv ) +{ + COMPONENTMEASUREMENTENTRY *FFIComponentMeasurement = &CurrentComponentMeasurement->FFIMeasurements [ FFI_MITLS_GLOBAL_FREE ]; + + int CallCount = FFIComponentMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "FFI_mitls_global_free () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->StartTimes [ CallCount ] ); + + FFI_mitls_global_free ( pv ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &FFIComponentMeasurement->EndTimes [ CallCount ] ); +} + +//********************************************************************************************************************************** +// +// PKI API Function wrappers +// +//********************************************************************************************************************************** + +int COMPONENT::InitialisePKI ( void ) +{ + signed int ErrorIndex; + mipki_config_entry Configuration [ 1 ]; + + COMPONENTMEASUREMENTENTRY *PKILibraryMeasurement = &CurrentComponentMeasurement->PKIMeasurements [ MIPKI_INIT ]; + + int CallCount = PKILibraryMeasurement->NumberOfCalls++; + + Configuration [ 0 ].cert_file = ServerCertificateFilename; // only 1 certificate and key + Configuration [ 0 ].key_file = ServerCertificateKeyFilename; + Configuration [ 0 ].is_universal = TRUE; + + fprintf ( DebugFile, "mipki_init () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->StartTimes [ CallCount ] ); + + PKIState = mipki_init ( Configuration, 1, NULL, &ErrorIndex ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->EndTimes [ CallCount ] ); + + return ( ErrorIndex ); +} + +//********************************************************************************************************************************** + +void COMPONENT::TerminatePKI ( void ) +{ + COMPONENTMEASUREMENTENTRY *PKILibraryMeasurement = &CurrentComponentMeasurement->PKIMeasurements [ MIPKI_FREE ]; + + int CallCount = PKILibraryMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "mipki_free () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->StartTimes [ CallCount ] ); + + mipki_free ( PKIState ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->EndTimes [ CallCount ] ); +} + +//********************************************************************************************************************************** + +int COMPONENT::AddRootFileOrPath ( const char *CertificateAuthorityFile ) +{ + COMPONENTMEASUREMENTENTRY *PKILibraryMeasurement = &CurrentComponentMeasurement->PKIMeasurements [ MIPKI_ADD_ROOT_FILE_OR_PATH ]; + + int CallCount = PKILibraryMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "mipki_add_root_file_or_path () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->StartTimes [ CallCount ] ); + + int Result = mipki_add_root_file_or_path ( PKIState, CertificateAuthorityFile ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +mipki_chain COMPONENT::SelectCertificate ( mipki_state *State, + const unsigned char *ServerNameIndicator, + size_t ServerNameIndicatorLength, + const mitls_signature_scheme *SignatureAlgorithms, + size_t SignatureAlgorithmsLength, + mitls_signature_scheme *SelectedSignatureScheme ) +{ + COMPONENTMEASUREMENTENTRY *PKILibraryMeasurement = &CurrentComponentMeasurement->PKIMeasurements [ MIPKI_SELECT_CERTIFICATE ]; + + int CallCount = PKILibraryMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "mipki_select_certificate () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->StartTimes [ CallCount ] ); + + mipki_chain Chain = mipki_select_certificate ( State, + (const char *) ServerNameIndicator, + ServerNameIndicatorLength, + SignatureAlgorithms, + SignatureAlgorithmsLength, + SelectedSignatureScheme ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->EndTimes [ CallCount ] ); + + return ( Chain ); +} + +//********************************************************************************************************************************** + +int COMPONENT::SignCertificate ( mipki_state *State, + mipki_chain CertificatePointer, + const mipki_signature SignatureAlgorithm, + const char *Certificate, + size_t CertificateLength, + char *Signature, + size_t *SignatureLength ) +{ + COMPONENTMEASUREMENTENTRY *PKILibraryMeasurement = &CurrentComponentMeasurement->PKIMeasurements [ MIPKI_SIGN_VERFIY ]; + + int CallCount = PKILibraryMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "mipki_sign_verify () called in Sign Mode\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->StartTimes [ CallCount ] ); + + int Result = mipki_sign_verify ( State, // use the state provided by the callback! + CertificatePointer, + SignatureAlgorithm, + Certificate, + CertificateLength, + Signature, + SignatureLength, + MIPKI_SIGN ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +int COMPONENT::VerifyCertificate ( mipki_state *State, + mipki_chain CertificatePointer, + const mipki_signature SignatureAlgorithm, + const char *Certificate, + size_t CertificateLength, + char *Signature, + size_t *SignatureLength ) +{ + COMPONENTMEASUREMENTENTRY *PKILibraryMeasurement = &CurrentComponentMeasurement->PKIMeasurements [ MIPKI_SIGN_VERFIY ]; + + int CallCount = PKILibraryMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "mipki_sign_verify () called in Verify Mode\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->StartTimes [ CallCount ] ); + + int Result = mipki_sign_verify ( State, // use the state provided by the callback! + CertificatePointer, + SignatureAlgorithm, + Certificate, + CertificateLength, + Signature, + SignatureLength, + MIPKI_VERIFY ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +int COMPONENT::ParseChain ( mipki_state *State, // use the state provided by the callback! + const char *ChainOfTrust, // the certificate chain of trust in TLS network format + size_t ChainLength ) // returns index into CertificateChains [] +{ + COMPONENTMEASUREMENTENTRY *PKILibraryMeasurement = &CurrentComponentMeasurement->PKIMeasurements [ MIPKI_PARSE_CHAIN ]; + + int CallCount = PKILibraryMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "mipki_parse_chain () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->StartTimes [ CallCount ] ); + + if ( NumberOfChainsAllocated < MAX_CERTIFICATE_CHAINS ) + { + // keep a record of the chains parsed and the parsed chain + + CertificateChains [ NumberOfChainsAllocated ] = mipki_parse_chain ( State, ChainOfTrust, ChainLength ); + } + else + { + printf ( "Number of certificate chains in component exceeded!\n" ); + } + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->EndTimes [ CallCount ] ); + + return ( NumberOfChainsAllocated++ ); +} + +//********************************************************************************************************************************** + +mipki_chain COMPONENT::ParseList ( void ) +{ + COMPONENTMEASUREMENTENTRY *PKILibraryMeasurement = &CurrentComponentMeasurement->PKIMeasurements [ MIPKI_PARSE_LIST ]; + + int CallCount = PKILibraryMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "mipki_parse_list () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->StartTimes [ CallCount ] ); + + // mipki_chain Chain = mipki_parse_list ( PKIState, const char **certs, const size_t* certs_len, size_t chain_len ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->EndTimes [ CallCount ] ); + + return ( NULL ); +} + +//********************************************************************************************************************************** + +size_t COMPONENT::FormatChain ( mipki_state *State, + mipki_chain ChainOfTrust, + unsigned char *ChainBuffer, + size_t ChainBufferLength ) +{ + COMPONENTMEASUREMENTENTRY *PKILibraryMeasurement = &CurrentComponentMeasurement->PKIMeasurements [ MIPKI_FORMAT_CHAIN ]; + + int CallCount = PKILibraryMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "mipki_format_chain () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->StartTimes [ CallCount ] ); + + size_t Result = mipki_format_chain ( State, ChainOfTrust, (char *) ChainBuffer, ChainBufferLength ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +void COMPONENT::FormatAllocation ( mipki_chain Chain ) +{ + COMPONENTMEASUREMENTENTRY *PKILibraryMeasurement = &CurrentComponentMeasurement->PKIMeasurements [ MIPKI_FORMAT_ALLOC ]; + + int CallCount = PKILibraryMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "mipki_format_alloc () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->StartTimes [ CallCount ] ); + + // mipki_format_alloc ( PKIState, Chain, void* init, alloc_callback cb ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->EndTimes [ CallCount ] ); +} + +//********************************************************************************************************************************** + +int COMPONENT::ValidateChain ( mipki_chain Chain ) +{ + COMPONENTMEASUREMENTENTRY *PKILibraryMeasurement = &CurrentComponentMeasurement->PKIMeasurements [ MIPKI_VALIDATE_CHAIN ]; + + int CallCount = PKILibraryMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "mipki_validate_chain () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->StartTimes [ CallCount ] ); + + int Result = mipki_validate_chain ( PKIState, Chain, "" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->EndTimes [ CallCount ] ); + + return ( Result ); +} + +//********************************************************************************************************************************** + +void COMPONENT::FreeChain ( mipki_chain Chain ) +{ + COMPONENTMEASUREMENTENTRY *PKILibraryMeasurement = &CurrentComponentMeasurement->PKIMeasurements [ MIPKI_FREE_CHAIN ]; + + int CallCount = PKILibraryMeasurement->NumberOfCalls++; + + fprintf ( DebugFile, "mipki_free_chain () called\n" ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->StartTimes [ CallCount ] ); + + mipki_free_chain ( PKIState, Chain ); + + if ( CallCount < MAX_COMPONENT_CALLS_PER_MEASUREMENT ) QueryPerformanceCounter ( &PKILibraryMeasurement->EndTimes [ CallCount ] ); +} + +//********************************************************************************************************************************** diff --git a/tests/Tester/Tester/InteropTester.cpp b/tests/Tester/Tester/InteropTester.cpp new file mode 100644 index 000000000..1442ab00f Binary files /dev/null and b/tests/Tester/Tester/InteropTester.cpp differ diff --git a/tests/Tester/Tester/InteropTester.h b/tests/Tester/Tester/InteropTester.h new file mode 100644 index 000000000..452106ad9 --- /dev/null +++ b/tests/Tester/Tester/InteropTester.h @@ -0,0 +1,39 @@ + +//********************************************************************************************************************************** +// +// Purpose: Interoperability Tester header file +// +// Project: Everest +// +// Filename: InteropTester.h +// +// Authors: Caroline.M.Mathieson (CMM) +// +//********************************************************************************************************************************** +// +// Description +// ----------- +// +//! \file InteropTester.h +//! \brief Contains the complete implementation of the Interoperability Tester. +//! +//********************************************************************************************************************************** + +#include "stdafx.h" + +//********************************************************************************************************************************** + +FILE *OpenStatisticsFile ( const char *StatisticsFileName ); + +FILE *OpenDebugFile ( const char *DebugFileName ); + +void OperatorConfidence ( void ); + +void ProcessCommandLine ( int ArgumentCount, + char *ArgumentList [], + char *EnvironmentVariables [], + bool Silent ); + +//********************************************************************************************************************************** + +#pragma once diff --git a/tests/Tester/Tester/SimpleServer.cpp b/tests/Tester/Tester/SimpleServer.cpp new file mode 100644 index 000000000..c24250939 Binary files /dev/null and b/tests/Tester/Tester/SimpleServer.cpp differ diff --git a/tests/Tester/Tester/TLSTester.cpp b/tests/Tester/Tester/TLSTester.cpp new file mode 100644 index 000000000..8ed0b828d --- /dev/null +++ b/tests/Tester/Tester/TLSTester.cpp @@ -0,0 +1,1655 @@ + +//********************************************************************************************************************************** +// +// Purpose: TLSTESTER OBJECT source code file +// +// Project: Everest +// +// Filename: TLSTester.cpp +// +// Authors: Caroline.M.Mathieson (CMM) +// +//********************************************************************************************************************************** +// +// Description +// ----------- +// +//! \file TLSTester.cpp +//! \brief Contains the complete implementation of the TLSTESTER Object. This covers TLS tester attributes and functions. +//! +//********************************************************************************************************************************** + +#include "Tester.h" // pulls in everything else + +//********************************************************************************************************************************** + +// see https://github.com/project-everest/mitls-fstar/blob/e2490b839c46beac96c0900beee4d19111355b21/src/tls/FFI.fst#L244 + +static const int NumberOfCipherSuites = 14; + +static const char *SupportedCipherSuites [ NumberOfCipherSuites ] = +{ + // these are the cipher suites offered by default in the ClientHello + + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256", + "TLS_AES_128_CCM_SHA256", + "TLS_AES_128_CCM_8_SHA256", + "ECDHE-RSA-AES256-GCM-SHA384", + "ECDHE-RSA-AES128-GCM-SHA256", + "ECDHE-RSA-CHACHA20-POLY1305-SHA256", + "ECDHE-ECDSA-AES256-GCM-SHA384", + "ECDHE-ECDSA-AES128-GCM-SHA256", + "ECDHE-ECDSA-CHACHA20-POLY1305-SHA256", + "DHE-RSA-AES256-GCM-SHA384", + "DHE-RSA-AES128-GCM-SHA256", + "DHE-RSA-CHACHA20-POLY1305-SHA256", +}; + +//********************************************************************************************************************************** + +// See https://github.com/project-everest/mitls-fstar/blob/master/src/tls/TLSConstants.fst and +// https://github.com/project-everest/mitls-fstar/blob/e2490b839c46beac96c0900beee4d19111355b21/src/tls/FFI.fst#L244 + +static const int NumberOfSignatureAlgorithms = 11; + +static const char *SupportedSignatureAlgorithms [ NumberOfSignatureAlgorithms ] = +{ + "RSAPSS+SHA512", + "RSAPSS+SHA384", + "RSAPSS+SHA256", + "RSA+SHA512", + "RSA+SHA384", + "RSA+SHA256", + "RSA+SHA1", + "ECDSA+SHA512", + "ECDSA+SHA384", + "ECDSA+SHA256", + "ECDSA+SHA1", + + // these are the signature algorithms offered by default in the ClientHello Signature Algorithms Extension + + // legacy algorithms +// "RSA_PKCS1_SHA1", // no longer supported in kremlin code +// "RSA_PKCS1_MD5SHA1", // only used internally for now +// "ECDSA_SHA1", // no longer supported in kremlin code + + // Not sure what these are (nothing in header file +// "RSA_PKCS1_SHA256", +// "RSA_PKCS1_SHA384", +// "RSA_PKCS1_SHA512", + + // RSASSA-PSS Algorithms +// "RSA_PSS_SHA256", +// "RSA_PSS_SHA384", +// "RSA_PSS_SHA512", + + // ECDSA Algorithms +// "ECDSA_SECP256R1_SHA256:", +// "ECDSA_SECP384R1_SHA384", +// "ECDSA_SECP521R1_SHA512", + + // EDDSA Algorithms +// "ED25519_SHA512", +// "ED448_SHAKE256", + + // Reserved code points +// "DSA_SHA1", +// "DSA_SHA256", +// "DSA_SHA384", +// "DSA_SHA512", + + // old list +// "ECDSA+SHA256", +// "ECDSA+SHA384", +// "ECDSA+SHA512", + +}; + +//********************************************************************************************************************************** + +// see https://github.com/project-everest/mitls-fstar/blob/master/src/tls/CommonDH.fst and +// https://github.com/project-everest/mitls-fstar/blob/e2490b839c46beac96c0900beee4d19111355b21/src/tls/FFI.fst#L244 + +static const int NumberOfNamedGroups = 8; + +static const char *SupportedNamedGroups [ NumberOfNamedGroups ] = +{ + "P-521", + "P-384", + "P-256", + "X25519", + "X448", + "FFDHE4096", + "FFDHE3072", + "FFDHE2048", +}; + +//********************************************************************************************************************************** + +TLSTESTER::TLSTESTER ( FILE *DebugFile, + FILE *TestResultsFile, + FILE *RecordedClientMeasurementsFile, + FILE *RecordedServerMeasurementsFile ) : TESTER ( DebugFile, + TestResultsFile, + RecordedClientMeasurementsFile, + RecordedServerMeasurementsFile ) +{ + ClientComponent = NULL; // we instantiate it in the client config method + ServerComponent = NULL; // we instantiate it in the server config method + + // set the default values here in case they are not over-ridden by command line arguments + + strcpy ( HostFileName, "\0" ); + + NumberOfHostsRead = 0; + + memset ( HostNames, 0, sizeof ( HostNames ) ); + + strcpy ( TLSVersion, "1.3" ); + + strcpy ( HostName, "google.com" ); + + PortNumber = 443; + + // certificate attributes + + strcpy ( ClientCertificateFilename, "server-ecdsa.crt" ); + strcpy ( ClientCertificateKeyFilename, "server-ecdsa.key" ); + strcpy ( ServerCertificateFilename, "server-ecdsa.crt" ); + strcpy ( ServerCertificateKeyFilename, "server-ecdsa.key" ); + + strcpy ( CertificateAuthorityChainFilename, "CAFile.pem" ); + + // command line over-ride flags + + GenerateImageFiles = FALSE; + + UseHostList = FALSE; + + UseHostName = FALSE; + + UsePortNumber = FALSE; + + DoTLSTests = FALSE; + DoQUICTests = FALSE; + DoClientTests = FALSE; + DoServerTests = FALSE; + + DoDefaultTests = FALSE; + DoCombinationTests = FALSE; + + DoClientInteroperabilityTests = FALSE; + DoServerInteroperabilityTests = FALSE; + + // thread attributes + + ClientTLSTestsThreadIdentifier = 0; + ServerTLSTestsThreadIdentifier = 0; + + ClientTLSTestsThreadHandle = INVALID_HANDLE_VALUE; + ServerTLSTestsThreadHandle = INVALID_HANDLE_VALUE; +} + +//********************************************************************************************************************************** + +void TLSTESTER::ConfigureClient ( void ) +{ + bool Result; + + ClientComponent = new COMPONENT ( this, DebugFile, FALSE ); + + // configure the ClientComponent attributes using the command line arguments if any given or the defaults otherwise + + if ( ClientComponent != NULL ) + { + ClientComponent->IsServer = FALSE; + + ClientComponent->SetVersion ( TLSVersion ); + + ClientComponent->SetHostName ( HostName ); + + ClientComponent->SetPortNumber ( PortNumber ); + + ClientComponent->SetClientCertificateFilename ( ClientCertificateFilename ); + + ClientComponent->SetClientCertificateKeyFilename ( ClientCertificateKeyFilename ); + + ClientComponent->SetServerCertificateFilename ( ServerCertificateFilename ); + + ClientComponent->SetServerCertificateKeyFilename ( ServerCertificateKeyFilename ); + } +} + +//********************************************************************************************************************************** + +void TLSTESTER::ConfigureServer ( void ) +{ + bool Result; + + ServerComponent = new COMPONENT ( this, DebugFile, TRUE ); + + // configure the ServerComponent attributes using the command line arguments if any given or the defaults otherwise + + if ( ServerComponent != NULL ) + { + ServerComponent->IsServer = TRUE; + + ServerComponent->SetVersion ( TLSVersion ); + + ServerComponent->SetHostName ( HostName ); + + ServerComponent->SetPortNumber ( PortNumber ); + + ServerComponent->SetClientCertificateFilename ( ClientCertificateFilename ); + + ServerComponent->SetClientCertificateKeyFilename ( ClientCertificateKeyFilename ); + + ServerComponent->SetServerCertificateFilename ( ServerCertificateFilename ); + + ServerComponent->SetServerCertificateKeyFilename ( ServerCertificateKeyFilename ); + } +} + +//********************************************************************************************************************************** + +TLSTESTER::~TLSTESTER ( void ) +{ + if ( ClientComponent != NULL ) + { + ClientComponent->PrintMeasurementResults ( RecordedClientMeasurementsFile ); + + delete ClientComponent; + } + + if ( ServerComponent != NULL ) + { + ServerComponent->PrintMeasurementResults ( RecordedServerMeasurementsFile ); + + delete ServerComponent; + } +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunClientTLSTests ( char *TestDateAndTimeString ) +{ + DateAndTimeString = TestDateAndTimeString; // record the date and time of the test + + ClientTestsFinished = FALSE; + + ClientTLSTestsThreadHandle = CreateThread ( NULL, // default security attributes + 0, // use default stack size + ClientTLSTestsThread, // thread function name + this, // argument to thread function is class instance + 0, // use default creation flags + &ClientTLSTestsThreadIdentifier ); // returns the thread identifier + + while ( ! ClientTestsFinished ) Sleep ( 1000 ); // wait for thread to finish +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunServerTLSTests ( char *TestDateAndTimeString ) +{ + DateAndTimeString = TestDateAndTimeString; // record the date and time of the test + + ClientTestsFinished = FALSE; + ServerTestsFinished = FALSE; + + ServerTLSTestsThreadHandle = CreateThread ( NULL, // default security attributes + 0, // use default stack size + ServerTLSTestsThread, // thread function name + this, // argument to thread function is class instance + 0, // use default creation flags + &ServerTLSTestsThreadIdentifier ); // returns the thread identifier + + // now that the server thread is running, start the client thread after a while + + Sleep ( 1000 ); + + ClientTLSTestsThreadHandle = CreateThread ( NULL, // default security attributes + 0, // use default stack size + ClientServerTLSTestsThread, // thread function name + this, // argument to thread function is class instance + 0, // use default creation flags + &ClientTLSTestsThreadIdentifier ); // returns the thread identifier + + while ( ( ! ServerTestsFinished ) && ( ! ClientTestsFinished ) ) + { + Sleep ( 1000 ); // wait for both threads to finish + } +} + +//********************************************************************************************************************************** + +DWORD WINAPI ClientTLSTestsThread ( LPVOID lpParam ) +{ + TLSTESTER *Tester = (TLSTESTER *) lpParam; + + Tester->ClientTLSTests (); + + Tester->ClientTestsFinished = TRUE; + + ExitThread ( 0 ); +} + +//********************************************************************************************************************************** + +DWORD WINAPI ClientServerTLSTestsThread ( LPVOID lpParam ) +{ + TLSTESTER *Tester = (TLSTESTER *) lpParam; + + Tester->ClientServerTLSTests (); + + Tester->ClientTestsFinished = TRUE; + + ExitThread ( 0 ); +} + +//********************************************************************************************************************************** + +DWORD WINAPI ServerTLSTestsThread ( LPVOID lpParam ) +{ + TLSTESTER *Tester = (TLSTESTER *) lpParam; + + Tester->ServerTLSTests (); + + Tester->ServerTestsFinished = TRUE; + + ExitThread ( 0 ); +} + +//********************************************************************************************************************************** + +void TLSTESTER::ClientTLSTests ( void ) +{ + int MeasurementNumber = 0; + long ExecutionTime = 0; + int Result = 0; + int ErrorIndex = 0; + bool Success = FALSE; + + ClientComponent->SetTestRunNumber ( TLS_CLIENT_MEASUREMENTS ); + + ClientComponent->RecordTestRunStartTime (); + + Result = ClientComponent->InitialiseTLS (); + + if ( ! Result ) { printf ( "Failed to Initialise TLS for client!\n" ); return; } + + ClientComponent->ConfigureTraceCallback (); + + ErrorIndex = ClientComponent->InitialisePKI (); + + if ( ErrorIndex != 0 ) { printf ( "Failed to Initialise PKI for client!\n" ); return; } + + if ( DoDefaultTests ) + { + // + // Run a measurement for just the default host, cipher suite, signature algorithm and named group + // + + QueryPerformanceCounter ( &MeasurementStartTime ); // just for this measurement to give a quick result below + + Success = RunSingleClientDefaultsTLSTest ( MeasurementNumber ); + + QueryPerformanceCounter ( &MeasurementEndTime ); + + ExecutionTime = CalculateExecutionTime ( MeasurementStartTime, MeasurementEndTime ); + + if ( Success ) + { + fprintf ( ComponentStatisticsFile, + "%s, %d, %d, %s, Default, Default, Default, PASS, %u\n", + DateAndTimeString, + ClientComponent->TestRunNumber, + MeasurementNumber, + ClientComponent->GetHostName (), + ExecutionTime ); + } + else + { + fprintf ( ComponentStatisticsFile, + "%s, %d, %d, %s, Default, Default, Default, FAIL, %u\n", + DateAndTimeString, + ClientComponent->TestRunNumber, + MeasurementNumber, + ClientComponent->GetHostName (), + ExecutionTime ); + } + + MeasurementNumber++; + } + + if ( DoCombinationTests ) + { + // + // Then run a measurement for each combination of supported cipher suite, signature algorithm and named groups + // for all specified hosts. + // + if ( UseHostList ) + { + for ( int HostNumber = 0; HostNumber < NumberOfHostsRead; HostNumber++ ) + { + ClientComponent->SetHostName ( HostNames [ HostNumber ] ); + + MeasurementNumber = RunCombinationTest ( MeasurementNumber, HostNames [ HostNumber ] ); + } + } + else + { + MeasurementNumber = RunCombinationTest ( MeasurementNumber, HostName ); + } + } + + ClientComponent->TerminatePKI (); + + ClientComponent->Cleanup (); + + ClientComponent->RecordTestRunEndTime (); + + // add this set of tests to the total run + + ClientComponent->NumberOfMeasurementsMade += MeasurementNumber; +} + +void TLSTESTER::ClientServerTLSTests ( void ) +{ + int MeasurementNumber = 0; + long ExecutionTime = 0; + int Result = 0; + int ErrorIndex = 0; + bool Success = FALSE; + + ClientComponent->SetTestRunNumber ( TLS_SERVER_MEASUREMENTS ); + + ClientComponent->RecordTestRunStartTime (); + ServerComponent->RecordTestRunStartTime (); + + // server tests mean that the servers are all local + + ClientComponent->SetHostName ( "localhost" ); + ServerComponent->SetHostName ( "localhost" ); + + Result = ClientComponent->InitialiseTLS (); + + if ( ! Result ) { printf ( "Failed to Initialise TLS for clientserver tests!\n" ); return; } + + ClientComponent->ConfigureTraceCallback (); + + ErrorIndex = ClientComponent->InitialisePKI (); + + if ( ErrorIndex != 0 ) { printf ( "Failed to Initialise PKI for clientserver tests!\n" ); return; } + + if ( DoDefaultTests ) + { + // + // Run a measurement for just the default host, cipher suite, signature algorithm and named group + // + + QueryPerformanceCounter ( &MeasurementStartTime ); // just for this measurement to give a quick result below + + Success = RunSingleServerDefaultsTLSTest ( MeasurementNumber ); + + QueryPerformanceCounter ( &MeasurementEndTime ); + + ExecutionTime = CalculateExecutionTime ( MeasurementStartTime, MeasurementEndTime ); + + if ( Success ) + { + fprintf ( ComponentStatisticsFile, + "%s, %d, %s, Default, Default, Default, PASS, %u\n", + DateAndTimeString, + /*ClientComponent->NumberOfMeasurementsMade +*/ MeasurementNumber, + ClientComponent->GetHostName (), + ExecutionTime ); + } + else + { + fprintf ( ComponentStatisticsFile, + "%s, %d, %s, Default, Default, Default, FAIL, %u\n", + DateAndTimeString, + /*ClientComponent->NumberOfMeasurementsMade +*/ MeasurementNumber, + ClientComponent->GetHostName (), + ExecutionTime ); + } + + MeasurementNumber++; + } + + if ( DoCombinationTests ) + { + MeasurementNumber = RunCombinationTest ( MeasurementNumber, HostName ); + } + + ClientComponent->TerminatePKI (); + + ClientComponent->Cleanup (); + + ClientComponent->RecordTestRunEndTime (); + ServerComponent->RecordTestRunEndTime (); + + // add this set of tests to the total run + + ClientComponent->NumberOfMeasurementsMade += MeasurementNumber; + ServerComponent->NumberOfMeasurementsMade += MeasurementNumber; +} + +//********************************************************************************************************************************** + +void TLSTESTER::ServerTLSTests ( void ) +{ + int MeasurementNumber = 0; + long ExecutionTime = 0; + int Result = 0; + int ErrorIndex = 0; + bool Success = FALSE; + + ConfigureServer (); // create and initialise a component for server dll access + + ServerComponent->SetTestRunNumber ( TLS_SERVER_MEASUREMENTS ); + + //ServerComponent->RecordTestRunStartTime (); + + Result = ServerComponent->InitialiseTLS (); + + if ( ! Result ) { printf ( "Failed to Initialise TLS!\n" ); return; } + + ServerComponent->ConfigureTraceCallback (); + + ErrorIndex = ServerComponent->InitialisePKI (); + + if ( ErrorIndex != 0 ) { printf ( "Failed to Initialise PKI for server!\n" ); return; } + + // run client tests with the server running + + Result = ServerComponent->AddRootFileOrPath ( CertificateAuthorityChainFilename ); // must be done before the configure + + if ( Result ) + { + // server is local in these tests so set host names accordingly + + ClientComponent->SetHostName ( "localhost" ); + ServerComponent->SetHostName ( "localhost" ); + + Result = ServerComponent->Configure (); // set default TLS version + + if ( Result ) + { + Result = ServerComponent->ConfigureCertificateCallbacks (); + + if ( Result ) + { + Result = ServerComponent->ConfigureNegotiationCallback (); + + if ( Result ) + { + while ( ! ClientTestsFinished ) // keep repeating while the client tests are stil running + { + fprintf ( stderr, "Server waiting for incoming connect () from client\n" ); + + Result = ServerComponent->AcceptConnected (); + + // + // The component will call the send() and receive() callback functions to perform the handshake and the + // AcceptConnected () function call returns only when the handshake is complete. + // + + if ( Result ) + { + if ( VerboseConsoleOutput ) printf ( "ServerComponent->ConnectAccepted() was successful!\n" ); + + // don't do any data transfer in this particular test + + // ServerComponent->Receive (); // get any data sent + + // ServerComponent->Free; // free the received item + + // ServerComponent->Send (); // send any data + + // ServerComponent->CloseConnection (); //its hard to know how long to wait for this before we call it. + + Success = TRUE; + } + else + { + fprintf ( stderr, "ServerComponent->AcceptConnected() failed!\n" ); + } + + } // end while + } + else + { + fprintf ( stderr, "ServerComponent->ConfigureNegotiationCallback () failed!\n" ); + } + } + else + { + fprintf ( stderr, "ServerComponent->ConfigureCertificateCallbacks () failed!\n" ); + } + } + else + { + fprintf ( stderr, "ServerComponent->Configure() failed!\n" ); + } + } + else + { + fprintf ( stderr, "ServerComponent->AddRootFileOrPath () failed!\n" ); + } + + ServerComponent->TerminatePKI (); + + //ServerComponent->Cleanup (); + + //ServerComponent->RecordTestRunEndTime (); +} + +//********************************************************************************************************************************** + +int TLSTESTER::RunCombinationTest ( int MeasurementNumber, + char *HostName ) +{ + int CipherSuiteNumber = 0; + int SignatureAlgorithmNumber = 0; + int NamedGroupNumber = 0; + int Success = 0; + long ExecutionTime = 0; + char *TestResult = "FAIL"; // or "PASS" + + for ( CipherSuiteNumber = 0; CipherSuiteNumber < NumberOfCipherSuites; CipherSuiteNumber++ ) + { + for ( SignatureAlgorithmNumber = 0; SignatureAlgorithmNumber < NumberOfSignatureAlgorithms; SignatureAlgorithmNumber++ ) + { + for ( NamedGroupNumber = 0; NamedGroupNumber < NumberOfNamedGroups; NamedGroupNumber++ ) + { + QueryPerformanceCounter ( &MeasurementStartTime ); // just for this measurement to give a quick result below + + Success = RunSingleClientTLSTest ( MeasurementNumber, + SupportedCipherSuites [ CipherSuiteNumber ], + SupportedSignatureAlgorithms [ SignatureAlgorithmNumber ], + SupportedNamedGroups [ NamedGroupNumber ] ); + + QueryPerformanceCounter ( &MeasurementEndTime ); + + ExecutionTime = CalculateExecutionTime ( MeasurementStartTime, MeasurementEndTime ); + + if ( Success ) TestResult = "PASS"; + + fprintf ( ComponentStatisticsFile, + "%s, %d, %s, %s, %s, %s, %s, %u\n", + DateAndTimeString, + ClientComponent->NumberOfMeasurementsMade + MeasurementNumber, + HostName, + SupportedCipherSuites [ CipherSuiteNumber ], + SupportedSignatureAlgorithms [ SignatureAlgorithmNumber ], + SupportedNamedGroups [ NamedGroupNumber ], + TestResult, + ExecutionTime ); + + OperatorConfidence (); + + MeasurementNumber++; + } + } + } + + return ( MeasurementNumber ); +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunClientQUICTests ( char * DateAndTimeString ) +{ + int CipherSuiteNumber = 0; + int SignatureAlgorithmNumber = 0; + int NamedGroupNumber = 0; + int MeasurementNumber = 0; + long ExecutionTime = 0; + int Result = 0; + int ErrorIndex = 0; + + ClientComponent->SetTestRunNumber ( QUIC_CLIENT_MEASUREMENTS ); + + ClientComponent->RecordTestRunStartTime (); + + Result = ClientComponent->InitialiseTLS (); + + if ( Result ) + { + ClientComponent->ConfigureTraceCallback (); + + ErrorIndex = ClientComponent->InitialisePKI (); + + if ( ErrorIndex == 0 ) + { + Result = ClientComponent->QuicCreate (); + + if ( Result ) + { + // + // run a measurement for each combination of cipher suite, algorithm and named group + // + + for ( CipherSuiteNumber = 0; CipherSuiteNumber < NumberOfCipherSuites; CipherSuiteNumber++ ) + { + for ( SignatureAlgorithmNumber = 0; SignatureAlgorithmNumber < NumberOfSignatureAlgorithms; SignatureAlgorithmNumber++ ) + { + for ( NamedGroupNumber = 0; NamedGroupNumber < NumberOfNamedGroups; NamedGroupNumber++ ) + { + QueryPerformanceCounter ( &TestStartTime ); + + RunSingleClientQUICTest ( MeasurementNumber, + SupportedCipherSuites [ CipherSuiteNumber ], + SupportedSignatureAlgorithms [ SignatureAlgorithmNumber ], + SupportedNamedGroups [ NamedGroupNumber ] ); + + QueryPerformanceCounter ( &TestEndTime ); + + ExecutionTime = CalculateExecutionTime ( TestStartTime, TestEndTime ); + + fprintf ( ComponentStatisticsFile, + "%s, %d, %s, %s, %s, %s, %u\n", + DateAndTimeString, + MeasurementNumber, + SupportedCipherSuites [ CipherSuiteNumber ], + SupportedSignatureAlgorithms [ SignatureAlgorithmNumber ], + SupportedNamedGroups [ NamedGroupNumber ], + "FAIL", + ExecutionTime ); + + OperatorConfidence (); + + MeasurementNumber++; + } + } + } + } + else + { + printf ( "ClientComponent->QuicCreate() call failed!\n" ); + } + + ClientComponent->TerminatePKI (); + } + else + { + printf ( "ClientComponent->InitialisePKI() call failed with error %d!\n", ErrorIndex ); + } + + ClientComponent->Cleanup (); + } + else + { + printf ( "ClientComponent->InitialiseTLS() call failed!\n" ); + } + + ClientComponent->RecordTestRunEndTime (); + + // add this set of tests to the total run + + ClientComponent->NumberOfMeasurementsMade += MeasurementNumber; +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunServerQUICTests ( char * DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** +// +// Client Interoperability TLS Tests +// +//********************************************************************************************************************************** + +void TLSTESTER::RunOpenSSLClientTLSTests ( char * DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunBoringClientTLSTests ( char * DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunMbedTLSClientTLSTests ( char * DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunWolfSSLClientTLSTests ( char *DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunFizzClientTLSTests ( char *DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** +// +// Client Interoperability QUIC Tests +// +//********************************************************************************************************************************** + +void TLSTESTER::RunOpenSSLClientQUICTests ( char * DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunBoringClientQUICTests ( char * DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunMbedTLSClientQUICTests ( char * DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunWolfSSLClientQUICTests ( char *DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunFizzClientQUICTests ( char *DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** +// +// Server Interoperability TLS Tests +// +//********************************************************************************************************************************** + +void TLSTESTER::RunOpenSSLServerTLSTests ( char * DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunBoringServerTLSTests ( char * DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunMbedTLSServerTLSTests ( char * DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunWolfSSLServerTLSTests ( char *DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunFizzServerTLSTests ( char *DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** +// +// Server Interoperability QUIC Tests +// +//********************************************************************************************************************************** + +void TLSTESTER::RunOpenSSLServerQUICTests ( char * DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunBoringServerQUICTests ( char * DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunMbedTLSServerQUICTests ( char * DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunWolfSSLServerQUICTests ( char *DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunFizzServerQUICTests ( char *DateAndTimeString ) +{ +} + +//********************************************************************************************************************************** +// +// In a client test, only one socket is required, a socket for the connection to the peer (server) as the component uses send and +// receive callbacks to communicate with the environment. This makes the component platform and transport agnostic. +// +//

+//                 ..
+//    --------    .  .     ----------  Receive() -------------
+//    |      |------------>|        |----------->|           |
+//    | Peer |    .  .     | Tester |            | Component |
+//    |      |<------------|        |<-----------|           |
+//    --------    .  .     ----------   Send()   -------------
+//                 ..
+//                Peer
+//               Socket
+//
+// 
+// +bool TLSTESTER::RunSingleClientTLSTest ( int MeasurementNumber, + const char *CipherSuite, + const char *SignatureAlgorithm, + const char *NamedGroup ) +{ + bool Success = FALSE; + + fprintf ( DebugFile, + "Running single client TLS test %d on Cipher Suite %s, Signature Algorithm %s and Named group %s\n", + MeasurementNumber, + CipherSuite, + SignatureAlgorithm, + NamedGroup ); + + if ( VerboseConsoleOutput ) + { + printf ( "Running single client TLS test %d on Cipher Suite %s, Signature Algorithm %s and Named group %s\n", + MeasurementNumber, + CipherSuite, + SignatureAlgorithm, + NamedGroup ); + } + + // open socket to communicate with peer (server) + + PeerSocket = OpenPeerSocket (); + + if ( PeerSocket != INVALID_SOCKET ) + { + Success = SingleClientTLSTest ( MeasurementNumber, CipherSuite, SignatureAlgorithm, NamedGroup ); + + closesocket ( PeerSocket ); + } + + return ( Success ); +} + +//********************************************************************************************************************************** + +SOCKET TLSTESTER::OpenPeerSocket ( void ) +{ + struct sockaddr_in PeerAddress; + struct hostent *Peer = NULL; + int Response = 0; + SOCKET PeerSocket = INVALID_SOCKET; + + // open socket to communicate with peer (server) + + PeerSocket = socket ( AF_INET, SOCK_STREAM, 0 ); // we need a TCP socket as this is TLS! + + if ( PeerSocket != INVALID_SOCKET ) + { + Peer = gethostbyname ( ClientComponent->GetHostName () ); + + memset ( &PeerAddress, 0, sizeof ( PeerAddress ) ); + + PeerAddress.sin_family = AF_INET; + + memcpy ( &PeerAddress.sin_addr.s_addr, Peer->h_addr, Peer->h_length ); + + PeerAddress.sin_port = htons ( ClientComponent->GetPortNumber () ); + + Response = connect ( PeerSocket, ( struct sockaddr* ) &PeerAddress, sizeof ( PeerAddress ) ); + + if ( Response != 0 ) + { + fprintf ( DebugFile, "Cannot connect to peer \"%s\" for test!\n", ClientComponent->GetHostName () ); + + PrintSocketError (); + + closesocket ( PeerSocket ); // we can't use this socket so just close it + + PeerSocket = INVALID_SOCKET; + } + } + else + { + fprintf ( DebugFile, "Cannot open TCP socket for peer!\n" ); + + PrintSocketError (); + } + + return ( PeerSocket ); +} + +//********************************************************************************************************************************** +// +// This test uses just the default configuration for the cipher suites, signature algorithms and named groups. The actual defaults +// could change from implementation to implementation as work progresses, so don't actually list them here. +// + +bool TLSTESTER::RunSingleClientDefaultsTLSTest ( int MeasurementNumber ) +{ + int Response; + int Result; + bool Success = FALSE; + SOCKET PeerSocket = INVALID_SOCKET; + + fprintf ( DebugFile, "Running single client defaults TLS test %d\n", MeasurementNumber ); + + if ( VerboseConsoleOutput ) + { + printf ( "Running single client defaults TLS test %d\n", MeasurementNumber ); + } + + // open socket to communicate with peer (server) + + PeerSocket = OpenPeerSocket (); + + if ( PeerSocket != INVALID_SOCKET ) + { + ClientComponent->SetMeasurementNumber ( MeasurementNumber ); + + ClientComponent->RecordMeasurementStartTime (); // start time for this measurement + + ClientComponent->SetSocket ( PeerSocket ); + + Result = ClientComponent->AddRootFileOrPath ( CertificateAuthorityChainFilename ); // must be done before the configure + + if ( Result ) + { + Result = ClientComponent->Configure (); // set default TLS version + + if ( Result ) + { + Result = ClientComponent->ConfigureCertificateCallbacks (); + + if ( Result ) + { + Result = ClientComponent->ConfigureNegotiationCallback (); + + if ( Result ) + { + Result = ClientComponent->Connect (); + + // + // The component will call the send() and receive() callback functions to perform the handshake and the + // Connect () function call returns only when the handshake is complete. + // + + if ( Result ) + { + if ( VerboseConsoleOutput ) printf ( "ClientComponent->Connect() was successful!\n" ); + + // don't do any data transfer in this particular test + + ClientComponent->Close (); + + Success = TRUE; + } + else + { + printf ( "ClientComponent->Connect() failed!\n" ); + } + } + else + { + printf ( "ClientComponent->ConfigureNegotiationCallback () failed!\n" ); + } + } + else + { + printf ( "ClientComponent->ConfigureCertificateCallbacks () failed!\n" ); + } + } + else + { + printf ( "ClientComponent->Configure() failed!\n" ); + } + } + else + { + printf ( "ClientComponent->AddRootFileOrPath () failed!\n" ); + } + + ClientComponent->RecordMeasurementEndTime (); + + if ( VerboseConsoleOutput ) printf ( "Last Error Code = %d\n", GetLastError () ); + } + + return ( Success ); +} + +//********************************************************************************************************************************** + +bool TLSTESTER::RunSingleServerDefaultsTLSTest ( int MeasurementNumber ) +{ + int Response; + int Result; + bool Success = FALSE; + + fprintf ( DebugFile, "Running single server defaults TLS test %d\n", MeasurementNumber ); + + if ( VerboseConsoleOutput ) + { + printf ( "Running single server defaults TLS test %d\n", MeasurementNumber ); + } + + ClientComponent->SetMeasurementNumber ( MeasurementNumber ); + ServerComponent->SetMeasurementNumber ( MeasurementNumber ); + + ClientComponent->RecordMeasurementStartTime (); // start time for this measurement + ServerComponent->RecordMeasurementStartTime (); // start time for this measurement + + Result = ClientComponent->AddRootFileOrPath ( CertificateAuthorityChainFilename ); // must be done before the configure + + if ( Result ) + { + Result = ClientComponent->Configure (); // set default TLS version + + if ( Result ) + { + Result = ClientComponent->ConfigureCertificateCallbacks (); + + if ( Result ) + { + Result = ClientComponent->ConfigureNegotiationCallback (); + + if ( Result ) + { + Result = ClientComponent->Connect (); + + // + // The component will call the send() and receive() callback functions to perform the handshake and the + // Connect () function call returns only when the handshake is complete. + // + + if ( Result ) + { + if ( VerboseConsoleOutput ) printf ( "ClientComponent->Connect() was successful!\n" ); + + // don't do any data transfer in this particular test + + ClientComponent->Close (); + + Success = TRUE; + } + else + { + printf ( "ClientComponent->Connect() failed!\n" ); + } + } + else + { + printf ( "ClientComponent->ConfigureNegotiationCallback () failed!\n" ); + } + } + else + { + printf ( "ClientComponent->ConfigureCertificateCallbacks () failed!\n" ); + } + } + else + { + printf ( "ClientComponent->Configure() failed!\n" ); + } + } + else + { + printf ( "ClientComponent->AddRootFileOrPath () failed!\n" ); + } + + ClientComponent->RecordMeasurementEndTime (); + ServerComponent->RecordMeasurementEndTime (); + + if ( VerboseConsoleOutput ) printf ( "Last Error Code = %d\n", GetLastError () ); + + return ( Success ); +} + +//********************************************************************************************************************************** +// +// In a server test, no sockets are required, buffers are used instead to remove network delay. The client and server components use +// their respective send and receive callbacks to communicate with the tester. These callbacks work with buffers. So the Client send +// callback writes into a buffer and the server receive callback reads from that buffer. Similarly the server send callback writes +// into another buffer and the client receive callback reads from that buffer. +// +//

+//
+//    ------------     Send()   ----------  Receive() -------------
+//    |           |------------>|        |----------->|           |
+//    |   Server  |    .  .     | Tester |            |   Client  |
+//    | Component |             |        |            | Component |
+//    |           |<------------|        |<-----------|           |
+//    ------------   Receive()  ----------   Send()   -------------
+//
+// 
+// +bool TLSTESTER::RunSingleServerTLSTest ( int MeasurementNumber, + const char *CipherSuite, + const char *SignatureAlgorithm, + const char *NamedGroup ) +{ + int Result; + bool Success = FALSE; + + fprintf ( DebugFile, + "Running single server TLS test %d on Cipher Suite %s, Signature Algorithm %s and Named group %s\n", + MeasurementNumber, + CipherSuite, + SignatureAlgorithm, + NamedGroup ); + + if ( VerboseConsoleOutput ) + { + printf ( "Running single server TLS test %d on Cipher Suite %s, Signature Algorithm %s and Named group %s\n", + MeasurementNumber, + CipherSuite, + SignatureAlgorithm, + NamedGroup ); + } + + // sockets are not used in the server tests as buffers are used instead to eliminate network delay + + Success = SingleClientTLSTest ( MeasurementNumber, CipherSuite, SignatureAlgorithm, NamedGroup ); + + return ( Success ); +} + +//********************************************************************************************************************************** + +bool TLSTESTER::SingleClientTLSTest ( int MeasurementNumber, + const char *CipherSuite, + const char *SignatureAlgorithm, + const char *NamedGroup ) +{ + int Result; + bool Success = FALSE; + + ClientComponent->SetMeasurementNumber ( MeasurementNumber ); + + ClientComponent->RecordMeasurementStartTime (); // start time for this measurement + + Result = ClientComponent->AddRootFileOrPath ( CertificateAuthorityChainFilename ); // must be done before the configure + + if ( Result ) + { + Result = ClientComponent->Configure (); + + if ( Result ) + { + Result = ClientComponent->ConfigureCipherSuites ( CipherSuite ); + + if ( Result ) + { + Result = ClientComponent->ConfigureSignatureAlgorithms ( SignatureAlgorithm ); + + if ( Result ) + { + Result = ClientComponent->ConfigureNamedGroups ( NamedGroup ); + + if ( Result ) + { + Result = ClientComponent->ConfigureCertificateCallbacks (); + + if ( Result ) + { + Result = ClientComponent->ConfigureNegotiationCallback (); + + if ( Result ) + { + Result = ClientComponent->Connect (); + + // + // The Client Component will call the send() and receive() callback functions to perform the + // handshake and the Connect () function call returns only when the handshake is complete. + // + + if ( Result ) + { + if ( VerboseConsoleOutput ) fprintf (stderr, "ClientComponent->Connect() was successful!\n" ); + + ClientComponent->Close (); + + Success = TRUE; + } + else + { + fprintf ( DebugFile, "ClientComponent->Connect() failed!\n" ); + } + } + else + { + fprintf ( DebugFile, "ClientComponent->ConfigureNegotiationCallback () failed!\n" ); + } + } + else + { + fprintf ( DebugFile, "ClientComponent->ConfigureCertificateCallbacks() failed!\n" ); + } + } + else + { + fprintf ( DebugFile, "ClientComponent->ConfigureNamedGroups ( %s ) failed!\n", NamedGroup ); + } + } + else + { + fprintf (DebugFile, "ClientComponent->ConfigureSignatureAlgorithms ( %s ) failed!\n", SignatureAlgorithm ); + } + } + else + { + fprintf ( DebugFile, "ClientComponent->ConfigureCipherSuites ( %s ) failed!\n", CipherSuite ); + } + } + else + { + fprintf ( DebugFile, "ClientComponent->Configure() failed!\n" ); + } + } + else + { + fprintf ( DebugFile, "ClientComponent->AddRootFileOrPath () failed!\n" ); + } + + ClientComponent->RecordMeasurementEndTime (); + + if ( VerboseConsoleOutput ) fprintf ( stderr, "Last Error Code = %d\n", GetLastError () ); + + return ( Success ); +} + +//********************************************************************************************************************************** + +const char *HashNames [] = +{ + "MD5", // TLS_hash_MD5 = 0, + "SHA1", // TLS_hash_SHA1 = 1, + "SHA224", // TLS_hash_SHA224 = 2, + "SHA256", // TLS_hash_SHA256 = 3, + "SHA384", // TLS_hash_SHA384 = 4, + "SHA512", // TLS_hash_SHA512 = 5 +}; + +const char *AEADNames [] = +{ + "AES_128_GCM", // TLS_aead_AES_128_GCM = 0, + "AES_256_GCM", // TLS_aead_AES_256_GCM = 1, + "CHACHA20_POLY1305", // TLS_aead_CHACHA20_POLY1305 = 2 +}; + +size_t InputBufferSize = 0; +size_t OutputBufferSize = 0; + +unsigned char InputBuffer [ 8192 ]; +unsigned char OutputBuffer [ 8192 ]; + +void TLSTESTER::RunSingleClientQUICTest ( int MeasurementNumber, + const char *CipherSuite, + const char *SignatureAlgorithm, + const char *NamedGroup ) +{ + struct hostent *Peer; + struct sockaddr_in PeerAddress; + int Response; + int Result; + int AmountSent; + int AmountReceived; + quic_result QuicResult; + quic_secret EarlySecret; + quic_secret MainSecret; + unsigned char SecretBuffer [ ( sizeof ( EarlySecret.secret ) * 2 ) + 2 ]; + + + fprintf ( DebugFile, + "Running single client QUIC test %d on Cipher Suite %s, Signature Algorithm %s and Named group %s\n", + MeasurementNumber, + CipherSuite, + SignatureAlgorithm, + NamedGroup ); + + if ( VerboseConsoleOutput ) + { + printf ( "Running single client QUIC test %d on Cipher Suite %s, Signature Algorithm %s and Named group %s\n", + MeasurementNumber, + CipherSuite, + SignatureAlgorithm, + NamedGroup ); + } + + // open socket to communicate with peer (server) + + PeerSocket = socket ( AF_INET, SOCK_STREAM, 0 ); // needs to be TCP as this is not a full implementation of QUIC! + + if ( PeerSocket != 0 ) + { + Peer = gethostbyname ( ClientComponent->GetHostName () ); + + memset ( &PeerAddress, 0, sizeof ( PeerAddress ) ); + + PeerAddress.sin_family = AF_INET; + + memcpy ( &PeerAddress.sin_addr.s_addr, Peer->h_addr, Peer->h_length ); + + PeerAddress.sin_port = htons ( ClientComponent->GetPortNumber () ); + + Response = connect ( PeerSocket, ( struct sockaddr* ) &PeerAddress, sizeof ( PeerAddress ) ); + + if ( Response == 0 ) + { + ClientComponent->SetMeasurementNumber ( MeasurementNumber ); + + ClientComponent->RecordMeasurementStartTime (); + + ClientComponent->SetSocket ( PeerSocket ); // use the peer for now but switch to the server thread ASAP + + Result = ClientComponent->QuicCreate (); + + if ( Result ) + { + //Result = ClientComponent->ConfigureCipherSuites ( CipherSuite ); + + if ( Result ) + { + //Result = ClientComponent->ConfigureSignatureAlgorithms ( SignatureAlgorithm ); + + if ( Result ) + { + //Result = ClientComponent->ConfigureNamedGroups ( NamedGroup ); + + if ( Result ) + { + QuicResult = TLS_would_block; + + while ( ( QuicResult != TLS_client_complete ) || ( QuicResult != TLS_client_complete_with_early_data ) ) + { + // rather than using the send and receive callbacks, QUIC uses buffers + + InputBufferSize = 0; + + QuicResult = ClientComponent->QuicProcess ( InputBuffer, + &InputBufferSize, + OutputBuffer, + &OutputBufferSize ); + + if ( ! PrintQuicResult ( QuicResult ) ); break; // stop if quic process returned an unknown result + + // send any message to the peer + + if ( OutputBufferSize != 0 ) + { + AmountSent = send ( PeerSocket, ( const char *) OutputBuffer, OutputBufferSize, 0 ); + + if ( AmountSent != OutputBufferSize ) + { + printf ( "network send() to peer failed!\n" ); PrintSocketError (); break; + } + else + { + DumpPacket ( OutputBuffer, OutputBufferSize, 0, 0, "sent to quic peer" ); + } + } + + // receive any response from the peer + + if ( InputBufferSize != 0 ) + { + AmountReceived = recv ( PeerSocket, (char *) InputBuffer, InputBufferSize, 0 ); + + if ( AmountReceived != InputBufferSize ) + { + printf ( "network recv() from peer failed!\n" ); PrintSocketError (); break; + } + else + { + DumpPacket ( InputBuffer, InputBufferSize, 0, 0, "received from quic peer" ); + } + } + } + + // get any early secret and print it out + + if ( ClientComponent->QuicGetExporter ( 0, &EarlySecret ) ) + { + fprintf ( DebugFile, + "EarlySecret: Hash = %d (%s), AEAD = %d (%s), Secret =", + EarlySecret.hash, + HashNames [ EarlySecret.hash ], + EarlySecret.ae, + AEADNames [ EarlySecret.ae ] ); + + for ( int Count = 0; Count < sizeof ( EarlySecret.secret ); Count++ ) + { + fprintf ( DebugFile, " %02x", EarlySecret.secret [ Count ] ); + } + + fprintf ( DebugFile, "\n" ); + } + + // get any main secret and print it out + + if ( ClientComponent->QuicGetExporter ( 1, &MainSecret ) ) + { + fprintf ( DebugFile, + "MainSecret: Hash = %d (%s), AEAD = %d (%s), Secret =", + MainSecret.hash, + HashNames [ MainSecret.hash ], + MainSecret.ae, + AEADNames [ MainSecret.ae ] ); + + for ( int Count = 0; Count < sizeof ( MainSecret.secret ); Count++ ) + { + fprintf ( DebugFile, " %02x", MainSecret.secret [ Count ] ); + } + + fprintf ( DebugFile, "\n" ); + } + } + else + { + printf ( "ClientComponent->ConfigureNamedGroups ( %s ) failed!\n", NamedGroup ); + } + } + else + { + printf ( "ClientComponent->ConfigureSignatureAlgorithms ( %s ) failed!\n", SignatureAlgorithm ); + } + } + else + { + printf ( "ClientComponent->ConfigureCipherSuites ( %s ) failed!\n", CipherSuite ); + } + } + else + { + printf ( "ClientComponent->Configure() failed!\n" ); + } + + ClientComponent->RecordMeasurementEndTime (); + + if ( VerboseConsoleOutput ) printf ( "Return Code = %d\n", GetLastError () ); + } + else + { + fprintf ( DebugFile, "Cannot connect to peer for test!\n" ); + + PrintSocketError (); + } + + closesocket ( PeerSocket ); + } + else + { + fprintf ( DebugFile, "Cannot open socket for peer!\n" ); + + PrintSocketError (); + } +} + +//********************************************************************************************************************************** + +void TLSTESTER::RunSingleServerQUICTest ( int MeasurementNumber, + const char *CipherSuite, + const char *SignatureAlgorithm, + const char *NamedGroup ) +{ + fprintf ( DebugFile, + "Running single server QUIC test %d on Cipher Suite %s, Signature Algorithm %s and Named group %s\n", + MeasurementNumber, + CipherSuite, + SignatureAlgorithm, + NamedGroup ); + + printf ( "Running single server QUIC test %d on Cipher Suite %s, Signature Algorithm %s and Named group %s\n", + MeasurementNumber, + CipherSuite, + SignatureAlgorithm, + NamedGroup ); +} + +//********************************************************************************************************************************** + +bool TLSTESTER::PrintQuicResult ( quic_result QuicResult ) // old knowledge now hidden! +{ + bool Result = TRUE; + + fprintf ( DebugFile, "QuicResult = %d, ", QuicResult ); + + switch ( QuicResult ) + { + case TLS_would_block : fprintf ( DebugFile, "Would block\n" ); break; + case TLS_error_local : fprintf ( DebugFile, "Error Local\n" ); break; + case TLS_error_alert : fprintf ( DebugFile, "Error Alert\n" ); break; + case TLS_client_early : fprintf ( DebugFile, "Client Early\n" ); break; + case TLS_client_complete : fprintf ( DebugFile, "Client Complete\n" ); break; + case TLS_client_complete_with_early_data : fprintf ( DebugFile, "Client Complete with Early Data\n" ); break; + case TLS_server_accept : fprintf ( DebugFile, "Server Accept\n" ); break; + case TLS_server_accept_with_early_data : fprintf ( DebugFile, "Server Accept with Early Data\n" ); break; + case TLS_server_complete : fprintf ( DebugFile, "Server Complete\n" ); break; + case TLS_server_stateless_retry : fprintf ( DebugFile, "Server Stateless Retry\n" ); break; + case TLS_error_other : fprintf ( DebugFile, "Error Other\n" ); break; + + default: fprintf ( DebugFile, "Unknown Quic Result\n" ); Result = FALSE; break; + } + + return ( Result ); +} + +//********************************************************************************************************************************** diff --git a/tests/Tester/Tester/Tester.cpp b/tests/Tester/Tester/Tester.cpp new file mode 100644 index 000000000..700ca79e6 --- /dev/null +++ b/tests/Tester/Tester/Tester.cpp @@ -0,0 +1,183 @@ + +//********************************************************************************************************************************** +// +// Purpose: TESTER OBJECT source code file +// +// Project: Everest +// +// Filename: Tester.cpp +// +// Authors: Caroline.M.Mathieson (CMM) +// +//********************************************************************************************************************************** +// +// Description +// ----------- +// +//! \file Tester.cpp +//! \brief Contains the complete implementation of the TESTER Object. This covers generic tester attributes and functions. +//! +//********************************************************************************************************************************** + +#include "Tester.h" // pulls in everything else + +//********************************************************************************************************************************** + +TESTER::TESTER ( FILE *NewDebugFile, + FILE *NewComponentStatisticsFile, + FILE *NewRecordedClientMeasurementsFile, + FILE *NewRecordedServerMeasurementsFile ) // maybe NULL +{ +/* protected */ + + DebugFile = NewDebugFile; + ComponentStatisticsFile = NewComponentStatisticsFile; + + // initialise basic measurement variables + + memset ( &StartTime, 0, sizeof ( StartTime ) ); + memset ( &EndTime, 0, sizeof ( EndTime ) ); + memset ( &Frequency, 0, sizeof ( Frequency ) ); + +/* public */ + + RecordedClientMeasurementsFile = NewRecordedClientMeasurementsFile; + RecordedServerMeasurementsFile = NewRecordedServerMeasurementsFile; + + // initialise debug and console flags + + ConsoleDebugging = FALSE; + + VerboseConsoleOutput = FALSE; + + RedirectedStandardOutputFile = NULL; + + memset ( &RedirectedStandardOutputFilename, 0, sizeof ( RedirectedStandardOutputFilename ) ); + } + +//********************************************************************************************************************************** + +TESTER::~TESTER ( void ) +{ +} + +//********************************************************************************************************************************** + +FILE *TESTER::GetDebugFile ( void ) +{ + return ( DebugFile ); +} + +//********************************************************************************************************************************** + +bool TESTER::Setup ( char *DateAndTimeString ) +{ + int ResultCode = 0; + WSADATA WindowsSocketsData; + time_t CurrentTime; + struct tm *LocalTime; + + ResultCode = WSAStartup ( MAKEWORD ( 2, 2 ), &WindowsSocketsData ); + + if ( ResultCode == 0 ) + { + fprintf ( DebugFile, "Windows Sockets Interface Started:-\n"); + fprintf ( DebugFile, "\n" ); + fprintf ( DebugFile, " Major Version: 0x%04X\n", WindowsSocketsData.wVersion ); + fprintf ( DebugFile, " Minor Version: 0x%04X\n", WindowsSocketsData.wHighVersion ); + fprintf ( DebugFile, " Max Sockets: %d\n", WindowsSocketsData.iMaxSockets ); + fprintf ( DebugFile, " Max UDP Packet: %d\n", WindowsSocketsData.iMaxUdpDg ); + fprintf ( DebugFile, " Description: %s\n", WindowsSocketsData.szDescription ); + fprintf ( DebugFile, " System Status: %s\n", WindowsSocketsData.szSystemStatus ); + fprintf ( DebugFile, "\n" ); + + if ( VerboseConsoleOutput ) + { + printf ( "Runnning!\n" ); + } + else + { + if ( ! ConsoleDebugging ) // if console debugging is enabled then we "DO" want the output on the console! + { + // get the current date and time + + time ( &CurrentTime ); + + LocalTime = localtime ( &CurrentTime ); + + // and create a filename based on that for the redirected standard output + + sprintf ( RedirectedStandardOutputFilename, + "RedirectedStandardOutput_%02d_%02d_%d_at_%02d_%02d_%02d.txt", + LocalTime->tm_wday, + LocalTime->tm_mday, + LocalTime->tm_year + 1900, + LocalTime->tm_hour, + LocalTime->tm_min, + LocalTime->tm_sec ); + + // now redirect the standard output stream into the capture file to hide the debug output from the dlls + + RedirectedStandardOutputFile = freopen ( RedirectedStandardOutputFilename, "a", stdout ); + } + } + + // you only need to get this once as it will not change for a given machine and os + + QueryPerformanceFrequency ( &Frequency ); // clock ticks per second + + QueryPerformanceCounter ( &StartTime ); // in clock ticks + + return ( TRUE ); + } + else + { + fprintf ( DebugFile, "Could not initialise Windows Sockets! ( ResultCode = %d )\n", ResultCode ); + + PrintSocketError (); + + return ( FALSE ); + } +} + +//********************************************************************************************************************************** + +bool TESTER::TearDown ( void ) +{ + QueryPerformanceCounter ( &EndTime ); // in clock ticks + + // now work out the run time + + fprintf ( DebugFile, "Total Run Time was: %u microseconds\n", CalculateExecutionTime ( StartTime, EndTime ) ); + + //if ( ClientComponent != NULL ) ClientComponent->PrintMeasurementResults ( RecordedClientMeasurementsFile ); + //if ( ServerComponent != NULL ) ServerComponent->PrintMeasurementResults ( RecordedServerMeasurementsFile ); + + fprintf ( DebugFile, "Closing Windows Sockets!\n" ); + + WSACleanup (); + + return ( TRUE ); +} + +//********************************************************************************************************************************** + +long TESTER::CalculateExecutionTime ( LARGE_INTEGER StartingTime, LARGE_INTEGER EndingTime ) +{ + LARGE_INTEGER ElapsedMicroseconds; + __int64 ScaledTime; + double ElapsedTime; + + ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart; // calculate delta time + ElapsedMicroseconds.QuadPart *= 1000000; // convert it to clock ticks + ElapsedMicroseconds.QuadPart /= Frequency.QuadPart; // convert to microseconds + + ScaledTime = ( (EndingTime.QuadPart) - (StartingTime.QuadPart) ) * 1000000; + + ElapsedTime = (double) ScaledTime / (double) ( Frequency.QuadPart ); + + return ( long ( ElapsedTime ) ); +} + +//********************************************************************************************************************************** + diff --git a/tests/Tester/Tester/Tester.h b/tests/Tester/Tester/Tester.h new file mode 100644 index 000000000..fd72a15c8 --- /dev/null +++ b/tests/Tester/Tester/Tester.h @@ -0,0 +1,1469 @@ + +//********************************************************************************************************************************** +// +// Purpose: Interoperability Tester header file +// +// Project: Everest +// +// Filename: Tester.h +// +// Authors: Caroline.M.Mathieson (CMM) +// +//********************************************************************************************************************************** +// +// Description +// ----------- +// +//! \file Tester.h +//! \brief Contains the complete definition of the TESTER Object. +//! +//********************************************************************************************************************************** + +#include "stdafx.h" +#include "process.h" +#include "string.h" +#include "stdlib.h" +#include "io.h" +#include "fcntl.h" // for _open_osfhandle() etc +#include "time.h" // for time and local_time +#include "winsock2.h" // for WSAStartup and WSACleanup +#include "windows.h" // for LARGE_INTEGER as used by QueryPerformanceCounter (), sleep () + +#include "mitlsffi.h" // for mitls_state etc +#include "mipki.h" // for mipki_state etc + +#include "pngwriter.h" + +//********************************************************************************************************************************** + +typedef struct optionstableentry +{ + const char *Name; + const char *Meaning; + + void ( OptionHandlerFunction ) ( const char *Argument ); // function to call to parse argument + +} OPTIONS_TABLE_ENTRY; + +//********************************************************************************************************************************** + +/* ansi screen escape sequences */ + +#define ASES_HOME_CURSOR "\033[;f" +#define ASES_CLEAR_SCREEN "\033[2J" +#define ASES_CLEAR_TO_END_OF_LINE "\033[K" +#define ASES_SET_CURSOR_POSITION (row, column) "\033[row;columnH" +#define ASES_MOVE_CURSOR_UP (rows) "\033[rowsA" +#define ASES_MOVE_CURSOR_DOWN (rows) "\033[rowsB" +#define ASES_MOVE_CURSOR_RIGHT (columns) "\033[columnsC" +#define ASES_MOVE_CURSOR_LEFT (columns) "\033[columnsD" +#define ASES_SAVE_CURSOR_POSITION "\033[s" +#define ASES_RESTORE_CURSOR_POSITION "\033[u" +#define ASES_GET_CURSOR_POSITION "\033[6n" +#define ASES_SET_NO_SPECIAL_ATTRIBUTES "\033[0m" +#define ASES_SET_HIGH_INTENSITY "\033[1m" +#define ASES_SET_LOW_INTENSITY "\033[2m" +#define ASES_SET_ITALIC "\033[3m" +#define ASES_SET_UNDERLINE "\033[4m" +#define ASES_SET_BLINK "\033[5m" +#define ASES_SET_RAPID_BLINK "\033[6m" +#define ASES_SET_REVERSE_VIDEO "\033[7m" +#define ASES_SET_CONCEALED_TEXT "\033[8m" +#define ASES_SET_FOREGROUND_BLACK "\033[30m" +#define ASES_SET_FOREGROUND_RED "\033[31m" +#define ASES_SET_FOREGROUND_GREEN "\033[32m" +#define ASES_SET_FOREGROUND_YELLOW "\033[33m" +#define ASES_SET_FOREGROUND_BLUE "\033[34m" +#define ASES_SET_FOREGROUND_MAGENTA "\033[35m" +#define ASES_SET_FOREGROUND_CYAN "\033[36m" +#define ASES_SET_FOREGROUND_WHITE "\033[37m" +#define ASES_SET_BACKGROUND_BLACK "\033[40m" +#define ASES_SET_BACKGROUND_RED "\033[41m" +#define ASES_SET_BACKGROUND_GREEN "\033[42m" +#define ASES_SET_BACKGROUND_YELLOW "\033[43m" +#define ASES_SET_BACKGROUND_BLUE "\033[44m" +#define ASES_SET_BACKGROUND_MAGENTA "\033[45m" +#define ASES_SET_BACKGROUND_CYAN "\033[46m" +#define ASES_SET_BACKGROUND_WHITE "\033[47m" +#define ASES_SET_DISPLAY_MODE_0 "\033[=0h" +#define ASES_SET_DISPLAY_MODE_1 "\033[=1h" +#define ASES_SET_DISPLAY_MODE_2 "\033[=2h" +#define ASES_SET_DISPLAY_MODE_3 "\033[=3h" +#define ASES_SET_DISPLAY_MODE_4 "\033[=4h" +#define ASES_SET_DISPLAY_MODE_5 "\033[=5h" +#define ASES_SET_DISPLAY_MODE_6 "\033[=6h" +#define ASES_SET_DISPLAY_MODE_14 "\033[=14h" +#define ASES_SET_DISPLAY_MODE_15 "\033[=15h" +#define ASES_SET_DISPLAY_MODE_16 "\033[=16h" +#define ASES_SET_DISPLAY_MODE_17 "\033[=17h" +#define ASES_SET_DISPLAY_MODE_18 "\033[=18h" +#define ASES_SET_DISPLAY_MODE_19 "\033[=19h" +#define ASES_ENABLE_LINE_WRAP "\033[=7h" +#define ASES_DISABLE_LINE_WRAP "\033[=7l" + +//********************************************************************************************************************************** + +typedef enum filemodes +{ + TEXT_MODE = 0x01, // create plain text files + CSV_MODE = 0x02, // create CSV files + XML_MODE = 0x04, // create XML files + HTML_MODE = 0x08, // create HTML files + GNUPLOT_MODE = 0x10, // create GNUPLOT files + PNG_MODE = 0x20, // create PNG files + + ALL_MODES = 0xFF // create all file types + +} FILE_MODES; + +//********************************************************************************************************************************** + +typedef enum measurementtypes +{ + TLS_CLIENT_MEASUREMENTS = 0, + QUIC_CLIENT_MEASUREMENTS, + + TLS_SERVER_MEASUREMENTS, + QUIC_SERVER_MEASUREMENTS, + + OPENSSL_SERVER_MEASUREMENTS, + BORINGSSL_SERVER_MEASUREMENTS, + MBEDTLS_SERVER_MEASUREMENTS, + WOLFSSL_SERVER_MEASUREMENTS, + FIZZ_SERVER_MEASUREMENTS, + + OPENSSL_CLIENT_MEASUREMENTS, + BORINGSSL_CLIENT_MEASUREMENTS, + MBEDTLS_CLIENT_MEASUREMENTS, + WOLFSSL_CLIENT_MEASUREMENTS, + FIZZ_CLIENT_MEASUREMENTS, + + MAX_MEASUREMENT_TYPES // the last one and gives the quantity + +} MEASUREMENTTYPES; + +//********************************************************************************************************************************** + +typedef enum ffifunctions +{ + // TLS API functions + + FFI_MITLS_INIT = 0, + FFI_MITLS_CONFIGURE, + FFI_MITLS_SET_TICKET_KEY, + FFI_MITLS_CONFIGURE_TICKET, + FFI_MITLS_CONFIGURE_CIPHER_SUITES, + FFI_MITLS_CONFIGURE_SIGNATURE_ALGORITHMS, + FFI_MITLS_CONFIGURE_NAMED_GROUPS, + FFI_MITLS_CONFIGURE_ALPN, + FFI_MITLS_CONFIGURE_EARLY_DATA, + FFI_MITLS_CONFIGURE_CUSTOM_EXTENSIONS, + FFI_MITLS_CONFIGURE_TICKET_CALLBACK, + FFI_MITLS_CONFIGURE_NEGO_CALLBACK, + FFI_MITLS_CONFIGURE_CERT_CALLBACKS, + FFI_MITLS_CLOSE, + FFI_MITLS_CONNECT, + FFI_MITLS_ACCEPT_CONNECTED, + FFI_MITLS_GET_EXPORTER, + FFI_MITLS_GET_CERT, + FFI_MITLS_SEND, + FFI_MITLS_RECEIVE, + FFI_MITLS_FREE, + FFI_MITLS_CLEANUP, + FFI_MITLS_SET_TRACE_CALLBACK, + + // QUIC API functions + + FFI_MITLS_QUIC_CREATE, + FFI_MITLS_QUIC_PROCESS, + FFI_MITLS_QUIC_GET_EXPORTER, + FFI_MITLS_QUIC_CLOSE, + FFI_MITLS_GET_HELLO_SUMMARY, + FFI_MITLS_FIND_CUSTOM_EXTENSION, + FFI_MITLS_GLOBAL_FREE, + + MAX_FFI_FUNCTIONS // the last one and gives the quantity + +} FFI_FUNCTIONS; + +typedef enum fficallbacks +{ + // TLS API callback functions (these can be called more than once by the component) + + FFI_MITLS_SEND_CALLBACK = 0, + FFI_MITLS_RECEIVE_CALLBACK, + + FFI_MITLS_CERTIFICATE_SELECT_CALLBACK, + FFI_MITLS_CERTIFICATE_FORMAT_CALLBACK, + FFI_MITLS_CERTIFICATE_SIGN_CALLBACK, + FFI_MITLS_CERTIFICATE_VERIFY_CALLBACK, + + FFI_MITLS_TICKET_CALLBACK, + FFI_MITLS_NEGOTIATION_CALLBACK, + FFI_MITLS_TRACE_CALLBACK, + + MAX_FFI_CALLBACK_FUNCTIONS // the last one and gives the quantity + +} FFI_CALLBACK_FUNCTIONS; + +typedef enum pkifunctions +{ + MIPKI_INIT = 0, + MIPKI_FREE, + MIPKI_ADD_ROOT_FILE_OR_PATH, + MIPKI_SELECT_CERTIFICATE, + MIPKI_SIGN_VERFIY, + MIPKI_PARSE_CHAIN, + MIPKI_PARSE_LIST, + MIPKI_FORMAT_CHAIN, + MIPKI_FORMAT_ALLOC, + MIPKI_VALIDATE_CHAIN, + MIPKI_FREE_CHAIN, + + MAX_PKI_FUNCTIONS // the last one and gives the quantity + +} PKI_FUNCTIONS; + +typedef enum pkicallbackfunctions +{ + MIPKI_PASSWORD_CALLBACK = 0, + MIPKI_ALLOC_CALLBACK, + + MAX_PKI_CALLBACK_FUNCTIONS // the last one and gives the quantity + +} PKI_CALLBACK_FUNCTIONS; + +//********************************************************************************************************************************** + +#define MAX_COMPONENT_CALLS_PER_MEASUREMENT (5) +#define MAX_CALLBACK_CALLS_PER_MEASUREMENT (200) +#define MAX_MEASUREMENTS (2000) + +typedef struct componentmeasuremententry +{ + const char *EntryName; + unsigned int NumberOfCalls; + LARGE_INTEGER StartTimes [ MAX_COMPONENT_CALLS_PER_MEASUREMENT ]; // when the function was called + LARGE_INTEGER EndTimes [ MAX_COMPONENT_CALLS_PER_MEASUREMENT ]; // when the function returned + +} COMPONENTMEASUREMENTENTRY; + +typedef struct callbackmeasuremententry +{ + const char *EntryName; + unsigned int NumberOfCalls; + + LARGE_INTEGER StartTimes [ MAX_CALLBACK_CALLS_PER_MEASUREMENT ]; // when the function was called + LARGE_INTEGER EndTimes [ MAX_CALLBACK_CALLS_PER_MEASUREMENT ]; // when the function returned + +} CALLBACKMEASUREMENTENTRY; + +typedef struct componentmeasurement +{ + LARGE_INTEGER MeasurementStartTime; // when the measurement started + LARGE_INTEGER MeasurementEndTime; // when the measurement finished + + COMPONENTMEASUREMENTENTRY FFIMeasurements [ MAX_FFI_FUNCTIONS ]; // one for each FFI function + + COMPONENTMEASUREMENTENTRY PKIMeasurements [ MAX_PKI_FUNCTIONS ]; // one for each PKI function + + CALLBACKMEASUREMENTENTRY FFICallbackMeasurements [ MAX_FFI_CALLBACK_FUNCTIONS ]; // one for each call back function + + CALLBACKMEASUREMENTENTRY PKICallbackMeasurements [ MAX_PKI_CALLBACK_FUNCTIONS ]; // one for each call back function + +} COMPONENTMEASUREMENT; + +typedef struct measurementresults +{ + const char *MeasurementTypeName; + + LARGE_INTEGER TestRunStartTime; // when the test run started + LARGE_INTEGER TestRunEndTime; // when the test run finished + + COMPONENTMEASUREMENT Measurements [ MAX_MEASUREMENTS ]; // individual component measurements + +} MEASUREMENTRESULTS; + +typedef struct measurementsummaryentry +{ + bool IsCallback; + bool IsServer; + + const char *FunctionName; + + unsigned int TestRunNumber; + unsigned int MeasurementNumber; + unsigned int CallNumber; + + unsigned long StartTime; + unsigned long Duration; + +} MEASUREMENT_SUMMARY_ENTRY; + +//********************************************************************************************************************************** + +typedef enum +{ + TLS_CT_CHANGE_CIPHER_SPEC = 20, + TLS_CT_ALERT = 21, + TLS_CT_HANDSHAKE = 22, + TLS_CT_APPLICATION_DATA = 23, + TLS_CT_HEARTBEAT = 24 + +} TLS_CONTENT_TYPE; + +typedef enum +{ + TLS_MT_HELLO_REQUEST = 0, + TLS_MT_CLIENT_HELLO = 1, + TLS_MT_SERVER_HELLO = 2, + TLS_MT_NEW_SESSION_TICKET = 4, + TLS_MT_END_OF_EARLY_DATA = 5, + TLS_MT_HELLO_RETRY_REQUEST = 6, + TLS_MT_ENCRYPTED_EXTENSIONS = 8, + TLS_MT_CERTIFICATE = 11, + TLS_MT_SERVER_KEY_EXCHANGE = 12, + TLS_MT_CERTIFICATE_REQUEST = 13, + TLS_MT_SERVER_HELLO_DONE = 14, + TLS_MT_CERTIFICATE_VERIFY = 15, + TLS_MT_CLIENT_KEY_EXCHANGE = 16, + TLS_MT_FINISHED = 20, + TLS_MT_KEY_UPDATE = 24, + TLS_MT_MESSAGE_HASH = 254 + +} TLS_MESSAGE_TYPE; + +typedef enum +{ + TLS_ET_SERVER_NAME = 0, + TLS_ET_MAX_FRAGMENT_LENGTH = 1, + TLS_ET_CLIENT_CERTIFICATE_URL = 2, + TLS_ET_TRUSTED_CA_KEYS = 3, + TLS_ET_TRUNCATED_HMAC = 4, + TLS_ET_STATUS_REQUEST = 5, + TLS_ET_USER_MAPPING = 6, + TLS_ET_CLIENT_AUTHZ = 7, + TLS_ET_SERVER_AUTHZ = 8, + TLS_ET_CERT_TYPE = 9, + TLS_ET_SUPPORTED_GROUPS = 10, + TLS_ET_EC_POINT_FORMATS = 11, + TLS_ET_SRP = 12, + TLS_ET_SIGNATURE_ALGORITHMS = 13, + TLS_ET_USE_SRTP = 14, + TLS_ET_HEARTBEAT = 15, + TLS_ET_APPLICATION_LAYER_PROTOCOL_NEGOTIATION = 16, + TLS_ET_STATUS_REQUEST_V2 = 17, + TLS_ET_SIGNED_CERTIFICATE_TIMESTAMP = 18, + TLS_ET_CLIENT_CERTIFICATE_TYPE = 19, + TLS_ET_SERVER_CERTIFICATE_TYPE = 20, + TLS_ET_PADDING = 21, + TLS_ET_ENCRYPT_THEN_MAC = 22, + TLS_ET_EXTENDED_MASTER_SECRET = 23, + TLS_ET_TOKEN_BINDING = 24, + TLS_ET_CACHED_INFO = 25, + TLS_ET_QUIC_TRANSPORT_PARAMETERS = 26, // new + TLS_ET_COMPRESS_CERTIFICATE = 27, + TLS_ET_RECORD_SIZE_LIMIT = 28, + TLS_ET_SESSIONTICKET = 35, + TLS_ET_PRE_SHARED_KEY = 41, + TLS_ET_EARLY_DATA = 42, + TLS_ET_SUPPORTED_VERSIONS = 43, + TLS_ET_COOKIE = 44, + TLS_ET_PSK_KEY_EXCHANGE_MODES = 45, + TLS_ET_CERTIFICATE_AUTHORITIES = 47, + TLS_ET_OID_FILTERS = 48, + TLS_ET_POST_HANDSHAKE_AUTH = 49, + TLS_ET_SIGNATURE_ALGORITHMS_CERT = 50, + TLS_ET_KEY_SHARE = 51, + TLS_ET_RESERVED_GREASE_0 = 0x0A0A, // Generate Random Extensions And Sustain Extensibility (Google). + TLS_ET_RESERVED_GREASE_1 = 0x1A1A, + TLS_ET_RESERVED_GREASE_2 = 0x2A2A, + TLS_ET_RESERVED_GREASE_3 = 0x3A3A, + TLS_ET_RESERVED_GREASE_4 = 0x4A4A, + TLS_ET_RESERVED_GREASE_5 = 0x5A5A, + TLS_ET_RESERVED_GREASE_6 = 0x6A6A, + TLS_ET_RESERVED_GREASE_7 = 0x7A7A, + TLS_ET_RESERVED_GREASE_8 = 0x8A8A, + TLS_ET_RESERVED_GREASE_9 = 0x9A9A, + TLS_ET_RESERVED_GREASE_A = 0xAAAA, + TLS_ET_RESERVED_GREASE_B = 0xBABA, + TLS_ET_RESERVED_GREASE_C = 0xCACA, + TLS_ET_RESERVED_GREASE_D = 0xDADA, + TLS_ET_RESERVED_GREASE_E = 0xEAEA, + TLS_ET_RESERVED_GREASE_F = 0xFAFA, + TLS_ET_RENEGOTIATION_INFO = 65281, + TLS_ET_UNDEFINED_EXTENSION_TYPE = 0xFFFF, + +} TLS_EXTENSION_TYPE; + +typedef struct extensiontypeentry +{ + TLS_EXTENSION_TYPE Value; + const char *Name; + const char *Text; + +} EXTENSION_TYPE_ENTRY; + +//********************************************************************************************************************************** + +typedef enum alertdescription +{ + TLS_AD_CLOSE_NOTIFY = (0), + TLS_AD_UNEXPECTED_MESSAGE = (10), + TLS_AD_BAD_RECORD_MAC = (20), + TLS_AD_DECRYPTION_FAILED_RESERVED = (21), + TLS_AD_RECORD_OVERFLOW = (22), + TLS_AD_DECOMPRESSION_FAILURE = (30), + TLS_AD_HANDSHAKE_FAILURE = (40), + TLS_AD_NO_CERTIFICATE_RESERVED = (41), + TLS_AD_BAD_CERTIFICATE = (42), + TLS_AD_UNSUPPORTED_CERTIFICATE = (43), + TLS_AD_CERTIFICATE_REVOKED = (44), + TLS_AD_CERTIFICATE_EXPIRED = (45), + TLS_AD_CERTIFICATE_UNKNOWN = (46), + TLS_AD_ILLEGAL_PARAMETER = (47), + TLS_AD_UNKNOWN_CA = (48), + TLS_AD_ACCESS_DENIED = (49), + TLS_AD_DECODE_ERROR = (50), + TLS_AD_DECRYPT_ERROR = (51), + TLS_AD_EXPORT_RESTRICTION_RESERVED = (60), + TLS_AD_PROTOCOL_VERSION = (70), + TLS_AD_INSUFFICIENT_SECURITY = (71), + TLS_AD_INTERNAL_ERROR = (80), + TLS_AD_USER_CANCELED = (90), + TLS_AD_NO_RENEGOTIATION = (100), + TLS_AD_UNSUPPORTED_EXTENSION = (110), + TLS_AD_CERTIFICATE_UNOBTAINABLE = (111), + TLS_AD_UNRECOGNIZED_NAME = (112), + TLS_AD_BAD_CERTIFICATE_STATUS_RESPONSE = (113), + TLS_AD_BAD_CERTIFICATE_HASH_VALUE = (114), + TLS_AD_UNKNOWN = (255) + +} TLS_ALERT_DESCRIPTION; + +typedef struct alertdescriptionentry +{ + TLS_ALERT_DESCRIPTION Value; + const char *Name; + const char *Text; + +} ALERT_DESCRIPTION_ENTRY; + +//********************************************************************************************************************************** + +typedef enum ciphersuites +{ + TLS_RSA_WITH_RC4_128_SHA = 0x0005, + TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A, + TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F, + TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x0030, + TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x0031, + TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033, + TLS_DH_ANON_WITH_AES_128_CBC_SHA = 0x0034, + TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035, + TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x0036, + TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x0037, + TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038, + TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039, + TLS_DH_ANON_WITH_AES_256_CBC_SHA = 0x003A, + TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C, + TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C, + TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D, + TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = 0x00A2, + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E, + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F, + TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF, + TLS_AES_128_GCM_SHA256 = 0x1301, + TLS_AES_256_GCM_SHA384 = 0x1302, + TLS_CHACHA20_POLY1305_SHA256 = 0x1303, + TLS_AES_128_CCM_SHA256 = 0x1304, + TLS_AES_128_CCM_8_SHA256 = 0x1305, + TLS_RESERVED_GREASE = 0x6A6A, + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A, + TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011, + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C, + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 = 0xCCA8, + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 = 0xCCA9, + TLS_DHE_RSA_WITH_CHACHA20_POLY1305 = 0xCCAA, + + TLS_CIPHER_SUITE_UNDEFINED = 0xFFFF + +} TLS_CIPHER_SUITES; + +typedef struct ciphersuitedescriptionentry +{ + TLS_CIPHER_SUITES Value; + const char *Name; + bool Supported; // in component + +} CIPHER_SUITE_DESCRIPTION_ENTRY; + +//********************************************************************************************************************************** + +typedef enum signaturealgorithms // grouped by type but numerical values over-ride normal assignment +{ + // theoretically supported by mitls + + TLS_SA_RSA_PKCS1_SHA256 = 0x0401, + TLS_SA_RSA_PKCS1_SHA384 = 0x0501, + TLS_SA_RSA_PKCS1_SHA512 = 0x0601, + + // ECDSA Algorithms + TLS_SA_ECDSA_SECP256R1_SHA256 = 0x0403, + TLS_SA_ECDSA_SECP384R1_SHA384 = 0x0503, + TLS_SA_ECDSA_SECP521R1_SHA512 = 0x0603, + + // RSASSA-PSS Algorithms + TLS_SA_RSA_PSS_SHA256 = 0x0804, + TLS_SA_RSA_PSS_SHA384 = 0x0805, + TLS_SA_RSA_PSS_SHA512 = 0x0806, + + // ECDSA Algorithms + TLS_SA_ED25519 = 0x0807, + TLS_SA_ED448 = 0x0808, + + // Legacy Algorithms (not supported by mitls) + TLS_SA_RSA_PKCS1_SHA1 = 0x0201, + TLS_SA_ECDSA_SHA1 = 0x0203, + + TLS_SA_DSA_SHA256 = 0x0402, + TLS_SA_DSA_SHA384 = 0x0502, + TLS_SA_DSA_SHA512 = 0x0602, + TLS_SA_DSA_SHA224 = 0x0302, + TLS_SA_DSA_SHA1 = 0x0202, + + TLS_SA_UNDEFINED = 0xFFFF + +} TLS_SIGNATURE_ALGORITHMS; + +typedef struct signaturealgorithmdescriptionentry +{ + TLS_SIGNATURE_ALGORITHMS Value; + const char *Name; + bool Supported; // in component + +} SIGNATURE_ALGORITHM_DESCRIPTION_ENTRY; + +//********************************************************************************************************************************** + +typedef enum namedgroups +{ + TLS_NG_SECP256R1 = 0x0017, // "secp256r1" + TLS_NG_SECP384R1 = 0x0018, // "secp384r1" + TLS_NG_SECP521R1 = 0x0019, // "secp521r1" + TLS_NG_X25519 = 0x001D, // "x25519" + TLS_NG_X448 = 0x001E, // "x448" + TLS_NG_FFDHE2048 = 0x0100, // "ffdhe2048" + TLS_NG_FFDHE3072 = 0x0101, // "ffdhe3072" + TLS_NG_FFDHE4096 = 0x0102, // "ffdhe4096" + TLS_NG_FFDHE6144 = 0x0103, // "ffdhe6144" + TLS_NG_FFDHE8192 = 0x0104, // "ffdhe8192" + + TLS_NG_UNDEFINED = 0xFFFF + +} TLS_NAMED_GROUPS; + +typedef struct namedgroupdescriptionentry +{ + TLS_NAMED_GROUPS Value; + const char *LoggingName; + const char *ExpectedName; + bool Supported; // in component + +} NAMED_GROUP_DESCRIPTION_ENTRY; + +//********************************************************************************************************************************** +// TLS Records +//********************************************************************************************************************************** + +typedef struct tlsalertrecord +{ +// type Field offset +//----------------------------------------------------------------- + unsigned char AlertLevel; // 5 + unsigned char AlertDescription; // 6 + +} TLS_ALERT_RECORD; + +#define TLS_RECORD_HEADER_SIZE (5) + +typedef struct protocolversion +{ + unsigned char MajorVersion; + unsigned char MinorVersion; + +} TLS_PROTOCOL_VERSION; + +typedef struct tlsmessageheader +{ +// type Field offset +//----------------------------------------------------------------- + unsigned char MessageType; // 5 + unsigned char MessageLengthHigh; // 6 + unsigned char MessageLengthMiddle; // 7 + unsigned char MessageLengthLow; // 8 + +} TLS_MESSAGE_HEADER; + +#define RANDOM_BYTES_LENGTH (28) + +typedef struct tlsgenericrecord +{ + TLS_MESSAGE_HEADER MessageHeader; // 5 to 8 + +} TLS_GENERIC_RECORD; + +#define MAX_SESSION_IDENTIFIER_LENGTH ( 255 ) // it's a single octet field + +typedef struct tlsclienthellorecord +{ + TLS_MESSAGE_HEADER MessageHeader; // 5 to 8 + + // message content + + TLS_PROTOCOL_VERSION HelloVersion; // 9 & 10 + + struct + { + unsigned char UnixTime [ 4 ]; // 11 to 14 + unsigned char RandomBytes [ RANDOM_BYTES_LENGTH ]; // 15 to 43 + + } Random; + + unsigned char SessionIdentifierLength; + + unsigned char SessionIdentifier [ 1 ]; // first variable length field (maybe be 0 length) + +} TLS_CLIENT_HELLO_RECORD; + +typedef struct tlsserverhellorecord +{ + TLS_MESSAGE_HEADER MessageHeader; // 5 to 8 + + // message content + + TLS_PROTOCOL_VERSION HelloVersion; // 9 & 10 + + struct + { + unsigned char UnixTime [ 4 ]; // 11 to 14 + unsigned char RandomBytes [ RANDOM_BYTES_LENGTH ]; // 15 to 43 + + } Random; + + unsigned char SessionIdentifierLength; + + unsigned char SessionIdentifier [ 1 ]; // first variable length field (maybe be 0 length) + +} TLS_SERVER_HELLO_RECORD; + +typedef struct tlscertificate +{ + unsigned char CertificateLengthHigh; + unsigned char CertificateLengthMiddle; + unsigned char CertificateLengthLow; + + unsigned char Certificate [ 1 ]; // size is CertificateLength + +} TLS_CERTIFICATE; + +typedef struct tlscertificaterecord +{ + TLS_MESSAGE_HEADER MessageHeader; // 5 to 8 + + // message content + + unsigned char CertificatesFieldLengthHigh; // 6 + unsigned char CertificatesFieldLengthMiddle; // 7 + unsigned char CertificatesFieldLengthLow; // 8 + + // there can be one or more certificates + + TLS_CERTIFICATE Certificates [ 1 ]; // total size is CertificatesFieldLength + +} TLS_CERTIFICATE_RECORD; + +typedef struct tlsrecordheader +{ +// type Field offset +//----------------------------------------------------------------- + unsigned char ContentType; // 0 + TLS_PROTOCOL_VERSION ProtocolVersion; // 1 & 2 aka LegacyVersion for TLS 1.3+ + unsigned char ContentLengthHigh; // 3 + unsigned char ContentLengthLow; // 4 + +} TLS_RECORD_HEADER; + +typedef struct tlsrecord +{ + TLS_RECORD_HEADER RecordHeader; // 0 to 4 + + union // note that there can be multiple records, each of a different type + { + TLS_GENERIC_RECORD TLSGenericRecord; + TLS_CLIENT_HELLO_RECORD TLSClientHelloRecord; + TLS_SERVER_HELLO_RECORD TLSServerHelloRecord; + TLS_CERTIFICATE_RECORD TLSCertificateRecord; + TLS_ALERT_RECORD TLSAlertRecord; + + } HandshakeRecords; // "fragment" + in RFC 5246 + +} TLS_RECORD; + +//********************************************************************************************************************************** + +typedef enum asnclass +{ + ASN_CLASS_UNIVERSAL = 0, // 0 0 + ASN_CLASS_APPLICATION = 1, // 0 1 + ASN_CLASS_CONTEXT_SPECIFIC = 2, // 1 0 + ASN_CLASS_PRIVATE = 3 // 1 1 + +} ASNCLASS; + +typedef enum asntagnumber +{ + ASN_TAG_UNUSED_0 = 0, + ASN_TAG_BOOLEAN = 1, + ASN_TAG_INTEGER = 2, + ASN_TAG_BIT_STRING = 3, + ASN_TAG_OCTET_STRING = 4, + ASN_TAG_NULL = 5, + ASN_TAG_OBJECT_ID = 6, + ASN_TAG_REAL = 9, + ASN_TAG_SEQUENCE = 16, + ASN_TAG_SET = 17, + ASN_TAG_PRINATBE_STRING = 19, + ASN_TAG_T61STRING = 20, + ASN_TAG_IA5STRING = 22, + ASN_TAG_UTC_TIME = 23, + ASN_TAG_EXTENDED = 31 + +} ASNTAGNUMBER; + +typedef struct asnentry +{ + bool InUse; + + // TAG + ASNCLASS Class; + bool IsPrimitive = FALSE; + ASNTAGNUMBER TagNumber; + + // LENGTH + unsigned long Length; // in octets + + // VALUE + unsigned char Value [ 1 ]; // actually Length octets + +} ASNENTRY; + +#define MAX_ASN_ENTRIES (100000) + +//********************************************************************************************************************************** +// +// This structure implements a very simplist buffering system. There is a simple linear array of unsigned bytes which are written +// into and read from. The bufer is not circular, so if it becomes full then there is a problem with the reading side. Reads and +// writes are performedd using pointers and when the pointers become the same then both are reset to zero since this indicates that +// everything written was read. A record is kept of the total amount of bytes ever written into and read from the buffer. +// + +#define TRANSFER_BUFFER_SIZE ( 1000000 ) // 1MB should be more than enough if the pointers are reset often + +typedef struct buffer +{ +#ifdef WIN32 + CRITICAL_SECTION CriticalSection; +#endif + unsigned char Buffer [ TRANSFER_BUFFER_SIZE ]; + + unsigned char *ReadPointer = Buffer; + unsigned char *WritePointer = Buffer; + + unsigned int ReadIndex = 0; + unsigned int WriteIndex = 0; + + unsigned long int TotalAmountWritten = 0; + unsigned long int TotalAmountRead = 0; + +} TRANSFER_BUFFER; + +//********************************************************************************************************************************** + +class TESTER +{ + protected: + + FILE *DebugFile; + FILE *ComponentStatisticsFile; + + // measurement variables + + LARGE_INTEGER StartTime; + LARGE_INTEGER EndTime; + LARGE_INTEGER Frequency; + + public: + + FILE *RecordedClientMeasurementsFile; + FILE *RecordedServerMeasurementsFile; + + // console output over-ride flags + + bool ConsoleDebugging; // if TRUE, produce console debug output (in addition to component's logging) + + bool VerboseConsoleOutput; // if TRUE, print out all information messages on the console, errors are always output + + FILE *RedirectedStandardOutputFile; // contains the output from the dll and any other stdout + + char RedirectedStandardOutputFilename [ MAX_PATH ]; // the filename of the redirected output file + + public: + + TESTER ( FILE *NewDebugFile, + FILE *NewComponentStatisticsFile, + FILE *NewRecordedClientMeasurementsFile, + FILE *NewRecordedServerMeasurementsFile ); + + ~TESTER ( void ); + + FILE *GetDebugFile ( void ); + + bool Setup ( char *DateAndTimeString ); + + bool TearDown ( void ); + + long CalculateExecutionTime ( LARGE_INTEGER StartingTime, LARGE_INTEGER EndingTime ); + + private: + +}; + +//********************************************************************************************************************************** + +#define MAX_HOST_NAMES (1000) + +class TLSTESTER : public TESTER +{ + protected: + + LARGE_INTEGER TestStartTime; // start time for a measurement + LARGE_INTEGER TestEndTime; // end time for a measurement + + LARGE_INTEGER MeasurementStartTime; // start time for a client TLS measurement + LARGE_INTEGER MeasurementEndTime; // end time for a client TLS measurement + + SOCKET PeerSocket; + + public: + + class COMPONENT *ClientComponent; // callback functions need access to this to do measurements + class COMPONENT *ServerComponent; + + char *DateAndTimeString; // the date and time of the test + + char HostFileName [ MAX_PATH ]; // the name of the file containing the list of hosts, if any + + int NumberOfHostsRead; + + char HostNames [ MAX_HOST_NAMES ] [ 100 ]; + + char TLSVersion [ 4 ]; + + char HostName [ MAX_PATH ]; // the default hostname + + int PortNumber; // the default port number + + // certificate attributes + + char ClientCertificateFilename [ MAX_PATH ]; + char ClientCertificateKeyFilename [ MAX_PATH ]; + + char ServerCertificateFilename [ MAX_PATH ]; + char ServerCertificateKeyFilename [ MAX_PATH ]; + + char CertificateAuthorityChainFilename [ MAX_PATH ]; + + // command line over-ride flags + + bool GenerateImageFiles; // if TRUE, generate a gantt chart style image for each component measurement + + bool UseHostList; // if TRUE, user has specified a list of hostnames in a file + + bool UseHostName; // if TRUE, then the host name is specified on the command line + + bool UsePortNumber; // if TRUE, then the port n umber is specified on the command line + + bool DoTLSTests; // if TRUE, do the TLS tests part of a measurement or test run + + bool DoQUICTests; // if TRUE, do the QUIC tests part of a measurement or test run + + bool DoClientTests; // if TRUE, do the client only TLS and DTLS tests + + bool DoServerTests; // if TRUE, do the client/server TLS and DTLS tests + + bool DoDefaultTests; // if TRUE, do default TLS Parameters part of tests (no config) + + bool DoCombinationTests; // if TRUE, do parameter combinations tests (all configurable TLS Parameters) + + bool DoClientInteroperabilityTests; // if TRUE, do the client mode interoperability TLS and DTLS tests + + bool DoServerInteroperabilityTests; // if TRUE, do the server mode interoperability TLS and DTLS tests + + // thread attributes + + HANDLE AppStandardOutput; + + DWORD ClientTLSTestsThreadIdentifier; + DWORD ServerTLSTestsThreadIdentifier; + + HANDLE ClientTLSTestsThreadHandle; + HANDLE ServerTLSTestsThreadHandle; + + bool ClientTestsFinished; // if TRUE, the client test thread has run and completed + bool ServerTestsFinished; // if TRUE, the server test thread has run and completed + + public: + + TLSTESTER ( FILE *NewDebugFile, + FILE *NewComponentStatisticsFile, + FILE *NewRecordedClientMeasurementsFile, + FILE *NewRecordedServerMeasurementsFile ); + + ~TLSTESTER ( void ); + + void ConfigureClient ( void ); // configure the client component settings from the tester settings + + void ConfigureServer ( void ); // configure the server component settings from the tester settings + + // basic TLS and QUIC client and server tests + + void RunClientTLSTests ( char *TestDateAndTimeString ); // mitls running in TLS client mode only + + void RunServerTLSTests ( char *TestDateAndTimeString ); // mitls running in TLS client and server mode + + void RunClientQUICTests ( char *DateAndTimeString ); // mitls running in QUIC client mode only + + void RunServerQUICTests ( char *DateAndTimeString ); // mitls running in QUIC client and server mode + + // client interoperability TLS tests + + void RunOpenSSLClientTLSTests ( char *DateAndTimeString ); // mitls as TLS client with OpenSSL Server + + void RunBoringClientTLSTests ( char *DateAndTimeString ); // mitls as TLS client with BoringSSL Server + + void RunMbedTLSClientTLSTests ( char *DateAndTimeString ); // mitls as TLS client with MbedTLS Server + + void RunWolfSSLClientTLSTests ( char *DateAndTimeString ); // mitls as TLS client with WolfSSL Server + + void RunFizzClientTLSTests ( char *DateAndTimeString ); // mitls as TLS client with Fizz Server + + // client interoperability QUIC tests + + void RunOpenSSLClientQUICTests ( char *DateAndTimeString ); // mitls as QUIC client with OpenSSL Server + + void RunBoringClientQUICTests ( char *DateAndTimeString ); // mitls as QUIC client with BoringSSL Server + + void RunMbedTLSClientQUICTests ( char *DateAndTimeString ); // mitls as QUIC client with MbedTLS Server + + void RunWolfSSLClientQUICTests ( char *DateAndTimeString ); // mitls as QUIC client with WolfSSL Server + + void RunFizzClientQUICTests ( char *DateAndTimeString ); // mitls as QUIC client with Fizz Server + + // server interoperability TLS tests + + void RunOpenSSLServerTLSTests ( char *DateAndTimeString ); // mitls as TLS server with OpenSSL Client + + void RunBoringServerTLSTests ( char *DateAndTimeString ); // mitls as TLS server with BoringSSL Client + + void RunMbedTLSServerTLSTests ( char *DateAndTimeString ); // mitls as TLS server with MbedTLS Client + + void RunWolfSSLServerTLSTests ( char *DateAndTimeString ); // mitls as TLS server with WolfSSL Client + + void RunFizzServerTLSTests ( char *DateAndTimeString ); // mitls as TLS server with Fizz Client + + // server interoperability QUIC tests + + void RunOpenSSLServerQUICTests ( char *DateAndTimeString ); // mitls as QUIC server with OpenSSL Client + + void RunBoringServerQUICTests ( char *DateAndTimeString ); // mitls as QUIC server with BoringSSL Client + + void RunMbedTLSServerQUICTests ( char *DateAndTimeString ); // mitls as QUIC server with MbedTLS Client + + void RunWolfSSLServerQUICTests ( char *DateAndTimeString ); // mitls as QUIC server with WolfSSL Client + + void RunFizzServerQUICTests ( char *DateAndTimeString ); // mitls as QUIC server with Fizz Client + + public: // equivalent of above methods but accessable from threads + + void ClientTLSTests ( void ); + + void ClientServerTLSTests ( void ); + + void ServerTLSTests ( void ); + + private: + + SOCKET OpenPeerSocket ( void ); + + int RunCombinationTest ( int MeasurementNumber, + char *HostName ); + + bool RunSingleClientDefaultsTLSTest ( int MeasurementNumber ); + + bool RunSingleServerDefaultsTLSTest ( int MeasurementNumber ); + + bool RunSingleClientTLSTest ( int MeasurementNumber, + const char *CipherSuite, + const char *SignatureAlgorithm, + const char *NamedGroup ); + + bool RunSingleServerTLSTest ( int MeasurementNumber, + const char *CipherSuite, + const char *SignatureAlgorithm, + const char *NamedGroup ); + + void RunSingleClientQUICTest ( int MeasurementNumber, + const char *CipherSuite, + const char *SignatureAlgorithm, + const char *NamedGroup ); + + void RunSingleServerQUICTest ( int MeasurementNumber, + const char *CipherSuite, + const char *SignatureAlgorithm, + const char *NamedGroup ); + + bool SingleClientTLSTest ( int MeasurementNumber, + const char *CipherSuite, + const char *SignatureAlgorithm, + const char *NamedGroup ); + + bool PrintQuicResult ( quic_result QuicResult ); +}; + +//********************************************************************************************************************************** + +#define MAX_CERTIFICATE_CHAINS (100) + +class COMPONENT +{ + protected: + + TLSTESTER *Tester = NULL; + + mitls_state *TLSState = NULL; // should be set by the first mitls_init function to the internal state address + + quic_state *QUICState = NULL; // should be set by the quic_create function to the internal state address + + mipki_state *PKIState = NULL; // should be set by the mipki_init function to the internal state address + + quic_config Configuration = + { + Configuration.is_server = IsServer, // should be boolean but defined as an int + + Configuration.alpn = NULL, + Configuration.cipher_suites = NULL, + Configuration.signature_algorithms = NULL, + Configuration.named_groups = NULL, + Configuration.enable_0rtt = 1, // should be boolean TRUE but defined as an int + + // client only + Configuration.host_name = NULL, + Configuration.server_ticket = NULL, + Configuration.exts = NULL, + Configuration.exts_count = 0, + + Configuration.callback_state = NULL, + Configuration.ticket_callback = NULL, + Configuration.nego_callback = NULL, + Configuration.cert_callbacks = NULL, + + // server only + Configuration.ticket_enc_alg = NULL, + Configuration.ticket_key = NULL, + Configuration.ticket_key_len = 0, + }; + + char ClientCertificateFilename [ MAX_PATH ]; + char ClientCertificateKeyFilename [ MAX_PATH ]; + + char ServerCertificateFilename [ MAX_PATH ]; + char ServerCertificateKeyFilename [ MAX_PATH ]; + + // kremlin generated code will abort if this is set to > "1.3". If set to "1.3" then the hello messages use "1.2" and uses + // the extensions to specify the right version. If set to "1.2" then the hello messages use "1.2". If set to "1.1" then the + // hello messages use "1.1". Earlier version are not supported. It is not possible to specify the TLS draft number. + + char TLSVersion [ 4 ]; // "1.X" plus terminating zero + + char HostName [ MAX_PATH ]; + + int PortNumber; + + public: // so callbacks can access them quickly + + bool IsServer = FALSE; + + SOCKET Socket = 0; + + FILE *DebugFile = NULL; + + int NumberOfChainsAllocated = 0; // index into CertificateChains + + mipki_chain CertificateChains [ MAX_CERTIFICATE_CHAINS ]; + + int TestRunNumber; + + int MeasurementNumber; + + int NumberOfMeasurementsMade; // the total number for all tests + + COMPONENTMEASUREMENT *CurrentComponentMeasurement = NULL; // for test run number and measurement number + + MEASUREMENTRESULTS *MeasurementResultsArray [ MAX_MEASUREMENT_TYPES ]; // actually indexed by TestRunNumber + + public: + + COMPONENT ( TLSTESTER *Parent, FILE *NewDebugFile, bool IsServer ); + + ~COMPONENT ( void ); + + // measurements + + void InitialiseMeasurementResults ( void ); + + void AllocateMeasurementResult ( int TestRunNumber ); + + void FreeMeasurementResults ( void ); + + void InitialiseMeasurementResult ( MEASUREMENTRESULTS *MeasurementResult ); + + void PrintMeasurementResults ( FILE *MeasurementsResultFile ); + + void PrintMeasurementResult ( FILE *MeasurementsResultFile, + MEASUREMENTRESULTS *MeasurementResult ); + + void PrintMeasurementSummary ( bool IsServer ); + + void AddMeasurementSummaryEntry ( FILE *MeasurementSummaryFile, + MEASUREMENTRESULTS *MeasurementResult, + COMPONENTMEASUREMENT *ComponentMeasurement, + COMPONENTMEASUREMENTENTRY *ComponentMeasurementEntry, + int TestRunNumber, + int MeasurementNumber, + int FunctionIndex, + int CallIndex ); + + void AddMeasurementSummaryEntry ( FILE *MeasurementSummaryFile, + COMPONENTMEASUREMENT *ComponentMeasurement, + CALLBACKMEASUREMENTENTRY *CallbackMeasurementEntry, + int TestRunNumber, + int MeasurementNumber, + int CallIndex ); + + void CreateMeasurementSummaryImage ( int TestRunNumber, int MeasurementNMumber ); + + void RecordTestRunStartTime ( void ); + + void RecordTestRunEndTime ( void ); + + void RecordMeasurementStartTime ( void ); + + void RecordMeasurementEndTime ( void ); + + // setters + + void SetClientCertificateFilename ( char *NewClientCertificateFilename ); + + void SetClientCertificateKeyFilename ( char *NewClientCertificateKeyFilename ); + + void SetServerCertificateFilename ( char *NewServerCertificateFilename ); + + void SetServerCertificateKeyFilename ( char *NewServerCertificateKeyFilename ); + + void SetVersion ( char *NewVersion ); + + void SetHostName ( char *NewHostName ); + + void SetPortNumber ( int NewPortNumber ); + + void SetTestRunNumber ( int NewTestRunNumber ); + + void SetMeasurementNumber ( int NewMeasurementNumber ); + + void SetNumberOfMeasurementsMade ( int NewNUmberOfMeasurementsMade ); + + void SetSocket ( SOCKET Socket ); + + // getters + + char *GetClientCertificateFilename ( void ); + + char *GetClientCertificateKeyFilename ( void ); + + char *GetServerCertificateFilename ( void ); + + char *GetServerCertificateKeyFilename ( void ); + + char *GetVersion ( void ); + + char *GetHostName ( void ); + + int GetPortNumber ( void ); + + int GetTestRunNumber ( void ); + + int GetMeasurementNumber ( void ); + + int GetNumberOfMeasurementsMade ( void ); + + SOCKET GetSocket ( void ); + + public: + + // TLS API Functions + + int InitialiseTLS ( void ); + + void Cleanup ( void ); + + int Configure ( void ); + + int Configure ( char *UseThisHostName ); // configure using the specified host name + + int SetTicketKey ( const char *Algorithm, + const unsigned char *TicketKey, + size_t TicketKeyLength ); + + int ConfigureCipherSuites ( const char *CipherSuites ) ; + + int ConfigureSignatureAlgorithms ( const char *SignatureAlgorithms ); + + int ConfigureNamedGroups ( const char *NamedGroups ); + + int ConfigureApplicationLayerProtocolNegotiation ( const char *ApplicationLayerProtocolNegotiation ); + + int ConfigureEarlyData ( uint32_t MaximumEarlyData ); + + void ConfigureTraceCallback ( void ); + + int ConfigureTicketCallback ( void *CallbackState, + pfn_FFI_ticket_cb TicketCallback ); + + int ConfigureNegotiationCallback ( void ); // uses the callback functions in component.cpp + + int ConfigureCertificateCallbacks ( void ); // uses the callback functions in component.cpp + + void Close ( void ); + + int Connect ( void ); // client side + + int AcceptConnected ( void ); // server side + + int GetExporter ( int early, + mitls_secret *secret ); + + void *GetCertificate ( size_t *cert_size ); + + int Send ( const unsigned char *buffer, + size_t buffer_size ); + + void *Receive ( size_t *packet_size ); + + // QUIC API Functions + + int QuicCreate ( void ); + + quic_result QuicProcess ( const unsigned char *inBuf, + size_t *pInBufLen, + unsigned char *outBuf, + size_t *pOutBufLen ); + + int QuicGetExporter ( int early, + quic_secret *secret ); + + void QuicClose ( void ); + + int GetHelloSummary ( const unsigned char *buffer, + size_t buffer_len, + mitls_hello_summary *summary, + unsigned char **cookie, + size_t *cookie_len ); + + int FindCustomExtension ( int is_server, + const unsigned char *exts, + size_t exts_len, + uint16_t ext_type, + unsigned char **ext_data, + size_t *ext_data_len ); + + void GlobalFree ( void *pv ); + + // PKI API Functions + + int InitialisePKI ( void ); + + void TerminatePKI ( void ); + + int AddRootFileOrPath ( const char *CertificateAuthorityFile ); + + mipki_chain SelectCertificate ( mipki_state *State, + const unsigned char *ServerNameIndicator, + size_t ServerNameIndicatorLength, + const mitls_signature_scheme *SignatureAlgorithms, + size_t SignatureAlgorithmsLength, + mitls_signature_scheme *SelectedSignature ); + + int SignCertificate ( mipki_state *State, + mipki_chain CertificatePointer, + const mipki_signature SignatureAlgorithm, + const char *Certificate, + size_t CertificateLength, + char *Signature, + size_t *SignatureLength ); + + int VerifyCertificate ( mipki_state *State, + mipki_chain CertificatePointer, + const mipki_signature SignatureAlgorithm, + const char *Certificate, + size_t CertificateLength, + char *Signature, + size_t *SignatureLength ); + + int ParseChain ( mipki_state *State, + const char *ChainOfTrust, + size_t ChainLength ); // returns index into CertificateChains [] + + mipki_chain ParseList ( void ); + + size_t FormatChain ( mipki_state *State, + mipki_chain ChainOfTrust, + unsigned char *ChainBuffer, + size_t ChainBufferLength ); + + void FormatAllocation ( mipki_chain Chain ); + + int ValidateChain ( mipki_chain Chain ); + + void FreeChain ( mipki_chain Chain ); + + private: +}; + +//********************************************************************************************************************************** + +// in InteropTester.cpp + +FILE *OpenRecordedMeasurementsFile ( char *RecordedMeasurementsFileName ); // there is more than one + +FILE *OpenStatisticsFile ( void ); + +FILE *OpenDebugFile ( void ); + +void OperatorConfidence ( void ); + +void ProcessCommandLine ( int ArgumentCount, + char *ArgumentList [], + char *EnvironmentVariables [], + bool Silent ); + +void GetTestParameters ( int ArgumentCount, + char *ArgumentList [], + char *EnvironmentVariables [], + bool Silent ); + +void TestImageCreation ( void ); + +int main ( int ArgumentCount, + char *ArgumentList [], + char *EnvironmentVariables [] ); + +//********************************************************************************************************************************** + +// in component.cpp + +void BufferInitialise ( TRANSFER_BUFFER *TransferBuffer ); + +unsigned long BufferWrite ( TRANSFER_BUFFER *TransferBuffer, unsigned char *Buffer, unsigned long BufferSize ); + +unsigned long BufferRead ( TRANSFER_BUFFER *TransferBuffer, unsigned char *Buffer, unsigned long BufferSize ); + +void BufferReset ( TRANSFER_BUFFER *TransferBuffer ); + +CALLBACKMEASUREMENTENTRY *GetFFICallbackMeasurement ( unsigned int CallBackNumber, + COMPONENT **Component ); + +CALLBACKMEASUREMENTENTRY *GetPKICallbackMeasurement ( unsigned int CallBackNumber, + COMPONENT **Component ); + +int MeasurementSummaryCompare ( const void *arg1, const void *arg2 ); + +//********************************************************************************************************************************** + +// in simpleserver.cpp + +void OpenConsoleCopyFile ( void ); + +void CloseConsoleCopyFile ( void ); + +void DumpPacket ( void *Packet, // the packet to be hex dumped + unsigned int PacketLength, // the length of the packet in octets + unsigned int HighlightStart, // the first octet of special interest + unsigned int HighlightEnd, // the last octet of special interest (0 = none) + const char *Title ); // the purpose of the packet (if known) + +unsigned long DecodePacket ( void *Packet, size_t PacketLength, const char *Title ); + +unsigned long DecodeRecord ( void *Record ); // the length is inside the record + +unsigned long DecodeHandshakeRecord ( void *HandshakeRecord ); // the length is inside the message + +void DecodeClientHello ( TLS_MESSAGE_HEADER *TLSMessage ); + +void DecodeExtension ( unsigned int ExtensionType, // the type of the extension (enumerated) + unsigned int ExtensionLength, // the length of the extension in octets + unsigned int ExtensionsIndex, // octet index into the extensions field + unsigned char *MessagePointer, // points at the beginning of the message + unsigned int MessageIndex ); // index into the message for the extension + +unsigned char *DecodeASN ( unsigned char *ASNMessage, + unsigned long MessageLength ); + +const char *GetVersionString ( unsigned char MajorVersion, + unsigned char MinorVersion ); + +int PrintSocketError ( void ); + +const char *LookupCipherSuite ( int CipherSuite, + bool *Supported ); + +const char *LookupSignatureAlgorithm ( int SignatureAlgorithm, + bool *Supported ); + +const char *LookupNamedGroup ( int NamedGroup, + bool *Supported ); + +//********************************************************************************************************************************** + +// threads for tests + +DWORD WINAPI ClientTLSTestsThread ( LPVOID lpParam ); + +DWORD WINAPI ClientServerTLSTestsThread ( LPVOID lpParam ); + +DWORD WINAPI ServerTLSTestsThread ( LPVOID lpParam ); + +//********************************************************************************************************************************** + +#pragma once diff --git a/tests/Tester/Tester/Tester.user b/tests/Tester/Tester/Tester.user new file mode 100644 index 000000000..23d69dfd0 --- /dev/null +++ b/tests/Tester/Tester/Tester.user @@ -0,0 +1,11 @@ + + + + Any + WindowsLocalDebugger + + + Any + WindowsLocalDebugger + + \ No newline at end of file diff --git a/tests/Tester/Tester/Tester.vcxproj b/tests/Tester/Tester/Tester.vcxproj new file mode 100644 index 000000000..cf2751aeb --- /dev/null +++ b/tests/Tester/Tester/Tester.vcxproj @@ -0,0 +1,149 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {CA0F3E1D-5DCD-4A24-A7E6-687502B7BE17} + Win32Proj + ConsoleApplication2 + 10.0.16299.0 + Tester + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Ws2_32.lib;libmitls.lib;libquiccrypto.lib;libmipki.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Tester/Tester/Tester.vcxproj.filters b/tests/Tester/Tester/Tester.vcxproj.filters new file mode 100644 index 000000000..cea9db7ec --- /dev/null +++ b/tests/Tester/Tester/Tester.vcxproj.filters @@ -0,0 +1,72 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + + + + + \ No newline at end of file diff --git a/tests/Tester/Tester/hostfilelist.txt b/tests/Tester/Tester/hostfilelist.txt new file mode 100644 index 000000000..75f5a8c08 --- /dev/null +++ b/tests/Tester/Tester/hostfilelist.txt @@ -0,0 +1,4 @@ +localhost +bing.com +google.com +tls13.cloudflare.com diff --git a/tests/Tester/Tester/mipki.h b/tests/Tester/Tester/mipki.h new file mode 100755 index 000000000..fb4dd79a2 --- /dev/null +++ b/tests/Tester/Tester/mipki.h @@ -0,0 +1,95 @@ +#ifndef HEADER_MIPKIH +#define HEADER_MIPKIH +#include + +#if defined(_MSC_VER) // Visual Studio - always use __cdecl keyword + #define MITLS_CALLCONV __cdecl +#elif defined(__cdecl) // GCC/MinGW targeting Windows 32-bit - use the __cdecl macro + #define MITLS_CALLCONV __cdecl +#else // Targeting other platforms - use the ambient calling convention + #define MITLS_CALLCONV +#endif + +typedef struct { + const char *cert_file; + const char *key_file; + int is_universal; // If true, this certificate can be used with any name +} mipki_config_entry; + +typedef enum { + MIPKI_SIGN = 0, + MIPKI_VERIFY = 1 +} mipki_mode; + +// Abstract state of the PKI library, implementation-specific +typedef struct mipki_state mipki_state; + +// Uses the TLS code points for signature schemes +// rsa_pkcs1_sha1(0x0201), +// rsa_pkcs1_sha256(0x0401), +// rsa_pkcs1_sha384(0x0501), +// rsa_pkcs1_sha512(0x0601), +// rsa_pss_sha256(0x0804), +// rsa_pss_sha384(0x0805), +// rsa_pss_sha512(0x0806), +// ecdsa_sha1(0x0203), +// ecdsa_secp256r1_sha256(0x0403), +// ecdsa_secp384r1_sha384(0x0503), +// ecdsa_secp521r1_sha512(0x0603), +// ed25519(0x0807), +// ed448(0x0808), +typedef uint16_t mipki_signature; + +// Abstract pointer to an entry in the certificate store +typedef const void* mipki_chain; + +// A callback used to ask for the passphrase of the private key +// Should return the size of the written passphrase, or 0 on error +typedef int (MITLS_CALLCONV *password_callback)(char *pass, int max_size, const char *key_file); + +// A callback to allocate a new buffer to write the chain element to +typedef void* (MITLS_CALLCONV *alloc_callback)(void* cur, size_t len, /*out*/ char **buf); + +// Create a new instance of the PKI library using the provided server configuration +// The configuration describes the selectable certificates as a server, and +// their private keys. They are loaded in memory until mipki_free is called. +// The created instance may be used in multiple TLS connections, for instance, +// it is recommanded to share the mipki_state accoress incoming connections on a server +extern "C" mipki_state* MITLS_CALLCONV mipki_init(const mipki_config_entry config[], size_t config_len, password_callback pcb, int *erridx); +extern "C" void MITLS_CALLCONV mipki_free(mipki_state *st); + +// OpenSSL specific: configure a root certificate file or hash directory. +// This is mandatory to perform certificate chain validation +extern "C" int MITLS_CALLCONV mipki_add_root_file_or_path(mipki_state *st, const char *ca_file); + +// Find a certificate and signature algorithm compatible with the given SNI and list of offered signature algorithms +// Returns a pointer to the selected entry or NULL if no certificate is suitable +extern "C" mipki_chain MITLS_CALLCONV mipki_select_certificate(mipki_state *st, const char *sni, size_t sni_len, const mipki_signature *algs, size_t algs_len, mipki_signature *selected); + +// A combined signature-and-verify function (depending on m) +// Returns 0 on error. When signing, pass a reference to the size of the signature buffer to sig_len, +// after calling sig_len contains the acutal size of the signature. When verifying, pass a reference to the +// input signature length. +extern "C" int MITLS_CALLCONV mipki_sign_verify(mipki_state *st, mipki_chain cert_ptr, const mipki_signature sigalg, const char *tbs, size_t tbs_len, char *sig, size_t *sig_len, mipki_mode m); + +// Parse a chain in TLS network format into an abstract chain object +// Each certificate in the chain is encoded in DER, prefixed with the size of the +// DER-encodeded structure over 3 bytes. The returned chain must be freed after use +extern "C" mipki_chain MITLS_CALLCONV mipki_parse_chain(mipki_state *st, const char *chain, size_t chain_len); + +// Parse an array of DER certificates into a chain object +extern "C" mipki_chain MITLS_CALLCONV mipki_parse_list(mipki_state *st, const char **certs, const size_t* certs_len, size_t chain_len); + +// Format an abstract chain into the TLS network format +extern "C" size_t MITLS_CALLCONV mipki_format_chain(mipki_state *st, mipki_chain chain, char *buffer, size_t buffer_len); + +// Format an abstract chain into a list of buffers allocated with a callback function +extern "C" void MITLS_CALLCONV mipki_format_alloc(mipki_state *st, mipki_chain chain, void* init, alloc_callback cb); + +// Certificate chain validation. This checks revocation, expiration, and matches the hostname +extern "C" int MITLS_CALLCONV mipki_validate_chain(mipki_state *st, mipki_chain chain, const char *host); + +// Free a chain after use. +extern "C" void MITLS_CALLCONV mipki_free_chain(mipki_state *st, mipki_chain chain); + +#endif diff --git a/tests/Tester/Tester/mitlsffi.h b/tests/Tester/Tester/mitlsffi.h new file mode 100755 index 000000000..5aa234a68 --- /dev/null +++ b/tests/Tester/Tester/mitlsffi.h @@ -0,0 +1,237 @@ +#ifndef HEADER_MITLS_FFI_H +#define HEADER_MITLS_FFI_H +#include + +#if defined(_MSC_VER) // Visual Studio - always use __cdecl keyword + #define MITLS_CALLCONV __cdecl +#elif defined(__cdecl) // GCC/MinGW targeting Windows 32-bit - use the __cdecl macro + #define MITLS_CALLCONV __cdecl +#else // Targeting other platforms - use the ambient calling convention + #define MITLS_CALLCONV +#endif + +typedef struct mitls_state mitls_state; // CMM: this has the effect of hiding the structure content! +typedef struct quic_state quic_state; + +typedef struct { + size_t ticket_len; + const unsigned char *ticket; + size_t session_len; + const unsigned char *session; +} mitls_ticket; + +typedef enum { + TLS_SSL3 = 0, + TLS_1p0 = 1, + TLS_1p1 = 2, + TLS_1p2 = 3, + TLS_1p3 = 4 +} mitls_version; + +typedef struct { + uint16_t ext_type; + const unsigned char *ext_data; + size_t ext_data_len; +} mitls_extension; + +typedef enum { + TLS_hash_MD5 = 0, + TLS_hash_SHA1 = 1, + TLS_hash_SHA224 = 2, + TLS_hash_SHA256 = 3, + TLS_hash_SHA384 = 4, + TLS_hash_SHA512 = 5 +} mitls_hash; + +typedef enum { + TLS_aead_AES_128_GCM = 0, + TLS_aead_AES_256_GCM = 1, + TLS_aead_CHACHA20_POLY1305 = 2 +} mitls_aead; + +typedef enum { + TLS_nego_abort = 0, + TLS_nego_accept = 1, + TLS_nego_retry = 2 +} mitls_nego_action; + +typedef uint16_t mitls_signature_scheme; + +// Agile secret with static allocation +typedef struct { + mitls_hash hash; + mitls_aead ae; + unsigned char secret[64]; // Max possible size, flat allocation +} mitls_secret; + +// Invoked when a TLS clients receives a new TLS ticket +typedef void (MITLS_CALLCONV *pfn_FFI_ticket_cb)(void *cb_state, const char *sni, const mitls_ticket *ticket); + +// Invoked when a TLS server is negotiating extensions and stateless retry, +// and when a TLS client is validating the server's negotiated extensions +typedef mitls_nego_action (MITLS_CALLCONV *pfn_FFI_nego_cb)(void *cb_state, mitls_version ver, const unsigned char *exts, size_t exts_len, /*out*/ mitls_extension **custom_exts, /*out*/size_t *custom_exts_len, /*inout*/ unsigned char **cookie, size_t *cookie_len); + +#define MAX_CHAIN_LEN 65536 +#define MAX_SIGNATURE_LEN 8192 +// Select a certificate based on the given SNI and list of signatures. +// Signature algorithms are represented as 16-bit integers using the TLS 1.3 RFC code points +typedef void* (MITLS_CALLCONV *pfn_FFI_cert_select_cb)(void *cb_state, mitls_version ver, const unsigned char *sni, size_t sni_len, const unsigned char *alpn, size_t alpn_len, const mitls_signature_scheme *sigalgs, size_t sigalgs_len, mitls_signature_scheme *selected); +// Write the certificate chain to buffer, returning the number of written bytes. +// The chain should be written by prefixing each certificate by its length encoded over 3 bytes +typedef size_t (MITLS_CALLCONV *pfn_FFI_cert_format_cb)(void *cb_state, const void *cert_ptr, unsigned char buffer[MAX_CHAIN_LEN]); +// Tries to sign and write the signature to sig, returning the signature size or 0 if signature failed +typedef size_t (MITLS_CALLCONV *pfn_FFI_cert_sign_cb)(void *cb_state, const void *cert_ptr, const mitls_signature_scheme sigalg, const unsigned char *tbs, size_t tbs_len, unsigned char *sig); +// Verifies that the chain (given in the same format as above) is valid, and that sig is a valid signature +// of tbs for sigalg using the public key stored in the leaf of the chain. +// N.B. this function must validate the chain (including applcation checks such as hostname matching) +typedef int (MITLS_CALLCONV *pfn_FFI_cert_verify_cb)(void *cb_state, const unsigned char* chain, size_t chain_len, const mitls_signature_scheme sigalg, const unsigned char *tbs, size_t tbs_len, const unsigned char *sig, size_t sig_len); + +typedef struct { + pfn_FFI_cert_select_cb select; + pfn_FFI_cert_format_cb format; + pfn_FFI_cert_sign_cb sign; + pfn_FFI_cert_verify_cb verify; +} mitls_cert_cb; + +// Functions exported from libmitls.dll +// Functions returning 'int' return 0 for failure, or nonzero for success + +// Redirect debug tracing to a callback function. This is process-wide and can +// be called before or after FFI_mitls_init(). +typedef void (MITLS_CALLCONV *pfn_mitls_trace_callback)(const char *msg); +extern "C" void MITLS_CALLCONV FFI_mitls_set_trace_callback(pfn_mitls_trace_callback cb); + +// Perform one-time initialization +extern "C" int MITLS_CALLCONV FFI_mitls_init(void); + +// Perform one-time termination +extern "C" void MITLS_CALLCONV FFI_mitls_cleanup(void); + +// Configure miTLS ahead of connecting +extern "C" int MITLS_CALLCONV FFI_mitls_configure(/* out */ mitls_state **state, const char *tls_version, const char *host_name); +extern "C" int MITLS_CALLCONV FFI_mitls_set_ticket_key(const char *alg, const unsigned char *ticketkey, size_t klen); + +// Configure a ticket to resume (client only). Can be called more than once to offer multiple 1.3 PSK +extern "C" int MITLS_CALLCONV FFI_mitls_configure_ticket(mitls_state *state, const mitls_ticket *ticket); + +// Set configuration options ahead of connecting +extern "C" int MITLS_CALLCONV FFI_mitls_configure_cipher_suites(/* in */ mitls_state *state, const char *cs); +extern "C" int MITLS_CALLCONV FFI_mitls_configure_signature_algorithms(/* in */ mitls_state *state, const char *sa); +extern "C" int MITLS_CALLCONV FFI_mitls_configure_named_groups(/* in */ mitls_state *state, const char *ng); +extern "C" int MITLS_CALLCONV FFI_mitls_configure_alpn(/* in */ mitls_state *state, const char *apl); +extern "C" int MITLS_CALLCONV FFI_mitls_configure_early_data(/* in */ mitls_state *state, uint32_t max_early_data); +extern "C" int MITLS_CALLCONV FFI_mitls_configure_custom_extensions(/* in */ mitls_state *state, const mitls_extension *exts, size_t exts_count); +extern "C" int MITLS_CALLCONV FFI_mitls_configure_ticket_callback(mitls_state *state, void *cb_state, pfn_FFI_ticket_cb ticket_cb); +extern "C" int MITLS_CALLCONV FFI_mitls_configure_nego_callback(mitls_state *state, void *cb_state, pfn_FFI_nego_cb nego_cb); +extern "C" int MITLS_CALLCONV FFI_mitls_configure_cert_callbacks(mitls_state *state, void *cb_state, mitls_cert_cb *cert_cb); + +// Close a miTLS session - either after configure or connect +extern "C" void MITLS_CALLCONV FFI_mitls_close(/* in */ mitls_state *state); + +// Callbacks from miTLS to the host application, to send and receive TCP +typedef int (MITLS_CALLCONV *pfn_FFI_send)(void *ctx, const unsigned char *buffer, size_t buffer_size); +typedef int (MITLS_CALLCONV *pfn_FFI_recv)(void *ctx, unsigned char *buffer, size_t buffer_size); + +// Connect to a TLS server +extern "C" int MITLS_CALLCONV FFI_mitls_connect(void *send_recv_ctx, pfn_FFI_send psend, pfn_FFI_recv precv, /* in */ mitls_state *state); + +// Act as a TLS server to a client +extern "C" int MITLS_CALLCONV FFI_mitls_accept_connected(void *send_recv_ctx, pfn_FFI_send psend, pfn_FFI_recv precv, /* in */ mitls_state *state); + +// Get the exporter secret (set early to true for the early exporter secret). Returns 1 if a secret was written +extern "C" int MITLS_CALLCONV FFI_mitls_get_exporter(/* in */ mitls_state *state, int early, /* out */ mitls_secret *secret); + +// Retrieve the server certificate after FFI_mitls_connect() completes +extern "C" void *MITLS_CALLCONV FFI_mitls_get_cert(/* in */ mitls_state *state, /* out */ size_t *cert_size); + +// Send a message +// Returns -1 for failure, or a TCP packet to be sent then freed with FFI_mitls_free() +extern "C" int MITLS_CALLCONV FFI_mitls_send(/* in */ mitls_state *state, const unsigned char *buffer, size_t buffer_size); + +// Receive a message +// Returns NULL for failure, a plaintext packet to be freed with FFI_mitls_free_packet() +extern "C" unsigned char *MITLS_CALLCONV FFI_mitls_receive(/* in */ mitls_state *state, /* out */ size_t *packet_size); + +// Free a packet returned FFI_mitls_*() family of APIs +extern "C" void MITLS_CALLCONV FFI_mitls_free(/* in */ mitls_state *state, void* pv); + +/************************************************************************* +* QUIC FFI +**************************************************************************/ +// bugbug: what about offered_psk to create_client()? +// bugbug: rich results from process + +typedef enum { + TLS_would_block = 0, + TLS_error_local = 1, + TLS_error_alert = 2, + TLS_client_early = 3, + TLS_client_complete = 4, + TLS_client_complete_with_early_data = 5, + TLS_server_accept = 6, + TLS_server_accept_with_early_data = 7, + TLS_server_complete = 8, + TLS_server_stateless_retry = 9, + TLS_error_other = 0xffff +} quic_result; + +typedef mitls_hash quic_hash; +typedef mitls_aead quic_aead; +typedef mitls_secret quic_secret; +typedef mitls_ticket quic_ticket; + +typedef struct { + int is_server; + + const char *alpn; // Colon separated list of application-level protocols, or NULL + const char *cipher_suites; // Colon separated list of ciphersuite or NULL + const char *signature_algorithms; // Colon separated list of signature schemes or NULL + const char *named_groups; // Colon separated list of Diffie-Hellman groups or NULL + int enable_0rtt; // Probably true for QUIC + + // only used by the client + const char *host_name; // Client only, sent in SNI. Can pass NULL for server + const quic_ticket *server_ticket; // May be NULL + const mitls_extension *exts; // Array of custom extensions to offer, may be NULL + size_t exts_count; // Size of custom extensions array + + void *callback_state; // Passed back as the first argument of callbacks, may be NULL + pfn_FFI_ticket_cb ticket_callback; // May be NULL + pfn_FFI_nego_cb nego_callback; // May be NULL + mitls_cert_cb *cert_callbacks; // May be NULL + + // only used by the server + const char *ticket_enc_alg; // one of "AES128-GCM" "AES256-GCM" "CHACHA20-POLY1305", or NULL + const unsigned char *ticket_key; // If NULL a random key will be sampled + size_t ticket_key_len; // Should be 28 or 44, concatenation of key and static IV +} quic_config; + + +// pass 0 to leave any of the configuration values undefined +extern "C" int MITLS_CALLCONV FFI_mitls_quic_create(/* out */ quic_state **state, quic_config *cfg); +extern "C" quic_result MITLS_CALLCONV FFI_mitls_quic_process(quic_state *state, const unsigned char* inBuf, /*inout*/ size_t *pInBufLen, /*out*/ unsigned char *outBuf, /*inout*/ size_t *pOutBufLen); +extern "C" int MITLS_CALLCONV FFI_mitls_quic_get_exporter(quic_state *state, int early, /* out */ quic_secret *secret); +extern "C" void MITLS_CALLCONV FFI_mitls_quic_close(quic_state *state); + +typedef struct { + const unsigned char *sni; + size_t sni_len; + const unsigned char *alpn; + size_t alpn_len; + const unsigned char *extensions; + size_t extensions_len; +} mitls_hello_summary; + +// N.B. *cookie must be freed with FFI_mitls_global_free as it is allocated in the global region +extern "C" int MITLS_CALLCONV FFI_mitls_get_hello_summary(const unsigned char *buffer, size_t buffer_len, mitls_hello_summary *summary, unsigned char **cookie, size_t *cookie_len); + +// *ext_data points to a location in exts - no freeing required +extern "C" int MITLS_CALLCONV FFI_mitls_find_custom_extension(int is_server, const unsigned char *exts, size_t exts_len, uint16_t ext_type, unsigned char **ext_data, size_t *ext_data_len); + +// Free 'out' variables returned by the FFI_mitls_quic*() family of functions. +extern "C" void MITLS_CALLCONV FFI_mitls_quic_free(quic_state *state, void* pv); + +// Free 'out' variables returned by functions that do not have a state as input +extern "C" void MITLS_CALLCONV FFI_mitls_global_free(void* pv); + +#endif // HEADER_MITLS_FFI_H diff --git a/tests/Tester/Tester/mitlsstub.cpp b/tests/Tester/Tester/mitlsstub.cpp new file mode 100644 index 000000000..3b9e224e9 --- /dev/null +++ b/tests/Tester/Tester/mitlsstub.cpp @@ -0,0 +1,307 @@ + +//********************************************************************************************************************************** +// +// Purpose: Component FFI stubs source code file +// +// Project: Everest +// +// Filename: mitlsstub.cpp +// +// Authors: Caroline.M.Mathieson (CMM) +// +//********************************************************************************************************************************** +// +// Description +// ----------- +// +//! \file mitlsstub.cpp +//! \brief Contains stub functions for the mitls FFI interface. This is to allow debugging without the real component. +//! +//!

+//!
+//!   The full TLS Handshake (Simplified) is:-
+//!
+//!      Client                                                           Server
+//!        |                          ClientHello                           |
+//!        |--------------------------------------------------------------->|
+//!        |                                                                |
+//!        |                          ServerHello                           |
+//!        |<---------------------------------------------------------------|
+//!        |                                                                |
+//!        |                      EncryptedExtensions                       |
+//!        |<---------------------------------------------------------------|
+//!        |                                                                |
+//!        |                      CertificateRequest                        |
+//!        |<---------------------------------------------------------------|
+//!        |                                                                |
+//!        |                          Certificate                           |
+//!        |--------------------------------------------------------------->|
+//!        |                                                                |
+//!        |                       CertificateVerify                        |
+//!        |<---------------------------------------------------------------|
+//!        |                                                                |
+//!        |                       Application Data                         |
+//!        |<-------------------------------------------------------------->|
+//!        |                                                                |
+//!
+//!
+//! +//********************************************************************************************************************************** + +#include "stdafx.h" + +#define USE_COMPONENT_DLL // turn on use of DLL + +#ifndef USE_COMPONENT_DLL + +#include "Tester.h" + +#include "mitlsffi.h" // this is the real interface! + +extern class TLSTESTER *Tester; + +//********************************************************************************************************************************** + +typedef int (MITLS_CALLCONV *pfn_FFI_send)(void *ctx, const unsigned char *buffer, size_t buffer_size); + +//********************************************************************************************************************************** + +typedef int (MITLS_CALLCONV *pfn_FFI_recv)(void *ctx, unsigned char *buffer, size_t buffer_size); + +//********************************************************************************************************************************** + +int MITLS_CALLCONV FFI_mitls_init ( void ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +void MITLS_CALLCONV FFI_mitls_cleanup ( void ) +{ + Sleep ( rand () % 10 ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV FFI_mitls_configure ( mitls_state **state, + const char *tls_version, + const char *host_name ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV FFI_mitls_set_ticket_key ( const char *alg, + const unsigned char *ticketkey, + size_t klen ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV FFI_mitls_configure_cipher_suites ( mitls_state *state, + const char *cs ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV FFI_mitls_configure_signature_algorithms ( mitls_state *state, + const char *sa ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV FFI_mitls_configure_named_groups ( mitls_state *state, + const char *ng ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV FFI_mitls_configure_alpn ( mitls_state *state, + const char *apl ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV FFI_mitls_configure_early_data ( mitls_state *state, + uint32_t max_early_data ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV FFI_mitls_configure_ticket_callback ( mitls_state *state, + void *cb_state, + pfn_FFI_ticket_cb ticket_cb ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV FFI_mitls_configure_cert_callbacks ( mitls_state *state, + void *cb_state, + mitls_cert_cb *cert_cb ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +void MITLS_CALLCONV FFI_mitls_close ( mitls_state *state ) +{ + Sleep ( rand () % 10 ); + +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV FFI_mitls_connect ( void *send_recv_ctx, + pfn_FFI_send psend, + pfn_FFI_recv precv, + mitls_state *state ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV FFI_mitls_accept_connected ( void *send_recv_ctx, + pfn_FFI_send psend, + pfn_FFI_recv precv, + mitls_state *state ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV FFI_mitls_get_exporter ( mitls_state *state, + int early, + mitls_secret *secret ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +void *MITLS_CALLCONV FFI_mitls_get_cert ( mitls_state *state, + size_t *cert_size ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV FFI_mitls_send ( mitls_state *state, + const unsigned char *buffer, + size_t buffer_size ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +unsigned char *MITLS_CALLCONV FFI_mitls_receive ( mitls_state *state, + size_t *packet_size ) +{ + Sleep ( rand () % 10 ); + + return ( NULL ); +} + +//********************************************************************************************************************************** + +void MITLS_CALLCONV FFI_mitls_free_packet ( mitls_state *state, + void *packet ) +{ + Sleep ( rand () % 10 ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV FFI_mitls_quic_create ( quic_state **state, + quic_config *cfg ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +quic_result MITLS_CALLCONV FFI_mitls_quic_process ( quic_state *state, + const unsigned char *inBuf, + size_t *pInBufLen, + unsigned char *outBuf, + size_t *pOutBufLen ) +{ + Sleep ( rand () % 10 ); + + return ( ( quic_result ) 0 ); +} + +//********************************************************************************************************************************** + +int MITLS_CALLCONV FFI_mitls_quic_get_exporter ( quic_state *state, + int early, + quic_secret *secret ) +{ + Sleep ( rand () % 10 ); + + return ( 0 ); +} + +//********************************************************************************************************************************** + +void MITLS_CALLCONV FFI_mitls_quic_free ( quic_state *state, + void *pv ) +{ + Sleep ( rand () % 10 ); +} + +//********************************************************************************************************************************** + +#endif USE_COMPONENT_DLL diff --git a/tests/Tester/Tester/packages.config b/tests/Tester/Tester/packages.config new file mode 100755 index 000000000..c56f68b51 --- /dev/null +++ b/tests/Tester/Tester/packages.config @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Tester/Tester/pngwriter.cpp b/tests/Tester/Tester/pngwriter.cpp new file mode 100755 index 000000000..3debafaf1 --- /dev/null +++ b/tests/Tester/Tester/pngwriter.cpp @@ -0,0 +1,4728 @@ +/********************************* PNGwriter ********************************** +* +* Website: Main: http://pngwriter.sourceforge.net/ +* GitHub.com: https://github.com/pngwriter/pngwriter +* Sourceforge.net: http://sourceforge.net/projects/pngwriter/ +* +* +* Author: Paul Blackburn https://github.com/individual61 +* Axel Huebl https://github.com/ax3l +* Rene Widera https://github.com/psychocoderHPC +* +* Email: individual61@users.sourceforge.net +* +* Version: 0.7.0 (January 2018) +* +* Description: Library that allows plotting a 48 bit +* PNG image pixel by pixel, which can +* then be opened with a graphics program. +* +* License: GNU General Public License +* (C) 2002-2018 Paul Blackburn +* (C) 2013-2018 Axel Huebl +* (C) 2016-2018 Rene Widera +* +******************************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * */ + +#include "stdafx.h" + +#include "pngwriter.h" + + +// Default Constructor +//////////////////////////////////////////////////////////////////////////// +pngwriter::pngwriter() +{ + + filename_ = "out.png"; + width_ = 250; + height_ = 250; + backgroundcolour_ = 65535; + compressionlevel_ = -2; + filegamma_ = 0.5; + transformation_ = 0; + + textauthor_ = "PNGwriter Author: Paul Blackburn"; + textdescription_ = "http://pngwriter.sourceforge.net/"; + textsoftware_ = "PNGwriter: An easy to use graphics library."; + texttitle_ = "out.png"; + + int kkkk; + + bit_depth_ = 16; //Default bit depth for new images + colortype_=2; + screengamma_ = 2.2; + + graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep)); + if(graph_ == NULL) + { + std::cerr << " PNGwriter::pngwriter - ERROR **: Not able to allocate memory for image." << std::endl; + } + + for (kkkk = 0; kkkk < height_; kkkk++) + { + graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte)); + if(graph_[kkkk] == NULL) + { + std::cerr << " PNGwriter::pngwriter - ERROR **: Not able to allocate memory for image." << std::endl; + } + } + + if(graph_ == NULL) + { + std::cerr << " PNGwriter::pngwriter - ERROR **: Not able to allocate memory for image." << std::endl; + } + + int tempindex; + for(int vhhh = 0; vhhh65535) + { + std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 65535. Setting to 65535."<65535) + { + std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 1.0. Setting to 1.0."<65535) + { + std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 65535. Setting to 65535."<65535) + { + std::cerr << " PNGwriter::pngwriter - WARNING **: Constructor called with background colour greater than 65535. Setting to 65535."< 65535) + { + red = 65535; + } + if(green > 65535) + { + green = 65535; + } + if(blue > 65535) + { + blue = 65535; + } + + if(red < 0) + { + red = 0; + } + if(green < 0) + { + green = 0; + } + if(blue < 0) + { + blue = 0; + } + + if( bit_depth_ == 16 ) + { + // if( (height_-y >-1) && (height_-y -1) && (6*(x-1)+5<6*width_) ) + if( (y<=height_) && (y>0) && (x>0) && (x<=width_) ) + { + //graph_[height_-y][6*(x-1) + i] where i goes from 0 to 5 + tempindex= 6*x-6; + graph_[height_-y][tempindex] = (char) floor(((double)red)/256); + graph_[height_-y][tempindex+1] = (char)(red%256); + graph_[height_-y][tempindex+2] = (char) floor(((double)green)/256); + graph_[height_-y][tempindex+3] = (char)(green%256); + graph_[height_-y][tempindex+4] = (char) floor(((double)blue)/256); + graph_[height_-y][tempindex+5] = (char)(blue%256); + } + + /* + if(!( (height_-y >-1) && (height_-y -1) && (6*(x-1)+5<6*width_) )) + { + std::cerr << " PNGwriter::plot-- Plotting out of range! " << y << " " << x << std::endl; + } + */ + } + + if( bit_depth_ == 8 ) + { + // if( (height_-y >-1) && (height_-y -1) && (3*(x-1)+5<3*width_) ) + if( (y0) && (x>0) && (x-1) && (height_-y -1) && (6*(x-1)+5<6*width_) )) + { + std::cerr << " PNGwriter::plot-- Plotting out of range! " << y << " " << x << std::endl; + } + */ + } +} + +void pngwriter::plot(int x, int y, double red, double green, double blue) +{ + /* assuming values >= 0 adding +0.5 will round them to the nearest + * * integer when typecasting it */ + this->plot(x,y,int(red*65535+0.5),int(green*65535+0.5),int(blue*65535+0.5)); +} + +/////////////////////////////////////////////////////////////// +int pngwriter::read(int x, int y, int colour) const +{ + int temp1,temp2; + + if((colour !=1)&&(colour !=2)&&(colour !=3)) + { + std::cerr << " PNGwriter::read - WARNING **: Invalid argument: should be 1, 2 or 3, is " << colour << std::endl; + return 0; + } + + if( ( x>0 ) && ( x <= (this->width_) ) && ( y>0 ) && ( y <= (this->height_) ) ) + { + + if(bit_depth_ == 16) + { + /* In these cases *256 is correct, because what we actually are + * doing is bitshifting by 8 bit and then appending the next lower + * 8 bit. + * These lines are inefficient. Bitshifting and bitwise anding may + * have better performance than multiplication and addition. + * We could also just convert (unsigned char*) to (uint16_t*). + * If the open file function does it in the same way, then this + * method makes no assumptions about platform endianness */ + temp2=6*(x-1); + if(colour == 1) + { + temp1 = (graph_[(height_-y)][temp2])*256 + graph_[height_-y][temp2+1]; + return temp1; + } + + if(colour == 2) + { + temp1 = (graph_[height_-y][temp2+2])*256 + graph_[height_-y][temp2+3]; + return temp1; + } + + if(colour == 3) + { + temp1 = (graph_[height_-y][temp2+4])*256 + graph_[height_-y][temp2+5]; + return temp1; + } + } + + if(bit_depth_ == 8) + { + int const scale8To16Bit = 257; // (x/255.0)*65535.0 -> x*257 + temp2=3*(x-1); + if(colour == 1) + { + temp1 = graph_[height_-y][temp2]; + return temp1*scale8To16Bit; + } + + if(colour == 2) + { + temp1 = graph_[height_-y][temp2+1]; + return temp1*scale8To16Bit; + } + + if(colour == 3) + { + temp1 = graph_[height_-y][temp2+2]; + return temp1*scale8To16Bit; + } + } + } + else + { + return 0; + } + + std::cerr << " PNGwriter::read - WARNING **: Returning 0 because of bitdepth/colour type mismatch."<< std::endl; + return 0; +} + +/////////////////////////////////////////////////////////////// +int pngwriter::read(int xxx, int yyy) const +{ + int sumRGB = 0; + for( int colour = 1; colour <= 3; ++colour ) + sumRGB += this->read(xxx, yyy, colour); + + return sumRGB / 3; +} + +///////////////////////////////////////////////////// +double pngwriter::dread(int x, int y, int colour) const +{ + // PNGwriter converts all read images to 16bit RGB + return double(this->read(x,y,colour))/65535.0; +} + +double pngwriter::dread(int x, int y) const +{ + // PNGwriter converts all read images to 16bit RGB + return double(this->read(x,y))/65535.0; +} + +/////////////////////////////////////////////////////// +void pngwriter::clear() +{ + int pen = 0; + int pencil = 0; + int tempindex; + + if(bit_depth_==16) + { + for(pencil = 0; pencil 999999999 ) + { + std::cerr << " PNGwriter::pngwriter_rename - ERROR **: Numerical name is out of 0 - 999 999 999 range (" << index <<")." << std::endl; + return; + } + + if( 0> sprintf(buffer, "%9.9lu.png",index)) + { + std::cerr << " PNGwriter::pngwriter_rename - ERROR **: Error creating numerical filename." << std::endl; + return; + } + + + filename_ = buffer; + texttitle_ = buffer; + +} + +/////////////////////////////////////////////////////// +void pngwriter::settext(char * title, char * author, char * description, char * software) +{ + texttitle_ = title; + textauthor_ = author; + textdescription_ = description; + textsoftware_ = software; +} + +/////////////////////////////////////////////////////// +void pngwriter::settext(const char * title, const char * author, const char * description, const char * software) +{ + texttitle_ = title; + textauthor_ = author; + textdescription_ = description; + textsoftware_ = software; +} + +/////////////////////////////////////////////////////// +void pngwriter::close() +{ + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + + fp = fopen(filename_.c_str(), "wb"); + if( fp == NULL) + { + std::cerr << " PNGwriter::close - ERROR **: Error creating file (fopen() returned NULL pointer)." << std::endl; + perror(" PNGwriter::close - ERROR **"); + return; + } + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + info_ptr = png_create_info_struct(png_ptr); + png_init_io(png_ptr, fp); + if(compressionlevel_ != -2) + { + png_set_compression_level(png_ptr, compressionlevel_); + } + else + { + png_set_compression_level(png_ptr, PNGWRITER_DEFAULT_COMPRESSION); + } + + png_set_IHDR(png_ptr, info_ptr, width_, height_, + bit_depth_, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + if(filegamma_ < 1.0e-1) + { + filegamma_ = 0.5; // Modified in 0.5.4 so as to be the same as the usual gamma. + } + + png_set_gAMA(png_ptr, info_ptr, filegamma_); + + time_t gmt; + png_time mod_time; + png_text text_ptr[5]; + int entries = 4; + time(&gmt); + png_convert_from_time_t(&mod_time, gmt); + png_set_tIME(png_ptr, info_ptr, &mod_time); + /* key is a 1-79 character description of type char* + * + * attention: the pointer of `c_str()` could be invalid if a non const + * operation to `key_title` is called + */ + std::string key_title("Title"); + text_ptr[0].key = const_cast(key_title.c_str()); + text_ptr[0].text = const_cast(texttitle_.c_str()); + text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; + std::string key_author("Author"); + text_ptr[1].key = const_cast(key_author.c_str()); + text_ptr[1].text = const_cast(textauthor_.c_str()); + text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE; + std::string key_descr("Description"); + text_ptr[2].key = const_cast(key_descr.c_str()); + text_ptr[2].text = const_cast(textdescription_.c_str()); + text_ptr[2].compression = PNG_TEXT_COMPRESSION_NONE; + std::string key_software("Software"); + text_ptr[3].key = const_cast(key_software.c_str()); + text_ptr[3].text = const_cast(textsoftware_.c_str()); + text_ptr[3].compression = PNG_TEXT_COMPRESSION_NONE; +#if defined(PNG_TIME_RFC1123_SUPPORTED) + char key_create[] = "Creation Time"; + text_ptr[4].key = key_create; + char textcrtime[29] = "tIME chunk is not present..."; +#if (PNG_LIBPNG_VER < 10600) + memcpy(textcrtime, + png_convert_to_rfc1123(png_ptr, &mod_time), + 29); +#else + png_convert_to_rfc1123_buffer(textcrtime, &mod_time); +#endif + textcrtime[sizeof(textcrtime) - 1] = '\0'; + text_ptr[4].text = textcrtime; + text_ptr[4].compression = PNG_TEXT_COMPRESSION_NONE; + entries++; +#endif + png_set_text(png_ptr, info_ptr, text_ptr, entries); + + png_write_info(png_ptr, info_ptr); + png_write_image(png_ptr, graph_); + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); +} + +////////////////////////////////////////////////////// +void pngwriter::line(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue) +{ + // Bresenham Algorithm. + // + int dy = yto - yfrom; + int dx = xto - xfrom; + int stepx, stepy; + + if (dy < 0) + { + dy = -dy; stepy = -1; + } + else + { + stepy = 1; + } + + if (dx < 0) + { + dx = -dx; stepx = -1; + } + else + { + stepx = 1; + } + dy <<= 1; // dy is now 2*dy + dx <<= 1; // dx is now 2*dx + + this->plot(xfrom,yfrom,red,green,blue); + + if (dx > dy) + { + int fraction = dy - (dx >> 1); + + while (xfrom != xto) + { + if (fraction >= 0) + { + yfrom += stepy; + fraction -= dx; + } + xfrom += stepx; + fraction += dy; + this->plot(xfrom,yfrom,red,green,blue); + } + } + else + { + int fraction = dx - (dy >> 1); + while (yfrom != yto) + { + if (fraction >= 0) + { + xfrom += stepx; + fraction -= dy; + } + yfrom += stepy; + fraction += dx; + this->plot(xfrom,yfrom,red,green,blue); + } + } + +} + +void pngwriter::line(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue) +{ + this->line( xfrom, + yfrom, + xto, + yto, + int (red*65535), + int (green*65535), + int (blue*65535) + ); +} + +/////////////////////////////////////////////////////////////////////////////////////////// +void pngwriter::square(int xfrom, int yfrom, int xto, int yto, int red, int green, int blue) +{ + this->line(xfrom, yfrom, xfrom, yto, red, green, blue); + this->line(xto, yfrom, xto, yto, red, green, blue); + this->line(xfrom, yfrom, xto, yfrom, red, green, blue); + this->line(xfrom, yto, xto, yto, red, green, blue); +} + +void pngwriter::square(int xfrom, int yfrom, int xto, int yto, double red, double green, double blue) +{ + this->square( xfrom, yfrom, xto, yto, int(red*65535), int(green*65535), int(blue*65535)); +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +void pngwriter::filledsquare(int xfrom, int yfrom, int xto, int yto, int red, int green, int blue) +{ + for(int caca = xfrom; caca line(caca, yfrom, caca, yto, red, green, blue); + } +} + +void pngwriter::filledsquare(int xfrom, int yfrom, int xto, int yto, double red, double green, double blue) +{ + this->filledsquare( xfrom, yfrom, xto, yto, int(red*65535), int(green*65535), int(blue*65535)); +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +void pngwriter::circle(int xcentre, int ycentre, int radius, int red, int green, int blue) +{ + int x = 0; + int y = radius; + int p = (5 - radius*4)/4; + + circle_aux(xcentre, ycentre, x, y, red, green, blue); + while (x < y) + { + x++; + if (p < 0) + { + p += 2*x+1; + } + else + { + y--; + p += 2*(x-y)+1; + } + circle_aux(xcentre, ycentre, x, y, red, green, blue); + } +} + +void pngwriter::circle(int xcentre, int ycentre, int radius, double red, double green, double blue) +{ + this->circle(xcentre,ycentre,radius, int(red*65535), int(green*65535), int(blue*65535)); +} + +//////////////////////////////////////////////////////////// + +void pngwriter::circle_aux(int xcentre, int ycentre, int x, int y, int red, int green, int blue) +{ + if (x == 0) + { + this->plot( xcentre, ycentre + y, red, green, blue); + this->plot( xcentre, ycentre - y, red, green, blue); + this->plot( xcentre + y, ycentre, red, green, blue); + this->plot( xcentre - y, ycentre, red, green, blue); + } + else + if (x == y) + { + this->plot( xcentre + x, ycentre + y, red, green, blue); + this->plot( xcentre - x, ycentre + y, red, green, blue); + this->plot( xcentre + x, ycentre - y, red, green, blue); + this->plot( xcentre - x, ycentre - y, red, green, blue); + } + else + if (x < y) + { + this->plot( xcentre + x, ycentre + y, red, green, blue); + this->plot( xcentre - x, ycentre + y, red, green, blue); + this->plot( xcentre + x, ycentre - y, red, green, blue); + this->plot( xcentre - x, ycentre - y, red, green, blue); + this->plot( xcentre + y, ycentre + x, red, green, blue); + this->plot( xcentre - y, ycentre + x, red, green, blue); + this->plot( xcentre + y, ycentre - x, red, green, blue); + this->plot( xcentre - y, ycentre - x, red, green, blue); + } + +} + +//////////////////////////////////////////////////////////// +void pngwriter::filledcircle(int xcentre, int ycentre, int radius, int red, int green, int blue) +{ + for(int jjj = ycentre-radius; jjj< ycentre+radius+1; jjj++) + { + this->line(xcentre - int(sqrt((double)(radius*radius) - (-ycentre + jjj)*(-ycentre + jjj ))), jjj, + xcentre + int(sqrt((double)(radius*radius) - (-ycentre + jjj)*(-ycentre + jjj ))),jjj,red,green,blue); + } +} + +void pngwriter::filledcircle(int xcentre, int ycentre, int radius, double red, double green, double blue) +{ + this->filledcircle( xcentre, ycentre, radius, int(red*65535), int(green*65535), int(blue*65535)); +} + +////////////////Reading routines///////////////////// +///////////////////////////////////////////////// + +// Modified with Mikkel's patch +void pngwriter::readfromfile(char * name) +{ + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + unsigned char **image; + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; + // png_uint_32 i; + // + fp = fopen (name,"rb"); + if (fp==NULL) + { + std::cerr << " PNGwriter::readfromfile - ERROR **: Error opening file \"" << std::flush; + std::cerr << name <readfromfile((char *)(name)); +} + +///////////////////////////////////////////////////////// +int pngwriter::check_if_png(char *file_name, FILE **fp) +{ + char sig[PNG_BYTES_TO_CHECK]; + + if ( /*(*fp = fopen(file_name, "rb")) */ *fp == NULL) // Fixed 10 10 04 + { + // exit(EXIT_FAILURE); + std::cerr << " PNGwriter::check_if_png - ERROR **: Could not open file " << file_name << " to read." << std::endl; + perror(" PNGwriter::check_if_png - ERROR **"); + return 0; + } + + if (fread(sig, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) + { + //exit(EXIT_FAILURE); + std::cerr << " PNGwriter::check_if_png - ERROR **: File " << file_name << " does not appear to be a valid PNG file." << std::endl; + perror(" PNGwriter::check_if_png - ERROR **"); + fclose(*fp); + return 0; + } + + if (png_sig_cmp( (png_bytep) sig, (png_size_t)0, PNG_BYTES_TO_CHECK) /*png_check_sig((png_bytep) sig, PNG_BYTES_TO_CHECK)*/ ) + { + std::cerr << " PNGwriter::check_if_png - ERROR **: File " << file_name << " does not appear to be a valid PNG file. png_check_sig() failed." << std::endl; + fclose(*fp); + return 0; + } + + + + return 1; //Success +} + +/////////////////////////////////////////////////////// +int pngwriter::read_png_info(FILE *fp, png_structp *png_ptr, png_infop *info_ptr) +{ + *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (*png_ptr == NULL) + { + std::cerr << " PNGwriter::read_png_info - ERROR **: Could not create read_struct." << std::endl; + fclose(fp); + return 0; + //exit(EXIT_FAILURE); + } + *info_ptr = png_create_info_struct(*png_ptr); + if (*info_ptr == NULL) + { + png_destroy_read_struct(png_ptr, (png_infopp)NULL, (png_infopp)NULL); + std::cerr << " PNGwriter::read_png_info - ERROR **: Could not create info_struct." << std::endl; + //exit(EXIT_FAILURE); + fclose(fp); + return 0; + } +#if (PNG_LIBPNG_VER < 10500) + if (setjmp((*png_ptr)->jmpbuf)) /*(setjmp(png_jmpbuf(*png_ptr)) )*////////////////////////////////////// +#else + if (setjmp(png_jmpbuf(*png_ptr))) +#endif + { + png_destroy_read_struct(png_ptr, info_ptr, (png_infopp)NULL); + std::cerr << " PNGwriter::read_png_info - ERROR **: This file may be a corrupted PNG file. (setjmp(*png_ptr)->jmpbf) failed)." << std::endl; + fclose(fp); + return 0; + //exit(EXIT_FAILURE); + } + png_init_io(*png_ptr, fp); + png_set_sig_bytes(*png_ptr, PNG_BYTES_TO_CHECK); + png_read_info(*png_ptr, *info_ptr); + + return 1; +} + +//////////////////////////////////////////////////////////// +int pngwriter::read_png_image(FILE *fp, png_structp png_ptr, png_infop info_ptr, + png_bytepp *image, png_uint_32& width, png_uint_32& height) +{ + unsigned int i,j; + + width = png_get_image_width(png_ptr, info_ptr); + height = png_get_image_height(png_ptr, info_ptr); + + if( width == 0 ) + { + std::cerr << " PNGwriter::read_png_image - ERROR **: png_get_image_width() returned 0." << std::endl; + fclose(fp); + return 0; + } + + if( height == 0 ) + { + std::cerr << " PNGwriter::read_png_image - ERROR **: png_get_image_height() returned 0." << std::endl; + fclose(fp); + return 0; + } + + if ((*image = (png_bytepp)malloc(height * sizeof(png_bytep))) == NULL) + { + std::cerr << " PNGwriter::read_png_image - ERROR **: Could not allocate memory for reading image." << std::endl; + fclose(fp); + return 0; + //exit(EXIT_FAILURE); + } + for (i = 0; i < height; i++) + { + (*image)[i] = (png_bytep)malloc(png_get_rowbytes(png_ptr, info_ptr)); + if ((*image)[i] == NULL) + { + for (j = 0; j < i; j++) free((*image)[j]); + free(*image); + fclose(fp); + std::cerr << " PNGwriter::read_png_image - ERROR **: Could not allocate memory for reading image." << std::endl; + return 0; + //exit(EXIT_FAILURE); + } + } + png_read_image(png_ptr, *image); + + return 1; +} + +/////////////////////////////////// +int pngwriter::getheight(void) const +{ + return height_; +} + +int pngwriter::getwidth(void) const +{ + return width_; +} + + +int pngwriter::getbitdepth(void) const +{ + return bit_depth_; +} + +int pngwriter::getcolortype(void) const +{ + return colortype_; +} + +double pngwriter::getgamma(void) const +{ + return filegamma_; +} + +void pngwriter::setgamma(double gamma) +{ + filegamma_ = gamma; +} + +// The algorithms HSVtoRGB and RGBtoHSV were found at http://www.cs.rit.edu/~ncs/ +// which is a page that belongs to Nan C. Schaller, though +// these algorithms appear to be the work of Eugene Vishnevsky. +////////////////////////////////////////////// +void pngwriter::HSVtoRGB( double *r, double *g, double *b, double h, double s, double v ) +{ + // r,g,b values are from 0 to 1 + // h = [0,1], s = [0,1], v = [0,1] + // if s == 0, then h = -1 (undefined) + // + h = h*360.0; + + int i; + double f, p, q, t; + if( s == 0 ) + { + // achromatic (grey) + *r = *g = *b = v; + return; + } + + h /= 60; // sector 0 to 5 + i = int(floor( h )); + f = h - i; // factorial part of h + p = v * ( 1 - s ); + q = v * ( 1 - s * f ); + t = v * ( 1 - s * ( 1 - f ) ); + + switch( i ) + { + case 0: + *r = v; + *g = t; + *b = p; + break; + case 1: + *r = q; + *g = v; + *b = p; + break; + case 2: + *r = p; + *g = v; + *b = t; + break; + case 3: + *r = p; + *g = q; + *b = v; + break; + case 4: + *r = t; + *g = p; + *b = v; + break; + default: // case 5: + *r = v; + *g = p; + *b = q; + break; + } +} + +void pngwriter::RGBtoHSV( float r, float g, float b, float *h, float *s, float *v ) +{ + + float min=0.0; //These values are not used. + float max=1.0; + float delta; + + if( (r>=g)&&(r>=b) ) + { + max = r; + } + if( (g>=r)&&(g>=b) ) + { + max = g; + } + if( (b>=g)&&(b>=r) ) + { + max = b; + } + + if( (r<=g)&&(r<=b) ) + { + min = r; + } + if( (g<=r)&&(g<=b) ) + { + min = g; + } + if( (b<=g)&&(b<=r) ) + { + min = b; + } + + *v = max; // v + + delta = max - min; + + if( max != 0 ) + *s = delta / max; // s + else + { + + // s = 0, v is undefined + *s = 0; + *h = -1; + return; + } + + if( r == max ) + *h = ( g - b ) / delta; // between yellow & magenta + else if( g == max ) + *h = 2 + ( b - r ) / delta; // between cyan & yellow + else + *h = 4 + ( r - g ) / delta; // between magenta & cyan + + *h *= 60; // degrees + if( *h < 0 ) + *h += 360; + +} + +// +////////////////////////////////////////////////////////////////////////////////// +void pngwriter::plotHSV(int x, int y, double hue, double saturation, double value) +{ + double red,green,blue; + double *redp; + double *greenp; + double *bluep; + + redp = &red; + greenp = &green; + bluep = &blue; + + HSVtoRGB(redp,greenp,bluep,hue,saturation,value); + plot(x,y,red,green,blue); +} + +void pngwriter::plotHSV(int x, int y, int hue, int saturation, int value) +{ + plotHSV(x, y, double(hue)/65535.0, double(saturation)/65535.0, double(value)/65535.0); +} + +// +////////////////////////////////////////////////////////////////////////////////// +double pngwriter::dreadHSV(int x, int y, int colour) const +{ + if( (x>0)&&(x<=width_)&&(y>0)&&(y<=height_) ) + { + + float * huep; + float * saturationp; + float * valuep; + float red,green,blue; + float hue, saturation, value; + + red = float(dread(x,y,1)); + green = float(dread(x,y,2)); + blue = float(dread(x,y,3)); + + huep = &hue; + saturationp = &saturation; + valuep = &value; + + RGBtoHSV( red, green, blue, huep, saturationp, valuep ); + + if(colour == 1) + { + return double(hue)/360.0; + } + + else if(colour == 2) + { + return saturation; + } + + else if(colour == 3) + { + return value; + } + + std::cerr << " PNGwriter::dreadHSV - ERROR **: Called with wrong colour argument: should be 1, 2 or 3; was: " << colour << "." << std::endl; + } + return 0.0; +} + +// +////////////////////////////////////////////////////////////////////////////////// +int pngwriter::readHSV(int x, int y, int colour) const +{ + if( (x>0)&&(x<=width_)&&(y>0)&&(y<=height_) ) + { + + float * huep; + float * saturationp; + float * valuep; + float red,green,blue; + float hue, saturation, value; + + red = float(dread(x,y,1)); + green = float(dread(x,y,2)); + blue = float(dread(x,y,3)); + + huep = &hue; + saturationp = &saturation; + valuep = &value; + + RGBtoHSV( red, green, blue, huep, saturationp, valuep ); + + if(colour == 1) + { + return int(65535*(double(hue)/360.0)); + } + + else if(colour == 2) + { + return int(65535*saturation); + } + + else if(colour == 3) + { + return int(65535*value); + } + + std::cerr << " PNGwriter::readHSV - ERROR **: Called with wrong colour argument: should be 1, 2 or 3; was: " << colour << "." << std::endl; + return 0; + } + else + { + return 0; + } +} + +void pngwriter::setcompressionlevel(int level) +{ + if( (level < -1)||(level > 9) ) + { + std::cerr << " PNGwriter::setcompressionlevel - ERROR **: Called with wrong compression level: should be -1 to 9, was: " << level << "." << std::endl; + } + compressionlevel_ = level; +} + +// An implementation of a Bezier curve. +void pngwriter::bezier( int startPtX, int startPtY, + int startControlX, int startControlY, + int endPtX, int endPtY, + int endControlX, int endControlY, + double red, double green, double blue) +{ + double cx = 3.0*(startControlX - startPtX); + double bx = 3.0*(endControlX - startControlX) - cx; + double ax = double(endPtX - startPtX - cx - bx); + + double cy = 3.0*(startControlY - startPtY); + double by = 3.0*(endControlY - startControlY) - cy; + double ay = double(endPtY - startPtY - cy - by); + + double x = startPtX; + double y = startPtY; + + for(double t = 0.0; t<=1.005; t += 0.005) + { + double const newx = startPtX + t*(double(cx) + t*(double(bx) + t*(double(ax)))); + double const newy = startPtY + t*(double(cy) + t*(double(by) + t*(double(ay)))); + this->line(int(x),int(y),int(newx),int(newy),red,green,blue); + x = newx; + y = newy; + } +} + +//int version of bezier +void pngwriter::bezier( int startPtX, int startPtY, + int startControlX, int startControlY, + int endPtX, int endPtY, + int endControlX, int endControlY, + int red, int green, int blue) +{ + this->bezier( startPtX, startPtY, + startControlX, startControlY, + endPtX, endPtY, + endControlX, endControlY, + double(red)/65535.0, double(green)/65535.0, double(blue)/65535.0); +} + +/* +int pngwriter::getcompressionlevel(void) +{ + return png_get_compression_level(png_ptr); +} +*/ + +double pngwriter::version(void) +{ + const char *a = "Jeramy Webb (jeramyw@gmail.com), Mike Heller (mkheller@gmail.com)"; // For their generosity ;-) + char b = a[27]; + b++; + return (PNGWRITER_VERSION); +} + +void pngwriter::write_png(void) +{ + this->close(); +} + +#ifndef NO_FREETYPE + +// Freetype-based text rendering functions. +/////////////////////////////////////////// +void pngwriter::plot_text( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double red, double green, double blue) +{ + FT_Library library; + FT_Face face; + FT_Matrix matrix; // transformation matrix + FT_Vector pen; + + FT_UInt glyph_index; + FT_Error error; + + FT_Bool use_kerning; + FT_UInt previous = 0; + + /* Set up transformation Matrix */ + matrix.xx = (FT_Fixed)( cos(angle)*0x10000); /* It would make more sense to do this (below), but, bizzarely, */ + matrix.xy = (FT_Fixed)(-sin(angle)*0x10000); /* if one does, FT_Load_Glyph fails consistently. */ + matrix.yx = (FT_Fixed)( sin(angle)*0x10000); // matrix.yx = - matrix.xy; + matrix.yy = (FT_Fixed)( cos(angle)*0x10000); // matrix.yy = matrix.xx; + + /* Place starting coordinates in adequate form. */ + pen.x = x_start*64 ; + pen.y = (int)(y_start/64.0); + + /*Count the length of the string */ + int num_chars = strlen(text); + + /* Initialize FT Library object */ + error = FT_Init_FreeType( &library ); + if (error) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Could not init Library."<< std::endl; return;} + + /* Initialize FT face object */ + error = FT_New_Face( library,face_path,0,&face ); + if ( error == FT_Err_Unknown_File_Format ) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Font was opened, but type not supported."<< std::endl; return; } else if (error){ std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Could not find or load font file."<< std::endl; return; } + + /* Set the Char size */ + error = FT_Set_Char_Size( face, /* handle to face object */ + 0, /* char_width in 1/64th of points */ + fontsize*64, /* char_height in 1/64th of points */ + 100, /* horizontal device resolution */ + 100 ); /* vertical device resolution */ + + /* A way of accesing the glyph directly */ + FT_GlyphSlot slot = face->glyph; // a small shortcut + + /* Does the font file support kerning? */ + use_kerning = FT_HAS_KERNING( face ); + + int n; + for ( n = 0; n < num_chars; n++ ) + { + /* Convert character code to glyph index */ + glyph_index = FT_Get_Char_Index( face, text[n] ); + + /* Retrieve kerning distance and move pen position */ + if ( use_kerning && previous&& glyph_index ) + { + FT_Vector delta; + FT_Get_Kerning( face, + previous, + glyph_index, + ft_kerning_default, //FT_KERNING_DEFAULT, + &delta ); + + /* Transform this kerning distance into rotated space */ + pen.x += (int) (((double) delta.x)*cos(angle)); + pen.y += (int) (((double) delta.x)*( sin(angle))); + } + + /* Set transform */ + FT_Set_Transform( face, &matrix, &pen ); + +/*set char size*/ + + if (error) { + std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Set char size error." << std::endl; return; + } + + /* Retrieve glyph index from character code */ + glyph_index = FT_Get_Char_Index( face, text[n] ); + + /* Load glyph image into the slot (erase previous one) */ + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT ); + if (error) { + std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error " << std::hex << error <<")." << std::endl; + std::cerr.copyfmt(std::ios(NULL)); + return; + } + + /* Convert to an anti-aliased bitmap */ + // error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL ); + error = FT_Render_Glyph( face->glyph, ft_render_mode_normal ); + if (error) { std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Render glyph error." << std::endl; return;} + + /* Now, draw to our target surface */ + my_draw_bitmap( &slot->bitmap, + slot->bitmap_left, + y_start + slot->bitmap_top, + red, + green, + blue ); + + /* Advance to the next position */ + pen.x += slot->advance.x; + pen.y += slot->advance.y; + + /* record current glyph index */ + previous = glyph_index; + } + + /* Free the face and the library objects */ + FT_Done_Face ( face ); + FT_Done_FreeType( library ); +} + +void pngwriter::plot_text_utf8( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double red, double green, double blue) +{ + FT_Library library; + FT_Face face; + FT_Matrix matrix; // transformation matrix + FT_Vector pen; + + FT_UInt glyph_index; + FT_Error error; + + FT_Bool use_kerning; + FT_UInt previous = 0; + + /* Set up transformation Matrix */ + matrix.xx = (FT_Fixed)( cos(angle)*0x10000); /* It would make more sense to do this (below), but, bizzarely, */ + matrix.xy = (FT_Fixed)(-sin(angle)*0x10000); /* if one does, FT_Load_Glyph fails consistently. */ + matrix.yx = (FT_Fixed)( sin(angle)*0x10000); // matrix.yx = - matrix.xy; + matrix.yy = (FT_Fixed)( cos(angle)*0x10000); // matrix.yy = matrix.xx; + + /* Place starting coordinates in adequate form. */ + pen.x = x_start*64 ; + pen.y = (int)(y_start/64.0); + + /*Count the length of the string */ + int num_bytes=0; + while(text[num_bytes]!=0) + { + num_bytes++; + } + + /* + std::cout << "Num bytes is: "<< num_bytes << std::endl; + */ + + //The array of ucs4 glyph indexes, which will by at most the number of bytes in the utf-8 file. + long * ucs4text; + ucs4text = new long[num_bytes+1]; + + unsigned char u,v,w,x,y; + + int num_chars=0; + + long iii=0; + + while(iiiglyph; // a small shortcut + + /* Does the font file support kerning? */ + use_kerning = FT_HAS_KERNING( face ); + + int n; + for ( n = 0; n < num_chars; n++ ) + { + /* Convert character code to glyph index */ + glyph_index = FT_Get_Char_Index( face, ucs4text[n] ); + + /* Retrieve kerning distance and move pen position */ + if ( use_kerning && previous&& glyph_index ) + { + FT_Vector delta; + FT_Get_Kerning( face, + previous, + glyph_index, + ft_kerning_default, //FT_KERNING_DEFAULT, + &delta ); + + /* Transform this kerning distance into rotated space */ + pen.x += (int) (((double) delta.x)*cos(angle)); + pen.y += (int) (((double) delta.x)*( sin(angle))); + } + + /* Set transform */ + FT_Set_Transform( face, &matrix, &pen ); + +/*set char size*/ + + if (error) { + std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: FreeType: Set char size error." << std::endl; + delete[] ucs4text; + return; + } + + /* Retrieve glyph index from character code */ + glyph_index = FT_Get_Char_Index( face, ucs4text[n] ); + + /* Load glyph image into the slot (erase previous one) */ + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT ); + if (error) { + std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error " << std::hex << error <<")." << std::endl; + std::cerr.copyfmt(std::ios(NULL)); + delete[] ucs4text; + return; + } + + /* Convert to an anti-aliased bitmap */ + error = FT_Render_Glyph( face->glyph, ft_render_mode_normal ); + if (error) { + std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: FreeType: Render glyph error." << std::endl; + delete[] ucs4text; + return; + } + + /* Now, draw to our target surface */ + my_draw_bitmap( &slot->bitmap, + slot->bitmap_left, + y_start + slot->bitmap_top, + red, + green, + blue ); + + /* Advance to the next position */ + pen.x += slot->advance.x; + pen.y += slot->advance.y; + + /* record current glyph index */ + previous = glyph_index; + } + + /* Free the face and the library objects */ + FT_Done_Face ( face ); + FT_Done_FreeType( library ); + + delete[] ucs4text; +} + +void pngwriter::plot_text( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, int red, int green, int blue) +{ + plot_text( face_path, fontsize, x_start, y_start, angle, text, ((double) red)/65535.0, ((double) green)/65535.0, ((double) blue)/65535.0 ); +} + +void pngwriter::plot_text_utf8( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, int red, int green, int blue) +{ + plot_text_utf8( face_path, fontsize, x_start, y_start, angle, text, ((double) red)/65535.0, ((double) green)/65535.0, ((double) blue)/65535.0 ); +} + +void pngwriter::my_draw_bitmap( FT_Bitmap * bitmap, int x, int y, double red, double green, double blue) +{ + double temp; + for(unsigned int j = 1u; j < bitmap->rows + 1u; j++) + { + for(unsigned int i = 1u; i < bitmap->width + 1u; i++) + { + temp = (double)(bitmap->buffer[(j-1u)*bitmap->width + (i-1u)] )/255.0; + + if(temp) + { + this->plot(x + i, + y - j, + temp*red + (1-temp)*(this->dread(x+i,y-j,1)), + temp*green + (1-temp)*(this->dread(x+i,y-j,2)), + temp*blue + (1-temp)*(this->dread(x+i,y-j,3)) + ); + } + } + } +} + + + +//////////// Get text width + +//put in freetype section + +int pngwriter::get_text_width(char * face_path, int fontsize, char * text) +{ + + FT_Library library; + FT_Face face; + FT_Matrix matrix; // transformation matrix + FT_Vector pen; + + FT_UInt glyph_index; + FT_Error error; + + FT_Bool use_kerning; + FT_UInt previous = 0; + + /* Set up transformation Matrix */ + matrix.xx = (FT_Fixed)( 1.0*0x10000); /* It would make more sense to do this (below), but, bizzarely, */ + matrix.xy = (FT_Fixed)( 0.0*0x10000); /* if one does, FT_Load_Glyph fails consistently. */ + matrix.yx = (FT_Fixed)( 0.0*0x10000); // matrix.yx = - matrix.xy; + matrix.yy = (FT_Fixed)( 1.0*0x10000); // matrix.yy = matrix.xx; + + /* Place starting coordinates in adequate form. */ + pen.x = 0; + pen.y = 0; + + /*Count the length of the string */ + int num_chars = strlen(text); + + /* Initialize FT Library object */ + error = FT_Init_FreeType( &library ); + if (error) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Could not init Library."<< std::endl; return 0;} + + /* Initialize FT face object */ + error = FT_New_Face( library,face_path,0,&face ); + if ( error == FT_Err_Unknown_File_Format ) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Font was opened, but type not supported."<< std::endl; return 0; } else if (error){ std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Could not find or load font file." << std::endl; return 0; } + + /* Set the Char size */ + error = FT_Set_Char_Size( face, /* handle to face object */ + 0, /* char_width in 1/64th of points */ + fontsize*64, /* char_height in 1/64th of points */ + 100, /* horizontal device resolution */ + 100 ); /* vertical device resolution */ + + /* A way of accesing the glyph directly */ + FT_GlyphSlot slot = face->glyph; // a small shortcut + + /* Does the font file support kerning? */ + use_kerning = FT_HAS_KERNING( face ); + + int n; + for ( n = 0; n < num_chars; n++ ) + { + /* Convert character code to glyph index */ + glyph_index = FT_Get_Char_Index( face, text[n] ); + + /* Retrieve kerning distance and move pen position */ + if ( use_kerning && previous&& glyph_index ) + { + FT_Vector delta; + FT_Get_Kerning( face, + previous, + glyph_index, + ft_kerning_default, //FT_KERNING_DEFAULT, + &delta ); + + /* Transform this kerning distance into rotated space */ + pen.x += (int) ( delta.x); + pen.y += 0; + } + + /* Set transform */ + FT_Set_Transform( face, &matrix, &pen ); + +/*set char size*/ + + if (error) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Set char size error." << std::endl; return 0; } + + /* Retrieve glyph index from character code */ + glyph_index = FT_Get_Char_Index( face, text[n] ); + + /* Load glyph image into the slot (erase previous one) */ + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT ); + if (error) { + std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error " << std::hex << error <<")." << std::endl; + std::cerr.copyfmt(std::ios(NULL)); + return 0; + } + + /* Convert to an anti-aliased bitmap */ + // error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL ); + error = FT_Render_Glyph( face->glyph, ft_render_mode_normal ); + if (error) { std::cerr << " PNGwriter::get_text_width - ERROR **: FreeType: Render glyph error." << std::endl; return 0;} + + /* Now, draw to our target surface */ +/* my_draw_bitmap( &slot->bitmap, + slot->bitmap_left, + slot->bitmap_top, + red, + green, + blue ); +*/ + /* Advance to the next position */ + pen.x += slot->advance.x; +// std::cout << ((double) pen.x)/64.0 << std::endl; + pen.y += slot->advance.y; + + /* record current glyph index */ + previous = glyph_index; + } + + + /* Free the face and the library objects */ + FT_Done_Face ( face ); + FT_Done_FreeType( library ); + + return (int)( ((double)pen.x)/64.0 ); +} + + +int pngwriter::get_text_width_utf8(char * face_path, int fontsize, char * text) +{ + FT_Library library; + FT_Face face; + FT_Matrix matrix; // transformation matrix + FT_Vector pen; + + FT_UInt glyph_index; + FT_Error error; + + FT_Bool use_kerning; + FT_UInt previous = 0; + + /* Set up transformation Matrix */ + matrix.xx = (FT_Fixed)( 0x10000); /* It would make more sense to do this (below), but, bizzarely, */ + matrix.xy = (FT_Fixed)( 0*0x10000); /* if one does, FT_Load_Glyph fails consistently. */ + matrix.yx = (FT_Fixed)( 0*0x10000); // matrix.yx = - matrix.xy; + matrix.yy = (FT_Fixed)( 0x10000); // matrix.yy = matrix.xx; + + /* Place starting coordinates in adequate form. */ + pen.x = 0 ; + pen.y = 0; + + /*Count the length of the string */ + int num_bytes=0; + while(text[num_bytes]!=0) + { + num_bytes++; + } + + /* + std::cout << "Num bytes is: "<< num_bytes << std::endl; + */ + + //The array of ucs4 glyph indexes, which will by at most the number of bytes in the utf-8 file. + long * ucs4text; + ucs4text = new long[num_bytes+1]; + + unsigned char u,v,w,x,y; + + int num_chars=0; + + long iii=0; + + while(iiiglyph; // a small shortcut + + /* Does the font file support kerning? */ + use_kerning = FT_HAS_KERNING( face ); + + int n; + for ( n = 0; n < num_chars; n++ ) + { + /* Convert character code to glyph index */ + glyph_index = FT_Get_Char_Index( face, ucs4text[n] ); + + /* Retrieve kerning distance and move pen position */ + if ( use_kerning && previous&& glyph_index ) + { + FT_Vector delta; + FT_Get_Kerning( face, + previous, + glyph_index, + ft_kerning_default, //FT_KERNING_DEFAULT, + &delta ); + + /* Transform this kerning distance into rotated space */ + pen.x += (int) (delta.x); + pen.y += 0; + } + + /* Set transform */ + FT_Set_Transform( face, &matrix, &pen ); + +/*set char size*/ + + if (error) { + std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: FreeType: Set char size error." << std::endl; + delete[] ucs4text; + return 0; + } + + /* Retrieve glyph index from character code */ + glyph_index = FT_Get_Char_Index( face, ucs4text[n] ); + + /* Load glyph image into the slot (erase previous one) */ + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT ); + if (error) { + std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error " << std::hex << error <<")." << std::endl; + std::cerr.copyfmt(std::ios(NULL)); + delete[] ucs4text; + return 0; + } + + /* Convert to an anti-aliased bitmap */ + error = FT_Render_Glyph( face->glyph, ft_render_mode_normal ); + if (error) { + std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: FreeType: Render glyph error." << std::endl; + delete[] ucs4text; + return 0; + } + + /* Now, draw to our target surface */ +/* my_draw_bitmap( &slot->bitmap, + slot->bitmap_left, + y_start + slot->bitmap_top, + red, + green, + blue ); +*/ + /* Advance to the next position */ + pen.x += slot->advance.x; + pen.y += slot->advance.y; + + /* record current glyph index */ + previous = glyph_index; + } + + /* Free the face and the library objects */ + FT_Done_Face ( face ); + FT_Done_FreeType( library ); + + delete[] ucs4text; + + return (int) (((double) pen.x)/64.0); +} + +/////////////// +#endif +#ifdef NO_FREETYPE + +void pngwriter::plot_text( char *, int, int, int, double, char *, int, int, int ) +{ + std::cerr << " PNGwriter::plot_text - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; + return; +} + +void pngwriter::plot_text( char *, int, int, int, double, char *, double, double, double ) +{ + std::cerr << " PNGwriter::plot_text - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; + return; + +} + +void pngwriter::plot_text_utf8( char *, int, int, int, double, char *, int, int, int ) +{ + std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; + return; +} + +void pngwriter::plot_text_utf8( char *, int, int, int, double, char *, double, double, double) +{ + std::cerr << " PNGwriter::plot_text_utf8 - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; + return; +} + +//////////// Get text width +int pngwriter::get_text_width(char *, int, char *) +{ + std::cerr << " PNGwriter::get_text_width - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; + return 0; +} + + +int pngwriter::get_text_width_utf8(char *, int, char *) +{ + std::cerr << " PNGwriter::get_text_width_utf8 - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; + return 0; +} + +/////////////// +#endif + +///////////////////////////////////// +int pngwriter::bilinear_interpolation_read(double x, double y, int colour) const +{ + + int inty, intx; + inty = (int) ceil(y); + intx = (int) ceil(x); + + //inty = (int) floor(y) +1; + // intx = (int) floor(x) +1; + // + bool attop, atright; + attop = inty==this->height_; + atright = intx==this->width_; +/* + if( intx==this->width_ +1) + { + intx--; + // std::cout << "intx--" << std::endl; + + } + */ + /* + if(inty == this->height_ +1) + { + inty--; + // std::cout << "inty--" << std::endl; + } + */ + + if( (!attop)&&(!atright) ) + { + + double f,g,f1,g1; + f = 1.0 + x - ((double) intx); + g = 1.0 + y - ((double) inty); + f1 = 1.0 - f; + g1 = 1.0 - g; + + return (int) ( + f1*g1*this->read(intx, inty,colour) + + f*g1*this->read(intx+1,inty,colour) + +f1*g*this->read(intx,inty+1,colour) + + f*g*(this->read(intx+1,inty+1,colour)) + ); + } + + if( (atright)&&(!attop)) + { + + double f,g,f1,g1; + f = 1.0 + x - ((double) intx); + g = 1.0 + y - ((double) inty); + f1 = 1.0 - f; + g1 = 1.0 - g; + + return (int) ( + f1*g1*this->read(intx, inty,colour) + + f*g1*( 2*(this->read(intx,inty,colour)) - (this->read(intx-1,inty,colour)) ) + +f1*g*this->read(intx,inty+1,colour) + + f*g*(2*(this->read(intx,inty+1,colour)) - (this->read(intx-1,inty+1,colour))) + ); + } + + if((attop)&&(!atright)) + { + double f,g,f1,g1; + f = 1.0 + x - ((double) intx); + g = 1.0 + y - ((double) inty); + f1 = 1.0 - f; + g1 = 1.0 - g; + + return (int) ( + f1*g1*this->read(intx, inty,colour) + + f*g1*this->read(intx+1,inty,colour) + +f1*g*( 2*(this->read(intx,inty,colour)) - this->read(intx,inty-1,colour) ) + + f*g*( 2*(this->read(intx+1,inty,colour)) - this->read(intx+1,inty-1,colour)) + ); + } + + double f,g,f1,g1; + f = 1.0 + x - ((double) intx); + g = 1.0 + y - ((double) inty); + f1 = 1.0 - f; + g1 = 1.0 - g; + + return (int) ( + f1*g1*this->read(intx, inty,colour) + + f*g1*( 2*(this->read(intx,inty,colour)) - (this->read(intx-1,inty,colour)) ) + +f1*g*( 2*(this->read(intx,inty,colour)) - this->read(intx,inty-1,colour) ) + + f*g*( 2*( 2*(this->read(intx,inty,colour)) - (this->read(intx-1,inty,colour)) ) - ( 2*(this->read(intx,inty-1,colour)) - (this->read(intx-1,inty-1,colour)) )) + ); + + /* + return (int) ( + f1*g1*this->read(intx, inty,colour) + + f*g1*this->read(intx+1,inty,colour) + +f1*g*this->read(intx,inty+1,colour) + + f*g*this->read(intx+1, inty+1,colour) + ); + * */ + +} + +double pngwriter::bilinear_interpolation_dread(double x, double y, int colour) const +{ + return double(this->bilinear_interpolation_read(x,y,colour))/65535.0; +} + +void pngwriter::plot_blend(int x, int y, double opacity, int red, int green, int blue) +{ + this->plot(x, y, + (int)( opacity*red + this->read(x,y,1)*(1.0-opacity)), + (int)( opacity*green + this->read(x,y,2)*(1.0-opacity)), + (int)( opacity*blue + this->read(x,y,3)*(1.0-opacity)) + ); +} + +void pngwriter::plot_blend(int x, int y, double opacity, double red, double green, double blue) +{ + this->plot_blend(x, y, opacity, (int) (65535*red), (int) (65535*green), (int) (65535*blue)); +} + +void pngwriter::invert(void) +{ + // int temp1, temp2, temp3; + double temp11, temp22, temp33; + + for(int jjj = 1; jjj <= (this->height_); jjj++) + { + for(int iii = 1; iii <= (this->width_); iii++) + { + /* temp11 = (this->read(iii,jjj,1)); + temp22 = (this->read(iii,jjj,2)); + temp33 = (this->read(iii,jjj,3)); + * + this->plot(iii,jjj, + ((double)(65535 - temp11))/65535.0, + ((double)(65535 - temp22))/65535.0, + ((double)(65535 - temp33))/65535.0 + ); + * + */ + temp11 = (this->read(iii,jjj,1)); + temp22 = (this->read(iii,jjj,2)); + temp33 = (this->read(iii,jjj,3)); + + this->plot(iii,jjj, + (int)(65535 - temp11), + (int)(65535 - temp22), + (int)(65535 - temp33) + ); + + } + } +} + +void pngwriter::resize(int width, int height) +{ + + for (int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]); + free(graph_); + + width_ = width; + height_ = height; + backgroundcolour_ = 0; + + graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep)); + if(graph_ == NULL) + { + std::cerr << " PNGwriter::resize - ERROR **: Not able to allocate memory for image." << std::endl; + } + + for (int kkkk = 0; kkkk < height_; kkkk++) + { + graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte)); + if(graph_[kkkk] == NULL) + { + std::cerr << " PNGwriter::resize - ERROR **: Not able to allocate memory for image." << std::endl; + } + } + + if(graph_ == NULL) + { + std::cerr << " PNGwriter::resize - ERROR **: Not able to allocate memory for image." << std::endl; + } + + int tempindex; + for(int vhhh = 0; vhhhdread(xstart,ystart,1) != boundary_red) || + (this->dread(xstart,ystart,2) != boundary_green) || + (this->dread(xstart,ystart,3) != boundary_blue) + ) + && + ( + (this->dread(xstart,ystart,1) != fill_red) || + (this->dread(xstart,ystart,2) != fill_green) || + (this->dread(xstart,ystart,3) != fill_blue) + ) + && + (xstart >0)&&(xstart <= width_)&&(ystart >0)&&(ystart <= height_) + ) + { + this->plot(xstart, ystart, fill_red, fill_green, fill_blue); + boundary_fill(xstart+1, ystart, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ; + boundary_fill(xstart, ystart+1, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ; + boundary_fill(xstart, ystart-1, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ; + boundary_fill(xstart-1, ystart, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ; + } +} + +//no int version needed +void pngwriter::flood_fill_internal(int xstart, int ystart, double start_red, double start_green, double start_blue, double fill_red, double fill_green, double fill_blue) +{ + if( ( + (this->dread(xstart,ystart,1) == start_red) && + (this->dread(xstart,ystart,2) == start_green) && + (this->dread(xstart,ystart,3) == start_blue) + ) + && + ( + (this->dread(xstart,ystart,1) != fill_red) || + (this->dread(xstart,ystart,2) != fill_green) || + (this->dread(xstart,ystart,3) != fill_blue) + ) + && + (xstart >0)&&(xstart <= width_)&&(ystart >0)&&(ystart <= height_) + ) + { + this->plot(xstart, ystart, fill_red, fill_green, fill_blue); + flood_fill_internal( xstart+1, ystart, start_red, start_green, start_blue, fill_red, fill_green, fill_blue); + flood_fill_internal( xstart-1, ystart, start_red, start_green, start_blue, fill_red, fill_green, fill_blue); + flood_fill_internal( xstart, ystart+1, start_red, start_green, start_blue, fill_red, fill_green, fill_blue); + flood_fill_internal( xstart, ystart-1, start_red, start_green, start_blue, fill_red, fill_green, fill_blue); + } + +} + +//int version +void pngwriter::boundary_fill(int xstart, int ystart, int boundary_red,int boundary_green,int boundary_blue,int fill_red, int fill_green, int fill_blue) +{ + + this->boundary_fill( xstart, ystart, + ((double) boundary_red)/65535.0, + ((double) boundary_green)/65535.0, + ((double) boundary_blue)/65535.0, + ((double) fill_red)/65535.0, + ((double) fill_green)/65535.0, + ((double) fill_blue)/65535.0 + ); +} + +void pngwriter::flood_fill(int xstart, int ystart, double fill_red, double fill_green, double fill_blue) +{ + flood_fill_internal( xstart, ystart, this->dread(xstart,ystart,1),this->dread(xstart,ystart,2),this->dread(xstart,ystart,3), fill_red, fill_green, fill_blue); +} + +//int version +void pngwriter::flood_fill(int xstart, int ystart, int fill_red, int fill_green, int fill_blue) +{ + this->flood_fill( xstart, ystart, + ((double) fill_red)/65535.0, + ((double) fill_green)/65535.0, + ((double) fill_blue)/65535.0 + ); +} + +void pngwriter::polygon( int * points, int number_of_points, double red, double green, double blue) +{ + if( (number_of_points<1)||(points ==NULL)) + { + std::cerr << " PNGwriter::polygon - ERROR **: Number of points is zero or negative, or array is NULL." << std::endl; + return; + } + + for(int k=0;k< number_of_points-1; k++) + { + this->line(points[2*k],points[2*k+1],points[2*k+2],points[2*k+3], red, green, blue); + } +} + +//int version +void pngwriter::polygon( int * points, int number_of_points, int red, int green, int blue) +{ + this->polygon(points, number_of_points, + ((double) red)/65535.0, + ((double) green)/65535.0, + ((double) blue)/65535.0 + ); +} + +void pngwriter::plotCMYK(int x, int y, double cyan, double magenta, double yellow, double black) +{ +/*CMYK to RGB: + * ----------- + * red = 255 - minimum(255,((cyan/255) * (255 - black) + black)) + * green = 255 - minimum(255,((magenta/255) * (255 - black) + black)) + * blue = 255 - minimum(255,((yellow/255) * (255 - black) + black)) + * */ + + if(cyan<0.0) + { + cyan = 0.0; + } + if(magenta<0.0) + { + magenta = 0.0; + } + if(yellow<0.0) + { + yellow = 0.0; + } + if(black<0.0) + { + black = 0.0; + } + + if(cyan>1.0) + { + cyan = 1.0; + } + if(magenta>1.0) + { + magenta = 1.0; + } + if(yellow>1.0) + { + yellow = 1.0; + } + if(black>1.0) + { + black = 1.0; + } + + double red, green, blue, minr, ming, minb, iblack; + + iblack = 1.0 - black; + + minr = 1.0; + ming = 1.0; + minb = 1.0; + + if( (cyan*iblack + black)<1.0 ) + { + minr = cyan*iblack + black; + } + + if( (magenta*iblack + black)<1.0 ) + { + ming = magenta*iblack + black; + } + + if( (yellow*iblack + black)<1.0 ) + { + minb = yellow*iblack + black; + } + + red = 1.0 - minr; + green = 1.0 - ming; + blue = 1.0 - minb; + + this->plot(x,y,red, green, blue); + +} + +//int version +void pngwriter::plotCMYK(int x, int y, int cyan, int magenta, int yellow, int black) +{ + this->plotCMYK( x, y, + ((double) cyan)/65535.0, + ((double) magenta)/65535.0, + ((double) yellow)/65535.0, + ((double) black)/65535.0 + ); +} + +double pngwriter::dreadCMYK(int x, int y, int colour) const +{ +/* + * Black = minimum(1-Red,1-Green,1-Blue) + * Cyan = (1-Red-Black)/(1-Black) + * Magenta = (1-Green-Black)/(1-Black) + * Yellow = (1-Blue-Black)/(1-Black) + * + * */ + double black, red, green, blue, ired, igreen, iblue, iblack; + //add error detection here + // not much to detect, really + red = this->dread(x, y, 1); + green = this->dread(x, y, 2); + blue = this->dread(x, y, 3); + + ired = 1.0 - red; + igreen = 1.0 - green; + iblue = 1.0 - blue; + + black = ired; + + //black is the mimimum of inverse RGB colours, and if they are all equal, it is the inverse of red. + if( (igreendread(x, y, 1); + green = this->dread(x, y, 2); + blue = this->dread(x, y, 3); + + ired = 1.0 - red; + igreen = 1.0 - green; + iblue = 1.0 - blue; + + black = ired; + + //black is the mimimum of inverse RGB colours, and if they are all equal, it is the inverse of red. + if( (igreenbilinear_interpolation_read(readx, ready, 1); + green = this->bilinear_interpolation_read(readx, ready, 2); + blue = this->bilinear_interpolation_read(readx, ready, 3); + temp.plot(x, y, red, green, blue); + + } + } + + // From here on, the process is the same for all scale functions. + //Get data out of temp and into this's storage. + + //Resize this instance + // Delete current storage. + for (int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]); + free(graph_); + + //New image will have bit depth 16, regardless of original bit depth. + bit_depth_ = 16; + + // New width and height will be the scaled width and height + width_ = scaledw; + height_ = scaledh; + backgroundcolour_ = 0; + + graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep)); + if(graph_ == NULL) + { + std::cerr << " PNGwriter::scale_k - ERROR **: Not able to allocate memory for image." << std::endl; + } + + for (int kkkk = 0; kkkk < height_; kkkk++) + { + graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte)); + if(graph_[kkkk] == NULL) + { + std::cerr << " PNGwriter::scale_k - ERROR **: Not able to allocate memory for image." << std::endl; + } + } + + if(graph_ == NULL) + { + std::cerr << " PNGwriter::scale_k - ERROR **: Not able to allocate memory for image." << std::endl; + } + + //This instance now has a new, resized storage space. + + //Copy the temp date into this's storage. + int tempindex; + for(int vhhh = 0; vhhhbilinear_interpolation_read(readx, ready, 1); + green = this->bilinear_interpolation_read(readx, ready, 2); + blue = this->bilinear_interpolation_read(readx, ready, 3); + temp.plot(x, y, red, green, blue); + + } + } + // From here on, the process is the same for all scale functions. + //Get data out of temp and into this's storage. + + //Resize this instance + // Delete current storage. + for (int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]); + free(graph_); + + //New image will have bit depth 16, regardless of original bit depth. + bit_depth_ = 16; + + // New width and height will be the scaled width and height + width_ = scaledw; + height_ = scaledh; + backgroundcolour_ = 0; + + graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep)); + if(graph_ == NULL) + { + std::cerr << " PNGwriter::scale_kxky - ERROR **: Not able to allocate memory for image." << std::endl; + } + + for (int kkkk = 0; kkkk < height_; kkkk++) + { + graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte)); + if(graph_[kkkk] == NULL) + { + std::cerr << " PNGwriter::scale_kxky - ERROR **: Not able to allocate memory for image." << std::endl; + } + } + + if(graph_ == NULL) + { + std::cerr << " PNGwriter::scale_kxky - ERROR **: Not able to allocate memory for image." << std::endl; + } + + //This instance now has a new, resized storage space. + + //Copy the temp date into this's storage. + int tempindex; + for(int vhhh = 0; vhhhbilinear_interpolation_read(readx, ready, 1); + green = this->bilinear_interpolation_read(readx, ready, 2); + blue = this->bilinear_interpolation_read(readx, ready, 3); + temp.plot(x, y, red, green, blue); + + } + } + + // From here on, the process is the same for all scale functions. + //Get data out of temp and into this's storage. + + //Resize this instance + // Delete current storage. + for (int jjj = 0; jjj < height_; jjj++) free(graph_[jjj]); + free(graph_); + + //New image will have bit depth 16, regardless of original bit depth. + bit_depth_ = 16; + + // New width and height will be the scaled width and height + width_ = finalwidth; + height_ = finalheight; + backgroundcolour_ = 0; + + graph_ = (png_bytepp)malloc(height_ * sizeof(png_bytep)); + if(graph_ == NULL) + { + std::cerr << " PNGwriter::scale_wh - ERROR **: Not able to allocate memory for image." << std::endl; + } + + for (int kkkk = 0; kkkk < height_; kkkk++) + { + graph_[kkkk] = (png_bytep)malloc(6*width_ * sizeof(png_byte)); + if(graph_[kkkk] == NULL) + { + std::cerr << " PNGwriter::scale_wh - ERROR **: Not able to allocate memory for image." << std::endl; + } + } + + if(graph_ == NULL) + { + std::cerr << " PNGwriter::scale_wh - ERROR **: Not able to allocate memory for image." << std::endl; + } + + //This instance now has a new, resized storage space. + + //Copy the temp date into this's storage. + int tempindex; + for(int vhhh = 0; vhhhplot_blend(xfrom,yfrom,opacity, red,green,blue); + + if (dx > dy) + { + int fraction = dy - (dx >> 1); + + while (xfrom != xto) + { + if (fraction >= 0) + { + yfrom += stepy; + fraction -= dx; + } + xfrom += stepx; + fraction += dy; + this->plot_blend(xfrom,yfrom,opacity, red,green,blue); + } + } + else + { + int fraction = dx - (dy >> 1); + while (yfrom != yto) + { + if (fraction >= 0) + { + xfrom += stepx; + fraction -= dy; + } + yfrom += stepy; + fraction += dx; + this->plot_blend(xfrom,yfrom, opacity, red,green,blue); + } + } + +} + +void pngwriter::line_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue) +{ + this->line_blend( xfrom, + yfrom, + xto, + yto, + opacity, + int (red*65535), + int (green*65535), + int (blue*65535) + ); + +} + +void pngwriter::square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue) +{ + this->line_blend(xfrom, yfrom, xfrom, yto, opacity, red, green, blue); + this->line_blend(xto, yfrom, xto, yto, opacity, red, green, blue); + this->line_blend(xfrom, yfrom, xto, yfrom, opacity, red, green, blue); + this->line_blend(xfrom, yto, xto, yto, opacity, red, green, blue); +} + +void pngwriter::square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue) +{ + this->square_blend( xfrom, yfrom, xto, yto, opacity, int(red*65535), int(green*65535), int(blue*65535)); +} + +void pngwriter::filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue) +{ + for(int caca = xfrom; caca line_blend(caca, yfrom, caca, yto, opacity, red, green, blue); + } + +} + +void pngwriter::filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue) +{ + this->filledsquare_blend( xfrom, yfrom, xto, yto, opacity, int(red*65535), int(green*65535), int(blue*65535)); +} + +void pngwriter::circle_aux_blend(int xcentre, int ycentre, int x, int y, double opacity, int red, int green, int blue) +{ + if (x == 0) + { + this->plot_blend( xcentre, ycentre + y, opacity, red, green, blue); + this->plot_blend( xcentre, ycentre - y, opacity, red, green, blue); + this->plot_blend( xcentre + y, ycentre, opacity, red, green, blue); + this->plot_blend( xcentre - y, ycentre, opacity, red, green, blue); + } + else + if (x == y) + { + this->plot_blend( xcentre + x, ycentre + y, opacity, red, green, blue); + this->plot_blend( xcentre - x, ycentre + y, opacity, red, green, blue); + this->plot_blend( xcentre + x, ycentre - y, opacity, red, green, blue); + this->plot_blend( xcentre - x, ycentre - y, opacity, red, green, blue); + } + else + if (x < y) + { + this->plot_blend( xcentre + x, ycentre + y, opacity, red, green, blue); + this->plot_blend( xcentre - x, ycentre + y, opacity, red, green, blue); + this->plot_blend( xcentre + x, ycentre - y, opacity, red, green, blue); + this->plot_blend( xcentre - x, ycentre - y, opacity, red, green, blue); + this->plot_blend( xcentre + y, ycentre + x, opacity, red, green, blue); + this->plot_blend( xcentre - y, ycentre + x, opacity, red, green, blue); + this->plot_blend( xcentre + y, ycentre - x, opacity, red, green, blue); + this->plot_blend( xcentre - y, ycentre - x, opacity, red, green, blue); + } + +} +// + +void pngwriter::circle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue) +{ + int x = 0; + int y = radius; + int p = (5 - radius*4)/4; + + circle_aux_blend(xcentre, ycentre, x, y, opacity, red, green, blue); + while (x < y) + { + x++; + if (p < 0) + { + p += 2*x+1; + } + else + { + y--; + p += 2*(x-y)+1; + } + circle_aux_blend(xcentre, ycentre, x, y, opacity, red, green, blue); + } + +} + +void pngwriter::circle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue) +{ + this->circle_blend(xcentre,ycentre,radius, opacity, int(red*65535), int(green*65535), int(blue*65535)); +} + +void pngwriter::filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue) +{ + for(int jjj = ycentre-radius; jjj< ycentre+radius+1; jjj++) + { + this->line_blend(xcentre - int(sqrt((double)(radius*radius) - (-ycentre + jjj)*(-ycentre + jjj ))), jjj, + xcentre + int(sqrt((double)(radius*radius) - (-ycentre + jjj)*(-ycentre + jjj ))),jjj, opacity, red,green,blue); + } + +} + +void pngwriter::filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue) +{ + this->filledcircle_blend( xcentre, ycentre, radius, opacity, int(red*65535), int(green*65535), int(blue*65535)); +} + +void pngwriter::bezier_blend( int startPtX, int startPtY, + int startControlX, int startControlY, + int endPtX, int endPtY, + int endControlX, int endControlY, + double opacity, + double red, double green, double blue) +{ + double cx = 3.0*(startControlX - startPtX); + double bx = 3.0*(endControlX - startControlX) - cx; + double ax = double(endPtX - startPtX - cx - bx); + + double cy = 3.0*(startControlY - startPtY); + double by = 3.0*(endControlY - startControlY) - cy; + double ay = double(endPtY - startPtY - cy - by); + + double x,y; + x = startPtX; + y = startPtY; + + for(double t = 0.0; t<=1.005; t += 0.005) + { + double const newx = startPtX + t*(double(cx) + t*(double(bx) + t*(double(ax)))); + double const newy = startPtY + t*(double(cy) + t*(double(by) + t*(double(ay)))); + this->line_blend(int(x),int(y),int(newx),int(newy),opacity, red,green,blue); + x = newx; + y = newy; + } +} + +void pngwriter::bezier_blend( int startPtX, int startPtY, + int startControlX, int startControlY, + int endPtX, int endPtY, + int endControlX, int endControlY, + double opacity, + int red, int green, int blue) +{ + this->bezier_blend( startPtX, startPtY, + startControlX, startControlY, + endPtX, endPtY, + endControlX, endControlY, + opacity, + double(red)/65535.0, double(green)/65535.0, double(blue)/65535.0); + +} + +///////////////////////////// +#ifndef NO_FREETYPE + +// Freetype-based text rendering functions. +/////////////////////////////////////////// +void pngwriter::plot_text_blend( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, double red, double green, double blue) +{ + FT_Library library; + FT_Face face; + FT_Matrix matrix; // transformation matrix + FT_Vector pen; + + FT_UInt glyph_index; + FT_Error error; + + FT_Bool use_kerning; + FT_UInt previous = 0; + + /* Set up transformation Matrix */ + matrix.xx = (FT_Fixed)( cos(angle)*0x10000); /* It would make more sense to do this (below), but, bizzarely, */ + matrix.xy = (FT_Fixed)(-sin(angle)*0x10000); /* if one does, FT_Load_Glyph fails consistently. */ + matrix.yx = (FT_Fixed)( sin(angle)*0x10000); // matrix.yx = - matrix.xy; + matrix.yy = (FT_Fixed)( cos(angle)*0x10000); // matrix.yy = matrix.xx; + + /* Place starting coordinates in adequate form. */ + pen.x = x_start*64 ; + pen.y = (int)(y_start/64.0); + + /*Count the length of the string */ + int num_chars = strlen(text); + + /* Initialize FT Library object */ + error = FT_Init_FreeType( &library ); + if (error) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Could not init Library."<< std::endl; return;} + + /* Initialize FT face object */ + error = FT_New_Face( library,face_path,0,&face ); + if ( error == FT_Err_Unknown_File_Format ) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Font was opened, but type not supported."<< std::endl; return; } else if (error){ std::cerr << " PNGwriter::plot_text - ERROR **: FreeType: Could not find or load font file."<< std::endl; return; } + + /* Set the Char size */ + error = FT_Set_Char_Size( face, /* handle to face object */ + 0, /* char_width in 1/64th of points */ + fontsize*64, /* char_height in 1/64th of points */ + 100, /* horizontal device resolution */ + 100 ); /* vertical device resolution */ + + /* A way of accesing the glyph directly */ + FT_GlyphSlot slot = face->glyph; // a small shortcut + + /* Does the font file support kerning? */ + use_kerning = FT_HAS_KERNING( face ); + + int n; + for ( n = 0; n < num_chars; n++ ) + { + /* Convert character code to glyph index */ + glyph_index = FT_Get_Char_Index( face, text[n] ); + + /* Retrieve kerning distance and move pen position */ + if ( use_kerning && previous&& glyph_index ) + { + FT_Vector delta; + FT_Get_Kerning( face, + previous, + glyph_index, + ft_kerning_default, //FT_KERNING_DEFAULT, + &delta ); + + /* Transform this kerning distance into rotated space */ + pen.x += (int) (((double) delta.x)*cos(angle)); + pen.y += (int) (((double) delta.x)*( sin(angle))); + } + + /* Set transform */ + FT_Set_Transform( face, &matrix, &pen ); + +/*set char size*/ + + if (error) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Set char size error." << std::endl; return;} + + /* Retrieve glyph index from character code */ + glyph_index = FT_Get_Char_Index( face, text[n] ); + + /* Load glyph image into the slot (erase previous one) */ + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT ); + if (error) { + std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error " << std::hex << error <<")." << std::endl; + std::cerr.copyfmt(std::ios(NULL)); + return; + } + + /* Convert to an anti-aliased bitmap */ + // error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL ); + error = FT_Render_Glyph( face->glyph, ft_render_mode_normal ); + if (error) { std::cerr << " PNGwriter::plot_text_blend - ERROR **: FreeType: Render glyph error." << std::endl; return;} + + /* Now, draw to our target surface */ + my_draw_bitmap_blend( &slot->bitmap, + slot->bitmap_left, + y_start + slot->bitmap_top, + opacity, + red, + green, + blue ); + + /* Advance to the next position */ + pen.x += slot->advance.x; + pen.y += slot->advance.y; + + /* record current glyph index */ + previous = glyph_index; + } + + /* Free the face and the library objects */ + FT_Done_Face ( face ); + FT_Done_FreeType( library ); +} + +void pngwriter::plot_text_utf8_blend( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, double red, double green, double blue) +{ + FT_Library library; + FT_Face face; + FT_Matrix matrix; // transformation matrix + FT_Vector pen; + + FT_UInt glyph_index; + FT_Error error; + + FT_Bool use_kerning; + FT_UInt previous = 0; + + /* Set up transformation Matrix */ + matrix.xx = (FT_Fixed)( cos(angle)*0x10000); /* It would make more sense to do this (below), but, bizzarely, */ + matrix.xy = (FT_Fixed)(-sin(angle)*0x10000); /* if one does, FT_Load_Glyph fails consistently. */ + matrix.yx = (FT_Fixed)( sin(angle)*0x10000); // matrix.yx = - matrix.xy; + matrix.yy = (FT_Fixed)( cos(angle)*0x10000); // matrix.yy = matrix.xx; + + /* Place starting coordinates in adequate form. */ + pen.x = x_start*64 ; + pen.y = (int)(y_start/64.0); + + /*Count the length of the string */ + int num_bytes=0; + while(text[num_bytes]!=0) + { + num_bytes++; + } + + /* + std::cout << "Num bytes is: "<< num_bytes << std::endl; + */ + + //The array of ucs4 glyph indexes, which will by at most the number of bytes in the utf-8 file. + long * ucs4text; + ucs4text = new long[num_bytes+1]; + + unsigned char u,v,w,x,y; + + int num_chars=0; + + long iii=0; + + while(iiiglyph; // a small shortcut + + /* Does the font file support kerning? */ + use_kerning = FT_HAS_KERNING( face ); + + int n; + for ( n = 0; n < num_chars; n++ ) + { + /* Convert character code to glyph index */ + glyph_index = FT_Get_Char_Index( face, ucs4text[n] ); + + /* Retrieve kerning distance and move pen position */ + if ( use_kerning && previous&& glyph_index ) + { + FT_Vector delta; + FT_Get_Kerning( face, + previous, + glyph_index, + ft_kerning_default, //FT_KERNING_DEFAULT, + &delta ); + + /* Transform this kerning distance into rotated space */ + pen.x += (int) (((double) delta.x)*cos(angle)); + pen.y += (int) (((double) delta.x)*( sin(angle))); + } + + /* Set transform */ + FT_Set_Transform( face, &matrix, &pen ); + +/*set char size*/ + + if (error) { + std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: FreeType: Set char size error." << std::endl; + delete[] ucs4text; + return; + } + + /* Retrieve glyph index from character code */ + glyph_index = FT_Get_Char_Index( face, ucs4text[n] ); + + /* Load glyph image into the slot (erase previous one) */ + error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT ); + if (error) { + std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: FreeType: Could not load glyph (in loop). (FreeType error " << std::hex << error <<")." << std::endl; + std::cout.copyfmt(std::ios(NULL)); + delete[] ucs4text; + return; + } + + /* Convert to an anti-aliased bitmap */ + error = FT_Render_Glyph( face->glyph, ft_render_mode_normal ); + if (error) { + std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: FreeType: Render glyph error." << std::endl; + delete[] ucs4text; + return; + } + + /* Now, draw to our target surface */ + my_draw_bitmap_blend( &slot->bitmap, + slot->bitmap_left, + y_start + slot->bitmap_top, + opacity, + red, + green, + blue ); + + /* Advance to the next position */ + pen.x += slot->advance.x; + pen.y += slot->advance.y; + + /* record current glyph index */ + previous = glyph_index; + } + + /* Free the face and the library objects */ + FT_Done_Face ( face ); + FT_Done_FreeType( library ); + + delete[] ucs4text; +} + +void pngwriter::plot_text_blend( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, int red, int green, int blue) +{ + plot_text_blend( face_path, fontsize, x_start, y_start, angle, text, opacity, ((double) red)/65535.0, ((double) green)/65535.0, ((double) blue)/65535.0 ); +} + +void pngwriter::plot_text_utf8_blend( char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, int red, int green, int blue) +{ + plot_text_utf8_blend( face_path, fontsize, x_start, y_start, angle, text, opacity, ((double) red)/65535.0, ((double) green)/65535.0, ((double) blue)/65535.0 ); +} + +void pngwriter::my_draw_bitmap_blend( FT_Bitmap * bitmap, int x, int y, double opacity, double red, double green, double blue) +{ + double temp; + for(unsigned int j = 1u; j < bitmap->rows + 1u; j++) + { + for(unsigned int i = 1u; i < bitmap->width + 1u; i++) + { + temp = (double)(bitmap->buffer[(j-1u)*bitmap->width + (i-1u)] )/255.0; + + if(temp) + { + this->plot_blend(x + i, + y - j, + opacity, + temp*red + (1-temp)*(this->dread(x+i,y-j,1)), + temp*green + (1-temp)*(this->dread(x+i,y-j,2)), + temp*blue + (1-temp)*(this->dread(x+i,y-j,3)) + ); + } + } + } +} + +#endif +#ifdef NO_FREETYPE + +void pngwriter::plot_text_blend( char *, int, int, int, double, char *, double, int, int, int ) +{ + std::cerr << " PNGwriter::plot_text_blend - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; + return; +} + +void pngwriter::plot_text_blend( char *, int, int, int, double, char *, double, double, double, double ) +{ + std::cerr << " PNGwriter::plot_text_blend - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; + return; + +} + +void pngwriter::plot_text_utf8_blend( char *, int, int, int, double, char *, double, int, int, int ) +{ + std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; + return; +} + +void pngwriter::plot_text_utf8_blend( char *, int, int, int, double, char *, double, double, double, double ) +{ + std::cerr << " PNGwriter::plot_text_utf8_blend - ERROR **: PNGwriter was compiled without Freetype support! Recompile PNGwriter with Freetype support (once you have Freetype installed, that is. Websites: www.freetype.org and pngwriter.sourceforge.net)." << std::endl; + return; +} + +#endif + +/////////////////////////// + +void pngwriter::boundary_fill_blend(int xstart, int ystart, double opacity, double boundary_red,double boundary_green,double boundary_blue,double fill_red, double fill_green, double fill_blue) +{ + if( ( + (this->dread(xstart,ystart,1) != boundary_red) || + (this->dread(xstart,ystart,2) != boundary_green) || + (this->dread(xstart,ystart,3) != boundary_blue) + ) + && + ( + (this->dread(xstart,ystart,1) != fill_red) || + (this->dread(xstart,ystart,2) != fill_green) || + (this->dread(xstart,ystart,3) != fill_blue) + ) + && + (xstart >0)&&(xstart <= width_)&&(ystart >0)&&(ystart <= height_) + ) + { + this->plot_blend(xstart, ystart, opacity, fill_red, fill_green, fill_blue); + boundary_fill_blend(xstart+1, ystart, opacity, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ; + boundary_fill_blend(xstart, ystart+1, opacity, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ; + boundary_fill_blend(xstart, ystart-1, opacity, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ; + boundary_fill_blend(xstart-1, ystart, opacity, boundary_red, boundary_green, boundary_blue, fill_red, fill_green, fill_blue) ; + } +} + +//no int version needed +void pngwriter::flood_fill_internal_blend(int xstart, int ystart, double opacity, double start_red, double start_green, double start_blue, double fill_red, double fill_green, double fill_blue) +{ + if( ( + (this->dread(xstart,ystart,1) == start_red) && + (this->dread(xstart,ystart,2) == start_green) && + (this->dread(xstart,ystart,3) == start_blue) + ) + && + ( + (this->dread(xstart,ystart,1) != fill_red) || + (this->dread(xstart,ystart,2) != fill_green) || + (this->dread(xstart,ystart,3) != fill_blue) + ) + && + (xstart >0)&&(xstart <= width_)&&(ystart >0)&&(ystart <= height_) + ) + { + this->plot_blend(xstart, ystart, opacity, fill_red, fill_green, fill_blue); + flood_fill_internal_blend( xstart+1, ystart, opacity, start_red, start_green, start_blue, fill_red, fill_green, fill_blue); + flood_fill_internal_blend( xstart-1, ystart,opacity, start_red, start_green, start_blue, fill_red, fill_green, fill_blue); + flood_fill_internal_blend( xstart, ystart+1, opacity, start_red, start_green, start_blue, fill_red, fill_green, fill_blue); + flood_fill_internal_blend( xstart, ystart-1, opacity, start_red, start_green, start_blue, fill_red, fill_green, fill_blue); + } + +} + +//int version +void pngwriter::boundary_fill_blend(int xstart, int ystart, double opacity, int boundary_red,int boundary_green,int boundary_blue,int fill_red, int fill_green, int fill_blue) +{ + + this->boundary_fill_blend( xstart, ystart, + opacity, + ((double) boundary_red)/65535.0, + ((double) boundary_green)/65535.0, + ((double) boundary_blue)/65535.0, + ((double) fill_red)/65535.0, + ((double) fill_green)/65535.0, + ((double) fill_blue)/65535.0 + ); +} + +void pngwriter::flood_fill_blend(int xstart, int ystart, double opacity, double fill_red, double fill_green, double fill_blue) +{ + flood_fill_internal_blend( xstart, ystart, opacity, this->dread(xstart,ystart,1),this->dread(xstart,ystart,2),this->dread(xstart,ystart,3), fill_red, fill_green, fill_blue); +} + +//int version +void pngwriter::flood_fill_blend(int xstart, int ystart, double opacity, int fill_red, int fill_green, int fill_blue) +{ + this->flood_fill_blend( xstart, ystart, + opacity, + ((double) fill_red)/65535.0, + ((double) fill_green)/65535.0, + ((double) fill_blue)/65535.0 + ); +} + +void pngwriter::polygon_blend( int * points, int number_of_points, double opacity, double red, double green, double blue) +{ + if( (number_of_points<1)||(points ==NULL)) + { + std::cerr << " PNGwriter::polygon_blend - ERROR **: Number of points is zero or negative, or array is NULL." << std::endl; + return; + } + + for(int k=0;k< number_of_points-1; k++) + { + this->line_blend(points[2*k],points[2*k+1],points[2*k+2],points[2*k+3], opacity, red, green, blue); + } +} + +//int version +void pngwriter::polygon_blend( int * points, int number_of_points, double opacity, int red, int green, int blue) +{ + this->polygon_blend(points, number_of_points, + opacity, + ((double) red)/65535.0, + ((double) green)/65535.0, + ((double) blue)/65535.0 + ); +} + +void pngwriter::plotCMYK_blend(int x, int y, double opacity, double cyan, double magenta, double yellow, double black) +{ +/*CMYK to RGB: + * ----------- + * red = 255 - minimum(255,((cyan/255) * (255 - black) + black)) + * green = 255 - minimum(255,((magenta/255) * (255 - black) + black)) + * blue = 255 - minimum(255,((yellow/255) * (255 - black) + black)) + * */ + + if(cyan<0.0) + { + cyan = 0.0; + } + if(magenta<0.0) + { + magenta = 0.0; + } + if(yellow<0.0) + { + yellow = 0.0; + } + if(black<0.0) + { + black = 0.0; + } + + if(cyan>1.0) + { + cyan = 1.0; + } + if(magenta>1.0) + { + magenta = 1.0; + } + if(yellow>1.0) + { + yellow = 1.0; + } + if(black>1.0) + { + black = 1.0; + } + + double red, green, blue, minr, ming, minb, iblack; + + iblack = 1.0 - black; + + minr = 1.0; + ming = 1.0; + minb = 1.0; + + if( (cyan*iblack + black)<1.0 ) + { + minr = cyan*iblack + black; + } + + if( (magenta*iblack + black)<1.0 ) + { + ming = magenta*iblack + black; + } + + if( (yellow*iblack + black)<1.0 ) + { + minb = yellow*iblack + black; + } + + red = 1.0 - minr; + green = 1.0 - ming; + blue = 1.0 - minb; + + this->plot_blend(x,y,opacity, red, green, blue); + +} + +//int version +void pngwriter::plotCMYK_blend(int x, int y, double opacity, int cyan, int magenta, int yellow, int black) +{ + this->plotCMYK_blend( x, y, + opacity, + ((double) cyan)/65535.0, + ((double) magenta)/65535.0, + ((double) yellow)/65535.0, + ((double) black)/65535.0 + ); +} + +void pngwriter::laplacian(double k, double offset) +{ + + // Create image storage. + pngwriter temp(width_,height_,0,"temp"); + + double red, green, blue; + + for(int y = 1; y <= height_; y++) + { + for(int x = 1; x <= width_; x++) + { + red = + 8.0*this->dread(x,y,1) - + ( this->dread(x+1, y-1, 1) + + this->dread(x, y-1, 1) + + this->dread(x-1, y-1, 1) + + this->dread(x-1, y, 1) + + this->dread(x+1, y, 1) + + this->dread(x+1, y+1, 1) + + this->dread(x, y+1, 1) + + this->dread(x-1, y+1, 1) ); + + green = + 8.0*this->dread(x,y,2) - + ( this->dread(x+1, y-1, 2) + + this->dread(x, y-1, 2) + + this->dread(x-1, y-1, 2) + + this->dread(x-1, y, 2) + + this->dread(x+1, y, 2) + + this->dread(x+1, y+1, 2) + + this->dread(x, y+1, 2) + + this->dread(x-1, y+1, 2)); + + blue = + 8.0*this->dread(x,y,3) - + ( this->dread(x+1, y-1, 3) + + this->dread(x, y-1, 3) + + this->dread(x-1, y-1, 3) + + this->dread(x-1, y, 3) + + this->dread(x+1, y, 3) + + this->dread(x+1, y+1, 3) + + this->dread(x, y+1, 3) + + this->dread(x-1, y+1, 3)); + + temp.plot(x,y,offset+k*red,offset+k*green,offset+k*blue); + + } + } + + for(int yy = 1; yy <= height_; yy++) + { + for(int xx = 1; xx <= width_; xx++) + { + this->plot(xx,yy, temp.read(xx,yy,1), temp.read(xx,yy,2), temp.read(xx,yy,3)); + } + } +} + + + +// drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun +// ( , http://www.linuks.mine.nu/ ) +void pngwriter::drawtop(long x1,long y1,long x2,long y2,long x3, int red, int green, int blue) +{ + // avoid division by zero + long dy = 1; + if(y2!=y1) + dy=y2-y1; + + // This swaps x2 and x3 + // if(x2>x3) x2^=x3^=x2^=x3; + if(x2>x3) + { + x2^=x3; + x3^=x2; + x2^=x3; + } + + long posl = x1*256; + long posr = posl; + + long cl=((x2-x1)*256)/dy; + long cr=((x3-x1)*256)/dy; + + for(int y=y1; y<=y2; y++) + { + this->line(posl/256, y, posr/256, y, red, green, blue); + posl+=cl; + posr+=cr; + } +} + +// drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun +// ( , http://www.linuks.mine.nu/ ) +void pngwriter::drawbottom(long x1,long y1,long x2,long x3,long y3, int red, int green, int blue) +{ + //Swap x1 and x2 + //if(x1>x2) x2^=x1^=x2^=x1; + if(x1>x2) + { + x2^=x1; + x1^=x2; + x2^=x1; + } + + long posl=x1*256; + long posr=x2*256; + + long cl=((x3-x1)*256)/(y3-y1); + long cr=((x3-x2)*256)/(y3-y1); + + for(int y=y1; y<=y3; y++) + { + this->line(posl/256, y, posr/256, y, red, green, blue); + + posl+=cl; + posr+=cr; + } +} + +// drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun +// ( , http://www.linuks.mine.nu/ ) +void pngwriter::filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, int red, int green, int blue) +{ + if((x1==x2 && x2==x3) || (y1==y2 && y2==y3)) return; + + if(y2drawtop(x1, y1, x2, y2, x3, red, green, blue); + } + else + { + if(y1==y3 || y1==y2) + { + this->drawbottom(x1, y1, x2, x3, y3, red, green, blue); + } + else + { + int new_x = x1 + (int)((double)(y2-y1)*(double)(x3-x1)/(double)(y3-y1)); + this->drawtop(x1, y1, new_x, y2, x2, red, green, blue); + this->drawbottom(x2, y2, new_x, x3, y3, red, green, blue); + } + } + +} + +//Double (bug found by Dave Wilks. Was: (int) red*65535, should have been (int) (red*65535). +void pngwriter::filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, double red, double green, double blue) +{ + this->filledtriangle(x1, y1, x2, y2, x3, y3, (int) (red*65535), (int) (green*65535), (int) (blue*65535)); +} + +//Blend, double. (bug found by Dave Wilks. Was: (int) red*65535, should have been (int) (red*65535). +void pngwriter::filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, double red, double green, double blue) +{ + this->filledtriangle_blend( x1, y1, x2, y2, x3, y3, opacity, (int) (red*65535), (int) (green*65535), (int) (blue*65535)); +} + +//Blend, int +void pngwriter::filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, int red, int green, int blue) +{ + if((x1==x2 && x2==x3) || (y1==y2 && y2==y3)) return; + + /*if(y2drawtop_blend(x1, y1, x2, y2, x3, opacity, red, green, blue); + } + else + { + if(y1==y3 || y1==y2) + { + this->drawbottom_blend(x1, y1, x2, x3, y3, opacity, red, green, blue); + } + else + { + int new_x = x1 + (int)((double)(y2-y1)*(double)(x3-x1)/(double)(y3-y1)); + this->drawtop_blend(x1, y1, new_x, y2, x2, opacity, red, green, blue); + this->drawbottom_blend(x2, y2, new_x, x3, y3, opacity, red, green, blue); + } + } + +} + +//Blend, int +void pngwriter::drawbottom_blend(long x1,long y1,long x2,long x3,long y3, double opacity, int red, int green, int blue) +{ + //Swap x1 and x2 + if(x1>x2) + { + x2^=x1; + x1^=x2; + x2^=x1; + } + + long posl=x1*256; + long posr=x2*256; + + long cl=((x3-x1)*256)/(y3-y1); + long cr=((x3-x2)*256)/(y3-y1); + + for(int y=y1; yline_blend(posl/256, y, posr/256, y, opacity, red, green, blue); + + posl+=cl; + posr+=cr; + } + +} + +//Blend, int +void pngwriter::drawtop_blend(long x1,long y1,long x2,long y2,long x3, double opacity, int red, int green, int blue) +{ + // This swaps x2 and x3 + if(x2>x3) + { + x2^=x3; + x3^=x2; + x2^=x3; +} + + long posl = x1*256; + long posr = posl; + + long cl=((x2-x1)*256)/(y2-y1); + long cr=((x3-x1)*256)/(y2-y1); + + for(int y=y1; yline_blend(posl/256, y, posr/256, y, opacity, red, green, blue); + posl+=cl; + posr+=cr; + } + +} + +void pngwriter::triangle(int x1, int y1, int x2, int y2, int x3, int y3, int red, int green, int blue) +{ + this->line(x1, y1, x2, y2, red, green, blue); + this->line(x2, y2, x3, y3, red, green, blue); + this->line(x3, y3, x1, y1, red, green, blue); +} + +void pngwriter::triangle(int x1, int y1, int x2, int y2, int x3, int y3, double red, double green, double blue) +{ + this->line(x1, y1, x2, y2, int(65535*red), int(65535*green), int(65535*blue)); + this->line(x2, y2, x3, y3, int(65535*red), int(65535*green), int(65535*blue)); + this->line(x3, y3, x1, y1, int(65535*red), int(65535*green), int(65535*blue)); +} + + +void pngwriter::arrow( int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue) +{ + + this->line(x1, y1, x2, y2, red, green, blue); + // double th = 3.141592653589793 + (head_angle)*3.141592653589793/180.0; //degrees + double th = 3.141592653589793 + head_angle; + double costh = cos(th); + double sinth = sin(th); + double t1, t2, r; + t1 = ((x2-x1)*costh - (y2-y1)*sinth); + t2 = ((x2-x1)*sinth + (y2-y1)*costh); + r = sqrt(t1*t1 + t2*t2); + + double advancex = size*t1/r; + double advancey = size*t2/r; + this->line(x2, y2, int(x2 + advancex), int(y2 + advancey), red, green, blue); + t1 = (x2-x1)*costh + (y2-y1)*sinth; + t2 = (y2-y1)*costh - (x2-x1)*sinth; + + advancex = size*t1/r; + advancey = size*t2/r; + this->line(x2, y2, int(x2 + advancex), int(y2 + advancey), red, green, blue); +} + +void pngwriter::filledarrow( int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue) +{ + int p1x, p2x, p3x, p1y, p2y, p3y; + + this->line(x1, y1, x2, y2, red, green, blue); + double th = 3.141592653589793 + head_angle; + double costh = cos(th); + double sinth = sin(th); + double t11, t12, t21, t22, r1, r2; + t11 = ((x2-x1)*costh - (y2-y1)*sinth); + t21 = ((x2-x1)*sinth + (y2-y1)*costh); + t12 = (x2-x1)*costh + (y2-y1)*sinth; + t22 = (y2-y1)*costh - (x2-x1)*sinth; + + r1 = sqrt(t11*t11 + t21*t21); + r2 = sqrt(t12*t12 + t22*t22); + + double advancex1 = size*t11/r1; + double advancey1 = size*t21/r1; + double advancex2 = size*t12/r2; + double advancey2 = size*t22/r2; + + p1x = x2; + p1y = y2; + + p2x = int(x2 + advancex1); + p2y = int(y2 + advancey1); + + p3x = int(x2 + advancex2); + p3y = int(y2 + advancey2); + + + this->filledtriangle( p1x, p1y, p2x, p2y, p3x, p3y, red, green, blue); + +} + +void pngwriter::arrow( int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue) +{ + this->arrow( x1, y1, x2, y2, size, head_angle, (double (red))/65535.0, (double (green))/65535.0, (double (blue))/65535.0 ); +} + +void pngwriter::filledarrow( int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue) +{ + this->filledarrow( x1, y1, x2, y2, size, head_angle, (double (red))/65535.0, (double (green))/65535.0, (double (blue))/65535.0 ); +} + + +void pngwriter::cross( int x, int y, int xwidth, int yheight, int red, int green, int blue) +{ + this->line(int(x - xwidth/2.0), y, int(x + xwidth/2.0), y, red, green, blue); + this->line(x, int(y - yheight/2.0), x, int(y + yheight/2.0), red, green, blue); +} + +void pngwriter::maltesecross( int x, int y, int xwidth, int yheight, int x_bar_height, int y_bar_width, int red, int green, int blue) +{ + this->line(int(x - xwidth/2.0), y, int(x + xwidth/2.0), y, red, green, blue); + this->line(x, int(y - yheight/2.0), x, int(y + yheight/2.0), red, green, blue); + // Bars on ends of vertical line + this->line(int(x - y_bar_width/2.0), int(y + yheight/2.0), int(x + y_bar_width/2.0), int(y + yheight/2.0), red, green, blue); + this->line(int(x - y_bar_width/2.0), int(y - yheight/2.0), int(x + y_bar_width/2.0), int(y - yheight/2.0), red, green, blue); + // Bars on ends of horizontal line. + this->line(int(x - xwidth/2.0), int(y - x_bar_height/2.0), int(x - xwidth/2.0), int(y + x_bar_height/2.0), red, green, blue); + this->line(int(x + xwidth/2.0), int(y - x_bar_height/2.0), int(x + xwidth/2.0), int(y + x_bar_height/2.0), red, green, blue); +} + +void pngwriter::cross( int x, int y, int xwidth, int yheight, double red, double green, double blue) +{ + this->cross( x, y, xwidth, yheight, int(65535*red), int(65535*green), int(65535*blue)); +} + +void pngwriter::maltesecross( int x, int y, int xwidth, int yheight, int x_bar_height, int y_bar_width, double red, double green, double blue) +{ + this->maltesecross( x, y, xwidth, yheight, x_bar_height, y_bar_width, int(65535*red), int(65535*green), int(65535*blue)); +} + + +void pngwriter::filleddiamond( int x, int y, int width, int height, int red, int green, int blue) +{ + this->filledtriangle( int(x - width/2.0), y, x, y, x, int(y + height/2.0), red, green, blue); + this->filledtriangle( int(x + width/2.0), y, x, y, x, int(y + height/2.0), red, green, blue); + this->filledtriangle( int(x - width/2.0), y, x, y, x, int(y - height/2.0), red, green, blue); + this->filledtriangle( int(x + width/2.0), y, x, y, x, int(y - height/2.0), red, green, blue); +} + +void pngwriter::diamond( int x, int y, int width, int height, int red, int green, int blue) +{ + this->line( int(x - width/2.0), y, x, int(y + height/2.0), red, green, blue); + this->line( int(x + width/2.0), y, x, int(y + height/2.0), red, green, blue); + this->line( int(x - width/2.0), y, x, int(y - height/2.0), red, green, blue); + this->line( int(x + width/2.0), y, x, int(y - height/2.0), red, green, blue); +} + + +void pngwriter::filleddiamond( int x, int y, int width, int height, double red, double green, double blue) +{ + this->filleddiamond( x, y, width, height, int(red*65535), int(green*65535), int(blue*65535) ); +} + +void pngwriter::diamond( int x, int y, int width, int height, double red, double green, double blue) +{ + this->diamond( x, y, width, height, int(red*65535), int(green*65535), int(blue*65535) ); +} diff --git a/tests/Tester/Tester/pngwriter.h b/tests/Tester/Tester/pngwriter.h new file mode 100755 index 000000000..63c5d71f7 --- /dev/null +++ b/tests/Tester/Tester/pngwriter.h @@ -0,0 +1,739 @@ +/********************************* PNGwriter ********************************** +* +* Website: Main: http://pngwriter.sourceforge.net/ +* GitHub.com: https://github.com/pngwriter/pngwriter +* Sourceforge.net: http://sourceforge.net/projects/pngwriter/ +* +* +* Author: Paul Blackburn https://github.com/individual61 +* Axel Huebl https://github.com/ax3l +* +* Email: individual61@users.sourceforge.net +* +* Version: 0.7.0 (January 2018) +* +* Description: Library that allows plotting a 48 bit +* PNG image pixel by pixel, which can +* then be opened with a graphics program. +* +* License: GNU General Public License +* (C) 2002-2018 Paul Blackburn +* (C) 2013-2018 Axel Huebl +* +******************************************************************************/ + + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * */ + +#ifndef PNGWRITER_H +#define PNGWRITER_H 1 + +#define PNGWRITER_VERSION_MAJOR 0 +#define PNGWRITER_VERSION_MINOR 7 +#define PNGWRITER_VERSION_PATCH 0 + +/* deprecated old define in style MAJOR.MINORREVISION, e.g., 0.56 for 0.5.6 */ +#define PNGWRITER_PASTE(x,y,z) x ## . ## y ## z +#define PNGWRITER_EVALUATE(x,y,z) PNGWRITER_PASTE(x,y,z) +#define PNGWRITER_VERSION PNGWRITER_EVALUATE(PNGWRITER_VERSION_MAJOR, PNGWRITER_VERSION_MINOR, PNGWRITER_VERSION_PATCH) + +/* includes */ +#include +#if (PNG_LIBPNG_VER >= 10500) +#include +#endif + +// REMEMBER TO ADD -DNO_FREETYPE TO YOUR COMPILATION FLAGS IF PNGwriter WAS +// COMPILED WITHOUT FREETYPE SUPPORT!!! +// +// must be included before FreeType headers. +#ifndef NO_FREETYPE +#include +#include FT_FREETYPE_H +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +#define PNG_BYTES_TO_CHECK (4) +#define PNGWRITER_DEFAULT_COMPRESSION (6) + +class pngwriter +{ + private: + + std::string filename_; + std::string textauthor_; + std::string textdescription_; + std::string texttitle_; + std::string textsoftware_; + + + + int height_; + int width_; + int backgroundcolour_; + int bit_depth_; + int colortype_; + int compressionlevel_; + bool transformation_; // Required by Mikkel's patch + + unsigned char * * graph_; + double filegamma_; + double screengamma_; + void circle_aux(int xcentre, int ycentre, int x, int y, int red, int green, int blue); + void circle_aux_blend(int xcentre, int ycentre, int x, int y, double opacity, int red, int green, int blue); + int static check_if_png(char *file_name, FILE **fp); + int static read_png_info(FILE *fp, png_structp *png_ptr, png_infop *info_ptr); + int static read_png_image(FILE *fp, png_structp png_ptr, png_infop info_ptr, + png_bytepp *image, png_uint_32& width, png_uint_32& height); + void flood_fill_internal( int xstart, int ystart, double start_red, double start_green, double start_blue, double fill_red, double fill_green, double fill_blue); + void flood_fill_internal_blend( int xstart, int ystart, double opacity, double start_red, double start_green, double start_blue, double fill_red, double fill_green, double fill_blue); + +#ifndef NO_FREETYPE + void my_draw_bitmap( FT_Bitmap * bitmap, int x, int y, double red, double green, double blue); + void my_draw_bitmap_blend( FT_Bitmap * bitmap, int x, int y,double opacity, double red, double green, double blue); +#endif + + /* The algorithms HSVtoRGB and RGBtoHSV were found at http://www.cs.rit.edu/~ncs/ + * which is a page that belongs to Nan C. Schaller, though + * these algorithms appear to be the work of Eugene Vishnevsky. + * */ + void static HSVtoRGB( double *r, double *g, double *b, double h, double s, double v ); + void static RGBtoHSV( float r, float g, float b, float *h, float *s, float *v ); + + /* drwatop(), drawbottom() and filledtriangle() were contributed by Gurkan Sengun + * ( , http://www.linuks.mine.nu/ ) + * */ + void drawtop(long x1,long y1,long x2,long y2,long x3, int red, int green, int blue); + void drawbottom(long x1,long y1,long x2,long x3,long y3, int red, int green, int blue); + void drawbottom_blend(long x1,long y1,long x2,long x3,long y3, double opacity, int red, int green, int blue); + void drawtop_blend(long x1,long y1,long x2,long y2,long x3, double opacity, int red, int green, int blue); + + /* free up memory of member variables and reset internal pointers to NULL */ + void deleteMembers(); + public: + + /* General Notes + * It is important to remember that all functions that accept an argument of type "const char *" will also + * accept "char *", this is done so you can have a changing filename (to make many PNG images in series + * with a different name, for example), and to allow you to use string type objects which can be easily + * turned into const char * (if theString is an object of type string, then it can be used as a const char * + * by saying theString.c_str()). + * It is also important to remember that whenever a function has a colour coeffiecient as its argument, + * that argument can be either an int from 0 to 65535 or a double from 0.0 to 1.0. + * It is important to make sure that you are calling the function with the type that you want. + * Remember that 1 is an int, while 1.0 is a double, and will thus determine what version of the function + * will be used. Similarly, do not make the mistake of calling for example plot(x, y, 0.0, 0.0, 65535), + * because + * there is no plot(int, int, double, double, int). + * Also, please note that plot() and read() (and the functions that use them internally) + * are protected against entering, for example, a colour coefficient that is over 65535 + * or over 1.0. Similarly, they are protected against negative coefficients. read() will return 0 + * when called outside the image range. This is actually useful as zero-padding should you need it. + * */ + + /* Compilation + * A typical compilation would look like this: + * + * g++ my_program.cc -o my_program freetype-config --cflags \ + * -I/usr/local/include -L/usr/local/lib -lpng -lpngwriter -lz -lfreetype + * + * If you did not compile PNGwriter with FreeType support, then remove the + * FreeType-related flags and add -DNO_FREETYPE above. + * */ + + /* Constructor + * The constructor requires the width and the height of the image, the background colour for the + * image and the filename of the file (a pointer or simple "myfile.png"). The background colour + * can only be initialized to a shade of grey (once the object has been created you can do whatever + * you want, though), because generally one wants either a white (65535 or 1.0) or a black (0 or 0.0) + * background to start with. + * The default constructor creates a PNGwriter instance that is 250x250, white background, + * and filename "out.png". + * Tip: The filename can be given as easily as: + * pngwriter mypng(300, 300, 0.0, "myfile.png"); + * Tip: If you are going to create a PNGwriter instance for reading in a file that already exists, + * then width and height can be 1 pixel, and the size will be automatically adjusted once you use + * readfromfile(). + * */ + pngwriter(); + pngwriter(const pngwriter &rhs); + pngwriter(int width, int height, int backgroundcolour, char * filename); + pngwriter(int width, int height, double backgroundcolour, char * filename); + pngwriter(int width, int height, int backgroundcolour, const char * filename); + pngwriter(int width, int height, double backgroundcolour, const char * filename); + + /* Destructor + * */ + ~pngwriter(); + + /* Assignment Operator + * */ + pngwriter & operator = (const pngwriter & rhs); + + /* Plot + * With this function a pixel at coordinates (x, y) can be set to the desired colour. + * The pixels are numbered starting from (1, 1) and go to (width, height). + * As with most functions in PNGwriter, it has been overloaded to accept either int arguments + * for the colour coefficients, or those of type double. If they are of type int, + * they go from 0 to 65535. If they are of type double, they go from 0.0 to 1.0. + * Tip: To plot using red, then specify plot(x, y, 1.0, 0.0, 0.0). To make pink, + * just add a constant value to all three coefficients, like this: + * plot(x, y, 1.0, 0.4, 0.4). + * Tip: If nothing is being plotted to your PNG file, make sure that you remember + * to close() the instance before your program is finished, and that the x and y position + * is actually within the bounds of your image. If either is not, then PNGwriter will + * not complain-- it is up to you to check for this! + * Tip: If you try to plot with a colour coefficient out of range, a maximum or minimum + * coefficient will be assumed, according to the given coefficient. For example, attempting + * to plot plot(x, y, 1.0,-0.2,3.7) will set the green coefficient to 0 and the red coefficient + * to 1.0. + * */ + void plot(int x, int y, int red, int green, int blue); + void plot(int x, int y, double red, double green, double blue); + + /* Plot HSV + * With this function a pixel at coordinates (x, y) can be set to the desired colour, + * but with the colour coefficients given in the Hue, Saturation, Value colourspace. + * This has the advantage that one can determine the colour that will be plotted with + * only one parameter, the Hue. The colour coefficients must go from 0 to 65535 and + * be of type int, or be of type double and go from 0.0 to 1.0. + * */ + void plotHSV(int x, int y, double hue, double saturation, double value); + void plotHSV(int x, int y, int hue, int saturation, int value); + + /* Read + * With this function we find out what colour the pixel (x, y) is. If "colour" is 1, + * it will return the red coefficient, if it is set to 2, the green one, and if + * it set to 3, the blue colour coefficient will be returned, + * and this returned value will be of type int and be between 0 and 65535. + * Note that if you call read() on a pixel outside the image range, the value returned + * will be 0. + * */ + int read(int x, int y, int colour) const; + + /* Read, Average + * Same as the above, only that the average of the three colour coefficients is returned. + */ + int read(int x, int y) const; + + /* dRead + * With this function we find out what colour the pixel (x, y) is. If "colour" is 1, + * it will return the red coefficient, if it is set to 2, the green one, and if + * it set to 3, the blue colour coefficient will be returned, + * and this returned value will be of type double and be between 0.0 and 1.0. + * Note that if you call dread() outside the image range, the value returned will be 0.0 + * */ + double dread(int x, int y, int colour) const; + + /* dRead, Average + * Same as the above, only that the average of the three colour coefficients is returned. + */ + double dread(int x, int y) const; + + /* Read HSV + * With this function we find out what colour the pixel (x, y) is, but in the Hue, + * Saturation, Value colourspace. If "colour" is 1, + * it will return the Hue coefficient, if it is set to 2, the Saturation one, and if + * it set to 3, the Value colour coefficient will be returned, and this returned + * value will be of type int and be between 0 and 65535. Important: If you attempt + * to read the Hue of a pixel that is a shade of grey, the value returned will be + * nonsensical or even NaN. This is just the way the RGB -> HSV algorithm works: + * the Hue of grey is not defined. You might want to check whether the pixel + * you are reading is grey before attempting a readHSV(). + * Tip: This is especially useful for categorizing sections of the image according + * to their colour. + * */ + int readHSV(int x, int y, int colour) const; + + /* dRead HSV + * With this function we find out what colour the pixel (x, y) is, but in the Hue, + * Saturation, Value colourspace. If "colour" is 1, + * it will return the Hue coefficient, if it is set to 2, the Saturation one, and if + * it set to 3, the Value colour coefficient will be returned, + * and this returned value will be of type double and be between 0.0 and 1.0. + * */ + double dreadHSV(int x, int y, int colour) const; + + /* Clear + * The whole image is set to black. + * */ + void clear(void); + + /* Close + * Close the instance of the class, and write the image to disk. + * Tip: If you do not call this function before your program ends, no image + * will be written to disk. + * */ + void close(void); + + /* Rename + * To rename the file once an instance of pngwriter has been created. + * Useful for assigning names to files based upon their content. + * Tip: This is as easy as calling pngwriter_rename("newname.png") + * If the argument is a long unsigned int, for example 77, the filename will be changed to + * 0000000077.png + * Tip: Use this to create sequences of images for movie generation. + * */ + void pngwriter_rename(char * newname); + void pngwriter_rename(const char * newname); + void pngwriter_rename(long unsigned int index); + + /* Figures + * These functions draw basic shapes. Available in both int and double versions. + * The line functions use the fast Bresenham algorithm. Despite the name, + * the square functions draw rectangles. The circle functions use a fast + * integer math algorithm. The filled circle functions make use of sqrt(). + * */ + void line(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue); + void line(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue); + + void triangle(int x1, int y1, int x2, int y2, int x3, int y3, int red, int green, int blue); + void triangle(int x1, int y1, int x2, int y2, int x3, int y3, double red, double green, double blue); + + void square(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue); + void square(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue); + + void filledsquare(int xfrom, int yfrom, int xto, int yto, int red, int green,int blue); + void filledsquare(int xfrom, int yfrom, int xto, int yto, double red, double green,double blue); + + void circle(int xcentre, int ycentre, int radius, int red, int green, int blue); + void circle(int xcentre, int ycentre, int radius, double red, double green, double blue); + + void filledcircle(int xcentre, int ycentre, int radius, int red, int green, int blue); + void filledcircle(int xcentre, int ycentre, int radius, double red, double green, double blue); + + + /* Read From File + * Open the existing PNG image, and copy it into this instance of the class. It is important to mention + * that PNG variants are supported. Very generally speaking, most PNG files can now be read (as of version 0.5.4), + * but if they have an alpha channel it will be completely stripped. If the PNG file uses GIF-style transparency + * (where one colour is chosen to be transparent), PNGwriter will not read the image properly, but will not + * complain. Also, if any ancillary chunks are included in the PNG file (chroma, filter, etc.), it will render + * with a slightly different tonality. For the vast majority of PNGs, this should not be an issue. Note: + * If you read an 8-bit PNG, the internal representation of that instance of PNGwriter will be 8-bit (PNG + * files of less than 8 bits will be upscaled to 8 bits). To convert it to 16-bit, just loop over all pixels, + * reading them into a new instance of PNGwriter. New instances of PNGwriter are 16-bit by default. + * */ + + void readfromfile(char * name); + void readfromfile(const char * name); + + /* Get Height + * When you open a PNG with readfromfile() you can find out its height with this function. + * */ + int getheight(void) const; + + /* Get Width + * When you open a PNG with readfromfile() you can find out its width with this function. + * */ + int getwidth(void) const; + + /* Set Compression Level + * Set the compression level that will be used for the image. -1 is to use the default, + * 0 is none, 9 is best compression. + * Remember that this will affect how long it will take to close() the image. A value of 2 or 3 + * is good enough for regular use, but for storage or transmission you might want to take the time + * to set it at 9. + * */ + void setcompressionlevel(int level); + + /* Get Bit Depth + * When you open a PNG with readfromfile() you can find out its bit depth with this function. + * Mostly for troubleshooting uses. + * */ + int getbitdepth(void) const; + + /* Get Colour Type + * When you open a PNG with readfromfile() you can find out its colour type (libpng categorizes + * different styles of image data with this number). + * Mostly for troubleshooting uses. + * */ + int getcolortype(void) const; + + /* Set Gamma Coeff + * Set the image's gamma (file gamma) coefficient. This is experimental, but use it if your image's colours seem too bright + * or too dark. The default value of 0.5 should be fine. The standard disclaimer about Mac and PC gamma + * settings applies. + * */ + void setgamma(double gamma); + + + /* Get Gamma Coeff + * Get the image's gamma coefficient. This is experimental. + * */ + double getgamma(void) const; + + /* Bezier Curve + * (After Frenchman Pierre Bezier from Regie Renault) + * A collection of formulae for describing curved lines + * and surfaces, first used in 1972 to model automobile surfaces. + * (from the The Free On-line Dictionary of Computing) + * See http://www.moshplant.com/direct-or/bezier/ for one of many + * available descriptions of bezier curves. + * There are four points used to define the curve: the two endpoints + * of the curve are called the anchor points, while the other points, + * which define the actual curvature, are called handles or control points. + * Moving the handles lets you modify the shape of the curve. + * */ + + void bezier( int startPtX, int startPtY, + int startControlX, int startControlY, + int endPtX, int endPtY, + int endControlX, int endControlY, + double red, double green, double blue); + + void bezier( int startPtX, int startPtY, + int startControlX, int startControlY, + int endPtX, int endPtY, + int endControlX, int endControlY, + int red, int green, int blue); + + /* Set Text + * Sets the text information in the PNG header. If it is not called, the default is used. + */ + void settext(char * title, char * author, char * description, char * software); + void settext(const char * title, const char * author, const char * description, const char * software); + + + /* Version Number + * Returns the PNGwriter version number. + */ + static double version(void); + + /* Write PNG + * Writes the PNG image to disk. You can still change the PNGwriter instance after this. + * Tip: This is exactly the same as close(), but easier to remember. + * Tip: To make a sequence of images using only one instance of PNGwriter, alter the image, change its name, + * write_png(), then alter the image, change its name, write_png(), etc. + */ + void write_png(void); + + /* Plot Text + * Uses the Freetype2 library to set text in the image. face_path is the file path to a + * TrueType font file (.ttf) (FreeType2 can also handle other types). fontsize specifices the approximate + * height of the rendered font in pixels. x_start and y_start specify the placement of the + * lower, left corner of the text string. angle is the text angle in radians. text is the text to be rendered. + * The colour coordinates can be doubles from 0.0 to 1.0 or ints from 0 to 65535. + * Tip: PNGwriter installs a few fonts in /usr/local/share/pngwriter/fonts to get you started. + * Tip: Remember to add -DNO_FREETYPE to your compilation flags if PNGwriter was compiled without FreeType support. + * */ + void plot_text(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double red, double green, double blue); + void plot_text(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, int red, int green, int blue); + + + /* Plot UTF-8 Text + * Same as the above, but the text to be plotted is encoded in UTF-8. Why would you want this? To be able to plot + * all characters available in a large TrueType font, for example: for rendering Japenese, Chinese and other + * languages not restricted to the standard 128 character ASCII space. + * Tip: The quickest way to get a string into UTF-8 is to write it in an adequate text editor, and save it as a file + * in UTF-8 encoding, which can then be read in in binary mode. + * */ + void plot_text_utf8(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double red, double green, double blue); + void plot_text_utf8(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, int red, int green, int blue); + + + /* Bilinear Interpolation of Image + * Given a floating point coordinate (x from 0.0 to width, y from 0.0 to height), + * this function will return the interpolated colour intensity specified by + * colour (where red = 1, green = 2, blue = 3). + * bilinear_interpolate_read() returns an int from 0 to 65535, and + * bilinear_interpolate_dread() returns a double from 0.0 to 1.0. + * Tip: Especially useful for enlarging an image. + * */ + int bilinear_interpolation_read(double x, double y, int colour) const; + double bilinear_interpolation_dread(double x, double y, int colour) const; + + /* Plot Blend + * Plots the colour given by red, green blue, but blended with the existing pixel + * value at that position. opacity is a double that goes from 0.0 to 1.0. + * 0.0 will not change the pixel at all, and 1.0 will plot the given colour. + * Anything in between will be a blend of both pixel levels. Please note: This is neither + * alpha channel nor PNG transparency chunk support. This merely blends the plotted pixels. + * */ + + void plot_blend(int x, int y, double opacity, int red, int green, int blue); + void plot_blend(int x, int y, double opacity, double red, double green, double blue); + + + /* Invert + * Inverts the image in RGB colourspace. + * */ + void invert(void); + + /* Resize Image + * Resizes the PNGwriter instance. Note: All image data is set to black (this is + * a resizing, not a scaling, of the image). + * */ + void resize(int width, int height); + + /* Boundary Fill + * All pixels adjacent to the start pixel will be filled with the fill colour, until the boundary colour is encountered. + * For example, calling boundary_fill() with the boundary colour set to red, on a pixel somewhere inside a red circle, + * will fill the entire circle with the desired fill colour. If, on the other hand, the circle is not the boundary colour, + * the rest of the image will be filled. + * The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535. + * */ + void boundary_fill(int xstart, int ystart, double boundary_red,double boundary_green,double boundary_blue,double fill_red, double fill_green, double fill_blue) ; + void boundary_fill(int xstart, int ystart, int boundary_red,int boundary_green,int boundary_blue,int fill_red, int fill_green, int fill_blue) ; + + /* Flood Fill + * All pixels adjacent to the start pixel will be filled with the fill colour, if they are the same colour as the + * start pixel. For example, calling flood_fill() somewhere in the interior of a solid blue rectangle will colour + * the entire rectangle the fill colour. The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535. + * */ + void flood_fill(int xstart, int ystart, double fill_red, double fill_green, double fill_blue) ; + void flood_fill(int xstart, int ystart, int fill_red, int fill_green, int fill_blue) ; + + /* Polygon + * This function takes an array of integer values containing the coordinates of the vertexes of a polygon. + * Note that if you want a closed polygon, you must repeat the first point's coordinates for the last point. + * It also requires the number of points contained in the array. For example, if you wish to plot a triangle, + * the array will contain 6 elements, and the number of points is 3. Be very careful about this; if you specify the wrong number + * of points, your program will either segfault or produce points at nonsensical coordinates. + * The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535. + * */ + void polygon(int * points, int number_of_points, double red, double green, double blue); + void polygon(int * points, int number_of_points, int red, int green, int blue); + + /* Plot CMYK + * Plot a point in the Cyan, Magenta, Yellow, Black colourspace. Please note that this colourspace is + * lossy, i.e. it cannot reproduce all colours on screen that RGB can. The difference, however, is + * barely noticeable. The algorithm used is a standard one. The colour components are either + * doubles from 0.0 to 1.0 or ints from 0 to 65535. + * */ + void plotCMYK(int x, int y, double cyan, double magenta, double yellow, double black); + void plotCMYK(int x, int y, int cyan, int magenta, int yellow, int black); + + /* Read CMYK, Double version + * Get a pixel in the Cyan, Magenta, Yellow, Black colourspace. if 'colour' is 1, the Cyan component will be returned + * as a double from 0.0 to 1.0. If 'colour is 2, the Magenta colour component will be returned, and so on, up to 4. + * */ + double dreadCMYK(int x, int y, int colour) const; + + /* Read CMYK + * Same as the above, but the colour components returned are an int from 0 to 65535. + * */ + int readCMYK(int x, int y, int colour) const; + + /* Scale Proportional + * Scale the image using bilinear interpolation. If k is greater than 1.0, the image will be enlarged. + * If k is less than 1.0, the image will be shrunk. Negative or null values of k are not allowed. + * The image will be resized and the previous content will be replaced by the scaled image. + * Tip: use getheight() and getwidth() to find out the new width and height of the scaled image. + * Note: After scaling, all images will have a bit depth of 16, even if the original image had + * a bit depth of 8. + * */ + void scale_k(double k); + + /* Scale Non-Proportional + * Scale the image using bilinear interpolation, with different horizontal and vertical scale factors. + * */ + void scale_kxky(double kx, double ky); + + /* Scale To Target Width and Height + * Scale the image in such a way as to meet the target width and height. + * Tip: if you want to keep the image proportional, scale_k() might be more appropriate. + * */ + void scale_wh(int finalwidth, int finalheight); + + + /* Blended Functions + * All these functions are identical to their non-blended types. They take an extra argument, opacity, which is + * a double from 0.0 to 1.0 and represents how much of the original pixel value is retained when plotting the + * new pixel. In other words, if opacity is 0.7, then after plotting, the new pixel will be 30% of the + * original colour the pixel was, and 70% of the new colour, whatever that may be. As usual, each function + * is available in int or double versions. Please note: This is neither alpha channel nor PNG transparency chunk support. This merely blends the plotted pixels. + * */ + + // Start Blended Functions + + void plotHSV_blend(int x, int y, double opacity, double hue, double saturation, double value); + void plotHSV_blend(int x, int y, double opacity, int hue, int saturation, int value); + + void line_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue); + void line_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue); + + void square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue); + void square_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue); + + void filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, int red, int green,int blue); + void filledsquare_blend(int xfrom, int yfrom, int xto, int yto, double opacity, double red, double green,double blue); + + void circle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue); + void circle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue); + + void filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, int red, int green, int blue); + void filledcircle_blend(int xcentre, int ycentre, int radius, double opacity, double red, double green, double blue); + + void bezier_blend( int startPtX, int startPtY, + int startControlX, int startControlY, + int endPtX, int endPtY, + int endControlX, int endControlY, + double opacity, + double red, double green, double blue); + + void bezier_blend( int startPtX, int startPtY, + int startControlX, int startControlY, + int endPtX, int endPtY, + int endControlX, int endControlY, + double opacity, + int red, int green, int blue); + + void plot_text_blend(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, double red, double green, double blue); + void plot_text_blend(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, int red, int green, int blue); + + void plot_text_utf8_blend(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, double red, double green, double blue); + void plot_text_utf8_blend(char * face_path, int fontsize, int x_start, int y_start, double angle, char * text, double opacity, int red, int green, int blue); + + void boundary_fill_blend(int xstart, int ystart, double opacity, double boundary_red,double boundary_green,double boundary_blue,double fill_red, double fill_green, double fill_blue) ; + void boundary_fill_blend(int xstart, int ystart, double opacity, int boundary_red,int boundary_green,int boundary_blue,int fill_red, int fill_green, int fill_blue) ; + + void flood_fill_blend(int xstart, int ystart, double opacity, double fill_red, double fill_green, double fill_blue) ; + void flood_fill_blend(int xstart, int ystart, double opacity, int fill_red, int fill_green, int fill_blue) ; + + void polygon_blend(int * points, int number_of_points, double opacity, double red, double green, double blue); + void polygon_blend(int * points, int number_of_points, double opacity, int red, int green, int blue); + + void plotCMYK_blend(int x, int y, double opacity, double cyan, double magenta, double yellow, double black); + void plotCMYK_blend(int x, int y, double opacity, int cyan, int magenta, int yellow, int black); + + // End of Blended Functions + + /* Laplacian + * This function applies a discrete laplacian to the image, multiplied by a constant factor. + * The kernel used in this case is: + * 1.0 1.0 1.0 + * 1.0 -8.0 1.0 + * 1.0 1.0 1.0 + * Basically, this works as an edge detector. The current pixel is assigned the sum of all neighbouring + * pixels, multiplied by the corresponding kernel element. For example, imagine a pixel and its 8 neighbours: + * 1.0 1.0 0.0 0.0 + * 1.0 ->1.0<- 0.0 0.0 + * 1.0 1.0 0.0 0.0 + * This represents a border between white and black, black is on the right. Applying the laplacian to + * the pixel specified above pixel gives: + * 1.0*1.0 + 1.0*1.0 + 0.0*1.0 + + * 1.0*1.0 + 1.0*-8.0 + 0.0*1.0 + + * 1.0*1.0 + 1.0*1.0 + 0.0*1.0 = -3.0 + * Applying this to the pixel to the right of the pixel considered previously, we get a sum of 3.0. + * That is, after passing over an edge, we get a high value for the pixel adjacent to the edge. Since + * PNGwriter limits the colour components if they are off-scale, and the result of the laplacian + * may be negative, a scale factor and an offset value are included. This might be useful for + * keeping things within range or for bringing out more detail in the edge detection. The + * final pixel value will be given by: + * final value = laplacian(original pixel)*k + offset + * Tip: Try a value of 1.0 for k to start with, and then experiment with other values. + * */ + void laplacian(double k, double offset); + + /* Filled Triangle + * Draws the triangle specified by the three pairs of points in the colour specified + * by the colour coefficients. The colour components are either doubles from 0.0 to + * 1.0 or ints from 0 to 65535. + * */ + void filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, int red, int green, int blue); + void filledtriangle(int x1,int y1,int x2,int y2,int x3,int y3, double red, double green, double blue); + + /* Filled Triangle, Blended + * Draws the triangle specified by the three pairs of points in the colour specified + * by the colour coefficients, and blended with the background. See the description for Blended Functions. + * The colour components are either doubles from 0.0 to 1.0 or ints from 0 to 65535. + * */ + void filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, int red, int green, int blue); + void filledtriangle_blend(int x1,int y1,int x2,int y2,int x3,int y3, double opacity, double red, double green, double blue); + + /* Arrow, Filled Arrow + * Plots an arrow from (x1, y1) to (x2, y2) with the arrowhead at the second point, given the size in pixels + * and the angle in radians of the arrowhead. The plotted arrow consists of one main line, and two smaller + * lines originating from the second point. Filled Arrow plots the same, but the arrowhead is a solid triangle. + * Tip: An angle of 10 to 30 degrees looks OK. + * */ + + void arrow( int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue); + void arrow( int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue); + + void filledarrow( int x1,int y1,int x2,int y2,int size, double head_angle, double red, double green, double blue); + void filledarrow( int x1,int y1,int x2,int y2,int size, double head_angle, int red, int green, int blue); + + /* Cross, Maltese Cross + * Plots a simple cross at x, y, with the specified height and width, and in the specified colour. + * Maltese cross plots a cross, as before, but adds bars at the end of each arm of the cross. + * The size of these bars is specified with x_bar_height and y_bar_width. + * The cross will look something like this: + * + * ----- <-- ( y_bar_width) + * | + * | + * |-------| <-- ( x_bar_height ) + * | + * | + * ----- + * */ + + void cross( int x, int y, int xwidth, int yheight, double red, double green, double blue); + void cross( int x, int y, int xwidth, int yheight, int red, int green, int blue); + + void maltesecross( int x, int y, int xwidth, int yheight, int x_bar_height, int y_bar_width, double red, double green, double blue); + void maltesecross( int x, int y, int xwidth, int yheight, int x_bar_height, int y_bar_width, int red, int green, int blue); + + /* Diamond and filled diamond + * Plots a diamond shape, given the x, y position, the width and height, and the colour. + * Filled diamond plots a filled diamond. + * */ + + void filleddiamond( int x, int y, int width, int height, int red, int green, int blue); + void diamond(int x, int y, int width, int height, int red, int green, int blue); + + void filleddiamond( int x, int y, int width, int height, double red, double green, double blue); + void diamond(int x, int y, int width, int height, double red, double green, double blue); + + /* Get Text Width, Get Text Width UTF8 + * Returns the approximate width, in pixels, of the specified *unrotated* text. It is calculated by adding + * each letter's width and kerning value (as specified in the TTF file). Note that this will not + * give the position of the farthest pixel, but it will give a pretty good idea of what area the + * text will occupy. Tip: The text, when plotted unrotated, will fit approximately in a box with its lower left corner at + * (x_start, y_start) and upper right at (x_start + width, y_start + size), where width is given by get_text_width() + * and size is the specified size of the text to be plotted. Tip: Text plotted at position + * (x_start, y_start), rotated with a given 'angle', and of a given 'size' + * whose width is 'width', will fit approximately inside a rectangle whose corners are at + * 1 (x_start, y_start) + * 2 (x_start + width*cos(angle), y_start + width*sin(angle)) + * 3 (x_start + width*cos(angle) - size*sin(angle), y_start + width*sin(angle) + size*cos(angle)) + * 4 (x_start - size*sin(angle), y_start + size*cos(angle)) + * */ + + int static get_text_width(char * face_path, int fontsize, char * text); + + int static get_text_width_utf8(char * face_path, int fontsize, char * text); + + +}; + + +#endif diff --git a/tests/Tester/Tester/quic_provider.h b/tests/Tester/Tester/quic_provider.h new file mode 100755 index 000000000..0cb08cdb8 --- /dev/null +++ b/tests/Tester/Tester/quic_provider.h @@ -0,0 +1,86 @@ +#ifndef __QUIC_PROVIDER +#define __QUIC_PROVIDER + +#include +#include +#include + +#include "mitlsffi.h" + +// mitlsffi defines quic_secret: the type of exported secrets + +// Calling convention: all functions in this library return +// 1 on success and 0 on failure. + +// Unlike secrets, AEAD keys are kept abstract; they hide the +// negotiated encryption algorithm and its expanded key materials; +// they are allocated internally by quic_crypto_derive_key and must be +// explicitly freed. Each key is used only for encrypting or only for +// decrypting. + +typedef struct quic_key quic_key; + +// Helper function to determine the buffer overhead for encryption. +#define quic_crypto_tag_length(pKey) 16 + +// Main functions for QUIC AEAD keying. Encryption keys for AEAD are +// derived as follows (see quic-tls#4 section 5) +// +// (1) get exporter secret from TLS (optional early, then main secret) +// +// (2) derive encryption secrets from the exporter secrets: +// +// early_secret, "EXPORTER-QUIC 0-RTT Secret" +// main_secret, "EXPORTER-QUIC client 1-RTT Secret" +// main_secret, "EXPORTER-QUIC server 1-RTT Secret" +// +// (3) derive an encryption key from each encryption secret. +// +// (4) optionally derive the next encryption secret from the current +// ones (to be use for later rekeying, resuming from step 3) +// +// (5) erase all secrets used for derivation. + +// con_id must be 8 bytes, salt must be the version-specific 20 bytes initial salt +int MITLS_CALLCONV quic_derive_handshake_secrets(/*out*/ quic_secret *client_hs, /*out*/ quic_secret *server_hs, const unsigned char *con_id, size_t con_id_len, const unsigned char *salt, size_t salt_len); +int MITLS_CALLCONV quic_crypto_tls_derive_secret(/*out*/ quic_secret *derived, const quic_secret *secret, const char *label); +int MITLS_CALLCONV quic_crypto_derive_key(/*out*/quic_key **key, const quic_secret *secret); + +// Low-level function to create an AEAD instance from a raw key and IV +// Note that iv is always 12 bytes and key is 16 bytes for AES-128 +// and 32 bytes for AES-256 and ChaCha20. +// Using quic_crypto_derive_key is recommended over quic_crypto_create +// The created key must be freed with quic_crypto_free_key +int MITLS_CALLCONV quic_crypto_create(quic_key **key, mitls_aead alg, const unsigned char *raw_key, const unsigned char *iv); + +// AEAD-encrypts plain with additional data ad, using counter sn, +// writing plain_len + 16 bytes to the output cipher. The input and +// output buffer must not overlap. +// +// The packet number sn is internally combined with the static IV +// to form the 12-byte AEAD IV +// +// NB: NOT DOT ENCRYPT TWICE WITH THE SAME KEY AND SN +// +int MITLS_CALLCONV quic_crypto_encrypt(quic_key *key, /*out*/ unsigned char *cipher, uint64_t sn, const unsigned char *ad, uint32_t ad_len, const unsigned char *plain, uint32_t plain_len); + +// AEAD-decrypts cipher and authenticate additional data ad, using +// counter; when successful, writes cipher_len - 16 bytes to the +// output plain. The input and output buffers must not overlap. +// +int MITLS_CALLCONV quic_crypto_decrypt(quic_key *key, /*out*/ unsigned char *plain, uint64_t sn, const unsigned char *ad, uint32_t ad_len, const unsigned char *cipher, uint32_t cipher_len); + +// Keys allocated by quic_crypto_derive_key and quic_crypto_create must be freed +int MITLS_CALLCONV quic_crypto_free_key(quic_key *key); + +// Auxiliary crypto functions, possibly useful elsewhere in QUIC. +// Hash, HMAC and HKDF only suport SHA256, SHA384, and SHA512 +int MITLS_CALLCONV quic_crypto_hash(quic_hash a, /*out*/ unsigned char *hash, const unsigned char *data, size_t data_len); +int MITLS_CALLCONV quic_crypto_hmac(quic_hash a, /*out*/ unsigned char *mac, const unsigned char *key, uint32_t key_len, const unsigned char *data, uint32_t data_len); + +int MITLS_CALLCONV quic_crypto_hkdf_extract(quic_hash a, /*out*/ unsigned char *prk, const unsigned char *salt, uint32_t salt_len, const unsigned char *ikm, uint32_t ikm_len); +int MITLS_CALLCONV quic_crypto_hkdf_expand(quic_hash a, /*out*/ unsigned char *okm, uint32_t okm_len, const unsigned char *prk, uint32_t prk_len, const unsigned char *info, uint32_t info_len); +int MITLS_CALLCONV quic_crypto_hkdf_quic_label(quic_hash a, /*out*/ unsigned char *info, /*out*/ size_t *info_len, const char *label, uint16_t key_len); +int MITLS_CALLCONV quic_crypto_hkdf_tls_label(quic_hash a, /*out*/ unsigned char *info, /*out*/ size_t *info_len, const char *label); + +#endif /* end of include guard: */ diff --git a/tests/Tester/Tester/stdafx.cpp b/tests/Tester/Tester/stdafx.cpp new file mode 100755 index 000000000..5f506ded8 Binary files /dev/null and b/tests/Tester/Tester/stdafx.cpp differ diff --git a/tests/Tester/Tester/stdafx.h b/tests/Tester/Tester/stdafx.h new file mode 100755 index 000000000..94d4ed877 Binary files /dev/null and b/tests/Tester/Tester/stdafx.h differ diff --git a/tests/Tester/Tester/targetver.h b/tests/Tester/Tester/targetver.h new file mode 100755 index 000000000..567cd346e Binary files /dev/null and b/tests/Tester/Tester/targetver.h differ diff --git a/tests/Tester/makefile.vs b/tests/Tester/makefile.vs new file mode 100644 index 000000000..c974a41a7 --- /dev/null +++ b/tests/Tester/makefile.vs @@ -0,0 +1,45 @@ +CCOPTS = /nologo /O2 /Gy /GF /Gw /GA /MD /Zi -I. + +COMPILE = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.15.26726\bin\Hostx64\x64\cl.exe" + +LINK = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.15.26726\bin\Hostx64\x64\link.exe" + +WINLIBDIR = "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17134.0\um\x64" + +all: tester.exe + +# 'dir /b *.c' then replace "^(.*)" by " \1 \\" +SOURCES = \ + Tester/InteropTester.cpp \ + Tester/Component.cpp \ + Tester/SimpleServer.cpp \ + Tester/Tester.cpp \ + Tester/TLSTester.cpp \ + Tester/stdafx.cpp \ + Tester/mitlsstub.cpp \ + Tester/pngwriter.cpp + +LIBRARIES = \ + Tester/libmipki.lib \ + Tester/libmitls.lib \ + Tester/libquiccrypto.lib + +OBJECTS = \ + Tester/x64/Debug/InteropTester.obj \ + Tester/x64/Debug/Component.obj \ + Tester/x64/Debug/SimpleServer.obj \ + Tester/x64/Debug/Tester.obj \ + Tester/x64/Debug/TLSTester.obj \ + Tester/x64/Debug/stdafx.obj \ + Tester/x64/Debug/mitlsstub.obj \ + Tester/x64/Debug/pngwriter.obj + +tester.exe: + $(LINK) -i$(OBJECTS) /MACHINE:X64 /nologo /dll /debug:full /out:tester.exe $(LIBRARIES) $(WINLIBDIR)\ntdll.lib + +.cpp.obj:: + $(COMPILE) $(CCOPTS) -c $< + +clean: + -del *.exe + -del *.obj