source upload
This commit is contained in:
26
contrib/fundamentals/TLS/flcTLS.inc
Normal file
26
contrib/fundamentals/TLS/flcTLS.inc
Normal file
@@ -0,0 +1,26 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLS.inc }
|
||||
{ Description: TLS library defines }
|
||||
{ Last updated: 2020/05/19 }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE ..\flcInclude.inc}
|
||||
|
||||
{$DEFINE TLS}
|
||||
|
||||
{$IFDEF DEBUG}
|
||||
{$DEFINE TLS_DEBUG}
|
||||
{$ENDIF}
|
||||
|
||||
{$IFDEF DEBUG}
|
||||
{$IFDEF TEST}
|
||||
{$DEFINE TLS_TEST}
|
||||
{.DEFINE TLS_TEST_NO_RANDOM_HELLO}
|
||||
{$ENDIF}
|
||||
{$ENDIF}
|
||||
|
||||
{$DEFINE TLS_ZLIB_DISABLE}
|
||||
|
210
contrib/fundamentals/TLS/flcTLSAlert.pas
Normal file
210
contrib/fundamentals/TLS/flcTLSAlert.pas
Normal file
@@ -0,0 +1,210 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSAlert.pas }
|
||||
{ File version: 5.04 }
|
||||
{ Description: TLS alert protocol }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2010/11/30 0.02 Additional alerts from RFC 4366. }
|
||||
{ 2018/07/17 5.03 Revised for Fundamentals 5. }
|
||||
{ 2020/05/09 5.04 TLS 1.3 alerts. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSAlert;
|
||||
|
||||
interface
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Alert Protocol }
|
||||
{ }
|
||||
type
|
||||
TTLSAlertLevel = (
|
||||
tlsalWarning = 1,
|
||||
tlsalFatal = 2,
|
||||
tlsalAlertLevelMax = 255
|
||||
);
|
||||
|
||||
TTLSAlertDescription = (
|
||||
tlsadClose_notify = 0, // SSL 3
|
||||
tlsadUnexpected_message = 10, // SSL 3
|
||||
tlsadBad_record_mac = 20, // SLL 3
|
||||
tlsadDecryption_failed = 21, // TLS 1.0 / TLS 1.2 reserved
|
||||
tlsadRecord_overflow = 22, // TLS 1.0
|
||||
tlsadDecompression_failure = 30, // SLL 3
|
||||
tlsadHandshake_failure = 40, // SLL 3
|
||||
tlsadNo_certificate = 41, // SLL 3 / TLS 1.1 reserved / TLS 1.2 reserved
|
||||
tlsadBad_certificate = 42, // SLL 3
|
||||
tlsadUnsupported_certificate = 43, // SLL 3
|
||||
tlsadCertificate_revoked = 44, // SLL 3
|
||||
tlsadCertificate_expired = 45, // SLL 3
|
||||
tlsadCertificate_unknown = 46, // SLL 3
|
||||
tlsadIllegal_parameter = 47, // SLL 3
|
||||
tlsadUnknown_ca = 48, // TLS 1.0
|
||||
tlsadAccess_denied = 49, // TLS 1.0
|
||||
tlsadDecode_error = 50, // TLS 1.0
|
||||
tlsadDecrypt_error = 51, // TLS 1.0
|
||||
tlsadExport_restriction = 60, // TLS 1.0 / TLS 1.1 reserved / TLS 1.2 reserved
|
||||
tlsadProtocol_version = 70, // TLS 1.0
|
||||
tlsadInsufficient_security = 71, // TLS 1.0
|
||||
tlsadInternal_error = 80, // TLS 1.0
|
||||
tlsadUser_canceled = 90, // TLS 1.0
|
||||
tlsadNo_renegotiation = 100, // TLS 1.0
|
||||
tlsadMissing_extension = 109, // TLS 1.3
|
||||
tlsadUnsupported_extention = 110, // TLS 1.2
|
||||
tlsadCertificate_unobtainable = 111, // RFC 4366
|
||||
tlsadUnrecognized_name = 112, // RFC 4366 / TLS 1.3
|
||||
tlsadBad_certificate_status_response = 113, // RFC 4366 / TLS 1.3
|
||||
tlsadBad_certificate_hash_value = 114, // RFC 4366
|
||||
tlsadUnknown_psk_identity = 115, // TLS 1.3
|
||||
tlsadCertificate_required = 116, // TLS 1.3
|
||||
tlsadNo_application_protocol = 120, { TLS 1.3 }
|
||||
tlsadMax = 255
|
||||
);
|
||||
|
||||
function TLSAlertLevelToStr(const Level: TTLSAlertLevel): String;
|
||||
function TLSAlertDescriptionToStr(const Description: TTLSAlertDescription): String;
|
||||
|
||||
type
|
||||
TTLSAlert = packed record
|
||||
level : TTLSAlertLevel;
|
||||
description : TTLSAlertDescription;
|
||||
end;
|
||||
PTLSAlert = ^TTLSAlert;
|
||||
|
||||
const
|
||||
TLSAlertSize = Sizeof(TTLSAlert);
|
||||
|
||||
procedure InitTLSAlert(var Alert: TTLSAlert;
|
||||
const Level: TTLSAlertLevel; const Description: TTLSAlertDescription);
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test cases }
|
||||
{ }
|
||||
{$IFDEF TLS_TEST}
|
||||
procedure Test;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{ System }
|
||||
SysUtils;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Alert Protocol }
|
||||
{ }
|
||||
function TLSAlertLevelToStr(const Level: TTLSAlertLevel): String;
|
||||
begin
|
||||
case Level of
|
||||
tlsalWarning : Result := 'Warning';
|
||||
tlsalFatal : Result := 'Fatal';
|
||||
else
|
||||
Result := '[Level#' + IntToStr(Ord(Level)) + ']';
|
||||
end;
|
||||
end;
|
||||
|
||||
function TLSAlertDescriptionToStr(const Description: TTLSAlertDescription): String;
|
||||
begin
|
||||
case Description of
|
||||
tlsadClose_notify : Result := 'Close notify';
|
||||
tlsadUnexpected_message : Result := 'Unexpected message';
|
||||
tlsadBad_record_mac : Result := 'Bad record MAC';
|
||||
tlsadDecryption_failed : Result := 'Decryption failed';
|
||||
tlsadRecord_overflow : Result := 'Record overflow';
|
||||
tlsadDecompression_failure : Result := 'Decompression failure';
|
||||
tlsadHandshake_failure : Result := 'Handshake failure';
|
||||
tlsadNo_certificate : Result := 'No certificate';
|
||||
tlsadBad_certificate : Result := 'Bad certificate';
|
||||
tlsadUnsupported_certificate : Result := 'Unsupported certificate';
|
||||
tlsadCertificate_revoked : Result := 'Certificate revoked';
|
||||
tlsadCertificate_expired : Result := 'Certificate expired';
|
||||
tlsadCertificate_unknown : Result := 'Certficiate unknown';
|
||||
tlsadIllegal_parameter : Result := 'Illegal parameter';
|
||||
tlsadUnknown_ca : Result := 'Unknown CA';
|
||||
tlsadAccess_denied : Result := 'Access denied';
|
||||
tlsadDecode_error : Result := 'Decode error';
|
||||
tlsadDecrypt_error : Result := 'Decrypt error';
|
||||
tlsadExport_restriction : Result := 'Export restriction';
|
||||
tlsadProtocol_version : Result := 'Protocol version';
|
||||
tlsadInsufficient_security : Result := 'Insufficient security';
|
||||
tlsadInternal_error : Result := 'Internal error';
|
||||
tlsadUser_canceled : Result := 'User cancelled';
|
||||
tlsadNo_renegotiation : Result := 'No renegotiation';
|
||||
tlsadMissing_extension : Result := 'Missing extention';
|
||||
tlsadUnsupported_extention : Result := 'Unsuported extention';
|
||||
tlsadCertificate_unobtainable : Result := 'Certificate unobtainable';
|
||||
tlsadUnrecognized_name : Result := 'Unrecognised name';
|
||||
tlsadBad_certificate_status_response : Result := 'Bad certificate status response';
|
||||
tlsadBad_certificate_hash_value : Result := 'Bad certificate hash value';
|
||||
tlsadUnknown_psk_identity : Result := 'Unknown PSK identitiy';
|
||||
tlsadCertificate_required : Result := 'Certificate required';
|
||||
tlsadNo_application_protocol : Result := 'No application protocol';
|
||||
else
|
||||
Result := '[Alert#' + IntToStr(Ord(Description)) + ']';
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure InitTLSAlert(
|
||||
var Alert: TTLSAlert;
|
||||
const Level: TTLSAlertLevel;
|
||||
const Description: TTLSAlertDescription);
|
||||
begin
|
||||
Alert.level := Level;
|
||||
Alert.description := Description;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test }
|
||||
{ }
|
||||
{$IFDEF TLS_TEST}
|
||||
{$ASSERTIONS ON}
|
||||
procedure Test;
|
||||
begin
|
||||
Assert(TLSAlertSize = 2);
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
|
448
contrib/fundamentals/TLS/flcTLSAlgorithmTypes.pas
Normal file
448
contrib/fundamentals/TLS/flcTLSAlgorithmTypes.pas
Normal file
@@ -0,0 +1,448 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSAlgorithmTypes.pas }
|
||||
{ File version: 5.03 }
|
||||
{ Description: TLS Algorithm Types }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2020/05/09 5.02 Create flcTLSAlgorithmTypes unit from flcTLSUtils unit. }
|
||||
{ 2020/05/11 5.03 NamedCurve and ECPointFormat enumerations. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSAlgorithmTypes;
|
||||
|
||||
interface
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ CompressionMethod }
|
||||
{ }
|
||||
type
|
||||
TTLSCompressionMethod = (
|
||||
tlscmNull = 0, // Enumerations from handshake
|
||||
tlscmDeflate = 1,
|
||||
tlscmMax = 255
|
||||
);
|
||||
PTLSCompressionMethod = ^TTLSCompressionMethod;
|
||||
|
||||
TTLSCompressionMethods = set of TTLSCompressionMethod;
|
||||
|
||||
const
|
||||
TLSCompressionMethodSize = Sizeof(TTLSCompressionMethod);
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ HashAlgorithm }
|
||||
{ }
|
||||
type
|
||||
TTLSHashAlgorithm = (
|
||||
tlshaNone = 0, // Enumerations from handshake
|
||||
tlshaMD5 = 1,
|
||||
tlshaSHA1 = 2,
|
||||
tlshaSHA224 = 3,
|
||||
tlshaSHA256 = 4,
|
||||
tlshaSHA384 = 5,
|
||||
tlshaSHA512 = 6,
|
||||
tlshaMax = 255
|
||||
);
|
||||
TTLSHashAlgorithms = set of TTLSHashAlgorithm;
|
||||
|
||||
function HashAlgorithmToStr(const A: TTLSHashAlgorithm): String;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ SignatureAlgorithm }
|
||||
{ }
|
||||
type
|
||||
TTLSSignatureAlgorithm = (
|
||||
tlssaAnonymous = 0, // Enumerations from handshake
|
||||
tlssaRSA = 1,
|
||||
tlssaDSA = 2,
|
||||
tlssaECDSA = 3,
|
||||
tlssaMax = 255
|
||||
);
|
||||
TTLSSignatureAlgorithms = set of TTLSSignatureAlgorithm;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ SignatureAndHashAlgorithm }
|
||||
{ }
|
||||
type
|
||||
TTLSSignatureAndHashAlgorithm = packed record
|
||||
|
||||
Hash : TTLSHashAlgorithm;
|
||||
|
||||
Signature : TTLSSignatureAlgorithm;
|
||||
end;
|
||||
|
||||
PTLSSignatureAndHashAlgorithm = ^TTLSSignatureAndHashAlgorithm;
|
||||
|
||||
TTLSSignatureAndHashAlgorithmArray = array of TTLSSignatureAndHashAlgorithm;
|
||||
|
||||
|
||||
const
|
||||
|
||||
TLSSignatureAndHashAlgorithmSize = SizeOf(TTLSSignatureAndHashAlgorithm);
|
||||
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ MACAlgorithm }
|
||||
{ Used in TLS record. }
|
||||
{ }
|
||||
type
|
||||
TTLSMACAlgorithm = (
|
||||
tlsmaNone,
|
||||
tlsmaNULL,
|
||||
tlsmaHMAC_MD5,
|
||||
tlsmaHMAC_SHA1,
|
||||
tlsmaHMAC_SHA256,
|
||||
tlsmaHMAC_SHA384,
|
||||
tlsmaHMAC_SHA512
|
||||
|
||||
);
|
||||
|
||||
|
||||
TTLSMacAlgorithmInfo = record
|
||||
|
||||
Name : RawByteString;
|
||||
|
||||
DigestSize : Integer;
|
||||
|
||||
Supported : Boolean; // Not used
|
||||
|
||||
end;
|
||||
|
||||
PTLSMacAlgorithmInfo = ^TTLSMacAlgorithmInfo;
|
||||
|
||||
|
||||
const
|
||||
|
||||
TLSMACAlgorithmInfo : array[TTLSMACAlgorithm] of TTLSMacAlgorithmInfo = (
|
||||
|
||||
( // None
|
||||
|
||||
Name : '';
|
||||
|
||||
DigestSize : 0;
|
||||
|
||||
Supported : False;
|
||||
|
||||
),
|
||||
|
||||
( // NULL
|
||||
|
||||
Name : 'NULL';
|
||||
|
||||
DigestSize : 0;
|
||||
|
||||
Supported : True;
|
||||
|
||||
),
|
||||
|
||||
( // HMAC_MD5
|
||||
|
||||
Name : 'HMAC-MD5';
|
||||
|
||||
DigestSize : 16;
|
||||
|
||||
Supported : True;
|
||||
|
||||
),
|
||||
|
||||
( // HMAC_SHA1
|
||||
|
||||
Name : 'HMAC-SHA1';
|
||||
|
||||
DigestSize : 20;
|
||||
|
||||
Supported : True;
|
||||
|
||||
),
|
||||
|
||||
( // HMAC_SHA256
|
||||
|
||||
Name : 'HMAC-SHA256';
|
||||
|
||||
DigestSize : 32;
|
||||
|
||||
Supported : True;
|
||||
|
||||
),
|
||||
|
||||
( // HMAC_SHA384
|
||||
|
||||
Name : 'HMAC-SHA384';
|
||||
|
||||
DigestSize : 48;
|
||||
|
||||
Supported : False;
|
||||
|
||||
),
|
||||
|
||||
( // HMAC_SHA512
|
||||
|
||||
Name : 'HMAC-SHA512';
|
||||
|
||||
DigestSize : 64;
|
||||
|
||||
Supported : True;
|
||||
|
||||
)
|
||||
|
||||
);
|
||||
|
||||
|
||||
const
|
||||
|
||||
TLS_MAC_MAXDIGESTSIZE = 64;
|
||||
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ KeyExchangeAlgorithm }
|
||||
{ }
|
||||
type
|
||||
TTLSKeyExchangeAlgorithm = (
|
||||
tlskeaNone,
|
||||
tlskeaNULL,
|
||||
tlskeaDHE_DSS,
|
||||
tlskeaDHE_RSA,
|
||||
tlskeaDH_Anon,
|
||||
tlskeaRSA,
|
||||
tlskeaDH_DSS,
|
||||
tlskeaDH_RSA,
|
||||
tlskeaECDHE_ECDSA,
|
||||
tlskeaECDH_ECDSA,
|
||||
tlskeaECDHE_RSA,
|
||||
tlskeaECDH_RSA
|
||||
);
|
||||
|
||||
TTLSKeyExchangeMethod = (
|
||||
tlskemNone,
|
||||
tlskemNULL,
|
||||
tlskemDHE,
|
||||
tlskemDH_Anon,
|
||||
tlskemRSA,
|
||||
tlskemDH,
|
||||
tlskemPSK,
|
||||
tlskemECDH,
|
||||
tlskemECDHE
|
||||
);
|
||||
|
||||
TTLSKeyExchangeAuthenticationType = (
|
||||
tlskeatNone,
|
||||
tlskeatAnon,
|
||||
tlskeatDSS,
|
||||
tlskeatRSA,
|
||||
tlskeatPSK,
|
||||
tlskeatECDSA
|
||||
);
|
||||
|
||||
TTLSKeyExchangeAlgorithmInfo = record
|
||||
Name : RawByteString;
|
||||
Method : TTLSKeyExchangeMethod;
|
||||
KeyType : TTLSKeyExchangeAuthenticationType;
|
||||
Supported : Boolean; // Not used
|
||||
end;
|
||||
PTLSKeyExchangeAlgorithmInfo = ^TTLSKeyExchangeAlgorithmInfo;
|
||||
|
||||
const
|
||||
TLSKeyExchangeAlgorithmInfo: array[TTLSKeyExchangeAlgorithm] of TTLSKeyExchangeAlgorithmInfo = (
|
||||
( // None
|
||||
Name : '';
|
||||
Method : tlskemNone;
|
||||
KeyType : tlskeatNone;
|
||||
Supported : False;
|
||||
),
|
||||
( // NULL
|
||||
Name : 'NULL';
|
||||
Method : tlskemNULL;
|
||||
KeyType : tlskeatNone;
|
||||
Supported : True;
|
||||
),
|
||||
( // DHE_DSS
|
||||
Name : 'DHE_DSS';
|
||||
Method : tlskemDHE;
|
||||
KeyType : tlskeatDSS;
|
||||
Supported : False;
|
||||
),
|
||||
( // DHE_RSA
|
||||
Name : 'DHE_RSA';
|
||||
Method : tlskemDHE;
|
||||
KeyType : tlskeatRSA;
|
||||
Supported : False;
|
||||
),
|
||||
( // DH_Anon
|
||||
Name : 'DH_Anon';
|
||||
Method : tlskemDH_Anon;
|
||||
KeyType : tlskeatNone;
|
||||
Supported : False;
|
||||
),
|
||||
( // RSA
|
||||
Name : 'RSA';
|
||||
Method : tlskemRSA;
|
||||
KeyType : tlskeatRSA;
|
||||
Supported : True;
|
||||
),
|
||||
( // DH_DSS
|
||||
Name : 'DH_DSS';
|
||||
Method : tlskemDH;
|
||||
KeyType : tlskeatDSS;
|
||||
Supported : False;
|
||||
),
|
||||
( // DH_RSA
|
||||
Name : 'DH_RSA';
|
||||
Method : tlskemDH;
|
||||
KeyType : tlskeatRSA;
|
||||
Supported : False;
|
||||
),
|
||||
( // ECDHE_ECDSA
|
||||
Name : 'ECDHE_ECDSA';
|
||||
Method : tlskemECDHE;
|
||||
KeyType : tlskeatECDSA;
|
||||
Supported : False;
|
||||
),
|
||||
( // ECDH_ECDSA
|
||||
Name : 'ECDH_ECDSA';
|
||||
Method : tlskemECDH;
|
||||
KeyType : tlskeatECDSA;
|
||||
Supported : False;
|
||||
),
|
||||
( // ECDHE_RSA
|
||||
Name : 'ECDHE_RSA';
|
||||
Method : tlskemECDHE;
|
||||
KeyType : tlskeatRSA;
|
||||
Supported : False;
|
||||
),
|
||||
( // ECDH_RSA
|
||||
Name : 'ECDH_RSA';
|
||||
Method : tlskemECDH;
|
||||
KeyType : tlskeatRSA;
|
||||
Supported : False;
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ClientCertificateType }
|
||||
{ }
|
||||
type
|
||||
TTLSClientCertificateType = (
|
||||
tlscctRsa_sign = 1,
|
||||
tlscctDss_sign = 2,
|
||||
tlscctRsa_fixed_dh = 3,
|
||||
tlscctDss_fixed_dh = 4,
|
||||
tlscctRsa_ephemeral_dh_RESERVED = 5,
|
||||
tlscctDss_ephemeral_dh_RESERVED = 6,
|
||||
tlscctFortezza_dms_RESERVED = 20,
|
||||
tlscctEcdsa_sign = 64, // RFC 8422
|
||||
tlscctRsa_fixed_ecdh = 65, // RFC 4492, deprecated in RFC 8422
|
||||
tlscctEcdsa_fixed_ecdh = 66, // RFC 4492, deprecated in RFC 8422
|
||||
tlscctMax = 255
|
||||
);
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ECCurveType }
|
||||
{ }
|
||||
type
|
||||
TTLSECCurveType = (
|
||||
tlsectExplicit_prime = 1, // RFC 4492, deprecated in RFC 8422
|
||||
tlsectExplicit_char2 = 2, // RFC 4492, deprecated in RFC 8422
|
||||
tlsectNamed_curve = 3, // RFC 4492
|
||||
tlsectMax = 255
|
||||
);
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ NamedCurve }
|
||||
{ }
|
||||
type
|
||||
TTLSNamedCurve = (
|
||||
tlsncSect163k1 = 1, // deprecated in RFC 8422
|
||||
tlsncSect163r1 = 2, // deprecated in RFC 8422
|
||||
tlsncSect163r2 = 3, // deprecated in RFC 8422
|
||||
tlsncSect193r1 = 4, // deprecated in RFC 8422
|
||||
tlsncSect193r2 = 5, // deprecated in RFC 8422
|
||||
tlsncSect233k1 = 6, // deprecated in RFC 8422
|
||||
tlsncSect233r1 = 7, // deprecated in RFC 8422
|
||||
tlsncSect239k1 = 8, // deprecated in RFC 8422
|
||||
tlsncSect283k1 = 9, // deprecated in RFC 8422
|
||||
tlsncSect283r1 = 10, // deprecated in RFC 8422
|
||||
tlsncSect409k1 = 11, // deprecated in RFC 8422
|
||||
tlsncSect409r1 = 12, // deprecated in RFC 8422
|
||||
tlsncSect571k1 = 13, // deprecated in RFC 8422
|
||||
tlsncSect571r1 = 14, // deprecated in RFC 8422
|
||||
tlsncSecp160k1 = 15, // deprecated in RFC 8422
|
||||
tlsncSecp160r1 = 16, // deprecated in RFC 8422
|
||||
tlsncSecp160r2 = 17, // deprecated in RFC 8422
|
||||
tlsncSecp192k1 = 18, // deprecated in RFC 8422
|
||||
tlsncSecp192r1 = 19, // deprecated in RFC 8422
|
||||
tlsncSecp224k1 = 20, // deprecated in RFC 8422
|
||||
tlsncSecp224r1 = 21, // deprecated in RFC 8422
|
||||
tlsncSecp256k1 = 22, // deprecated in RFC 8422
|
||||
tlsncSecp256r1 = 23,
|
||||
tlsncSecp384r1 = 24,
|
||||
tlsncSecp521r1 = 25,
|
||||
tlsncX25519 = 29, // RFC 8422
|
||||
tlsncX448 = 30, // RFC 8422
|
||||
tlsncArbitrary_explicit_prime_curves = $FF01, // deprecated in RFC 8422
|
||||
tlsncArbitrary_explicit_char2_curves = $FF02, // deprecated in RFC 8422
|
||||
tlsncMax = $FFFF
|
||||
);
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ECPointFormat }
|
||||
{ }
|
||||
type
|
||||
TTLSECPointFormat = (
|
||||
tlsepfUncompressed = 0,
|
||||
tlsepfAnsiX962_compressed_prime = 1,
|
||||
tlsepfAnsiX962_compressed_char2 = 2,
|
||||
tlsepfMax = 255
|
||||
);
|
414
contrib/fundamentals/TLS/flcTLSBuffer.pas
Normal file
414
contrib/fundamentals/TLS/flcTLSBuffer.pas
Normal file
@@ -0,0 +1,414 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSBuffer.pas }
|
||||
{ File version: 5.02 }
|
||||
{ Description: TLS buffer }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2010/11/26 0.01 Initial development. }
|
||||
{ 2018/07/17 5.02 Revised for Fundamentals 5. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSBuffer;
|
||||
|
||||
interface
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ TLS Buffer }
|
||||
{ }
|
||||
type
|
||||
TTLSBuffer = record
|
||||
Ptr : Pointer;
|
||||
Size : Integer;
|
||||
Head : Integer;
|
||||
Used : Integer;
|
||||
end;
|
||||
|
||||
procedure TLSBufferInitialise(
|
||||
var TLSBuf: TTLSBuffer;
|
||||
const TLSBufSize: Integer = -1);
|
||||
procedure TLSBufferFinalise(var TLSBuf: TTLSBuffer);
|
||||
procedure TLSBufferPack(var TLSBuf: TTLSBuffer);
|
||||
procedure TLSBufferResize(
|
||||
var TLSBuf: TTLSBuffer;
|
||||
const TLSBufSize: Integer);
|
||||
procedure TLSBufferExpand(
|
||||
var TLSBuf: TTLSBuffer;
|
||||
const Size: Integer);
|
||||
function TLSBufferAddPtr(
|
||||
var TLSBuf: TTLSBuffer;
|
||||
const Size: Integer): Pointer;
|
||||
procedure TLSBufferAddBuf(
|
||||
var TLSBuf: TTLSBuffer;
|
||||
const Buf; const Size: Integer);
|
||||
procedure TLSBufferShrink(var TLSBuf: TTLSBuffer);
|
||||
function TLSBufferPeekPtr(
|
||||
const TLSBuf: TTLSBuffer;
|
||||
var BufPtr: Pointer; const Size: Integer): Integer;
|
||||
function TLSBufferPeek(
|
||||
var TLSBuf: TTLSBuffer;
|
||||
var Buf; const Size: Integer): Integer;
|
||||
function TLSBufferRemove(
|
||||
var TLSBuf: TTLSBuffer;
|
||||
var Buf; const Size: Integer): Integer;
|
||||
function TLSBufferUsed(const TLSBuf: TTLSBuffer): Integer;
|
||||
function TLSBufferPtr(const TLSBuf: TTLSBuffer): Pointer;
|
||||
procedure TLSBufferClear(var TLSBuf: TTLSBuffer);
|
||||
function TLSBufferDiscard(
|
||||
var TLSBuf: TTLSBuffer;
|
||||
const Size: Integer): Integer;
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{ TLS }
|
||||
|
||||
flcTLSErrors;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ TLS Buffer }
|
||||
{ }
|
||||
const
|
||||
TLS_CLIENT_DEFAULTBUFFERSIZE = 16384;
|
||||
|
||||
// Initialise a TLS buffer
|
||||
procedure TLSBufferInitialise(
|
||||
var TLSBuf: TTLSBuffer;
|
||||
const TLSBufSize: Integer = -1);
|
||||
var L : Integer;
|
||||
begin
|
||||
TLSBuf.Ptr := nil;
|
||||
TLSBuf.Size := 0;
|
||||
TLSBuf.Head := 0;
|
||||
TLSBuf.Used := 0;
|
||||
L := TLSBufSize;
|
||||
if L < 0 then
|
||||
L := TLS_CLIENT_DEFAULTBUFFERSIZE;
|
||||
if L > 0 then
|
||||
GetMem(TLSBuf.Ptr, L);
|
||||
TLSBuf.Size := L;
|
||||
end;
|
||||
|
||||
// Finalise a TLS buffer
|
||||
procedure TLSBufferFinalise(var TLSBuf: TTLSBuffer);
|
||||
var P : Pointer;
|
||||
begin
|
||||
P := TLSBuf.Ptr;
|
||||
if Assigned(P) then
|
||||
begin
|
||||
TLSBuf.Ptr := nil;
|
||||
FreeMem(P);
|
||||
end;
|
||||
TLSBuf.Size := 0;
|
||||
end;
|
||||
|
||||
// Pack a TLS buffer
|
||||
// Moves data to front of buffer
|
||||
// Post: TLSBuf.Head = 0
|
||||
procedure TLSBufferPack(var TLSBuf: TTLSBuffer);
|
||||
var P, Q : PByte;
|
||||
U, H : Integer;
|
||||
begin
|
||||
H := TLSBuf.Head;
|
||||
if H <= 0 then
|
||||
exit;
|
||||
U := TLSBuf.Used;
|
||||
if U <= 0 then
|
||||
begin
|
||||
TLSBuf.Head := 0;
|
||||
exit;
|
||||
end;
|
||||
Assert(Assigned(TLSBuf.Ptr));
|
||||
P := TLSBuf.Ptr;
|
||||
Q := P;
|
||||
Inc(P, H);
|
||||
Move(P^, Q^, U);
|
||||
TLSBuf.Head := 0;
|
||||
end;
|
||||
|
||||
// Resize a TLS buffer
|
||||
// New buffer size must be large enough to hold existing data
|
||||
// Post: TLSBuf.Size = TLSBufSize
|
||||
procedure TLSBufferResize(
|
||||
var TLSBuf: TTLSBuffer;
|
||||
const TLSBufSize: Integer);
|
||||
var U, L : Integer;
|
||||
begin
|
||||
L := TLSBufSize;
|
||||
U := TLSBuf.Used;
|
||||
// treat negative TLSBufSize parameter as zero
|
||||
if L < 0 then
|
||||
L := 0;
|
||||
// check if shrinking buffer to less than used size
|
||||
if U > L then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter);
|
||||
// check if packing required to fit buffer
|
||||
if U + TLSBuf.Head > L then
|
||||
TLSBufferPack(TLSBuf);
|
||||
Assert(U + TLSBuf.Head <= L);
|
||||
// resize
|
||||
ReallocMem(TLSBuf.Ptr, L);
|
||||
TLSBuf.Size := L;
|
||||
end;
|
||||
|
||||
// Expand a TLS buffer
|
||||
// Expands the size of the buffer to at least Size
|
||||
procedure TLSBufferExpand(
|
||||
var TLSBuf: TTLSBuffer;
|
||||
const Size: Integer);
|
||||
var S, N, I : Integer;
|
||||
begin
|
||||
S := TLSBuf.Size;
|
||||
N := Size;
|
||||
// check if expansion not required
|
||||
if N <= S then
|
||||
exit;
|
||||
// scale up new size proportional to current size
|
||||
// increase by at least quarter of current size
|
||||
// this reduces the number of resizes in growing buffers
|
||||
I := S + (S div 4);
|
||||
if N < I then
|
||||
N := I;
|
||||
// resize buffer
|
||||
Assert(N >= Size);
|
||||
TLSBufferResize(TLSBuf, N);
|
||||
end;
|
||||
|
||||
// Returns a pointer to position in buffer to add new data of Size
|
||||
// Handles resizing and packing of buffer to fit new data
|
||||
function TLSBufferAddPtr(
|
||||
var TLSBuf: TTLSBuffer;
|
||||
const Size: Integer): Pointer; {$IFDEF UseInline}inline;{$ENDIF}
|
||||
var P : PByte;
|
||||
U, L : Integer;
|
||||
begin
|
||||
// return nil if nothing to add
|
||||
if Size <= 0 then
|
||||
begin
|
||||
Result := nil;
|
||||
exit;
|
||||
end;
|
||||
U := TLSBuf.Used;
|
||||
L := U + Size;
|
||||
// resize if necessary
|
||||
if L > TLSBuf.Size then
|
||||
TLSBufferExpand(TLSBuf, L);
|
||||
// pack if necessary
|
||||
if TLSBuf.Head + L > TLSBuf.Size then
|
||||
TLSBufferPack(TLSBuf);
|
||||
// buffer should now be large enough for new data
|
||||
Assert(TLSBuf.Size > 0);
|
||||
Assert(TLSBuf.Head + TLSBuf.Used + Size <= TLSBuf.Size);
|
||||
// get buffer pointer
|
||||
Assert(Assigned(TLSBuf.Ptr));
|
||||
P := TLSBuf.Ptr;
|
||||
Inc(P, TLSBuf.Head + U);
|
||||
Result := P;
|
||||
end;
|
||||
|
||||
// Adds new data from a buffer to a TLS buffer
|
||||
procedure TLSBufferAddBuf(
|
||||
var TLSBuf: TTLSBuffer;
|
||||
const Buf; const Size: Integer); {$IFDEF UseInline}inline;{$ENDIF}
|
||||
var P : PByte;
|
||||
begin
|
||||
if Size <= 0 then
|
||||
exit;
|
||||
// get buffer pointer
|
||||
P := TLSBufferAddPtr(TLSBuf, Size);
|
||||
// move user buffer to buffer
|
||||
Assert(Assigned(P));
|
||||
Move(Buf, P^, Size);
|
||||
Inc(TLSBuf.Used, Size);
|
||||
Assert(TLSBuf.Head + TLSBuf.Used <= TLSBuf.Size);
|
||||
end;
|
||||
|
||||
// Shrink the size of a TLS buffer to release all unused memory
|
||||
// Post: TLSBuf.Used = TLSBuf.Size and TLSBuf.Head = 0
|
||||
procedure TLSBufferShrink(var TLSBuf: TTLSBuffer);
|
||||
var S, U : Integer;
|
||||
begin
|
||||
S := TLSBuf.Size;
|
||||
if S <= 0 then
|
||||
exit;
|
||||
U := TLSBuf.Used;
|
||||
if U = 0 then
|
||||
begin
|
||||
TLSBufferResize(TLSBuf, 0);
|
||||
TLSBuf.Head := 0;
|
||||
exit;
|
||||
end;
|
||||
if U = S then
|
||||
exit;
|
||||
TLSBufferPack(TLSBuf); // move data to front of buffer
|
||||
TLSBufferResize(TLSBuf, U); // set size equal to used bytes
|
||||
Assert(TLSBuf.Used = TLSBuf.Size);
|
||||
end;
|
||||
|
||||
// Peek TLS buffer
|
||||
// Returns the number of bytes actually available to peek (up to requested size)
|
||||
function TLSBufferPeekPtr(
|
||||
const TLSBuf: TTLSBuffer;
|
||||
var BufPtr: Pointer; const Size: Integer): Integer; {$IFDEF UseInline}inline;{$ENDIF}
|
||||
var P : PByte;
|
||||
L : Integer;
|
||||
begin
|
||||
// handle peeking zero bytes
|
||||
if Size <= 0 then
|
||||
begin
|
||||
BufPtr := nil;
|
||||
Result := 0;
|
||||
exit;
|
||||
end;
|
||||
// handle empty buffer
|
||||
L := TLSBuf.Used;
|
||||
if L <= 0 then
|
||||
begin
|
||||
BufPtr := nil;
|
||||
Result := 0;
|
||||
exit;
|
||||
end;
|
||||
// peek from buffer
|
||||
if L > Size then
|
||||
L := Size;
|
||||
Assert(TLSBuf.Head + L <= TLSBuf.Size);
|
||||
Assert(Assigned(TLSBuf.Ptr));
|
||||
P := TLSBuf.Ptr;
|
||||
Inc(P, TLSBuf.Head);
|
||||
BufPtr := P;
|
||||
Result := L;
|
||||
end;
|
||||
|
||||
// Peek data from a TLS buffer
|
||||
// Returns the number of bytes actually available and copied into the buffer
|
||||
function TLSBufferPeek(
|
||||
var TLSBuf: TTLSBuffer;
|
||||
var Buf; const Size: Integer): Integer; {$IFDEF UseInline}inline;{$ENDIF}
|
||||
var P : Pointer;
|
||||
L : Integer;
|
||||
begin
|
||||
L := TLSBufferPeekPtr(TLSBuf, P, Size);
|
||||
Move(P^, Buf, L);
|
||||
Result := L;
|
||||
end;
|
||||
|
||||
// Remove data from a TLS buffer
|
||||
// Returns the number of bytes actually available and copied into the user buffer
|
||||
function TLSBufferRemove(
|
||||
var TLSBuf: TTLSBuffer;
|
||||
var Buf; const Size: Integer): Integer; {$IFDEF UseInline}inline;{$ENDIF}
|
||||
var L, H, U : Integer;
|
||||
begin
|
||||
// peek data from buffer
|
||||
L := TLSBufferPeek(TLSBuf, Buf, Size);
|
||||
if L = 0 then
|
||||
begin
|
||||
Result := 0;
|
||||
exit;
|
||||
end;
|
||||
// remove from buffer
|
||||
H := TLSBuf.Head;
|
||||
U := TLSBuf.Used;
|
||||
Inc(H, L);
|
||||
Dec(U, L);
|
||||
if U = 0 then
|
||||
H := 0;
|
||||
TLSBuf.Head := H;
|
||||
TLSBuf.Used := U;
|
||||
Result := L;
|
||||
end;
|
||||
|
||||
// Returns number of bytes used in TLS buffer
|
||||
function TLSBufferUsed(const TLSBuf: TTLSBuffer): Integer; {$IFDEF UseInline}inline;{$ENDIF}
|
||||
begin
|
||||
Result := TLSBuf.Used;
|
||||
end;
|
||||
|
||||
// Returns pointer to TLS buffer head
|
||||
function TLSBufferPtr(const TLSBuf: TTLSBuffer): Pointer; {$IFDEF UseInline}inline;{$ENDIF}
|
||||
var P : PByte;
|
||||
begin
|
||||
P := PByte(TLSBuf.Ptr);
|
||||
Inc(P, TLSBuf.Head);
|
||||
Result := P;
|
||||
end;
|
||||
|
||||
// Clear the data from a TLS buffer
|
||||
procedure TLSBufferClear(var TLSBuf: TTLSBuffer);
|
||||
begin
|
||||
TLSBuf.Used := 0;
|
||||
TLSBuf.Head := 0;
|
||||
end;
|
||||
|
||||
// Discard a number of bytes from the TLS buffer
|
||||
// Returns the number of bytes actually discarded from buffer
|
||||
function TLSBufferDiscard(
|
||||
var TLSBuf: TTLSBuffer;
|
||||
const Size: Integer): Integer; {$IFDEF UseInline}inline;{$ENDIF}
|
||||
var L, U : Integer;
|
||||
begin
|
||||
// handle discarding zero bytes from buffer
|
||||
L := Size;
|
||||
if L <= 0 then
|
||||
begin
|
||||
Result := 0;
|
||||
exit;
|
||||
end;
|
||||
// handle discarding the complete buffer
|
||||
U := TLSBuf.Used;
|
||||
if L >= U then
|
||||
begin
|
||||
TLSBuf.Used := 0;
|
||||
TLSBuf.Head := 0;
|
||||
Result := U;
|
||||
exit;
|
||||
end;
|
||||
// discard partial buffer
|
||||
Inc(TLSBuf.Head, L);
|
||||
Dec(U, L);
|
||||
TLSBuf.Used := U;
|
||||
Result := L;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
end.
|
||||
|
244
contrib/fundamentals/TLS/flcTLSCertificate.pas
Normal file
244
contrib/fundamentals/TLS/flcTLSCertificate.pas
Normal file
@@ -0,0 +1,244 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSCertificate.pas }
|
||||
{ File version: 5.02 }
|
||||
{ Description: TLS Certificate }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2020/05/11 5.02 Create unit flcTLSCertificate from units }
|
||||
{ flcTLSHandshake and flcTLSClient. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSCertificate;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
{ Utils }
|
||||
|
||||
flcX509Certificate,
|
||||
|
||||
{ Cipher }
|
||||
|
||||
flcCipherRSA;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Certificate }
|
||||
{ }
|
||||
type
|
||||
TTLSCertificateList = array of RawByteString;
|
||||
|
||||
procedure TLSCertificateListAppend(var List: TTLSCertificateList; const A: RawByteString);
|
||||
|
||||
function EncodeTLSCertificate(
|
||||
var Buffer; const Size: Integer;
|
||||
const CertificateList: TTLSCertificateList): Integer;
|
||||
|
||||
function DecodeTLSCertificate(
|
||||
const Buffer; const Size: Integer;
|
||||
var CertificateList: TTLSCertificateList): Integer;
|
||||
|
||||
procedure ParseX509Certificates(
|
||||
const CertificateList: TTLSCertificateList;
|
||||
var X509Certificates: TX509CertificateArray);
|
||||
|
||||
function GetCertificateRSAPublicKey(
|
||||
const X509Certificates: TX509CertificateArray;
|
||||
var RSAPublicKey: TRSAPublicKey): Boolean;
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{ Utils }
|
||||
|
||||
flcASN1,
|
||||
|
||||
{ TLS }
|
||||
|
||||
flcTLSErrors,
|
||||
flcTLSOpaqueEncoding;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Certificate }
|
||||
{ certificate_list : <0..2^24-1> ASN.1Cert; }
|
||||
{ }
|
||||
{ ASN.1Cert = <1..2^24-1> opaque; }
|
||||
{ }
|
||||
procedure TLSCertificateListAppend(var List: TTLSCertificateList; const A: RawByteString);
|
||||
var L : Integer;
|
||||
begin
|
||||
L := Length(List);
|
||||
SetLength(List, L + 1);
|
||||
List[L] := A;
|
||||
end;
|
||||
|
||||
function EncodeTLSCertificate(
|
||||
var Buffer; const Size: Integer;
|
||||
const CertificateList: TTLSCertificateList): Integer;
|
||||
var P : PByte;
|
||||
N, L, I, M, T : Integer;
|
||||
C : RawByteString;
|
||||
begin
|
||||
Assert(Size >= 0);
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
// certificate_list
|
||||
L := Length(CertificateList);
|
||||
T := 0;
|
||||
for I := 0 to L - 1 do
|
||||
Inc(T, 3 + Length(CertificateList[I]));
|
||||
EncodeTLSLen24(P^, N, T);
|
||||
Dec(N, 3);
|
||||
Inc(P, 3);
|
||||
for I := 0 to L - 1 do
|
||||
begin
|
||||
// ASN.1Cert
|
||||
C := CertificateList[I];
|
||||
if C = '' then
|
||||
raise ETLSError.Create(TLSError_InvalidCertificate);
|
||||
M := EncodeTLSOpaque24(P^, N, C);
|
||||
Dec(N, M);
|
||||
Inc(P, M);
|
||||
end;
|
||||
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
function DecodeTLSCertificate(
|
||||
const Buffer; const Size: Integer;
|
||||
var CertificateList: TTLSCertificateList): Integer;
|
||||
var P : PByte;
|
||||
N, L, M, F : Integer;
|
||||
C : RawByteString;
|
||||
begin
|
||||
Assert(Size >= 0);
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
// certificate_list
|
||||
DecodeTLSLen24(P^, N, L);
|
||||
Dec(N, 3);
|
||||
Inc(P, 3);
|
||||
SetLength(CertificateList, 0);
|
||||
F := 0;
|
||||
while L > 0 do
|
||||
begin
|
||||
// ASN.1Cert
|
||||
M := DecodeTLSOpaque24(P^, N, C);
|
||||
Dec(N, M);
|
||||
Inc(P, M);
|
||||
Dec(L, M);
|
||||
Inc(F);
|
||||
SetLength(CertificateList, F);
|
||||
CertificateList[F - 1] := C;
|
||||
end;
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
procedure ParseX509Certificates(
|
||||
const CertificateList: TTLSCertificateList;
|
||||
var X509Certificates: TX509CertificateArray);
|
||||
var
|
||||
L : Integer;
|
||||
I : Integer;
|
||||
C : RawByteString;
|
||||
begin
|
||||
L := Length(CertificateList);
|
||||
SetLength(X509Certificates, L);
|
||||
for I := 0 to L - 1 do
|
||||
begin
|
||||
C := CertificateList[I];
|
||||
InitX509Certificate(X509Certificates[I]);
|
||||
if C <> '' then
|
||||
try
|
||||
ParseX509Certificate(C[1], Length(C), X509Certificates[I])
|
||||
except
|
||||
raise ETLSError.Create(TLSError_InvalidCertificate);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function GetCertificateRSAPublicKey(
|
||||
const X509Certificates: TX509CertificateArray;
|
||||
var RSAPublicKey: TRSAPublicKey): Boolean;
|
||||
var
|
||||
I, L, N1, N2 : Integer;
|
||||
C : PX509Certificate;
|
||||
S : RawByteString;
|
||||
PKR : TX509RSAPublicKey;
|
||||
R : Boolean;
|
||||
begin
|
||||
// find RSA public key from certificates
|
||||
R := False;
|
||||
L := Length(X509Certificates);
|
||||
for I := 0 to L - 1 do
|
||||
begin
|
||||
C := @X509Certificates[I];
|
||||
if ASN1OIDEqual(C^.TBSCertificate.SubjectPublicKeyInfo.Algorithm.Algorithm, OID_RSA) then
|
||||
begin
|
||||
S := C^.TBSCertificate.SubjectPublicKeyInfo.SubjectPublicKey;
|
||||
Assert(S <> '');
|
||||
ParseX509RSAPublicKey(S[1], Length(S), PKR);
|
||||
R := True;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
if not R then
|
||||
begin
|
||||
Result := False;
|
||||
exit;
|
||||
end;
|
||||
N1 := NormaliseX509IntKeyBuf(PKR.Modulus);
|
||||
N2 := NormaliseX509IntKeyBuf(PKR.PublicExponent);
|
||||
if N2 > N1 then
|
||||
N1 := N2;
|
||||
// initialise RSA public key
|
||||
RSAPublicKeyAssignBuf(RSAPublicKey, N1 * 8,
|
||||
PKR.Modulus[1], Length(PKR.Modulus),
|
||||
PKR.PublicExponent[1], Length(PKR.PublicExponent), True);
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
|
||||
end.
|
||||
|
335
contrib/fundamentals/TLS/flcTLSCipher.pas
Normal file
335
contrib/fundamentals/TLS/flcTLSCipher.pas
Normal file
@@ -0,0 +1,335 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: cTLSCipher.pas }
|
||||
{ File version: 5.04 }
|
||||
{ Description: TLS cipher }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2018, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial version. }
|
||||
{ 2010/11/30 0.02 Revision. }
|
||||
{ 2010/12/16 0.03 AES support. }
|
||||
{ 2018/07/17 5.04 Revised for Fundamentals 5. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSCipher;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
{ Cipher }
|
||||
|
||||
flcCipher,
|
||||
|
||||
{ TLS }
|
||||
|
||||
flcTLSCipherSuite;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Cipher info }
|
||||
{ }
|
||||
type
|
||||
TTLSCipherSuiteCipherCipherInfo = record
|
||||
CipherType : TCipherType;
|
||||
CipherMode : TCipherMode;
|
||||
Padding : TCipherPadding;
|
||||
end;
|
||||
PTLSCipherSuiteCipherCipherInfo = ^TTLSCipherSuiteCipherCipherInfo;
|
||||
|
||||
const
|
||||
TLSCipherSuiteCipherCipherInfo : array[TTLSCipherSuiteCipher] of TTLSCipherSuiteCipherCipherInfo = (
|
||||
( // None
|
||||
CipherType : ctNone;
|
||||
CipherMode : cmECB;
|
||||
Padding : cpNone),
|
||||
( // NULL
|
||||
CipherType : ctNone;
|
||||
CipherMode : cmECB;
|
||||
Padding : cpNone),
|
||||
( // RC2_CBC_40
|
||||
CipherType : ctRC2;
|
||||
CipherMode : cmCBC;
|
||||
Padding : cpNone),
|
||||
( // RC4_40
|
||||
CipherType : ctRC4;
|
||||
CipherMode : cmECB;
|
||||
Padding : cpNone),
|
||||
( // RC4_56
|
||||
CipherType : ctRC4;
|
||||
CipherMode : cmECB;
|
||||
Padding : cpNone),
|
||||
( // RC4_128
|
||||
CipherType : ctRC4;
|
||||
CipherMode : cmECB;
|
||||
Padding : cpNone),
|
||||
( // IDEA_CBC
|
||||
CipherType : ctNone;
|
||||
CipherMode : cmCBC;
|
||||
Padding : cpNone),
|
||||
( // DES40_CBC
|
||||
CipherType : ctDES;
|
||||
CipherMode : cmCBC;
|
||||
Padding : cpNone),
|
||||
( // DES_CBC
|
||||
CipherType : ctDES;
|
||||
CipherMode : cmCBC;
|
||||
Padding : cpNone),
|
||||
( // 3DES_EDE_CBC
|
||||
CipherType : ctTripleDES3EDE; //// TripleDESEDE or TripleDES3EDE ?
|
||||
CipherMode : cmCBC;
|
||||
Padding : cpNone),
|
||||
( // AES_128_CBC
|
||||
CipherType : ctAES;
|
||||
CipherMode : cmCBC;
|
||||
Padding : cpNone),
|
||||
( // AES_256_CBC
|
||||
CipherType : ctAES;
|
||||
CipherMode : cmCBC;
|
||||
Padding : cpNone)
|
||||
);
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Cipher state }
|
||||
{ }
|
||||
type
|
||||
TTLSCipherOperation = (
|
||||
tlscoNone,
|
||||
tlscoEncrypt,
|
||||
tlscoDecrypt);
|
||||
|
||||
TTLSCipherState = record
|
||||
Operation : TTLSCipherOperation;
|
||||
TLSCipher : TTLSCipherSuiteCipher;
|
||||
TLSCipherInfo : TTLSCipherSuiteCipherInfo;
|
||||
CipherInfo : TTLSCipherSuiteCipherCipherInfo;
|
||||
CipherState : TCipherState;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Cipher }
|
||||
{ }
|
||||
procedure TLSCipherInitNone(
|
||||
var CipherState: TTLSCipherState;
|
||||
const Operation: TTLSCipherOperation);
|
||||
procedure TLSCipherInitNULL(
|
||||
var CipherState: TTLSCipherState;
|
||||
const Operation: TTLSCipherOperation);
|
||||
procedure TLSCipherInit(
|
||||
var CipherState: TTLSCipherState;
|
||||
const Operation: TTLSCipherOperation;
|
||||
const TLSCipher: TTLSCipherSuiteCipher;
|
||||
const KeyBuf;
|
||||
const KeySize: Integer);
|
||||
|
||||
procedure TLSCipherBuf(
|
||||
var CipherState: TTLSCipherState;
|
||||
const MessageBuf;
|
||||
const MessageSize: Integer;
|
||||
var CipherBuf;
|
||||
const CipherBufSize: Integer;
|
||||
out CipherSize: Integer;
|
||||
const IVBufPtr: Pointer;
|
||||
const IVBufSize: Integer);
|
||||
|
||||
procedure TLSCipherFinalise(var CipherState: TTLSCipherState);
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test cases }
|
||||
{ }
|
||||
{$IFDEF TLS_TEST}
|
||||
procedure Test;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{ Utils }
|
||||
|
||||
flcStdTypes,
|
||||
|
||||
{ TLS }
|
||||
|
||||
flcTLSErrors;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Cipher }
|
||||
{ }
|
||||
procedure TLSCipherInitNone(
|
||||
var CipherState: TTLSCipherState;
|
||||
const Operation: TTLSCipherOperation);
|
||||
begin
|
||||
FillChar(CipherState, SizeOf(CipherState), 0);
|
||||
CipherState.Operation := Operation;
|
||||
CipherState.TLSCipher := tlscscNone;
|
||||
CipherState.TLSCipherInfo := TLSCipherSuiteCipherInfo[tlscscNone];
|
||||
CipherState.CipherInfo := TLSCipherSuiteCipherCipherInfo[tlscscNone];
|
||||
end;
|
||||
|
||||
procedure TLSCipherInitNULL(
|
||||
var CipherState: TTLSCipherState;
|
||||
const Operation: TTLSCipherOperation);
|
||||
begin
|
||||
FillChar(CipherState, SizeOf(CipherState), 0);
|
||||
CipherState.Operation := Operation;
|
||||
CipherState.TLSCipher := tlscscNULL;
|
||||
CipherState.TLSCipherInfo := TLSCipherSuiteCipherInfo[tlscscNULL];
|
||||
CipherState.CipherInfo := TLSCipherSuiteCipherCipherInfo[tlscscNULL];
|
||||
end;
|
||||
|
||||
procedure TLSCipherInit(
|
||||
var CipherState: TTLSCipherState;
|
||||
const Operation: TTLSCipherOperation;
|
||||
const TLSCipher: TTLSCipherSuiteCipher;
|
||||
const KeyBuf;
|
||||
const KeySize: Integer);
|
||||
begin
|
||||
FillChar(CipherState, SizeOf(CipherState), 0);
|
||||
CipherState.Operation := Operation;
|
||||
CipherState.TLSCipher := TLSCipher;
|
||||
CipherState.TLSCipherInfo := TLSCipherSuiteCipherInfo[TLSCipher];
|
||||
CipherState.CipherInfo := TLSCipherSuiteCipherCipherInfo[TLSCipher];
|
||||
case Operation of
|
||||
tlscoEncrypt :
|
||||
EncryptInit(
|
||||
CipherState.CipherState,
|
||||
CipherState.CipherInfo.CipherType,
|
||||
CipherState.CipherInfo.CipherMode,
|
||||
CipherState.CipherInfo.Padding,
|
||||
CipherState.TLSCipherInfo.KeyBits, @KeyBuf, KeySize);
|
||||
tlscoDecrypt :
|
||||
DecryptInit(
|
||||
CipherState.CipherState,
|
||||
CipherState.CipherInfo.CipherType,
|
||||
CipherState.CipherInfo.CipherMode,
|
||||
CipherState.CipherInfo.Padding,
|
||||
CipherState.TLSCipherInfo.KeyBits, @KeyBuf, KeySize);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TLSCipherBuf(
|
||||
var CipherState: TTLSCipherState;
|
||||
const MessageBuf;
|
||||
const MessageSize: Integer;
|
||||
var CipherBuf;
|
||||
const CipherBufSize: Integer;
|
||||
out CipherSize: Integer;
|
||||
const IVBufPtr: Pointer;
|
||||
const IVBufSize: Integer);
|
||||
begin
|
||||
if CipherState.Operation = tlscoNone then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter); // cipher not initialised
|
||||
if MessageSize < 0 then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
if CipherBufSize < MessageSize then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
if CipherState.TLSCipher in [tlscscNone, tlscscNULL] then
|
||||
begin
|
||||
Move(MessageBuf, CipherBuf, MessageSize);
|
||||
CipherSize := MessageSize;
|
||||
end
|
||||
else
|
||||
case CipherState.Operation of
|
||||
tlscoEncrypt :
|
||||
CipherSize := EncryptBuf(CipherState.CipherState,
|
||||
@MessageBuf, MessageSize,
|
||||
@CipherBuf, CipherBufSize,
|
||||
IVBufPtr, IVBufSize);
|
||||
tlscoDecrypt :
|
||||
begin
|
||||
Move(MessageBuf, CipherBuf, MessageSize);
|
||||
CipherSize := DecryptBuf(CipherState.CipherState,
|
||||
@CipherBuf, MessageSize,
|
||||
IVBufPtr, IVBufSize);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TLSCipherFinalise(var CipherState: TTLSCipherState);
|
||||
begin
|
||||
case CipherState.Operation of
|
||||
tlscoEncrypt : EncryptFinalise(CipherState.CipherState);
|
||||
tlscoDecrypt : DecryptFinalise(CipherState.CipherState);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test cases }
|
||||
{ }
|
||||
{$IFDEF TLS_TEST}
|
||||
procedure Test;
|
||||
const
|
||||
ClientWriteKey = RawByteString(#$10#$D0#$D6#$C2#$D9#$B7#$62#$CB#$2C#$74#$BF#$5F#$85#$3C#$6F#$E7);
|
||||
var
|
||||
S, T : RawByteString;
|
||||
C : TTLSCipherState;
|
||||
B : RawByteString;
|
||||
L : Integer;
|
||||
begin
|
||||
// //
|
||||
// Example from http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/ReadDebug.html //
|
||||
|
||||
// //
|
||||
|
||||
S := ClientWriteKey;
|
||||
TLSCipherInit(C, tlscoEncrypt, tlscscRC4_128, S[1], Length(S));
|
||||
T := RawByteString(
|
||||
#$14#$00#$00#$0C#$F2#$62#$42#$AA#$7C#$7C#$CC#$E7#$49#$0F#$ED#$AC +
|
||||
#$FA#$06#$3C#$9F#$8C#$41#$1D#$ED#$2B#$06#$D0#$5A#$ED#$31#$F2#$80);
|
||||
SetLength(B, 1024);
|
||||
L := 1024;
|
||||
TLSCipherBuf(C, T[1], Length(T), B[1], L, L, nil, 0);
|
||||
SetLength(B, L);
|
||||
Assert(B = RawByteString(
|
||||
#$15#$8C#$25#$BA#$4E#$73#$F5#$27#$79#$49#$B1 +
|
||||
#$E9#$F5#$7E#$C8#$48#$A7#$D3#$A6#$9B#$BD#$6F#$8E#$A5#$8E#$2B#$B7 +
|
||||
#$EE#$DC#$BD#$F4#$D7));
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
1305
contrib/fundamentals/TLS/flcTLSCipherSuite.pas
Normal file
1305
contrib/fundamentals/TLS/flcTLSCipherSuite.pas
Normal file
File diff suppressed because it is too large
Load Diff
175
contrib/fundamentals/TLS/flcTLSCompress.pas
Normal file
175
contrib/fundamentals/TLS/flcTLSCompress.pas
Normal file
@@ -0,0 +1,175 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSCompress.pas }
|
||||
{ File version: 5.03 }
|
||||
{ Description: TLS compression }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2010/11/30 0.02 Revision. }
|
||||
{ 2018/07/17 5.03 Revised for Fundamentals 5. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
{$IFDEF TLS_ZLIB_DISABLE}
|
||||
{$UNDEF TLS_COMPRESS_ZLIB}
|
||||
{$ELSE}
|
||||
{$DEFINE TLS_COMPRESS_ZLIB}
|
||||
{$ENDIF}
|
||||
|
||||
unit flcTLSCompress;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
{ TLS }
|
||||
|
||||
flcTLSConsts,
|
||||
flcTLSErrors,
|
||||
flcTLSAlgorithmTypes;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Fragment compression }
|
||||
{ }
|
||||
procedure TLSCompressFragment(
|
||||
const CompressionMethod: TTLSCompressionMethod;
|
||||
const PlainTextBuf; const PlainTextSize: Integer;
|
||||
var CompressedBuf; const CompressedBufSize: Integer;
|
||||
var CompressedSize: Integer);
|
||||
|
||||
procedure TLSDecompressFragment(
|
||||
const CompressionMethod: TTLSCompressionMethod;
|
||||
const CompressedBuf; const CompressedSize: Integer;
|
||||
var PlainTextBuf; const PlainTextBufSize: Integer;
|
||||
var PlainTextSize: Integer);
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
{$IFDEF TLS_COMPRESS_ZLIB}
|
||||
uses
|
||||
{ Utils }
|
||||
flcZLib;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Fragment compression }
|
||||
{ }
|
||||
procedure TLSCompressFragment(
|
||||
const CompressionMethod: TTLSCompressionMethod;
|
||||
const PlainTextBuf; const PlainTextSize: Integer;
|
||||
var CompressedBuf; const CompressedBufSize: Integer;
|
||||
var CompressedSize: Integer);
|
||||
{$IFDEF TLS_COMPRESS_ZLIB}
|
||||
var OutBuf : Pointer;
|
||||
OutSize : Integer;
|
||||
{$ENDIF}
|
||||
begin
|
||||
if (PlainTextSize <= 0) or
|
||||
(PlainTextSize > TLS_PLAINTEXT_FRAGMENT_MAXSIZE) then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
case CompressionMethod of
|
||||
tlscmNull :
|
||||
begin
|
||||
if CompressedBufSize < PlainTextSize then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
Move(PlainTextBuf, CompressedBuf, PlainTextSize);
|
||||
CompressedSize := PlainTextSize;
|
||||
end;
|
||||
{$IFDEF TLS_COMPRESS_ZLIB}
|
||||
tlscmDeflate :
|
||||
begin
|
||||
ZLibCompressBuf(@PlainTextBuf, PlainTextSize, OutBuf, OutSize, zclDefault);
|
||||
if CompressedBufSize < OutSize then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
if OutSize > TLS_COMPRESSED_FRAGMENT_MAXSIZE then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer); // compressed fragment larger than maximum allowed size
|
||||
Move(OutBuf^, CompressedBuf, OutSize);
|
||||
FreeMem(OutBuf);
|
||||
CompressedSize := OutSize;
|
||||
end;
|
||||
{$ENDIF}
|
||||
else
|
||||
raise ETLSError.Create(TLSError_InvalidParameter, 'Invalid compression method');
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TLSDecompressFragment(
|
||||
const CompressionMethod: TTLSCompressionMethod;
|
||||
const CompressedBuf; const CompressedSize: Integer;
|
||||
var PlainTextBuf; const PlainTextBufSize: Integer;
|
||||
var PlainTextSize: Integer);
|
||||
{$IFDEF TLS_COMPRESS_ZLIB}
|
||||
var OutBuf : Pointer;
|
||||
OutSize : Integer;
|
||||
{$ENDIF}
|
||||
begin
|
||||
if (CompressedSize < 0) or
|
||||
(CompressedSize > TLS_COMPRESSED_FRAGMENT_MAXSIZE) then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
case CompressionMethod of
|
||||
tlscmNull :
|
||||
begin
|
||||
if PlainTextBufSize < CompressedSize then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
Move(CompressedBuf, PlainTextBuf, CompressedSize);
|
||||
PlainTextSize := CompressedSize;
|
||||
end;
|
||||
{$IFDEF TLS_COMPRESS_ZLIB}
|
||||
tlscmDeflate :
|
||||
begin
|
||||
ZLibDecompressBuf(@CompressedBuf, CompressedSize, OutBuf, OutSize);
|
||||
if PlainTextBufSize < OutSize then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
if OutSize > TLS_PLAINTEXT_FRAGMENT_MAXSIZE then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer); // uncompressed fragment larger than maximum allowed size
|
||||
Move(OutBuf^, PlainTextBuf, OutSize);
|
||||
FreeMem(OutBuf);
|
||||
PlainTextSize := OutSize;
|
||||
end;
|
||||
{$ENDIF}
|
||||
else
|
||||
raise ETLSError.Create(TLSError_InvalidParameter, 'Invalid compression method');
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
end.
|
||||
|
69
contrib/fundamentals/TLS/flcTLSConsts.pas
Normal file
69
contrib/fundamentals/TLS/flcTLSConsts.pas
Normal file
@@ -0,0 +1,69 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSConsts.pas }
|
||||
{ File version: 5.02 }
|
||||
{ Description: TLS Constants }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2020/05/09 5.02 Create flcTLSConsts unit from flcTLSUtils unit. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSConsts;
|
||||
|
||||
interface
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Fundamentals TLS library }
|
||||
{ }
|
||||
const
|
||||
FundamentalsTLSLibraryVersion = '1.00';
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ TLS Limits }
|
||||
{ }
|
||||
const
|
||||
TLS_PLAINTEXT_FRAGMENT_MAXSIZE = 16384 - 1; // 2^14 - 1
|
||||
TLS_COMPRESSED_FRAGMENT_MAXSIZE = 16384 + 1024; // 2^14 + 1024
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
201
contrib/fundamentals/TLS/flcTLSErrors.pas
Normal file
201
contrib/fundamentals/TLS/flcTLSErrors.pas
Normal file
@@ -0,0 +1,201 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSErrors.pas }
|
||||
{ File version: 5.03 }
|
||||
{ Description: TLS Errors }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2020/05/09 5.02 Create flcTLSErrors unit from flcTLSUtils unit. }
|
||||
{ 2020/05/11 5.03 ETLSError CreateAlert constructor. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSErrors;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
{ System }
|
||||
|
||||
SysUtils,
|
||||
|
||||
{ TLS }
|
||||
|
||||
flcTLSAlert;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Errors }
|
||||
{ }
|
||||
const
|
||||
TLSError_None = 0;
|
||||
TLSError_InvalidBuffer = 1;
|
||||
TLSError_InvalidParameter = 2;
|
||||
TLSError_InvalidCertificate = 3;
|
||||
TLSError_InvalidState = 4;
|
||||
TLSError_DecodeError = 5;
|
||||
TLSError_BadProtocol = 6;
|
||||
|
||||
function TLSErrorMessage(const TLSError: Integer): String;
|
||||
|
||||
type
|
||||
ETLSError = class(Exception)
|
||||
private
|
||||
FTLSError : Integer;
|
||||
FAlertDescription : TTLSAlertDescription;
|
||||
|
||||
function InitAlert(
|
||||
const ATLSError: Integer;
|
||||
const AAlertDescription: TTLSAlertDescription;
|
||||
const AMsg: String = ''): String;
|
||||
|
||||
public
|
||||
constructor Create(
|
||||
const ATLSError: Integer;
|
||||
const AMsg: String = '');
|
||||
|
||||
constructor CreateAlert(
|
||||
const ATLSError: Integer;
|
||||
const AAlertDescription: TTLSAlertDescription;
|
||||
const AMsg: String = '');
|
||||
|
||||
constructor CreateAlertBufferDecode;
|
||||
constructor CreateAlertBufferEncode;
|
||||
|
||||
constructor CreateAlertUnexpectedMessage;
|
||||
|
||||
constructor CreateAlertBadProtocolVersion;
|
||||
|
||||
property TLSError: Integer read FTLSError;
|
||||
property AlertDescription: TTLSAlertDescription read FAlertDescription;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Errors }
|
||||
{ }
|
||||
const
|
||||
SErr_InvalidBuffer = 'Invalid buffer';
|
||||
SErr_InvalidCertificate = 'Invalid certificate';
|
||||
SErr_InvalidParameter = 'Invalid parameter';
|
||||
SErr_InvalidState = 'Invalid state';
|
||||
SErr_DecodeError = 'Decode error';
|
||||
SErr_BadProtocol = 'Bad protocol';
|
||||
|
||||
function TLSErrorMessage(const TLSError: Integer): String;
|
||||
begin
|
||||
case TLSError of
|
||||
TLSError_None : Result := '';
|
||||
TLSError_InvalidBuffer : Result := SErr_InvalidBuffer;
|
||||
TLSError_InvalidParameter : Result := SErr_InvalidParameter;
|
||||
TLSError_InvalidCertificate : Result := SErr_InvalidCertificate;
|
||||
TLSError_InvalidState : Result := SErr_InvalidState;
|
||||
TLSError_DecodeError : Result := SErr_DecodeError;
|
||||
TLSError_BadProtocol : Result := SErr_BadProtocol;
|
||||
else
|
||||
Result := '[TLSError#' + IntToStr(TLSError) + ']';
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor ETLSError.Create(
|
||||
const ATLSError: Integer;
|
||||
const AMsg: String);
|
||||
var S : String;
|
||||
begin
|
||||
FTLSError := ATLSError;
|
||||
if AMsg = '' then
|
||||
S := TLSErrorMessage(ATLSError)
|
||||
else
|
||||
S := AMsg;
|
||||
FAlertDescription := tlsadMax;
|
||||
inherited Create(S);
|
||||
end;
|
||||
|
||||
constructor ETLSError.CreateAlert(
|
||||
const ATLSError: Integer;
|
||||
const AAlertDescription: TTLSAlertDescription;
|
||||
const AMsg: String);
|
||||
begin
|
||||
inherited Create(InitAlert(ATLSError, AAlertDescription, AMsg));
|
||||
end;
|
||||
|
||||
function ETLSError.InitAlert(
|
||||
const ATLSError: Integer;
|
||||
const AAlertDescription: TTLSAlertDescription;
|
||||
const AMsg: String): String;
|
||||
var
|
||||
S : String;
|
||||
begin
|
||||
FTLSError := ATLSError;
|
||||
FAlertDescription := AAlertDescription;
|
||||
|
||||
if AMsg = '' then
|
||||
S := TLSErrorMessage(ATLSError) + ':' + TLSAlertDescriptionToStr(AAlertDescription)
|
||||
else
|
||||
S := AMsg;
|
||||
|
||||
Result := S;
|
||||
end;
|
||||
|
||||
constructor ETLSError.CreateAlertBufferDecode;
|
||||
begin
|
||||
inherited Create(InitAlert(TLSError_InvalidBuffer, tlsadDecode_error));
|
||||
end;
|
||||
|
||||
constructor ETLSError.CreateAlertBufferEncode;
|
||||
begin
|
||||
inherited Create(InitAlert(TLSError_InvalidBuffer, tlsadInternal_error));
|
||||
end;
|
||||
|
||||
constructor ETLSError.CreateAlertUnexpectedMessage;
|
||||
begin
|
||||
inherited Create(InitAlert(TLSError_BadProtocol, tlsadUnexpected_message));
|
||||
end;
|
||||
|
||||
constructor ETLSError.CreateAlertBadProtocolVersion;
|
||||
begin
|
||||
inherited Create(InitAlert(TLSError_BadProtocol, tlsadProtocol_version));
|
||||
end;
|
||||
|
||||
|
||||
|
||||
end.
|
||||
|
1199
contrib/fundamentals/TLS/flcTLSHandshake.pas
Normal file
1199
contrib/fundamentals/TLS/flcTLSHandshake.pas
Normal file
File diff suppressed because it is too large
Load Diff
152
contrib/fundamentals/TLS/flcTLSHandshakeExtension.pas
Normal file
152
contrib/fundamentals/TLS/flcTLSHandshakeExtension.pas
Normal file
@@ -0,0 +1,152 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSHandshakeExtension.pas }
|
||||
{ File version: 5.03 }
|
||||
{ Description: TLS handshake extension }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2020/05/11 5.02 ExtensionType. }
|
||||
{ SignatureAlgorithms ClientHello extension. }
|
||||
{ 2020/05/19 5.03 Create flcTLSHandshakeExtension unit from }
|
||||
{ flcTLSHandshake unit. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSHandshakeExtension;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
{ TLS }
|
||||
|
||||
flcTLSAlgorithmTypes;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ExtensionType }
|
||||
{ }
|
||||
type
|
||||
TTLSExtensionType = (
|
||||
tlsetServer_name = 0, // RFC 6066
|
||||
tlsetMax_fragment_length = 1, // RFC 6066
|
||||
tlsetStatus_request = 5, // RFC 6066
|
||||
tlsetSupported_groups = 10, // RFC 8422, 7919
|
||||
tlsetSignature_algorithms = 13, // RFC 8446 - TLS 1.2
|
||||
tlsetUse_srtp = 14, // RFC 5764
|
||||
tlsetHeartbeat = 15, // RFC 6520
|
||||
tlsetApplication_layer_protocol_negotiation = 16, // RFC 7301
|
||||
tlsetSigned_certificate_timestamp = 18, // RFC 6962
|
||||
tlsetClient_certificate_type = 19, // RFC 7250
|
||||
tlsetServer_certificate_type = 20, // RFC 7250
|
||||
tlsetPadding = 21, // RFC 7685
|
||||
tlsetPre_shared_key = 41, // RFC 8446
|
||||
tlsetEarly_data = 42, // RFC 8446
|
||||
tlsetSupported_versions = 43, // RFC 8446
|
||||
tlsetCookie = 44, // RFC 8446
|
||||
tlsetPsk_key_exchange_modes = 45, // RFC 8446
|
||||
tlsetCertificate_authorities = 47, // RFC 8446
|
||||
tlsetOid_filters = 48, // RFC 8446
|
||||
tlsetPost_handshake_auth = 49, // RFC 8446
|
||||
tlsetSignature_algorithms_cert = 50, // RFC 8446
|
||||
tlsetKey_share = 51, // RFC 8446
|
||||
tlsetMax = 65535
|
||||
);
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ SignatureAlgorithms }
|
||||
{ }
|
||||
function EncodeTLSExtension_SignatureAlgorithms(
|
||||
var Buffer; const Size: Integer;
|
||||
const SignAndHashAlgos: TTLSSignatureAndHashAlgorithmArray): Integer;
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{ TLS }
|
||||
|
||||
flcTLSErrors,
|
||||
flcTLSOpaqueEncoding;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ SignatureAlgorithms }
|
||||
{ }
|
||||
function EncodeTLSExtension_SignatureAlgorithms(
|
||||
var Buffer; const Size: Integer;
|
||||
const SignAndHashAlgos: TTLSSignatureAndHashAlgorithmArray): Integer;
|
||||
var P : PByte;
|
||||
L, N : Integer;
|
||||
C, I : Integer;
|
||||
begin
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
|
||||
Dec(N, 2);
|
||||
if N < 0 then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
EncodeTLSWord16(P^, N, Ord(TTLSExtensionType.tlsetSignature_algorithms));
|
||||
Inc(P, 2);
|
||||
|
||||
C := Length(SignAndHashAlgos);
|
||||
Assert(C > 0);
|
||||
L := C * TLSSignatureAndHashAlgorithmSize;
|
||||
EncodeTLSLen16(P^, N, L);
|
||||
Inc(P, 2);
|
||||
Dec(N, 2);
|
||||
|
||||
Dec(N, L);
|
||||
if N < 0 then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
|
||||
for I := 0 to C - 1 do
|
||||
begin
|
||||
P^ := Ord(SignAndHashAlgos[I].Hash);
|
||||
Inc(P);
|
||||
P^ := Ord(SignAndHashAlgos[I].Signature);
|
||||
Inc(P);
|
||||
end;
|
||||
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
end.
|
885
contrib/fundamentals/TLS/flcTLSKeyExchangeParams.pas
Normal file
885
contrib/fundamentals/TLS/flcTLSKeyExchangeParams.pas
Normal file
@@ -0,0 +1,885 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSKeyExchangeParams.pas }
|
||||
{ File version: 5.04 }
|
||||
{ Description: TLS Key Exchange Parameters }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ References: }
|
||||
{ }
|
||||
{ RFC 4492 - Elliptic Curve Cryptography (ECC) Cipher Suites for }
|
||||
{ Transport Layer Security (TLS) }
|
||||
{ https://tools.ietf.org/html/rfc4492 }
|
||||
{ }
|
||||
{ RFC 8422 - Elliptic Curve Cryptography (ECC) Cipher Suites for }
|
||||
{ Transport Layer Security (TLS) Versions 1.2 and Earlier }
|
||||
{ https://tools.ietf.org/html/rfc8422 }
|
||||
{ }
|
||||
{ https://ldapwiki.com/wiki/Key-Exchange }
|
||||
{ https://crypto.stackexchange.com/questions/26354/whats-the-structure-of-server-key-exchange-message-during-tls-handshake }
|
||||
{ https://security.stackexchange.com/questions/8343/what-key-exchange-mechanism-should-be-used-in-tls }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2020/05/09 5.02 Create flcTLSKeyExchangeParams unit from }
|
||||
{ flcTLSUtils unit. }
|
||||
{ 2020/05/11 5.03 TLSDigitallySigned, SignTLSServerKeyExchangeDH_RSA. }
|
||||
{ 2020/05/19 5.04 Sign/Verify RSA authentication signature for DHE_RSA. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSKeyExchangeParams;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
{ System }
|
||||
|
||||
SysUtils,
|
||||
|
||||
{ Utils }
|
||||
|
||||
flcStdTypes,
|
||||
|
||||
{ Cipher }
|
||||
|
||||
flcCipherRSA,
|
||||
|
||||
{ TLS }
|
||||
|
||||
flcTLSAlgorithmTypes;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ServerDHParams }
|
||||
{ Ephemeral DH parameters }
|
||||
{ }
|
||||
type
|
||||
TTLSServerDHParams = record
|
||||
dh_p : RawByteString;
|
||||
dh_g : RawByteString;
|
||||
dh_Ys : RawByteString;
|
||||
end;
|
||||
|
||||
procedure AssignTLSServerDHParams(var ServerDHParams: TTLSServerDHParams;
|
||||
const p, g, Ys: RawByteString);
|
||||
|
||||
function EncodeTLSServerDHParams(
|
||||
var Buffer; const Size: Integer;
|
||||
const ServerDHParams: TTLSServerDHParams): Integer;
|
||||
|
||||
function DecodeTLSServerDHParams(
|
||||
const Buffer; const Size: Integer;
|
||||
var ServerDHParams: TTLSServerDHParams): Integer;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ServerRSAParams }
|
||||
{ }
|
||||
type
|
||||
TTLSServerRSAParams = record
|
||||
rsa_modulus : RawByteString;
|
||||
rsa_exponent : RawByteString;
|
||||
end;
|
||||
|
||||
procedure AssignTLSServerRSAParams(var ServerRSAParams: TTLSServerRSAParams;
|
||||
const modulus, exponent: RawByteString);
|
||||
|
||||
function EncodeTLSServerRSAParams(
|
||||
var Buffer; const Size: Integer;
|
||||
const ServerRSAParams: TTLSServerRSAParams): Integer;
|
||||
|
||||
function DecodeTLSServerRSAParams(
|
||||
const Buffer; const Size: Integer;
|
||||
var ServerRSAParams: TTLSServerRSAParams): Integer;
|
||||
|
||||
|
||||
{ }
|
||||
{ ServerECDHParams }
|
||||
{ }
|
||||
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ServerParamsHashBuf }
|
||||
{ }
|
||||
type
|
||||
TTLSClientServerRandom = array[0..31] of Byte;
|
||||
PTLSClientServerRandom = ^TTLSClientServerRandom;
|
||||
|
||||
function EncodeTLSServerDHParamsHashBuf(
|
||||
var Buffer; const Size: Integer;
|
||||
const client_random: TTLSClientServerRandom;
|
||||
const server_random: TTLSClientServerRandom;
|
||||
const Params: TTLSServerDHParams): Integer;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ SignedStruct }
|
||||
{ }
|
||||
type
|
||||
TTLSRSASignedStruct = packed record
|
||||
md5_hash : array[0..15] of Byte;
|
||||
sha_hash : array[0..19] of Byte;
|
||||
end;
|
||||
|
||||
TTLSDSASignedStruct = packed record
|
||||
sha_hash : array[0..19] of Byte;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ DigitallySigned }
|
||||
{ }
|
||||
{ SignatureAndHashAlgorithm algorithm; }
|
||||
{ opaque signature<0..2^16-1>; }
|
||||
{ }
|
||||
type
|
||||
TTLSDigitallySigned = record
|
||||
Algorithm : TTLSSignatureAndHashAlgorithm;
|
||||
Signature : RawByteString;
|
||||
end;
|
||||
|
||||
function EncodeTLSDigitallySigned(
|
||||
var Buffer; const Size: Integer;
|
||||
const Signed: TTLSDigitallySigned): Integer;
|
||||
|
||||
function DecodeTLSDigitallySigned(
|
||||
const Buffer; const Size: Integer;
|
||||
var Signed: TTLSDigitallySigned): Integer;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ServerKeyExchange }
|
||||
{ }
|
||||
type
|
||||
TTLSServerKeyExchange = record
|
||||
DHParams : TTLSServerDHParams;
|
||||
RSAParams : TTLSServerRSAParams;
|
||||
SignedParams : TTLSDigitallySigned;
|
||||
end;
|
||||
|
||||
procedure InitTLSServerKeyExchange(var ServerKeyExchange: TTLSServerKeyExchange);
|
||||
|
||||
procedure AssignTLSServerKeyExchangeDHParams(
|
||||
var ServerKeyExchange: TTLSServerKeyExchange;
|
||||
const p, g, Ys: RawByteString);
|
||||
|
||||
function EncodeTLSServerKeyExchange(
|
||||
var Buffer; const Size: Integer;
|
||||
const KeyExchangeAlgorithm: TTLSKeyExchangeAlgorithm;
|
||||
const ServerKeyExchange: TTLSServerKeyExchange): Integer;
|
||||
|
||||
function DecodeTLSServerKeyExchange(
|
||||
const Buffer; const Size: Integer;
|
||||
const KeyExchangeAlgorithm: TTLSKeyExchangeAlgorithm;
|
||||
var ServerKeyExchange: TTLSServerKeyExchange): Integer;
|
||||
|
||||
procedure SignTLSServerKeyExchangeDH_RSA(
|
||||
var ServerKeyExchange: TTLSServerKeyExchange;
|
||||
const client_random : TTLSClientServerRandom;
|
||||
const server_random : TTLSClientServerRandom;
|
||||
const RSAPrivateKey: TRSAPrivateKey);
|
||||
|
||||
function VerifyTLSServerKeyExchangeDH_RSA(
|
||||
const ServerKeyExchange: TTLSServerKeyExchange;
|
||||
const client_random : TTLSClientServerRandom;
|
||||
const server_random : TTLSClientServerRandom;
|
||||
const RSAPublicKey: TRSAPublicKey): Boolean;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ClientDiffieHellmanPublic }
|
||||
{ }
|
||||
type
|
||||
TTLSClientDiffieHellmanPublic = record
|
||||
PublicValueEncodingExplicit : Boolean;
|
||||
dh_Yc : RawByteString;
|
||||
end;
|
||||
|
||||
function EncodeTLSClientDiffieHellmanPublic(
|
||||
var Buffer; const Size: Integer;
|
||||
const ClientDiffieHellmanPublic: TTLSClientDiffieHellmanPublic): Integer;
|
||||
|
||||
function DecodeTLSClientDiffieHellmanPublic(
|
||||
const Buffer; const Size: Integer;
|
||||
const PublicValueEncodingExplicit: Boolean;
|
||||
var ClientDiffieHellmanPublic: TTLSClientDiffieHellmanPublic): Integer;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ClientKeyExchange }
|
||||
{ }
|
||||
type
|
||||
TTLSClientKeyExchange = record
|
||||
EncryptedPreMasterSecret : RawByteString;
|
||||
ClientDiffieHellmanPublic : TTLSClientDiffieHellmanPublic;
|
||||
end;
|
||||
|
||||
function EncodeTLSClientKeyExchange(
|
||||
var Buffer; const Size: Integer;
|
||||
const KeyExchangeAlgorithm: TTLSKeyExchangeAlgorithm;
|
||||
const ClientKeyExchange: TTLSClientKeyExchange): Integer;
|
||||
|
||||
function DecodeTLSClientKeyExchange(
|
||||
const Buffer; const Size: Integer;
|
||||
const KeyExchangeAlgorithm: TTLSKeyExchangeAlgorithm;
|
||||
const PublicValueEncodingExplicit: Boolean;
|
||||
var ClientKeyExchange: TTLSClientKeyExchange): Integer;
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{ Utils }
|
||||
|
||||
flcHash,
|
||||
flcHugeInt,
|
||||
|
||||
{ TLS }
|
||||
|
||||
flcTLSAlert,
|
||||
flcTLSErrors,
|
||||
flcTLSOpaqueEncoding;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ServerDHParams }
|
||||
{ Ephemeral DH parameters }
|
||||
{ }
|
||||
{ struct }
|
||||
{ dh_p : opaque <1..2^16-1>; }
|
||||
{ dh_g : opaque <1..2^16-1>; }
|
||||
{ dh_Ys : opaque <1..2^16-1>; }
|
||||
{ }
|
||||
procedure AssignTLSServerDHParams(var ServerDHParams: TTLSServerDHParams;
|
||||
const p, g, Ys: RawByteString);
|
||||
begin
|
||||
ServerDHParams.dh_p := p;
|
||||
ServerDHParams.dh_g := g;
|
||||
ServerDHParams.dh_Ys := Ys;
|
||||
end;
|
||||
|
||||
function EncodeTLSServerDHParams(
|
||||
var Buffer; const Size: Integer;
|
||||
const ServerDHParams: TTLSServerDHParams): Integer;
|
||||
var P : PByte;
|
||||
N, L : Integer;
|
||||
begin
|
||||
Assert(Size >= 0);
|
||||
|
||||
if (ServerDHParams.dh_p = '') or
|
||||
(ServerDHParams.dh_g = '') or
|
||||
(ServerDHParams.dh_Ys = '') then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter);
|
||||
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
// dh_p
|
||||
L := EncodeTLSOpaque16(P^, N, ServerDHParams.dh_p);
|
||||
Dec(N, L);
|
||||
Inc(P, L);
|
||||
// dh_g
|
||||
L := EncodeTLSOpaque16(P^, N, ServerDHParams.dh_g);
|
||||
Dec(N, L);
|
||||
Inc(P, L);
|
||||
// dh_Ys
|
||||
L := EncodeTLSOpaque16(P^, N, ServerDHParams.dh_Ys);
|
||||
Dec(N, L);
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
function DecodeTLSServerDHParams(
|
||||
const Buffer; const Size: Integer;
|
||||
var ServerDHParams: TTLSServerDHParams): Integer;
|
||||
var P : PByte;
|
||||
N, L : Integer;
|
||||
begin
|
||||
Assert(Size >= 0);
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
// dh_p
|
||||
L := DecodeTLSOpaque16(P^, N, ServerDHParams.dh_p);
|
||||
Dec(N, L);
|
||||
Inc(P, L);
|
||||
// dh_g
|
||||
L := DecodeTLSOpaque16(P^, N, ServerDHParams.dh_g);
|
||||
Dec(N, L);
|
||||
Inc(P, L);
|
||||
// dh_Ys
|
||||
L := DecodeTLSOpaque16(P^, N, ServerDHParams.dh_Ys);
|
||||
Dec(N, L);
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ServerRSAParams }
|
||||
{ }
|
||||
{ struct }
|
||||
{ rsa_modulus : opaque <1..2^16-1>; }
|
||||
{ rsa_exponent : opaque <1..2^16-1>; }
|
||||
{ }
|
||||
procedure AssignTLSServerRSAParams(var ServerRSAParams: TTLSServerRSAParams;
|
||||
const modulus, exponent: RawByteString);
|
||||
begin
|
||||
ServerRSAParams.rsa_modulus := modulus;
|
||||
ServerRSAParams.rsa_exponent := exponent;
|
||||
end;
|
||||
|
||||
function EncodeTLSServerRSAParams(
|
||||
var Buffer; const Size: Integer;
|
||||
const ServerRSAParams: TTLSServerRSAParams): Integer;
|
||||
var P : PByte;
|
||||
N, L : Integer;
|
||||
begin
|
||||
Assert(Size >= 0);
|
||||
if (ServerRSAParams.rsa_modulus = '') or
|
||||
(ServerRSAParams.rsa_exponent = '') then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter);
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
// rsa_modulus
|
||||
L := EncodeTLSOpaque16(P^, N, ServerRSAParams.rsa_modulus);
|
||||
Dec(N, L);
|
||||
Inc(P, L);
|
||||
// rsa_exponent
|
||||
L := EncodeTLSOpaque16(P^, N, ServerRSAParams.rsa_exponent);
|
||||
Dec(N, L);
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
function DecodeTLSServerRSAParams(
|
||||
const Buffer; const Size: Integer;
|
||||
var ServerRSAParams: TTLSServerRSAParams): Integer;
|
||||
var P : PByte;
|
||||
N, L : Integer;
|
||||
begin
|
||||
Assert(Size >= 0);
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
// rsa_modulus
|
||||
L := DecodeTLSOpaque16(P^, N, ServerRSAParams.rsa_modulus);
|
||||
Dec(N, L);
|
||||
Inc(P, L);
|
||||
// rsa_exponent
|
||||
L := DecodeTLSOpaque16(P^, N, ServerRSAParams.rsa_exponent);
|
||||
Dec(N, L);
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ECParameters }
|
||||
{ }
|
||||
type
|
||||
TTLSECParameters = record
|
||||
CurveType : TTLSECCurveType;
|
||||
NamedCurve : TTLSNamedCurve;
|
||||
end;
|
||||
|
||||
|
||||
(*
|
||||
ECCurveType curve_type;
|
||||
select (curve_type) {
|
||||
case explicit_prime:
|
||||
opaque prime_p <1..2^8-1>;
|
||||
ECCurve curve;
|
||||
ECPoint base;
|
||||
opaque order <1..2^8-1>;
|
||||
opaque cofactor <1..2^8-1>;
|
||||
case explicit_char2:
|
||||
uint16 m;
|
||||
ECBasisType basis;
|
||||
select (basis) {
|
||||
case ec_trinomial:
|
||||
opaque k <1..2^8-1>;
|
||||
case ec_pentanomial:
|
||||
opaque k1 <1..2^8-1>;
|
||||
opaque k2 <1..2^8-1>;
|
||||
opaque k3 <1..2^8-1>;
|
||||
};
|
||||
ECCurve curve;
|
||||
ECPoint base;
|
||||
opaque order <1..2^8-1>;
|
||||
opaque cofactor <1..2^8-1>;
|
||||
case named_curve:
|
||||
NamedCurve namedcurve;
|
||||
};
|
||||
}
|
||||
*)
|
||||
|
||||
|
||||
{ }
|
||||
{ ECPoint }
|
||||
{ }
|
||||
{ opaque point <1..2^8-1>; }
|
||||
{ }
|
||||
type
|
||||
TTLSECPoint = array of Byte;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ServerECDHParams }
|
||||
{ }
|
||||
{ ECParameters curve_params; }
|
||||
{ ECPoint public; }
|
||||
{ }
|
||||
type
|
||||
TTLSServerECDHParams = record
|
||||
CurveParams : TTLSECParameters;
|
||||
PublicKey : TTLSECPoint;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ServerParamsHashBuf }
|
||||
{ }
|
||||
function EncodeTLSServerDHParamsHashBuf(
|
||||
var Buffer; const Size: Integer;
|
||||
const client_random: TTLSClientServerRandom;
|
||||
const server_random: TTLSClientServerRandom;
|
||||
const Params: TTLSServerDHParams): Integer;
|
||||
var P : PByte;
|
||||
N, L : Integer;
|
||||
begin
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
Dec(N, 64);
|
||||
if N < 0 then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
Move(client_random, P^, 32);
|
||||
Inc(P, 32);
|
||||
Move(server_random, P^, 32);
|
||||
Inc(P, 32);
|
||||
L := EncodeTLSServerDHParams(P^, N, Params);
|
||||
Dec(N, L);
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ DigitallySigned }
|
||||
{ }
|
||||
(* struct { *)
|
||||
(* SignatureAndHashAlgorithm algorithm; *)
|
||||
(* opaque signature<0..2^16-1>; *)
|
||||
(* } DigitallySigned; *)
|
||||
{ }
|
||||
function EncodeTLSDigitallySigned(
|
||||
var Buffer; const Size: Integer;
|
||||
const Signed: TTLSDigitallySigned): Integer;
|
||||
var P : PByte;
|
||||
N, L : Integer;
|
||||
begin
|
||||
Assert(Signed.Algorithm.Hash <> tlshaNone);
|
||||
Assert(Signed.Algorithm.Signature <> tlssaAnonymous);
|
||||
Assert(Length(Signed.Signature) > 0);
|
||||
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
Dec(N, 2);
|
||||
if N < 0 then
|
||||
raise ETLSError.CreateAlertBufferEncode;
|
||||
P^ := Ord(Signed.Algorithm.Hash);
|
||||
Inc(P);
|
||||
P^ := Ord(Signed.Algorithm.Signature);
|
||||
Inc(P);
|
||||
L := EncodeTLSOpaque16(P^, N, Signed.Signature);
|
||||
Dec(N, L);
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
function DecodeTLSDigitallySigned(
|
||||
const Buffer; const Size: Integer;
|
||||
var Signed: TTLSDigitallySigned): Integer;
|
||||
var P : PByte;
|
||||
N, L : Integer;
|
||||
begin
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
Dec(N, 2);
|
||||
if N < 0 then
|
||||
raise ETLSError.CreateAlertBufferDecode;
|
||||
Signed.Algorithm.Hash := TTLSHashAlgorithm(P^);
|
||||
Inc(P);
|
||||
Signed.Algorithm.Signature := TTLSSignatureAlgorithm(P^);
|
||||
Inc(P);
|
||||
L := DecodeTLSOpaque16(P^, N, Signed.Signature);
|
||||
Dec(N, L);
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Server Key Exchange }
|
||||
{ }
|
||||
{ select (KeyExchangeAlgorithm) }
|
||||
{ case dh_anon: params : ServerDHParams; }
|
||||
{ case dhe_dss: }
|
||||
{ case dhe_rsa: params : ServerDHParams; }
|
||||
{ signed_params : digitally-signed struct ( }
|
||||
{ client_random : opaque [32]; }
|
||||
{ server_random : opaque [32]; }
|
||||
{ params : ServerDHParams ; }
|
||||
{ ); }
|
||||
{ case rsa: }
|
||||
{ case dh_dss: }
|
||||
{ case dh_rsa: struct (); }
|
||||
{ case ec_diffie_hellman: }
|
||||
{ ServerECDHParams params; }
|
||||
{ Signature signed_params; }
|
||||
{ }
|
||||
procedure InitTLSServerKeyExchange(var ServerKeyExchange: TTLSServerKeyExchange);
|
||||
begin
|
||||
FillChar(ServerKeyExchange, SizeOf(ServerKeyExchange), 0);
|
||||
end;
|
||||
|
||||
procedure AssignTLSServerKeyExchangeDHParams(
|
||||
var ServerKeyExchange: TTLSServerKeyExchange;
|
||||
const p, g, Ys: RawByteString);
|
||||
begin
|
||||
AssignTLSServerDHParams(ServerKeyExchange.DHParams, p, g, Ys);
|
||||
end;
|
||||
|
||||
function EncodeTLSServerKeyExchange(
|
||||
var Buffer; const Size: Integer;
|
||||
const KeyExchangeAlgorithm: TTLSKeyExchangeAlgorithm;
|
||||
const ServerKeyExchange: TTLSServerKeyExchange): Integer;
|
||||
var P : PByte;
|
||||
N, L : Integer;
|
||||
begin
|
||||
Assert(KeyExchangeAlgorithm <> tlskeaNone);
|
||||
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
case KeyExchangeAlgorithm of
|
||||
tlskeaDH_Anon :
|
||||
begin
|
||||
L := EncodeTLSServerDHParams(P^, N, ServerKeyExchange.DHParams);
|
||||
Dec(N, L);
|
||||
end;
|
||||
tlskeaDHE_DSS,
|
||||
tlskeaDHE_RSA :
|
||||
begin
|
||||
L := EncodeTLSServerDHParams(P^, N, ServerKeyExchange.DHParams);
|
||||
Dec(N, L);
|
||||
Inc(P, L);
|
||||
L := EncodeTLSDigitallySigned(P^, N, ServerKeyExchange.SignedParams);
|
||||
Dec(N, L);
|
||||
end;
|
||||
tlskeaECDHE_ECDSA,
|
||||
tlskeaECDHE_RSA : ;
|
||||
tlskeaRSA,
|
||||
tlskeaDH_DSS,
|
||||
tlskeaDH_RSA : ;
|
||||
end;
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
function DecodeTLSServerKeyExchange(
|
||||
const Buffer; const Size: Integer;
|
||||
const KeyExchangeAlgorithm: TTLSKeyExchangeAlgorithm;
|
||||
var ServerKeyExchange: TTLSServerKeyExchange): Integer;
|
||||
var P : PByte;
|
||||
N, L : Integer;
|
||||
begin
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
case KeyExchangeAlgorithm of
|
||||
tlskeaDH_Anon :
|
||||
begin
|
||||
L := DecodeTLSServerDHParams(P^, N, ServerKeyExchange.DHParams);
|
||||
Dec(N, L);
|
||||
end;
|
||||
tlskeaDHE_DSS,
|
||||
tlskeaDHE_RSA :
|
||||
begin
|
||||
L := DecodeTLSServerDHParams(P^, N, ServerKeyExchange.DHParams);
|
||||
Dec(N, L);
|
||||
Inc(P, L);
|
||||
L := DecodeTLSDigitallySigned(P^, N, ServerKeyExchange.SignedParams);
|
||||
Dec(N, L);
|
||||
end;
|
||||
tlskeaRSA,
|
||||
tlskeaDH_DSS,
|
||||
tlskeaDH_RSA : ;
|
||||
end;
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
procedure SignTLSServerKeyExchangeDH_RSA(
|
||||
var ServerKeyExchange: TTLSServerKeyExchange;
|
||||
const client_random : TTLSClientServerRandom;
|
||||
const server_random : TTLSClientServerRandom;
|
||||
const RSAPrivateKey: TRSAPrivateKey);
|
||||
const
|
||||
MaxHashBufSize = 32768;
|
||||
var
|
||||
HashBuf : array[0..MaxHashBufSize - 1] of Byte;
|
||||
L : Integer;
|
||||
//HashMd5 : T128BitDigest;
|
||||
//HashSha : T160BitDigest;
|
||||
//SignedStruct : TTLSRSASignedStruct;
|
||||
//SignHash : T256BitDigest;
|
||||
SignatureBuf : RawByteString;
|
||||
begin
|
||||
Writeln('Sign:');
|
||||
|
||||
Assert(Length(ServerKeyExchange.DHParams.dh_p) > 0);
|
||||
Assert(Length(ServerKeyExchange.DHParams.dh_g) > 0);
|
||||
Assert(Length(ServerKeyExchange.DHParams.dh_Ys) > 0);
|
||||
Assert(RSAPrivateKey.KeyBits > 0);
|
||||
|
||||
L := EncodeTLSServerDHParamsHashBuf(
|
||||
HashBuf, SizeOf(HashBuf),
|
||||
client_random,
|
||||
server_random,
|
||||
ServerKeyExchange.DHParams);
|
||||
|
||||
{
|
||||
HashMd5 := CalcMD5(HashBuf, L);
|
||||
HashSha := CalcSHA1(HashBuf, L);
|
||||
Move(HashMd5, SignedStruct.md5_hash, SizeOf(SignedStruct.md5_hash));
|
||||
Move(HashSha, SignedStruct.sha_hash, SizeOf(SignedStruct.sha_hash));
|
||||
SignHash := CalcSHA256(SignedStruct, SizeOf(SignedStruct));
|
||||
Writeln('SignHash:', DigestToHexU(SignHash, Sizeof(SignHash)));
|
||||
Writeln('PrivateKey:', HugeWordToHex(RSAPrivateKey.Exponent), ' ', HugeWordToHex(RSAPrivateKey.Modulus));
|
||||
}
|
||||
|
||||
SetLength(SignatureBuf, RSAPrivateKey.KeyBits div 8);
|
||||
|
||||
RSASignMessage(rsastEMSA_PKCS1, rsahfSHA256, RSAPrivateKey,
|
||||
HashBuf, L,
|
||||
Pointer(SignatureBuf)^, Length(SignatureBuf));
|
||||
|
||||
ServerKeyExchange.SignedParams.Algorithm.Hash := tlshaSHA256;
|
||||
ServerKeyExchange.SignedParams.Algorithm.Signature := tlssaRSA;
|
||||
ServerKeyExchange.SignedParams.Signature := SignatureBuf;
|
||||
end;
|
||||
|
||||
function VerifyTLSServerKeyExchangeDH_RSA(
|
||||
const ServerKeyExchange: TTLSServerKeyExchange;
|
||||
const client_random : TTLSClientServerRandom;
|
||||
const server_random : TTLSClientServerRandom;
|
||||
const RSAPublicKey: TRSAPublicKey): Boolean;
|
||||
const
|
||||
MaxHashBufSize = 32768;
|
||||
var
|
||||
HashBuf : array[0..MaxHashBufSize - 1] of Byte;
|
||||
L : Integer;
|
||||
// HashMd5 : T128BitDigest;
|
||||
// HashSha : T160BitDigest;
|
||||
// SignedStruct : TTLSRSASignedStruct;
|
||||
// SignHash : T256BitDigest;
|
||||
SignatureBuf : RawByteString;
|
||||
begin
|
||||
Assert(Length(ServerKeyExchange.DHParams.dh_p) > 0);
|
||||
Assert(Length(ServerKeyExchange.DHParams.dh_g) > 0);
|
||||
Assert(Length(ServerKeyExchange.DHParams.dh_Ys) > 0);
|
||||
Assert(RSAPublicKey.KeyBits > 0);
|
||||
|
||||
//// After validated, encode hash buf using received Params buf, it might
|
||||
//// have params in a different order.
|
||||
L := EncodeTLSServerDHParamsHashBuf(HashBuf, SizeOf(HashBuf),
|
||||
client_random,
|
||||
server_random,
|
||||
ServerKeyExchange.DHParams);
|
||||
|
||||
SignatureBuf := ServerKeyExchange.SignedParams.Signature;
|
||||
|
||||
(*
|
||||
HashMd5 := CalcMD5(HashBuf, L);
|
||||
HashSha := CalcSHA1(HashBuf, L);
|
||||
Move(HashMd5, SignedStruct.md5_hash, SizeOf(SignedStruct.md5_hash));
|
||||
Move(HashSha, SignedStruct.sha_hash, SizeOf(SignedStruct.sha_hash));
|
||||
SignHash := CalcSHA256(SignedStruct, SizeOf(SignedStruct));
|
||||
Writeln('SignHash:', DigestToHexU(SignHash, Sizeof(SignHash)));
|
||||
Writeln('Signature:', DigestToHexU(Pointer(SignatureBuf)^, Length(SignatureBuf)));
|
||||
Writeln('PublicKey:', HugeWordToHex(RSAPublicKey.Exponent), ' ', HugeWordToHex(RSAPublicKey.Modulus));
|
||||
*)
|
||||
|
||||
Result :=
|
||||
RSACheckSignature(rsastEMSA_PKCS1, RSAPublicKey,
|
||||
HashBuf, L,
|
||||
Pointer(SignatureBuf)^, Length(SignatureBuf));
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ClientDiffieHellmanPublic }
|
||||
{ select (PublicValueEncoding) }
|
||||
{ case implicit: struct (); }
|
||||
{ case explicit: opaque dh_Yc<1..2^16-1>; }
|
||||
{ }
|
||||
function EncodeTLSClientDiffieHellmanPublic(
|
||||
var Buffer; const Size: Integer;
|
||||
const ClientDiffieHellmanPublic: TTLSClientDiffieHellmanPublic): Integer;
|
||||
var P : PByte;
|
||||
N, L : Integer;
|
||||
begin
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
if ClientDiffieHellmanPublic.PublicValueEncodingExplicit then
|
||||
begin
|
||||
if ClientDiffieHellmanPublic.dh_Yc = '' then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter);
|
||||
L := EncodeTLSOpaque16(P^, N, ClientDiffieHellmanPublic.dh_Yc);
|
||||
Dec(N, L);
|
||||
end;
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
function DecodeTLSClientDiffieHellmanPublic(
|
||||
const Buffer; const Size: Integer;
|
||||
const PublicValueEncodingExplicit: Boolean;
|
||||
var ClientDiffieHellmanPublic: TTLSClientDiffieHellmanPublic): Integer;
|
||||
var P : PByte;
|
||||
N, L : Integer;
|
||||
begin
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
if PublicValueEncodingExplicit then
|
||||
begin
|
||||
L := DecodeTLSOpaque16(P^, N, ClientDiffieHellmanPublic.dh_Yc);
|
||||
Dec(N, L);
|
||||
end;
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
(*
|
||||
struct {
|
||||
ECPoint ecdh_Yc;
|
||||
} ClientECDiffieHellmanPublic;
|
||||
*)
|
||||
|
||||
|
||||
{ }
|
||||
{ ClientKeyExchange }
|
||||
{ }
|
||||
{ select (KeyExchangeAlgorithm) }
|
||||
{ case rsa : EncryptedPreMasterSecret; }
|
||||
{ case dhe_dss : }
|
||||
{ case dhe_rsa : }
|
||||
{ case dh_dss : }
|
||||
{ case dh_rsa : }
|
||||
{ case dh_anon : ClientDiffieHellmanPublic; }
|
||||
{ }
|
||||
function EncodeTLSClientKeyExchange(
|
||||
var Buffer; const Size: Integer;
|
||||
const KeyExchangeAlgorithm: TTLSKeyExchangeAlgorithm;
|
||||
const ClientKeyExchange: TTLSClientKeyExchange): Integer;
|
||||
var P : PByte;
|
||||
N, L : Integer;
|
||||
begin
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
case KeyExchangeAlgorithm of
|
||||
tlskeaRSA :
|
||||
begin
|
||||
L := Length(ClientKeyExchange.EncryptedPreMasterSecret);
|
||||
if L = 0 then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter);
|
||||
Move(ClientKeyExchange.EncryptedPreMasterSecret[1], P^, L);
|
||||
Dec(N, L);
|
||||
end;
|
||||
tlskeaDHE_DSS,
|
||||
tlskeaDHE_RSA,
|
||||
tlskeaDH_DSS,
|
||||
tlskeaDH_RSA,
|
||||
tlskeaDH_Anon :
|
||||
begin
|
||||
L := EncodeTLSClientDiffieHellmanPublic(P^, N, ClientKeyExchange.ClientDiffieHellmanPublic);
|
||||
Dec(N, L);
|
||||
end;
|
||||
end;
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
function DecodeTLSClientKeyExchange(
|
||||
const Buffer; const Size: Integer;
|
||||
const KeyExchangeAlgorithm: TTLSKeyExchangeAlgorithm;
|
||||
const PublicValueEncodingExplicit: Boolean;
|
||||
var ClientKeyExchange: TTLSClientKeyExchange): Integer;
|
||||
var P : PByte;
|
||||
N, L, C : Integer;
|
||||
begin
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
case KeyExchangeAlgorithm of
|
||||
tlskeaRSA :
|
||||
begin
|
||||
L := DecodeTLSLen16(P^, N, C);
|
||||
Dec(N, L);
|
||||
Inc(P, L);
|
||||
Assert(N = C);
|
||||
SetLength(ClientKeyExchange.EncryptedPreMasterSecret, C);
|
||||
Move(P^, ClientKeyExchange.EncryptedPreMasterSecret[1], C);
|
||||
Dec(N, C);
|
||||
end;
|
||||
tlskeaDHE_DSS,
|
||||
tlskeaDHE_RSA,
|
||||
tlskeaDH_DSS,
|
||||
tlskeaDH_RSA,
|
||||
tlskeaDH_Anon :
|
||||
begin
|
||||
L := DecodeTLSClientDiffieHellmanPublic(P^, N, PublicValueEncodingExplicit, ClientKeyExchange.ClientDiffieHellmanPublic);
|
||||
Dec(N, L);
|
||||
end;
|
||||
end;
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
end.
|
||||
|
427
contrib/fundamentals/TLS/flcTLSKeys.pas
Normal file
427
contrib/fundamentals/TLS/flcTLSKeys.pas
Normal file
@@ -0,0 +1,427 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSKeys.pas }
|
||||
{ File version: 5.02 }
|
||||
{ Description: TLS Keys }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2020/05/09 5.02 Create flcTLSKeys unit from flcTLSUtils unit. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSKeys;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
{ Utils }
|
||||
|
||||
flcStdTypes,
|
||||
|
||||
{ TLS }
|
||||
|
||||
flcTLSProtocolVersion;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Key block }
|
||||
{ }
|
||||
function tls10KeyBlock(const MasterSecret, ServerRandom, ClientRandom: RawByteString; const Size: Integer): RawByteString;
|
||||
function tls12SHA256KeyBlock(const MasterSecret, ServerRandom, ClientRandom: RawByteString; const Size: Integer): RawByteString;
|
||||
function tls12SHA512KeyBlock(const MasterSecret, ServerRandom, ClientRandom: RawByteString; const Size: Integer): RawByteString;
|
||||
|
||||
function TLSKeyBlock(const ProtocolVersion: TTLSProtocolVersion;
|
||||
const MasterSecret, ServerRandom, ClientRandom: RawByteString; const Size: Integer): RawByteString;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Master secret }
|
||||
{ }
|
||||
function tls10MasterSecret(const PreMasterSecret, ClientRandom, ServerRandom: RawByteString): RawByteString;
|
||||
function tls12SHA256MasterSecret(const PreMasterSecret, ClientRandom, ServerRandom: RawByteString): RawByteString;
|
||||
function tls12SHA512MasterSecret(const PreMasterSecret, ClientRandom, ServerRandom: RawByteString): RawByteString;
|
||||
|
||||
function TLSMasterSecret(const ProtocolVersion: TTLSProtocolVersion;
|
||||
|
||||
const PreMasterSecret, ClientRandom, ServerRandom: RawByteString): RawByteString;
|
||||
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ TLS Keys }
|
||||
{ }
|
||||
type
|
||||
TTLSKeys = record
|
||||
KeyBlock : RawByteString;
|
||||
ClientMACKey : RawByteString;
|
||||
ServerMACKey : RawByteString;
|
||||
ClientEncKey : RawByteString;
|
||||
ServerEncKey : RawByteString;
|
||||
ClientIV : RawByteString;
|
||||
ServerIV : RawByteString;
|
||||
end;
|
||||
|
||||
procedure GenerateTLSKeys(
|
||||
const ProtocolVersion: TTLSProtocolVersion;
|
||||
const MACKeyBits, CipherKeyBits, IVBits: Integer;
|
||||
const MasterSecret, ServerRandom, ClientRandom: RawByteString;
|
||||
var TLSKeys: TTLSKeys);
|
||||
|
||||
procedure GenerateFinalTLSKeys(
|
||||
const ProtocolVersion: TTLSProtocolVersion;
|
||||
const IsExportable: Boolean;
|
||||
const ExpandedKeyBits: Integer;
|
||||
const ServerRandom, ClientRandom: RawByteString;
|
||||
var TLSKeys: TTLSKeys);
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test }
|
||||
{ }
|
||||
{$IFDEF TLS_TEST}
|
||||
|
||||
procedure Test;
|
||||
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{ Utils }
|
||||
|
||||
flcHash,
|
||||
flcStrings,
|
||||
|
||||
{ TLS }
|
||||
|
||||
flcTLSErrors,
|
||||
flcTLSPRF;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Key block }
|
||||
{ }
|
||||
{ SSL 3.0: }
|
||||
{ key_block = }
|
||||
{ MD5(master_secret + SHA('A' + master_secret + }
|
||||
{ ServerHello.random + ClientHello.random)) + }
|
||||
{ MD5(master_secret + SHA('BB' + master_secret + }
|
||||
{ ServerHello.random + ClientHello.random)) + }
|
||||
{ MD5(master_secret + SHA('CCC' + master_secret + }
|
||||
{ ServerHello.random + ClientHello.random)) + }
|
||||
{ [...]; }
|
||||
{ }
|
||||
{ TLS 1.0 / 1.1 / 1.2: }
|
||||
{ key_block = PRF(SecurityParameters.master_secret, }
|
||||
{ "key expansion", }
|
||||
{ SecurityParameters.server_random + }
|
||||
{ SecurityParameters.client_random); }
|
||||
{ }
|
||||
function ssl30KeyBlockP(const Prefix, MasterSecret, ServerRandom, ClientRandom: RawByteString): RawByteString;
|
||||
begin
|
||||
Result :=
|
||||
MD5DigestToStrA(
|
||||
CalcMD5(MasterSecret +
|
||||
SHA1DigestToStrA(
|
||||
CalcSHA1(Prefix + MasterSecret + ServerRandom + ClientRandom))));
|
||||
end;
|
||||
|
||||
function ssl30KeyBlockPF(const MasterSecret, ServerRandom, ClientRandom: RawByteString; const Size: Integer): RawByteString;
|
||||
var Salt : RawByteString;
|
||||
I : Integer;
|
||||
begin
|
||||
Result := '';
|
||||
I := 1;
|
||||
while Length(Result) < Size do
|
||||
begin
|
||||
if I > 26 then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter);
|
||||
Salt := DupCharB(ByteChar(Ord('A') + I - 1), I);
|
||||
Result := Result +
|
||||
ssl30KeyBlockP(Salt, MasterSecret, ServerRandom, ClientRandom);
|
||||
Inc(I);
|
||||
end;
|
||||
SetLength(Result, Size);
|
||||
end;
|
||||
|
||||
function ssl30KeyBlock(const MasterSecret, ServerRandom, ClientRandom: RawByteString; const Size: Integer): RawByteString;
|
||||
begin
|
||||
Result := ssl30KeyBlockPF(MasterSecret, ServerRandom, ClientRandom, Size);
|
||||
end;
|
||||
|
||||
const
|
||||
LabelKeyExpansion = 'key expansion';
|
||||
|
||||
function tls10KeyBlock(const MasterSecret, ServerRandom, ClientRandom: RawByteString; const Size: Integer): RawByteString;
|
||||
var S : RawByteString;
|
||||
begin
|
||||
S := ServerRandom + ClientRandom;
|
||||
Result := tls10PRF(MasterSecret, LabelKeyExpansion, S, Size);
|
||||
end;
|
||||
|
||||
function tls12SHA256KeyBlock(const MasterSecret, ServerRandom, ClientRandom: RawByteString; const Size: Integer): RawByteString;
|
||||
var S : RawByteString;
|
||||
begin
|
||||
S := ServerRandom + ClientRandom;
|
||||
Result := tls12PRF_SHA256(MasterSecret, LabelKeyExpansion, S, Size);
|
||||
end;
|
||||
|
||||
function tls12SHA512KeyBlock(const MasterSecret, ServerRandom, ClientRandom: RawByteString; const Size: Integer): RawByteString;
|
||||
var S : RawByteString;
|
||||
begin
|
||||
S := ServerRandom + ClientRandom;
|
||||
Result := tls12PRF_SHA512(MasterSecret, LabelKeyExpansion, S, Size);
|
||||
end;
|
||||
|
||||
function TLSKeyBlock(const ProtocolVersion: TTLSProtocolVersion;
|
||||
const MasterSecret, ServerRandom, ClientRandom: RawByteString; const Size: Integer): RawByteString;
|
||||
begin
|
||||
if IsTLS12OrLater(ProtocolVersion) then
|
||||
Result := tls12SHA256KeyBlock(MasterSecret, ServerRandom, ClientRandom, Size) else
|
||||
if IsTLS10OrLater(ProtocolVersion) then
|
||||
Result := tls10KeyBlock(MasterSecret, ServerRandom, ClientRandom, Size) else
|
||||
if IsSSL3(ProtocolVersion) then
|
||||
Result := ssl30KeyBlock(MasterSecret, ServerRandom, ClientRandom, Size)
|
||||
else
|
||||
raise ETLSError.Create(TLSError_InvalidParameter);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Master secret }
|
||||
{ }
|
||||
{ SSL 3: }
|
||||
{ master_secret = }
|
||||
{ MD5(pre_master_secret + SHA('A' + pre_master_secret + }
|
||||
{ ClientHello.random + ServerHello.random)) + }
|
||||
{ MD5(pre_master_secret + SHA('BB' + pre_master_secret + }
|
||||
{ ClientHello.random + ServerHello.random)) + }
|
||||
{ MD5(pre_master_secret + SHA('CCC' + pre_master_secret + }
|
||||
{ ClientHello.random + ServerHello.random)); }
|
||||
{ }
|
||||
{ TLS 1.0 1.1 1.2: }
|
||||
{ master_secret = PRF(pre_master_secret, }
|
||||
{ "master secret", }
|
||||
{ ClientHello.random + ServerHello.random) }
|
||||
{ }
|
||||
{ The master secret is always exactly 48 bytes in length. The length of }
|
||||
{ the premaster secret will vary depending on key exchange method. }
|
||||
{ }
|
||||
const
|
||||
LabelMasterSecret = 'master secret';
|
||||
MasterSecretSize = 48;
|
||||
|
||||
function ssl30MasterSecretP(const Prefix, PreMasterSecret, ClientRandom, ServerRandom: RawByteString): RawByteString;
|
||||
begin
|
||||
Result :=
|
||||
MD5DigestToStrA(
|
||||
CalcMD5(PreMasterSecret +
|
||||
SHA1DigestToStrA(
|
||||
CalcSHA1(Prefix + PreMasterSecret + ClientRandom + ServerRandom))));
|
||||
end;
|
||||
|
||||
function ssl30MasterSecret(const PreMasterSecret, ClientRandom, ServerRandom: RawByteString): RawByteString;
|
||||
begin
|
||||
Result :=
|
||||
ssl30MasterSecretP('A', PreMasterSecret, ClientRandom, ServerRandom) +
|
||||
ssl30MasterSecretP('BB', PreMasterSecret, ClientRandom, ServerRandom) +
|
||||
ssl30MasterSecretP('CCC', PreMasterSecret, ClientRandom, ServerRandom);
|
||||
end;
|
||||
|
||||
function tls10MasterSecret(const PreMasterSecret, ClientRandom, ServerRandom: RawByteString): RawByteString;
|
||||
var S : RawByteString;
|
||||
begin
|
||||
S := ClientRandom + ServerRandom;
|
||||
Result := tls10PRF(PreMasterSecret, LabelMasterSecret, S, MasterSecretSize);
|
||||
end;
|
||||
|
||||
function tls12SHA256MasterSecret(const PreMasterSecret, ClientRandom, ServerRandom: RawByteString): RawByteString;
|
||||
var S : RawByteString;
|
||||
begin
|
||||
S := ClientRandom + ServerRandom;
|
||||
Result := tls12PRF_SHA256(PreMasterSecret, LabelMasterSecret, S, MasterSecretSize);
|
||||
end;
|
||||
|
||||
function tls12SHA512MasterSecret(const PreMasterSecret, ClientRandom, ServerRandom: RawByteString): RawByteString;
|
||||
var S : RawByteString;
|
||||
begin
|
||||
S := ClientRandom + ServerRandom;
|
||||
Result := tls12PRF_SHA512(PreMasterSecret, LabelMasterSecret, S, MasterSecretSize);
|
||||
end;
|
||||
|
||||
function TLSMasterSecret(const ProtocolVersion: TTLSProtocolVersion;
|
||||
const PreMasterSecret, ClientRandom, ServerRandom: RawByteString): RawByteString;
|
||||
|
||||
begin
|
||||
|
||||
if IsTLS12OrLater(ProtocolVersion) then
|
||||
|
||||
Result := tls12SHA256MasterSecret(PreMasterSecret, ClientRandom, ServerRandom) else
|
||||
|
||||
if IsTLS10OrLater(ProtocolVersion) then
|
||||
|
||||
Result := tls10MasterSecret(PreMasterSecret, ClientRandom, ServerRandom) else
|
||||
|
||||
if IsSSL3(ProtocolVersion) then
|
||||
|
||||
Result := ssl30MasterSecret(PreMasterSecret, ClientRandom, ServerRandom)
|
||||
|
||||
else
|
||||
|
||||
raise ETLSError.Create(TLSError_InvalidParameter);
|
||||
|
||||
end;
|
||||
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ TLS Keys }
|
||||
{ }
|
||||
procedure GenerateTLSKeys(
|
||||
const ProtocolVersion: TTLSProtocolVersion;
|
||||
const MACKeyBits, CipherKeyBits, IVBits: Integer;
|
||||
const MasterSecret, ServerRandom, ClientRandom: RawByteString;
|
||||
var TLSKeys: TTLSKeys);
|
||||
var L, I, N : Integer;
|
||||
S : RawByteString;
|
||||
begin
|
||||
Assert(MACKeyBits mod 8 = 0);
|
||||
Assert(CipherKeyBits mod 8 = 0);
|
||||
Assert(IVBits mod 8 = 0);
|
||||
|
||||
L := MACKeyBits * 2 + CipherKeyBits * 2 + IVBits * 2;
|
||||
L := L div 8;
|
||||
S := TLSKeyBlock(ProtocolVersion, MasterSecret, ServerRandom, ClientRandom, L);
|
||||
TLSKeys.KeyBlock := S;
|
||||
I := 1;
|
||||
N := MACKeyBits div 8;
|
||||
TLSKeys.ClientMACKey := Copy(S, I, N);
|
||||
TLSKeys.ServerMACKey := Copy(S, I + N, N);
|
||||
Inc(I, N * 2);
|
||||
N := CipherKeyBits div 8;
|
||||
TLSKeys.ClientEncKey := Copy(S, I, N);
|
||||
TLSKeys.ServerEncKey := Copy(S, I + N, N);
|
||||
Inc(I, N * 2);
|
||||
N := IVBits div 8;
|
||||
TLSKeys.ClientIV := Copy(S, I, N);
|
||||
TLSKeys.ServerIV := Copy(S, I + N, N);
|
||||
end;
|
||||
|
||||
{ TLS 1.0: }
|
||||
{ final_client_write_key = PRF(SecurityParameters.client_write_key, }
|
||||
{ "client write key", }
|
||||
{ SecurityParameters.client_random + SecurityParameters.server_random); }
|
||||
{ final_server_write_key = PRF(SecurityParameters.server_write_key, }
|
||||
{ "server write key", }
|
||||
{ SecurityParameters.client_random + SecurityParameters.server_random); }
|
||||
{ iv_block = PRF("", "IV block", }
|
||||
{ SecurityParameters.client_random + SecurityParameters.server_random); }
|
||||
const
|
||||
LabelClientWriteKey = 'client write key';
|
||||
LabelServerWriteKey = 'server write key';
|
||||
LabelIVBlock = 'IV block';
|
||||
|
||||
procedure GenerateFinalTLSKeys(
|
||||
const ProtocolVersion: TTLSProtocolVersion;
|
||||
const IsExportable: Boolean;
|
||||
const ExpandedKeyBits: Integer;
|
||||
const ServerRandom, ClientRandom: RawByteString;
|
||||
var TLSKeys: TTLSKeys);
|
||||
var S : RawByteString;
|
||||
L : Integer;
|
||||
V : RawByteString;
|
||||
begin
|
||||
if IsTLS11OrLater(ProtocolVersion) then
|
||||
exit;
|
||||
if not IsExportable then
|
||||
exit;
|
||||
if IsSSL2(ProtocolVersion) or IsSSL3(ProtocolVersion) then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter, 'Unsupported version');
|
||||
S := ClientRandom + ServerRandom;
|
||||
Assert(ExpandedKeyBits mod 8 = 0);
|
||||
L := ExpandedKeyBits div 8;
|
||||
TLSKeys.ClientEncKey := tls10PRF(TLSKeys.ClientEncKey, LabelClientWriteKey, S, L);
|
||||
TLSKeys.ServerEncKey := tls10PRF(TLSKeys.ServerEncKey, LabelServerWriteKey, S, L);
|
||||
L := Length(TLSKeys.ClientIV);
|
||||
if L > 0 then
|
||||
begin
|
||||
V := tls10PRF('', LabelIVBlock, S, L * 2);
|
||||
TLSKeys.ClientIV := Copy(V, 1, L);
|
||||
TLSKeys.ServerIV := Copy(V, L + 1, L);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test }
|
||||
{ }
|
||||
{$IFDEF TLS_TEST}
|
||||
{$ASSERTIONS ON}
|
||||
const
|
||||
PreMasterSecret = RawByteString(
|
||||
#$03#$01#$84#$54#$F5#$D6#$EB#$F5#$A8#$08#$BA#$FA#$7A#$22#$61#$2D +
|
||||
#$75#$DC#$40#$E8#$98#$F9#$0E#$B2#$87#$80#$B8#$1A#$8F#$68#$25#$B8 +
|
||||
#$51#$D0#$54#$45#$61#$8A#$50#$C9#$BB#$0E#$39#$53#$45#$78#$BE#$79);
|
||||
ClientRandom = RawByteString(
|
||||
#$40#$FC#$30#$AE#$2D#$63#$84#$BB#$C5#$4B#$27#$FD#$58#$21#$CA#$90 +
|
||||
#$05#$F6#$A7#$7B#$37#$BB#$72#$E1#$FC#$1D#$1B#$6A#$F5#$1C#$C8#$9F);
|
||||
ServerRandom = RawByteString(
|
||||
#$40#$FC#$31#$10#$79#$AB#$17#$66#$FA#$8B#$3F#$AA#$FD#$5E#$48#$23 +
|
||||
#$FA#$90#$31#$D8#$3C#$B9#$A3#$2C#$8C#$F5#$E9#$81#$9B#$A2#$63#$6C);
|
||||
MasterSecret = RawByteString(
|
||||
#$B0#$00#$22#$34#$59#$03#$16#$B7#$7A#$6C#$56#$9B#$89#$D2#$7A#$CC +
|
||||
#$F3#$85#$55#$59#$3A#$14#$76#$3D#$54#$BF#$EB#$3F#$E0#$2F#$B1#$4B +
|
||||
#$79#$8C#$75#$A9#$78#$55#$6C#$8E#$A2#$14#$60#$B7#$45#$EB#$77#$B2);
|
||||
MACWriteKey = RawByteString(
|
||||
#$85#$F0#$56#$F8#$07#$1D#$B1#$89#$89#$D0#$E1#$33#$3C#$CA#$63#$F9);
|
||||
|
||||
procedure TestKeyBlock;
|
||||
|
||||
var S : RawByteString;
|
||||
|
||||
begin
|
||||
|
||||
// //
|
229
contrib/fundamentals/TLS/flcTLSOpaqueEncoding.pas
Normal file
229
contrib/fundamentals/TLS/flcTLSOpaqueEncoding.pas
Normal file
@@ -0,0 +1,229 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSOpaqueEncoding.pas }
|
||||
{ File version: 5.02 }
|
||||
{ Description: TLS Opaque Encoding }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2020/05/09 5.02 Create flcTLSOpaqueEncoding unit from flcTLSUtils unit. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSOpaqueEncoding;
|
||||
|
||||
interface
|
||||
|
||||
|
||||
|
||||
function EncodeTLSWord16(var Buffer; const Size: Integer; const AVal: Integer): Integer;
|
||||
function DecodeTLSWord16(const Buffer; const Size: Integer; var AVal: Integer): Integer;
|
||||
|
||||
function EncodeTLSLen16(var Buffer; const Size: Integer; const ALen: Integer): Integer;
|
||||
function EncodeTLSLen24(var Buffer; const Size: Integer; const ALen: Integer): Integer;
|
||||
|
||||
function DecodeTLSLen16(const Buffer; const Size: Integer; var ALen: Integer): Integer;
|
||||
function DecodeTLSLen24(const Buffer; const Size: Integer; var ALen: Integer): Integer;
|
||||
|
||||
function EncodeTLSOpaque16(var Buffer; const Size: Integer; const A: RawByteString): Integer;
|
||||
function EncodeTLSOpaque24(var Buffer; const Size: Integer; const A: RawByteString): Integer;
|
||||
|
||||
function DecodeTLSOpaque16(const Buffer; const Size: Integer; var A: RawByteString): Integer;
|
||||
function DecodeTLSOpaque24(const Buffer; const Size: Integer; var A: RawByteString): Integer;
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
|
||||
uses
|
||||
{ TLS }
|
||||
|
||||
flcTLSAlert,
|
||||
flcTLSErrors;
|
||||
|
||||
|
||||
|
||||
function EncodeTLSWord16(var Buffer; const Size: Integer; const AVal: Integer): Integer;
|
||||
var
|
||||
P : PByte;
|
||||
begin
|
||||
Assert(AVal >= 0);
|
||||
Assert(AVal <= $FFFF);
|
||||
|
||||
if Size < 2 then
|
||||
raise ETLSError.CreateAlertBufferEncode;
|
||||
P := @Buffer;
|
||||
P^ := (AVal and $FF00) shr 8;
|
||||
Inc(P);
|
||||
P^ := (AVal and $00FF);
|
||||
Result := 2;
|
||||
end;
|
||||
|
||||
function DecodeTLSWord16(const Buffer; const Size: Integer; var AVal: Integer): Integer;
|
||||
var
|
||||
P : PByte;
|
||||
begin
|
||||
if Size < 2 then
|
||||
raise ETLSError.CreateAlertBufferDecode;
|
||||
P := @Buffer;
|
||||
AVal := P^ shl 8;
|
||||
Inc(P);
|
||||
Inc(AVal, P^);
|
||||
Result := 2;
|
||||
end;
|
||||
|
||||
function EncodeTLSLen16(var Buffer; const Size: Integer; const ALen: Integer): Integer;
|
||||
begin
|
||||
Result := EncodeTLSWord16(Buffer, Size, ALen);
|
||||
end;
|
||||
|
||||
function EncodeTLSLen24(var Buffer; const Size: Integer; const ALen: Integer): Integer;
|
||||
var
|
||||
P : PByte;
|
||||
begin
|
||||
Assert(ALen >= 0);
|
||||
Assert(ALen <= $FFFFFF);
|
||||
|
||||
if Size < 3 then
|
||||
raise ETLSError.CreateAlertBufferEncode;
|
||||
P := @Buffer;
|
||||
P^ := (ALen and $FF0000) shr 16;
|
||||
Inc(P);
|
||||
P^ := (ALen and $00FF00) shr 8;
|
||||
Inc(P);
|
||||
P^ := (ALen and $0000FF);
|
||||
Result := 3;
|
||||
end;
|
||||
|
||||
function DecodeTLSLen16(const Buffer; const Size: Integer; var ALen: Integer): Integer;
|
||||
begin
|
||||
Result := DecodeTLSWord16(Buffer, Size, ALen);
|
||||
end;
|
||||
|
||||
function DecodeTLSLen24(const Buffer; const Size: Integer; var ALen: Integer): Integer;
|
||||
var
|
||||
P : PByte;
|
||||
begin
|
||||
if Size < 3 then
|
||||
raise ETLSError.CreateAlertBufferDecode;
|
||||
P := @Buffer;
|
||||
ALen := P^ shl 16;
|
||||
Inc(P);
|
||||
Inc(ALen, P^ shl 8);
|
||||
Inc(P);
|
||||
Inc(ALen, P^);
|
||||
Result := 3;
|
||||
end;
|
||||
|
||||
function EncodeTLSOpaque16(var Buffer; const Size: Integer; const A: RawByteString): Integer;
|
||||
var
|
||||
P : PByte;
|
||||
N, L : Integer;
|
||||
begin
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
L := Length(A);
|
||||
EncodeTLSLen16(P^, N, L);
|
||||
Inc(P, 2);
|
||||
Dec(N, 2);
|
||||
Dec(N, L);
|
||||
if N < 0 then
|
||||
raise ETLSError.CreateAlertBufferEncode;
|
||||
if L > 0 then
|
||||
Move(Pointer(A)^, P^, L);
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
function EncodeTLSOpaque24(var Buffer; const Size: Integer; const A: RawByteString): Integer;
|
||||
var
|
||||
P : PByte;
|
||||
N, L : Integer;
|
||||
begin
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
L := Length(A);
|
||||
EncodeTLSLen24(P^, N, L);
|
||||
Inc(P, 3);
|
||||
Dec(N, 3);
|
||||
Dec(N, L);
|
||||
if N < 0 then
|
||||
raise ETLSError.CreateAlertBufferEncode;
|
||||
if L > 0 then
|
||||
Move(Pointer(A)^, P^, L);
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
function DecodeTLSOpaque16(const Buffer; const Size: Integer; var A: RawByteString): Integer;
|
||||
var
|
||||
P : PByte;
|
||||
N, L : Integer;
|
||||
begin
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
DecodeTLSLen16(P^, N, L);
|
||||
Inc(P, 2);
|
||||
Dec(N, 2);
|
||||
Dec(N, L);
|
||||
if N < 0 then
|
||||
raise ETLSError.CreateAlertBufferDecode;
|
||||
SetLength(A, L);
|
||||
if L > 0 then
|
||||
Move(P^, Pointer(A)^, L);
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
function DecodeTLSOpaque24(const Buffer; const Size: Integer; var A: RawByteString): Integer;
|
||||
var
|
||||
P : PByte;
|
||||
N, L : Integer;
|
||||
begin
|
||||
N := Size;
|
||||
P := @Buffer;
|
||||
DecodeTLSLen24(P^, N, L);
|
||||
Inc(P, 3);
|
||||
Dec(N, 3);
|
||||
Dec(N, L);
|
||||
if N < 0 then
|
||||
raise ETLSError.CreateAlertBufferDecode;
|
||||
SetLength(A, L);
|
||||
if L > 0 then
|
||||
Move(P^, Pointer(A)^, L);
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
end.
|
||||
|
315
contrib/fundamentals/TLS/flcTLSPRF.pas
Normal file
315
contrib/fundamentals/TLS/flcTLSPRF.pas
Normal file
@@ -0,0 +1,315 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSPRF.pas }
|
||||
{ File version: 5.02 }
|
||||
{ Description: TLS PRF (Pseudo Random Function) }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2020/05/09 5.02 Create flcTLSPRF unit from flcTLSUtils unit. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSPRF;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
{ Utils }
|
||||
|
||||
flcStdTypes,
|
||||
|
||||
{ TLS }
|
||||
|
||||
flcTLSProtocolVersion;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ PRFAlgorithm }
|
||||
|
||||
{ }
|
||||
|
||||
type
|
||||
|
||||
TTLSPRFAlgorithm = (
|
||||
|
||||
tlspaSHA256
|
||||
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
|
||||
{ PRF (Pseudo-Random Function) }
|
||||
{ }
|
||||
function tlsP_MD5(const Secret, Seed: RawByteString; const Size: Integer): RawByteString;
|
||||
function tlsP_SHA1(const Secret, Seed: RawByteString; const Size: Integer): RawByteString;
|
||||
function tlsP_SHA256(const Secret, Seed: RawByteString; const Size: Integer): RawByteString;
|
||||
function tlsP_SHA512(const Secret, Seed: RawByteString; const Size: Integer): RawByteString;
|
||||
|
||||
function tls10PRF(const Secret, ALabel, Seed: RawByteString; const Size: Integer): RawByteString;
|
||||
function tls12PRF_SHA256(const Secret, ALabel, Seed: RawByteString; const Size: Integer): RawByteString;
|
||||
function tls12PRF_SHA512(const Secret, ALabel, Seed: RawByteString; const Size: Integer): RawByteString;
|
||||
|
||||
function TLSPRF(const ProtocolVersion: TTLSProtocolVersion;
|
||||
const Secret, ALabel, Seed: RawByteString; const Size: Integer): RawByteString;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test }
|
||||
{ }
|
||||
{$IFDEF TLS_TEST}
|
||||
procedure Test;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{ Utils }
|
||||
|
||||
flcHash,
|
||||
|
||||
{ TLS }
|
||||
|
||||
flcTLSErrors;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ P_hash }
|
||||
|
||||
{ P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + }
|
||||
{ HMAC_hash(secret, A(2) + seed) + }
|
||||
{ HMAC_hash(secret, A(3) + seed) + ... }
|
||||
{ Where + indicates concatenation. }
|
||||
{ A() is defined as: }
|
||||
{ A(0) = seed }
|
||||
{ A(i) = HMAC_hash(secret, A(i-1)) }
|
||||
{ }
|
||||
function tlsP_MD5(const Secret, Seed: RawByteString; const Size: Integer): RawByteString;
|
||||
var A, P : RawByteString;
|
||||
L : Integer;
|
||||
begin
|
||||
P := '';
|
||||
L := 0;
|
||||
A := Seed;
|
||||
repeat
|
||||
A := MD5DigestToStrA(CalcHMAC_MD5(Secret, A));
|
||||
P := P + MD5DigestToStrA(CalcHMAC_MD5(Secret, A + Seed));
|
||||
Inc(L, 16);
|
||||
until L >= Size;
|
||||
if L > Size then
|
||||
SetLength(P, Size);
|
||||
Result := P;
|
||||
end;
|
||||
|
||||
function tlsP_SHA1(const Secret, Seed: RawByteString; const Size: Integer): RawByteString;
|
||||
var A, P : RawByteString;
|
||||
L : Integer;
|
||||
begin
|
||||
P := '';
|
||||
L := 0;
|
||||
A := Seed;
|
||||
repeat
|
||||
A := SHA1DigestToStrA(CalcHMAC_SHA1(Secret, A));
|
||||
P := P + SHA1DigestToStrA(CalcHMAC_SHA1(Secret, A + Seed));
|
||||
Inc(L, 20);
|
||||
until L >= Size;
|
||||
if L > Size then
|
||||
SetLength(P, Size);
|
||||
Result := P;
|
||||
end;
|
||||
|
||||
function tlsP_SHA256(const Secret, Seed: RawByteString; const Size: Integer): RawByteString;
|
||||
var A, P : RawByteString;
|
||||
L : Integer;
|
||||
begin
|
||||
P := '';
|
||||
L := 0;
|
||||
A := Seed;
|
||||
repeat
|
||||
A := SHA256DigestToStrA(CalcHMAC_SHA256(Secret, A));
|
||||
P := P + SHA256DigestToStrA(CalcHMAC_SHA256(Secret, A + Seed));
|
||||
Inc(L, 32);
|
||||
until L >= Size;
|
||||
if L > Size then
|
||||
SetLength(P, Size);
|
||||
Result := P;
|
||||
end;
|
||||
|
||||
function tlsP_SHA512(const Secret, Seed: RawByteString; const Size: Integer): RawByteString;
|
||||
var A, P : RawByteString;
|
||||
L : Integer;
|
||||
begin
|
||||
P := '';
|
||||
L := 0;
|
||||
A := Seed;
|
||||
repeat
|
||||
A := SHA512DigestToStrA(CalcHMAC_SHA512(Secret, A));
|
||||
P := P + SHA512DigestToStrA(CalcHMAC_SHA512(Secret, A + Seed));
|
||||
Inc(L, 64);
|
||||
until L >= Size;
|
||||
if L > Size then
|
||||
SetLength(P, Size);
|
||||
Result := P;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ PRF }
|
||||
{ TLS 1.0: }
|
||||
{ PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR }
|
||||
{ P_SHA-1(S2, label + seed); }
|
||||
{ S1 and S2 are the two halves of the secret and each is the same length. }
|
||||
{ S1 is taken from the first half of the secret, S2 from the second half. }
|
||||
{ Their length is created by rounding up the length of the overall secret }
|
||||
{ divided by two; thus, if the original secret is an odd number of bytes }
|
||||
{ long, the last byte of S1 will be the same as the first byte of S2. }
|
||||
{ }
|
||||
{ TLS 1.2: }
|
||||
{ PRF(secret, label, seed) = P_<hash>(secret, label + seed) }
|
||||
{ P_SHA-256 }
|
||||
{ }
|
||||
procedure tls10PRFSplitSecret(const Secret: RawByteString; var S1, S2: RawByteString);
|
||||
var L, N : Integer;
|
||||
begin
|
||||
N := Length(Secret);
|
||||
L := N;
|
||||
if L mod 2 = 1 then
|
||||
Inc(L);
|
||||
L := L div 2;
|
||||
S1 := Copy(Secret, 1, L);
|
||||
S2 := Copy(Secret, N - L + 1, L);
|
||||
end;
|
||||
|
||||
function tls10PRF(const Secret, ALabel, Seed: RawByteString; const Size: Integer): RawByteString;
|
||||
var S1, S2 : RawByteString;
|
||||
P1, P2 : RawByteString;
|
||||
R : RawByteString;
|
||||
I : Integer;
|
||||
begin
|
||||
tls10PRFSplitSecret(Secret, S1, S2);
|
||||
P1 := tlsP_MD5(S1, ALabel + Seed, Size);
|
||||
P2 := tlsP_SHA1(S2, ALabel + Seed, Size);
|
||||
SetLength(R, Size);
|
||||
for I := 1 to Size do
|
||||
R[I] := AnsiChar(Byte(P1[I]) xor Byte(P2[I]));
|
||||
Result := R;
|
||||
end;
|
||||
|
||||
function tls12PRF_SHA256(const Secret, ALabel, Seed: RawByteString; const Size: Integer): RawByteString;
|
||||
begin
|
||||
Result := tlsP_SHA256(Secret, ALabel + Seed, Size);
|
||||
end;
|
||||
|
||||
function tls12PRF_SHA512(const Secret, ALabel, Seed: RawByteString; const Size: Integer): RawByteString;
|
||||
begin
|
||||
Result := tlsP_SHA512(Secret, ALabel + Seed, Size);
|
||||
end;
|
||||
|
||||
function TLSPRF(const ProtocolVersion: TTLSProtocolVersion;
|
||||
const Secret, ALabel, Seed: RawByteString; const Size: Integer): RawByteString;
|
||||
begin
|
||||
if IsTLS12OrLater(ProtocolVersion) then
|
||||
Result := tls12PRF_SHA256(Secret, ALabel, Seed, Size) else
|
||||
if IsTLS10OrLater(ProtocolVersion) then
|
||||
Result := tls10PRF(Secret, ALabel, Seed, Size)
|
||||
else
|
||||
raise ETLSError.Create(TLSError_InvalidParameter);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test }
|
||||
{ }
|
||||
{$IFDEF TLS_TEST}
|
||||
{$ASSERTIONS ON}
|
||||
procedure Test;
|
||||
begin
|
||||
// //
|
||||
// Test vectors from http://www6.ietf.org/mail-archive/web/tls/current/msg03416.html //
|
||||
// //
|
||||
Assert(tls12PRF_SHA256(
|
||||
RawByteString(#$9b#$be#$43#$6b#$a9#$40#$f0#$17#$b1#$76#$52#$84#$9a#$71#$db#$35),
|
||||
'test label',
|
||||
RawByteString(#$a0#$ba#$9f#$93#$6c#$da#$31#$18#$27#$a6#$f7#$96#$ff#$d5#$19#$8c), 100) =
|
||||
#$e3#$f2#$29#$ba#$72#$7b#$e1#$7b +
|
||||
#$8d#$12#$26#$20#$55#$7c#$d4#$53 +
|
||||
#$c2#$aa#$b2#$1d#$07#$c3#$d4#$95 +
|
||||
#$32#$9b#$52#$d4#$e6#$1e#$db#$5a +
|
||||
#$6b#$30#$17#$91#$e9#$0d#$35#$c9 +
|
||||
#$c9#$a4#$6b#$4e#$14#$ba#$f9#$af +
|
||||
#$0f#$a0#$22#$f7#$07#$7d#$ef#$17 +
|
||||
#$ab#$fd#$37#$97#$c0#$56#$4b#$ab +
|
||||
#$4f#$bc#$91#$66#$6e#$9d#$ef#$9b +
|
||||
#$97#$fc#$e3#$4f#$79#$67#$89#$ba +
|
||||
#$a4#$80#$82#$d1#$22#$ee#$42#$c5 +
|
||||
#$a7#$2e#$5a#$51#$10#$ff#$f7#$01 +
|
||||
#$87#$34#$7b#$66);
|
||||
Assert(tls12PRF_SHA512(
|
||||
RawByteString(#$b0#$32#$35#$23#$c1#$85#$35#$99#$58#$4d#$88#$56#$8b#$bb#$05#$eb),
|
||||
'test label',
|
||||
RawByteString(#$d4#$64#$0e#$12#$e4#$bc#$db#$fb#$43#$7f#$03#$e6#$ae#$41#$8e#$e5), 196) =
|
||||
#$12#$61#$f5#$88#$c7#$98#$c5#$c2 +
|
||||
#$01#$ff#$03#$6e#$7a#$9c#$b5#$ed +
|
||||
#$cd#$7f#$e3#$f9#$4c#$66#$9a#$12 +
|
||||
#$2a#$46#$38#$d7#$d5#$08#$b2#$83 +
|
||||
#$04#$2d#$f6#$78#$98#$75#$c7#$14 +
|
||||
#$7e#$90#$6d#$86#$8b#$c7#$5c#$45 +
|
||||
#$e2#$0e#$b4#$0c#$1c#$f4#$a1#$71 +
|
||||
#$3b#$27#$37#$1f#$68#$43#$25#$92 +
|
||||
#$f7#$dc#$8e#$a8#$ef#$22#$3e#$12 +
|
||||
#$ea#$85#$07#$84#$13#$11#$bf#$68 +
|
||||
#$65#$3d#$0c#$fc#$40#$56#$d8#$11 +
|
||||
#$f0#$25#$c4#$5d#$df#$a6#$e6#$fe +
|
||||
#$c7#$02#$f0#$54#$b4#$09#$d6#$f2 +
|
||||
#$8d#$d0#$a3#$23#$3e#$49#$8d#$a4 +
|
||||
#$1a#$3e#$75#$c5#$63#$0e#$ed#$be +
|
||||
#$22#$fe#$25#$4e#$33#$a1#$b0#$e9 +
|
||||
#$f6#$b9#$82#$66#$75#$be#$c7#$d0 +
|
||||
#$1a#$84#$56#$58#$dc#$9c#$39#$75 +
|
||||
#$45#$40#$1d#$40#$b9#$f4#$6c#$7a +
|
||||
#$40#$0e#$e1#$b8#$f8#$1c#$a0#$a6 +
|
||||
#$0d#$1a#$39#$7a#$10#$28#$bf#$f5 +
|
||||
#$d2#$ef#$50#$66#$12#$68#$42#$fb +
|
||||
#$8d#$a4#$19#$76#$32#$bd#$b5#$4f +
|
||||
#$f6#$63#$3f#$86#$bb#$c8#$36#$e6 +
|
259
contrib/fundamentals/TLS/flcTLSProtocolVersion.pas
Normal file
259
contrib/fundamentals/TLS/flcTLSProtocolVersion.pas
Normal file
@@ -0,0 +1,259 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSProtocolVersion.pas }
|
||||
{ File version: 5.02 }
|
||||
{ Description: TLS Protocol Version }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2020/05/09 5.02 Create flcTLSProtocolVersion unit from flcTLSUtils unit. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSProtocolVersion;
|
||||
|
||||
interface
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ProtocolVersion }
|
||||
{ }
|
||||
type
|
||||
TTLSProtocolVersion = packed record
|
||||
major, minor : Byte;
|
||||
end;
|
||||
PTLSProtocolVersion = ^TTLSProtocolVersion;
|
||||
|
||||
const
|
||||
TLSProtocolVersionSize = Sizeof(TTLSProtocolVersion);
|
||||
|
||||
SSLProtocolVersion20 : TTLSProtocolVersion = (major: 0; minor: 2);
|
||||
SSLProtocolVersion30 : TTLSProtocolVersion = (major: 3; minor: 0);
|
||||
TLSProtocolVersion10 : TTLSProtocolVersion = (major: 3; minor: 1);
|
||||
TLSProtocolVersion11 : TTLSProtocolVersion = (major: 3; minor: 2);
|
||||
TLSProtocolVersion12 : TTLSProtocolVersion = (major: 3; minor: 3);
|
||||
TLSProtocolVersion13 : TTLSProtocolVersion = (major: 3; minor: 4);
|
||||
|
||||
procedure InitSSLProtocolVersion30(var A: TTLSProtocolVersion);
|
||||
procedure InitTLSProtocolVersion10(var A: TTLSProtocolVersion);
|
||||
procedure InitTLSProtocolVersion11(var A: TTLSProtocolVersion);
|
||||
procedure InitTLSProtocolVersion12(var A: TTLSProtocolVersion);
|
||||
function IsTLSProtocolVersion(const A, B: TTLSProtocolVersion): Boolean;
|
||||
function IsSSL2(const A: TTLSProtocolVersion): Boolean;
|
||||
function IsSSL3(const A: TTLSProtocolVersion): Boolean;
|
||||
function IsTLS10(const A: TTLSProtocolVersion): Boolean;
|
||||
function IsTLS11(const A: TTLSProtocolVersion): Boolean;
|
||||
function IsTLS12(const A: TTLSProtocolVersion): Boolean;
|
||||
function IsTLS13(const A: TTLSProtocolVersion): Boolean;
|
||||
function IsTLS10OrLater(const A: TTLSProtocolVersion): Boolean;
|
||||
function IsTLS11OrLater(const A: TTLSProtocolVersion): Boolean;
|
||||
function IsTLS12OrLater(const A: TTLSProtocolVersion): Boolean;
|
||||
function IsPostTLS12(const A: TTLSProtocolVersion): Boolean;
|
||||
function IsKnownTLSVersion(const A: TTLSProtocolVersion): Boolean; ////
|
||||
function TLSProtocolVersionToStr(const A: TTLSProtocolVersion): String;
|
||||
function TLSProtocolVersionName(const A: TTLSProtocolVersion): String;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Tests }
|
||||
{ }
|
||||
{$IFDEF TLS_TEST}
|
||||
procedure Test;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{ System }
|
||||
|
||||
SysUtils;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ProtocolVersion }
|
||||
{ }
|
||||
procedure InitSSLProtocolVersion30(var A: TTLSProtocolVersion);
|
||||
begin
|
||||
A := SSLProtocolVersion30;
|
||||
end;
|
||||
|
||||
procedure InitTLSProtocolVersion10(var A: TTLSProtocolVersion);
|
||||
begin
|
||||
A := TLSProtocolVersion10;
|
||||
end;
|
||||
|
||||
procedure InitTLSProtocolVersion11(var A: TTLSProtocolVersion);
|
||||
begin
|
||||
A := TLSProtocolVersion11;
|
||||
end;
|
||||
|
||||
procedure InitTLSProtocolVersion12(var A: TTLSProtocolVersion);
|
||||
begin
|
||||
A := TLSProtocolVersion12;
|
||||
end;
|
||||
|
||||
function IsTLSProtocolVersion(const A, B: TTLSProtocolVersion): Boolean;
|
||||
begin
|
||||
Result :=
|
||||
(A.major = B.major) and
|
||||
(A.minor = B.minor);
|
||||
end;
|
||||
|
||||
function IsSSL2(const A: TTLSProtocolVersion): Boolean;
|
||||
begin
|
||||
Result := IsTLSProtocolVersion(A, SSLProtocolVersion20);
|
||||
end;
|
||||
|
||||
function IsSSL3(const A: TTLSProtocolVersion): Boolean;
|
||||
begin
|
||||
Result := IsTLSProtocolVersion(A, SSLProtocolVersion30);
|
||||
end;
|
||||
|
||||
function IsTLS10(const A: TTLSProtocolVersion): Boolean;
|
||||
begin
|
||||
Result := IsTLSProtocolVersion(A, TLSProtocolVersion10);
|
||||
end;
|
||||
|
||||
function IsTLS11(const A: TTLSProtocolVersion): Boolean;
|
||||
begin
|
||||
Result := IsTLSProtocolVersion(A, TLSProtocolVersion11);
|
||||
end;
|
||||
|
||||
function IsTLS12(const A: TTLSProtocolVersion): Boolean;
|
||||
begin
|
||||
Result := IsTLSProtocolVersion(A, TLSProtocolVersion12);
|
||||
end;
|
||||
|
||||
function IsTLS13(const A: TTLSProtocolVersion): Boolean;
|
||||
begin
|
||||
Result := IsTLSProtocolVersion(A, TLSProtocolVersion13);
|
||||
end;
|
||||
|
||||
function IsTLS10OrLater(const A: TTLSProtocolVersion): Boolean;
|
||||
begin
|
||||
Result :=
|
||||
((A.major = TLSProtocolVersion10.major) and
|
||||
(A.minor >= TLSProtocolVersion10.minor))
|
||||
or
|
||||
(A.major > TLSProtocolVersion10.major);
|
||||
end;
|
||||
|
||||
function IsTLS11OrLater(const A: TTLSProtocolVersion): Boolean;
|
||||
begin
|
||||
Result :=
|
||||
((A.major = TLSProtocolVersion11.major) and
|
||||
(A.minor >= TLSProtocolVersion11.minor))
|
||||
or
|
||||
(A.major > TLSProtocolVersion11.major);
|
||||
end;
|
||||
|
||||
function IsTLS12OrLater(const A: TTLSProtocolVersion): Boolean;
|
||||
begin
|
||||
Result :=
|
||||
((A.major = TLSProtocolVersion12.major) and
|
||||
(A.minor >= TLSProtocolVersion12.minor))
|
||||
or
|
||||
(A.major > TLSProtocolVersion12.major);
|
||||
end;
|
||||
|
||||
function IsPostTLS12(const A: TTLSProtocolVersion): Boolean;
|
||||
begin
|
||||
Result :=
|
||||
((A.major = TLSProtocolVersion12.major) and
|
||||
(A.minor > TLSProtocolVersion12.minor))
|
||||
or
|
||||
(A.major > TLSProtocolVersion12.major);
|
||||
end;
|
||||
|
||||
function IsKnownTLSVersion(const A: TTLSProtocolVersion): Boolean;
|
||||
begin
|
||||
Result := IsTLS12(A) or IsTLS11(A) or IsTLS10(A) or IsSSL3(A);
|
||||
end;
|
||||
|
||||
function TLSProtocolVersionToStr(const A: TTLSProtocolVersion): String;
|
||||
begin
|
||||
Result := IntToStr(A.major) + '.' + IntToStr(A.minor);
|
||||
end;
|
||||
|
||||
function TLSProtocolVersionName(const A: TTLSProtocolVersion): String;
|
||||
begin
|
||||
if IsSSL2(A) then
|
||||
Result := 'SSL2' else
|
||||
if IsSSL3(A) then
|
||||
Result := 'SSL3' else
|
||||
if IsTLS10(A) then
|
||||
Result := 'TLS1.0' else
|
||||
if IsTLS11(A) then
|
||||
Result := 'TLS1.1' else
|
||||
if IsTLS12(A) then
|
||||
Result := 'TLS1.2'
|
||||
else
|
||||
if IsTLS13(A) then
|
||||
Result := 'TLS1.3'
|
||||
else
|
||||
Result := '[TLS' + TLSProtocolVersionToStr(A) + ']';
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Tests }
|
||||
{ }
|
||||
{$IFDEF TLS_TEST}
|
||||
{$ASSERTIONS ON}
|
||||
procedure Test;
|
||||
begin
|
||||
|
||||
Assert(TLSProtocolVersionSize = 2);
|
||||
|
||||
|
||||
Assert(IsTLS12OrLater(TLSProtocolVersion12));
|
||||
|
||||
Assert(not IsTLS12OrLater(TLSProtocolVersion10));
|
||||
|
||||
|
||||
Assert(TLSProtocolVersionToStr(TLSProtocolVersion12) = '3.3');
|
||||
|
||||
|
||||
Assert(TLSProtocolVersionName(SSLProtocolVersion20) = 'SSL2');
|
||||
|
||||
Assert(TLSProtocolVersionName(SSLProtocolVersion30) = 'SSL3');
|
||||
|
||||
Assert(TLSProtocolVersionName(TLSProtocolVersion10) = 'TLS1.0');
|
132
contrib/fundamentals/TLS/flcTLSRandom.pas
Normal file
132
contrib/fundamentals/TLS/flcTLSRandom.pas
Normal file
@@ -0,0 +1,132 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSRandom.pas }
|
||||
{ File version: 5.02 }
|
||||
{ Description: TLS Random }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2020/05/09 5.02 Create flcTLSRandom unit from flcTLSUtils unit. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSRandom;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
{ Utils }
|
||||
|
||||
flcStdTypes;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Random }
|
||||
{ }
|
||||
type
|
||||
TTLSRandom = packed record
|
||||
gmt_unix_time : Word32;
|
||||
random_bytes : array[0..27] of Byte;
|
||||
end;
|
||||
PTLSRandom = ^TTLSRandom;
|
||||
|
||||
const
|
||||
TLSRandomSize = Sizeof(TTLSRandom);
|
||||
|
||||
procedure InitTLSRandom(var Random: TTLSRandom);
|
||||
function TLSRandomToStr(const Random: TTLSRandom): RawByteString;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test }
|
||||
{ }
|
||||
{$IFDEF TLS_TEST}
|
||||
procedure Test;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{ System }
|
||||
|
||||
SysUtils,
|
||||
|
||||
{ Cipher }
|
||||
|
||||
flcCipherRandom;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Random }
|
||||
{ gmt_unix_time The current time and date in standard UNIX }
|
||||
{ 32-bit format according to the sender's }
|
||||
{ internal clock. Clocks are not required to be }
|
||||
{ set correctly by the basic SSL Protocol; higher }
|
||||
{ level or application protocols may define }
|
||||
{ additional requirements. }
|
||||
{ random_bytes 28 bytes generated by a secure random number }
|
||||
{ generator. }
|
||||
{ }
|
||||
procedure InitTLSRandom(var Random: TTLSRandom);
|
||||
begin
|
||||
Random.gmt_unix_time := Word32(DateTimeToFileDate(Now));
|
||||
SecureRandomBuf(Random.random_bytes, SizeOf(Random.random_bytes));
|
||||
end;
|
||||
|
||||
|
||||
function TLSRandomToStr(const Random: TTLSRandom): RawByteString;
|
||||
|
||||
begin
|
||||
|
||||
SetLength(Result, TLSRandomSize);
|
||||
|
||||
Move(Random, Result[1], TLSRandomSize);
|
||||
|
||||
end;
|
||||
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test }
|
||||
{ }
|
||||
{$IFDEF TLS_TEST}
|
||||
{$ASSERTIONS ON}
|
||||
procedure Test;
|
||||
begin
|
968
contrib/fundamentals/TLS/flcTLSRecord.pas
Normal file
968
contrib/fundamentals/TLS/flcTLSRecord.pas
Normal file
@@ -0,0 +1,968 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSRecord.pas }
|
||||
{ File version: 5.08 }
|
||||
{ Description: TLS records }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2010/11/30 0.02 Stream cipher. }
|
||||
{ 2010/12/01 0.03 Block cipher for TLS 1.0. }
|
||||
{ 2010/12/02 0.04 Block cipher for TLS 1.1 and TLS 1.2. }
|
||||
{ 2010/12/17 0.05 Fixes for TLS 1.1 and TLS 1.2 block ciphers. }
|
||||
{ 2011/10/11 0.06 Fixes for TLS 1.1 block cipher encoding. }
|
||||
{ 2011/10/12 0.07 MAC validation on decoding. }
|
||||
{ 2018/07/17 5.08 Revised for Fundamentals 5. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSRecord;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
{ TLS }
|
||||
|
||||
flcTLSProtocolVersion,
|
||||
flcTLSAlgorithmTypes,
|
||||
flcTLSCipherSuite,
|
||||
flcTLSCipher;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ContentType }
|
||||
{ }
|
||||
type
|
||||
TTLSContentType = (
|
||||
tlsctInvalid = 0,
|
||||
tlsctChange_cipher_spec = 20,
|
||||
tlsctAlert = 21,
|
||||
tlsctHandshake = 22,
|
||||
tlsctApplication_data = 23,
|
||||
tlsctHeartbeat = 24, // RFC 6520
|
||||
tlsctMax = 255
|
||||
);
|
||||
PTLSContentType = ^TTLSContentType;
|
||||
|
||||
const
|
||||
TLSContentTypeSize = Sizeof(TTLSContentType);
|
||||
|
||||
function TLSContentTypeToStr(const A: TTLSContentType): String;
|
||||
function IsKnownTLSContentType(const A: TTLSContentType): Boolean;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ TLS Record Header }
|
||||
{ }
|
||||
type
|
||||
TTLSRecordHeader = packed record
|
||||
_type : TTLSContentType;
|
||||
version : TTLSProtocolVersion;
|
||||
length : Word;
|
||||
end;
|
||||
PTLSRecordHeader = ^TTLSRecordHeader;
|
||||
|
||||
const
|
||||
TLSRecordHeaderSize = Sizeof(TTLSRecordHeader);
|
||||
|
||||
procedure InitTLSRecordHeader(var RecordHeader: TTLSRecordHeader;
|
||||
const ContentType: TTLSContentType;
|
||||
const Version: TTLSProtocolVersion;
|
||||
const Length: Word);
|
||||
procedure DecodeTLSRecordHeader(const RecordHeader: TTLSRecordHeader;
|
||||
var ContentType: TTLSContentType;
|
||||
var Version: TTLSProtocolVersion;
|
||||
var Length: Word);
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Record payload MAC }
|
||||
{ }
|
||||
function PrepareTLSRecordPayloadMACBuffer(
|
||||
var Buffer; const Size: Integer;
|
||||
const ProtocolVersion: TTLSProtocolVersion;
|
||||
const MACSize: Integer;
|
||||
const SequenceNumber: Int64;
|
||||
const TLSCompressedHdr;
|
||||
const TLSCompressedBuf; const TLSCompressedBufSize: Integer): Integer;
|
||||
|
||||
function GenerateTLSRecordPayloadMAC(
|
||||
const MACAlgorithm: TTLSMACAlgorithm;
|
||||
const Key; const KeySize: Integer;
|
||||
const Buf; const BufSize: Integer;
|
||||
var Digest; const DigestSize: Integer): Integer;
|
||||
|
||||
function GenerateRecordPayloadMAC(
|
||||
const ProtocolVersion: TTLSProtocolVersion;
|
||||
const CipherSuiteDetails: TTLSCipherSuiteDetails;
|
||||
const Key; const KeySize: Integer;
|
||||
const SequenceNumber: Int64;
|
||||
const TLSCompressedHdr: PTLSRecordHeader;
|
||||
const TLSCompressedBuf; const TLSCompressedBufSize: Integer;
|
||||
var Digest; const DigestSize: Integer): Integer;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Record }
|
||||
{ }
|
||||
function EncodeTLSRecord(
|
||||
var Buffer; const Size: Integer;
|
||||
const ProtocolVersion: TTLSProtocolVersion;
|
||||
const ContentType: TTLSContentType;
|
||||
const ContentBuffer; const ContentSize: Integer;
|
||||
const CompressionMethod: TTLSCompressionMethod;
|
||||
const CipherSuiteDetails: TTLSCipherSuiteDetails;
|
||||
const SequenceNumber: Int64;
|
||||
const MACKey; const MACKeySize: Integer;
|
||||
var CipherState: TTLSCipherState;
|
||||
const IVBufPtr: Pointer; const IVBufSize: Integer): Integer;
|
||||
|
||||
procedure DecodeTLSRecord(
|
||||
const RecHeader: PTLSRecordHeader;
|
||||
const Buffer; const Size: Integer;
|
||||
const ProtocolVersion: TTLSProtocolVersion;
|
||||
const CompressionMethod: TTLSCompressionMethod;
|
||||
const CipherSuiteDetails: TTLSCipherSuiteDetails;
|
||||
const SequenceNumber: Int64;
|
||||
const MACKey; const MACKeySize: Integer;
|
||||
var CipherState: TTLSCipherState;
|
||||
const IVBufPtr: Pointer; const IVBufSize: Integer;
|
||||
var ContentBuffer; const ContentBufferSize: Integer;
|
||||
out ContentSize: Integer);
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test cases }
|
||||
{ }
|
||||
{$IFDEF TLS_TEST}
|
||||
procedure Test;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{ System }
|
||||
|
||||
SysUtils,
|
||||
|
||||
{ Utils }
|
||||
|
||||
flcStdTypes,
|
||||
flcHash,
|
||||
|
||||
{ Cipher }
|
||||
|
||||
flcCipherRandom,
|
||||
|
||||
{ TLS }
|
||||
|
||||
flcTLSConsts,
|
||||
flcTLSErrors,
|
||||
flcTLSCompress;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ ContentType }
|
||||
{ }
|
||||
function TLSContentTypeToStr(const A: TTLSContentType): String;
|
||||
begin
|
||||
case A of
|
||||
tlsctInvalid : Result := 'Invalid';
|
||||
tlsctChange_cipher_spec : Result := 'Change_cipher_spec';
|
||||
tlsctAlert : Result := 'Alert';
|
||||
tlsctHandshake : Result := 'Handshake';
|
||||
tlsctApplication_data : Result := 'Application_data';
|
||||
tlsctHeartbeat : Result := 'Heartbeat';
|
||||
else
|
||||
Result := '[TLSContentType#' + IntToStr(Ord(A)) + ']';
|
||||
end;
|
||||
end;
|
||||
|
||||
function IsKnownTLSContentType(const A: TTLSContentType): Boolean;
|
||||
begin
|
||||
Result := A in [
|
||||
tlsctChange_cipher_spec,
|
||||
tlsctAlert,
|
||||
tlsctHandshake,
|
||||
tlsctApplication_data,
|
||||
tlsctHeartbeat];
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ TLS Record Header }
|
||||
{ }
|
||||
{ SSL3 / TLS 1.0 / TLS 1.1 / TLS 1.2: }
|
||||
{ ContentType type }
|
||||
{ ProtocolVersion version }
|
||||
{ uint16 length }
|
||||
{ }
|
||||
procedure InitTLSRecordHeader(var RecordHeader: TTLSRecordHeader;
|
||||
const ContentType: TTLSContentType;
|
||||
const Version: TTLSProtocolVersion;
|
||||
const Length: Word);
|
||||
begin
|
||||
RecordHeader._type := ContentType;
|
||||
RecordHeader.version := Version;
|
||||
RecordHeader.length :=
|
||||
((Length and $FF) shl 8) or
|
||||
(Length shr 8);
|
||||
end;
|
||||
|
||||
procedure DecodeTLSRecordHeader(const RecordHeader: TTLSRecordHeader;
|
||||
var ContentType: TTLSContentType;
|
||||
var Version: TTLSProtocolVersion;
|
||||
var Length: Word);
|
||||
begin
|
||||
ContentType := RecordHeader._type;
|
||||
Version := RecordHeader.version ;
|
||||
Length :=
|
||||
((RecordHeader.length and $FF) shl 8) or
|
||||
(RecordHeader.length shr 8);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Record payload MAC }
|
||||
{ }
|
||||
{ SSL 3: }
|
||||
{ hash(MAC_write_secret + pad_2 + }
|
||||
{ hash(MAC_write_secret + pad_1 + }
|
||||
{ seq_num + }
|
||||
{ SSLCompressed.type + }
|
||||
{ SSLCompressed.length + }
|
||||
{ SSLCompressed.fragment)); }
|
||||
{ pad_1 = The character 0x36 repeated 48 times for MD5 or 40 times for SHA. }
|
||||
{ pad_2 = The character 0x5c repeated 48 times for MD5 or 40 times for SHA. }
|
||||
{ }
|
||||
{ TLS 1.0 / TLS 1.1 / TLS 1.2: }
|
||||
{ HMAC_hash(MAC_write_key, seq_num + }
|
||||
{ TLSCompressed.type + }
|
||||
{ TLSCompressed.version + }
|
||||
{ TLSCompressed.length + }
|
||||
{ TLSCompressed.fragment); }
|
||||
{ }
|
||||
procedure EncodeSequenceNumber(
|
||||
const SequenceNumber: Int64;
|
||||
const Buf; const BufSize: Integer);
|
||||
var P : PByte;
|
||||
B : array[0..7] of Byte;
|
||||
I : Integer;
|
||||
begin
|
||||
if BufSize < 8 then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
P := @Buf;
|
||||
Move(SequenceNumber, B, 8);
|
||||
for I := 0 to 7 do
|
||||
begin
|
||||
P^ := B[7 - I];
|
||||
Inc(P);
|
||||
end;
|
||||
end;
|
||||
|
||||
function CalculateSSLHash(
|
||||
const Hash: TTLSCipherSuiteHash;
|
||||
const Buf; const BufSize: Integer;
|
||||
var Digest; const DigestSize: Integer): Integer;
|
||||
var L : Integer;
|
||||
begin
|
||||
L := TLSCipherSuiteHashInfo[Hash].HashSize div 8;
|
||||
if DigestSize < L then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
case Hash of
|
||||
tlscshMD5 : P128BitDigest(@Digest)^ := CalcMD5(Buf, BufSize);
|
||||
tlscshSHA : P160BitDigest(@Digest)^ := CalcSHA1(Buf, BufSize);
|
||||
else
|
||||
raise ETLSError.Create(TLSError_InvalidParameter);
|
||||
end;
|
||||
Result := L;
|
||||
end;
|
||||
|
||||
const
|
||||
SSL_MACBufSize = (TLS_PLAINTEXT_FRAGMENT_MAXSIZE + 1024) * 2;
|
||||
|
||||
function GenerateSSLRecordPayloadMAC(
|
||||
const Hash: TTLSCipherSuiteHash;
|
||||
const Key; const KeySize: Integer;
|
||||
const SequenceNumber: Int64;
|
||||
const TLSCompressedHdr: PTLSRecordHeader;
|
||||
const TLSCompressedBuf; const TLSCompressedBufSize: Integer;
|
||||
var Digest; const DigestSize: Integer): Integer;
|
||||
var PadN : Integer;
|
||||
Buf1 : array[0..SSL_MACBufSize - 1] of Byte;
|
||||
Len1 : Integer;
|
||||
Buf2 : array[0..SSL_MACBufSize - 1] of Byte;
|
||||
Len2 : Integer;
|
||||
Hash1 : array[0..TLS_MAC_MAXDIGESTSIZE - 1] of Byte;
|
||||
Hash1Len : Integer;
|
||||
Hash2 : array[0..TLS_MAC_MAXDIGESTSIZE - 1] of Byte;
|
||||
Hash2Len : Integer;
|
||||
P : PByte;
|
||||
begin
|
||||
case Hash of
|
||||
tlscshMD5 : PadN := 48;
|
||||
tlscshSHA : PadN := 40;
|
||||
else
|
||||
raise ETLSError.Create(TLSError_InvalidParameter);
|
||||
end;
|
||||
// hash(MAC_write_secret + pad_1 + seq_num + SSLCompressed.type + SSLCompressed.length + SSLCompressed.fragment)
|
||||
P := @Buf1;
|
||||
Len1 := 0;
|
||||
Move(Key, P^, KeySize);
|
||||
Inc(P, KeySize);
|
||||
Inc(Len1, KeySize);
|
||||
FillChar(P^, PadN, #$36);
|
||||
Inc(P, PadN);
|
||||
Inc(Len1, PadN);
|
||||
EncodeSequenceNumber(SequenceNumber, P^, SSL_MACBufSize - Len1);
|
||||
Inc(P, 8);
|
||||
Inc(Len1, 8);
|
||||
Move(TLSCompressedHdr^._type, P^, 1);
|
||||
Inc(P);
|
||||
Inc(Len1);
|
||||
Move(TLSCompressedHdr^.length, P^, 2);
|
||||
Inc(P, 2);
|
||||
Inc(Len1, 2);
|
||||
Move(TLSCompressedBuf, P^, TLSCompressedBufSize);
|
||||
Inc(Len1, TLSCompressedBufSize);
|
||||
Hash1Len := CalculateSSLHash(Hash, Buf1, Len1, Hash1, SizeOf(Hash1));
|
||||
// hash(MAC_write_secret + pad_2 + hash1)
|
||||
P := @Buf2;
|
||||
Len2 := 0;
|
||||
Move(Key, P^, KeySize);
|
||||
Inc(P, KeySize);
|
||||
Inc(Len2, KeySize);
|
||||
FillChar(P^, PadN, #$5C);
|
||||
Inc(P, PadN);
|
||||
Inc(Len2, PadN);
|
||||
Move(Hash1, P^, Hash1Len);
|
||||
Inc(Len2, Hash1Len);
|
||||
Hash2Len := CalculateSSLHash(Hash, Buf2, Len2, Hash2, SizeOf(Hash2));
|
||||
// result
|
||||
if DigestSize < Hash2Len then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
Move(Hash2, Digest, Hash2Len);
|
||||
Result := Hash2Len;
|
||||
end;
|
||||
|
||||
function PrepareTLSRecordPayloadMACBuffer(
|
||||
var Buffer; const Size: Integer;
|
||||
const ProtocolVersion: TTLSProtocolVersion;
|
||||
const MACSize: Integer;
|
||||
const SequenceNumber: Int64;
|
||||
const TLSCompressedHdr;
|
||||
const TLSCompressedBuf; const TLSCompressedBufSize: Integer): Integer;
|
||||
var P : PByte;
|
||||
N : Integer;
|
||||
begin
|
||||
if not IsTLS10OrLater(ProtocolVersion) then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter);
|
||||
N := Size;
|
||||
Dec(N, 8);
|
||||
Dec(N, TLSRecordHeaderSize);
|
||||
Dec(N, TLSCompressedBufSize);
|
||||
if N < 0 then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
P := @Buffer;
|
||||
EncodeSequenceNumber(SequenceNumber, P^, Size);
|
||||
Inc(P, 8);
|
||||
Move(TLSCompressedHdr, P^, TLSRecordHeaderSize);
|
||||
Inc(P, TLSRecordHeaderSize);
|
||||
Move(TLSCompressedBuf, P^, TLSCompressedBufSize);
|
||||
Result := Size - N;
|
||||
end;
|
||||
|
||||
function GenerateTLSRecordPayloadMAC(
|
||||
const MACAlgorithm: TTLSMACAlgorithm;
|
||||
const Key; const KeySize: Integer;
|
||||
const Buf; const BufSize: Integer;
|
||||
var Digest; const DigestSize: Integer): Integer;
|
||||
var L : Integer;
|
||||
begin
|
||||
L := TLSMACAlgorithmInfo[MACAlgorithm].DigestSize;
|
||||
if DigestSize < L then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
case MACAlgorithm of
|
||||
tlsmaHMAC_MD5 : P128BitDigest(@Digest)^ := CalcHMAC_MD5(@Key, KeySize, Buf, BufSize);
|
||||
tlsmaHMAC_SHA1 : P160BitDigest(@Digest)^ := CalcHMAC_SHA1(@Key, KeySize, Buf, BufSize);
|
||||
tlsmaHMAC_SHA256 : P256BitDigest(@Digest)^ := CalcHMAC_SHA256(@Key, KeySize, Buf, BufSize);
|
||||
tlsmaHMAC_SHA512 : P512BitDigest(@Digest)^ := CalcHMAC_SHA512(@Key, KeySize, Buf, BufSize);
|
||||
else
|
||||
raise ETLSError.Create(TLSError_InvalidParameter, 'Invalid MAC algorithm[' + IntToStr(Ord(MACAlgorithm)) + ']');
|
||||
end;
|
||||
Result := L;
|
||||
end;
|
||||
|
||||
const
|
||||
// size of temporary buffers used in record encoding and decoding
|
||||
// this should be large enough to hold any plain, compressed or encrypted record
|
||||
TLS_RecordBufSize = (TLS_PLAINTEXT_FRAGMENT_MAXSIZE + 1024) * 2;
|
||||
|
||||
function GenerateRecordPayloadMAC(
|
||||
const ProtocolVersion: TTLSProtocolVersion;
|
||||
const CipherSuiteDetails: TTLSCipherSuiteDetails;
|
||||
const Key; const KeySize: Integer;
|
||||
const SequenceNumber: Int64;
|
||||
const TLSCompressedHdr: PTLSRecordHeader;
|
||||
const TLSCompressedBuf; const TLSCompressedBufSize: Integer;
|
||||
var Digest; const DigestSize: Integer): Integer;
|
||||
var MACSize : Integer;
|
||||
MACAlgo : TTLSMACAlgorithm;
|
||||
BufMAC : array[0..TLS_RecordBufSize - 1] of Byte;
|
||||
BufMACSize : Integer;
|
||||
begin
|
||||
if IsSSL3(ProtocolVersion) then
|
||||
begin
|
||||
Result := GenerateSSLRecordPayloadMAC(
|
||||
CipherSuiteDetails.CipherSuiteInfo^.Hash,
|
||||
Key, KeySize,
|
||||
SequenceNumber,
|
||||
TLSCompressedHdr,
|
||||
TLSCompressedBuf, TLSCompressedBufSize,
|
||||
Digest, DigestSize);
|
||||
end
|
||||
else
|
||||
if IsTLS10OrLater(ProtocolVersion) then
|
||||
begin
|
||||
MACSize := CipherSuiteDetails.HashInfo^.HashSize div 8;
|
||||
MACAlgo := TLSCipherSuiteHashInfo[CipherSuiteDetails.CipherSuiteInfo^.Hash].MACAlgorithm;
|
||||
BufMACSize := PrepareTLSRecordPayloadMACBuffer(
|
||||
BufMAC, SizeOf(BufMAC),
|
||||
ProtocolVersion,
|
||||
MACSize,
|
||||
SequenceNumber,
|
||||
TLSCompressedHdr^,
|
||||
TLSCompressedBuf, TLSCompressedBufSize);
|
||||
Result := GenerateTLSRecordPayloadMAC(
|
||||
MACAlgo,
|
||||
Key, KeySize,
|
||||
BufMAC, BufMACSize,
|
||||
Digest, DigestSize);
|
||||
SecureClear(BufMAC, BufMACSize);
|
||||
end
|
||||
else
|
||||
raise ETLSError.Create(TLSError_InvalidParameter);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Record }
|
||||
{ }
|
||||
{ SSL 3: }
|
||||
{ GenericStreamCipher }
|
||||
{ stream-ciphered struct }
|
||||
{ opaque content[SSLCompressed.length]; }
|
||||
{ opaque MAC[CipherSpec.hash_size]; }
|
||||
{ }
|
||||
{ TLS 1.0 / 1.1 / 1.2: }
|
||||
{ GenericStreamCipher }
|
||||
{ stream-ciphered struct }
|
||||
{ opaque content[TLSCompressed.length]; }
|
||||
{ opaque MAC[SecurityParameters.mac_length]; }
|
||||
{ }
|
||||
{ SSL 3: }
|
||||
{ GenericBlockCipher }
|
||||
{ block-ciphered struct }
|
||||
{ opaque content[SSLCompressed.length]; }
|
||||
{ opaque MAC[CipherSpec.hash_size]; }
|
||||
{ uint8 padding[GenericBlockCipher.padding_length]; }
|
||||
{ uint8 padding_length; }
|
||||
{ }
|
||||
{ TLS 1.0: }
|
||||
{ GenericBlockCipher }
|
||||
{ block-ciphered struct }
|
||||
{ opaque content[TLSCompressed.length]; }
|
||||
{ opaque MAC[CipherSpec.hash_size]; }
|
||||
{ uint8 padding[GenericBlockCipher.padding_length]; }
|
||||
{ uint8 padding_length; }
|
||||
{ }
|
||||
{ TLS 1.1: }
|
||||
{ GenericBlockCipher }
|
||||
{ block-ciphered struct }
|
||||
{ opaque IV[CipherSpec.block_length]; }
|
||||
{ opaque content[TLSCompressed.length]; }
|
||||
{ opaque MAC[CipherSpec.hash_size]; }
|
||||
{ uint8 padding[GenericBlockCipher.padding_length]; }
|
||||
{ uint8 padding_length; }
|
||||
{ }
|
||||
{ TLS 1.2: }
|
||||
{ GenericBlockCipher }
|
||||
{ opaque IV[SecurityParameters.record_iv_length]; }
|
||||
{ block-ciphered struct }
|
||||
{ opaque content[TLSCompressed.length]; }
|
||||
{ opaque MAC[SecurityParameters.mac_length]; }
|
||||
{ uint8 padding[GenericBlockCipher.padding_length]; }
|
||||
{ uint8 padding_length; }
|
||||
{ }
|
||||
|
||||
// Returns number of padding bytes encoded
|
||||
function EncodeTLSGenericBlockCipherPadding(
|
||||
var Buffer; const BufferSize: Integer;
|
||||
const GenericBlockSize: Integer;
|
||||
const CipherBlockSize: Integer): Integer;
|
||||
var L, I, N : Integer;
|
||||
P : PByte;
|
||||
begin
|
||||
if (CipherBlockSize <= 0) or (CipherBlockSize > 256) then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter);
|
||||
|
||||
L := (GenericBlockSize + 1) mod CipherBlockSize;
|
||||
if L > 0 then
|
||||
L := CipherBlockSize - L;
|
||||
Assert(L <= $FF);
|
||||
Assert((GenericBlockSize + L + 1) mod CipherBlockSize = 0);
|
||||
|
||||
N := L + 1;
|
||||
if BufferSize < N then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
P := @Buffer;
|
||||
for I := 1 to L do
|
||||
begin
|
||||
P^ := L;
|
||||
Inc(P);
|
||||
end;
|
||||
P^ := L;
|
||||
Result := N;
|
||||
end;
|
||||
|
||||
// Returns number of padding bytes at end of padded buffer
|
||||
// Validates padding bytes
|
||||
function DecodeTLSGenericBlockCipherPadding(const Buffer; const Size: Integer): Integer;
|
||||
var P : PByte;
|
||||
C : Byte;
|
||||
L, I : Integer;
|
||||
begin
|
||||
P := @Buffer;
|
||||
Inc(P, Size - 1);
|
||||
C := P^;
|
||||
L := C + 1;
|
||||
if Size < L then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
for I := 0 to C - 1 do
|
||||
begin
|
||||
Dec(P);
|
||||
if P^ <> C then
|
||||
raise ETLSError.Create(TLSError_DecodeError);
|
||||
end;
|
||||
Result := C + 1;
|
||||
end;
|
||||
|
||||
// TLS 1.0: get IV from last cipher block
|
||||
procedure tls10UpdateIV(
|
||||
const Buffer; const Size: Integer;
|
||||
var IVBuffer; const IVBufferSize: Integer);
|
||||
var P : PByte;
|
||||
begin
|
||||
if (IVBufferSize <= 0) or (Size < IVBufferSize) then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
P := @Buffer;
|
||||
Inc(P, Size - IVBufferSize);
|
||||
Move(P^, IVBuffer, IVBufferSize);
|
||||
end;
|
||||
|
||||
// TLS 1.1 1.2: generate random IV
|
||||
procedure tls11UpdateIV(var IVBuffer; const IVBufferSize: Integer);
|
||||
begin
|
||||
if IVBufferSize <= 0 then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
SecureRandomBuf(IVBuffer, IVBufferSize);
|
||||
end;
|
||||
|
||||
// Encode a TLS record and update IV
|
||||
// Returns size of encoded TLS record (including header)
|
||||
function EncodeTLSRecord(
|
||||
var Buffer; const Size: Integer;
|
||||
const ProtocolVersion: TTLSProtocolVersion;
|
||||
const ContentType: TTLSContentType;
|
||||
const ContentBuffer; const ContentSize: Integer;
|
||||
const CompressionMethod: TTLSCompressionMethod;
|
||||
const CipherSuiteDetails: TTLSCipherSuiteDetails;
|
||||
const SequenceNumber: Int64;
|
||||
const MACKey; const MACKeySize: Integer;
|
||||
var CipherState: TTLSCipherState;
|
||||
const IVBufPtr: Pointer; const IVBufSize: Integer): Integer;
|
||||
var BufP : PByte;
|
||||
BufLeft : Integer;
|
||||
HasCipher : Boolean;
|
||||
IsBlockCipher : Boolean;
|
||||
UseIV : Boolean;
|
||||
IVSize : Integer;
|
||||
RecHeader : PTLSRecordHeader;
|
||||
RecContent : Pointer;
|
||||
RecMAC : Pointer;
|
||||
RecCipher : Pointer;
|
||||
ComprSize : Integer;
|
||||
MACSize : Integer;
|
||||
CipherSize : Integer;
|
||||
BlockSize : Integer;
|
||||
BufCipher : array[0..TLS_RecordBufSize - 1] of Byte;
|
||||
CipheredSize : Integer;
|
||||
FinalSize : Integer;
|
||||
begin
|
||||
if ContentSize > TLS_PLAINTEXT_FRAGMENT_MAXSIZE then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter);
|
||||
|
||||
// initialise parameters
|
||||
HasCipher := CipherSuiteDetails.CipherSuite <> tlscsNone;
|
||||
IsBlockCipher :=
|
||||
HasCipher and
|
||||
(CipherSuiteDetails.CipherInfo^.CipherType = tlscsctBlock);
|
||||
UseIV :=
|
||||
IsBlockCipher and
|
||||
(CipherSuiteDetails.CipherInfo^.IVSize > 0);
|
||||
if UseIV then
|
||||
IVSize := CipherSuiteDetails.CipherInfo^.IVSize
|
||||
else
|
||||
IVSize := 0;
|
||||
if UseIV and (IVBufSize < IVSize) then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
|
||||
// encode to Buffer
|
||||
BufP := @Buffer;
|
||||
BufLeft := Size;
|
||||
|
||||
// header
|
||||
Dec(BufLeft, TLSRecordHeaderSize);
|
||||
if BufLeft < 0 then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
RecHeader := Pointer(BufP);
|
||||
Inc(BufP, TLSRecordHeaderSize);
|
||||
|
||||
// TLS 1.1/1.2: generate random IV
|
||||
if UseIV then
|
||||
if IsTLS11OrLater(ProtocolVersion) then
|
||||
tls11UpdateIV(IVBufPtr^, IVBufSize);
|
||||
|
||||
// TLS 1.1/1.2: encode IV field
|
||||
if UseIV then
|
||||
if IsTLS11OrLater(ProtocolVersion) then
|
||||
begin
|
||||
Dec(BufLeft, IVSize);
|
||||
if BufLeft < 0 then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
Move(IVBufPtr^, BufP^, IVSize);
|
||||
Inc(BufP, IVSize);
|
||||
end;
|
||||
|
||||
// compress content
|
||||
RecContent := BufP;
|
||||
TLSCompressFragment(CompressionMethod,
|
||||
ContentBuffer, ContentSize,
|
||||
BufP^, BufLeft,
|
||||
ComprSize);
|
||||
Inc(BufP, ComprSize);
|
||||
Dec(BufLeft, ComprSize);
|
||||
|
||||
// update header with compressed details
|
||||
InitTLSRecordHeader(RecHeader^, ContentType, ProtocolVersion, ComprSize);
|
||||
|
||||
if HasCipher then
|
||||
begin
|
||||
// calculate MAC
|
||||
RecMAC := BufP;
|
||||
MACSize := CipherSuiteDetails.HashInfo^.HashSize div 8;
|
||||
GenerateRecordPayloadMAC(
|
||||
ProtocolVersion,
|
||||
CipherSuiteDetails,
|
||||
MACKey, MACKeySize,
|
||||
SequenceNumber,
|
||||
RecHeader,
|
||||
RecContent^, ComprSize,
|
||||
RecMAC^, BufLeft);
|
||||
Inc(BufP, MACSize);
|
||||
Dec(BufLeft, MACSize);
|
||||
|
||||
// cipher size
|
||||
CipherSize := ComprSize + MACSize;
|
||||
|
||||
// block cipher padding
|
||||
if IsBlockCipher then
|
||||
begin
|
||||
BlockSize := CipherSuiteDetails.CipherInfo^.BlockSize;
|
||||
Inc(CipherSize,
|
||||
EncodeTLSGenericBlockCipherPadding(BufP^, BufLeft, CipherSize, BlockSize));
|
||||
end;
|
||||
|
||||
// Encrypts content (excluding IV)
|
||||
RecCipher := RecContent;
|
||||
TLSCipherBuf(CipherState,
|
||||
RecCipher^, CipherSize,
|
||||
BufCipher, SizeOf(BufCipher),
|
||||
CipheredSize,
|
||||
IVBufPtr, IVSize);
|
||||
Move(BufCipher, RecCipher^, CipheredSize);
|
||||
|
||||
// update IV
|
||||
if UseIV then
|
||||
if IsTLS10(ProtocolVersion) or IsSSL3(ProtocolVersion) then
|
||||
tls10UpdateIV(RecContent^, CipheredSize, IVBufPtr^, IVBufSize);
|
||||
|
||||
// final size
|
||||
FinalSize := CipheredSize;
|
||||
if UseIV then
|
||||
if IsTLS11OrLater(ProtocolVersion) then
|
||||
Inc(FinalSize, IVSize);
|
||||
|
||||
// update header with final encrypted details
|
||||
InitTLSRecordHeader(RecHeader^, ContentType, ProtocolVersion, FinalSize);
|
||||
end
|
||||
else
|
||||
FinalSize := ComprSize;
|
||||
|
||||
Result := TLSRecordHeaderSize + FinalSize;
|
||||
end;
|
||||
|
||||
// Decode a TLS record into ContentBuffer and returns size of decoded content in ContentSize
|
||||
// Updates IV for next record
|
||||
// Buffer points to first byte afer record header
|
||||
procedure DecodeTLSRecord(
|
||||
const RecHeader: PTLSRecordHeader;
|
||||
const Buffer; const Size: Integer;
|
||||
const ProtocolVersion: TTLSProtocolVersion;
|
||||
const CompressionMethod: TTLSCompressionMethod;
|
||||
const CipherSuiteDetails: TTLSCipherSuiteDetails;
|
||||
const SequenceNumber: Int64;
|
||||
const MACKey; const MACKeySize: Integer;
|
||||
var CipherState: TTLSCipherState;
|
||||
const IVBufPtr: Pointer; const IVBufSize: Integer;
|
||||
var ContentBuffer; const ContentBufferSize: Integer;
|
||||
out ContentSize: Integer);
|
||||
var BufP : PByte;
|
||||
BufPLeft : Integer;
|
||||
BufQ : PByte;
|
||||
BufQLeft : Integer;
|
||||
HasCipher : Boolean;
|
||||
IsBlockCipher : Boolean;
|
||||
UseIV : Boolean;
|
||||
IVSize : Integer;
|
||||
BufCipher : array[0..TLS_RecordBufSize - 1] of Byte;
|
||||
CipherSize : Integer;
|
||||
RecContent : Pointer;
|
||||
ComprSize : Integer;
|
||||
BufPlain : array[0..TLS_RecordBufSize - 1] of Byte;
|
||||
PlainSize : Integer;
|
||||
NextIV : array[0..TLS_CIPHERSUITE_MaxIVSize - 1] of Byte;
|
||||
MACSize : Integer;
|
||||
PadSize : Integer;
|
||||
CalcMAC : array[0..TLS_MAC_MAXDIGESTSIZE - 1] of Byte;
|
||||
RecMAC : Pointer;
|
||||
MACOk : Boolean;
|
||||
MACIdx : Integer;
|
||||
ComprHdr : TTLSRecordHeader;
|
||||
P, Q : PByte;
|
||||
begin
|
||||
// initialise parameters
|
||||
HasCipher := CipherSuiteDetails.CipherSuite <> tlscsNone;
|
||||
IsBlockCipher :=
|
||||
HasCipher and
|
||||
(CipherSuiteDetails.CipherInfo^.CipherType = tlscsctBlock);
|
||||
UseIV :=
|
||||
IsBlockCipher and
|
||||
(CipherSuiteDetails.CipherInfo^.IVSize > 0);
|
||||
if UseIV then
|
||||
IVSize := CipherSuiteDetails.CipherInfo^.IVSize
|
||||
else
|
||||
IVSize := 0;
|
||||
Assert(IVSize <= TLS_CIPHERSUITE_MaxIVSize);
|
||||
if UseIV and (IVBufSize < IVSize) then
|
||||
raise ETLSError.Create(TLSError_InvalidBuffer);
|
||||
|
||||
if HasCipher then
|
||||
begin
|
||||
// decode Buffer
|
||||
BufP := @Buffer;
|
||||
BufPLeft := Size;
|
||||
|
||||
// TLS 1.2: get IV field from unencrypted buffer
|
||||
if UseIV then
|
||||
if IsTLS12OrLater(ProtocolVersion) then
|
||||
begin
|
||||
Move(BufP^, IVBufPtr^, IVSize);
|
||||
Inc(BufP, IVSize);
|
||||
Dec(BufPLeft, IVSize);
|
||||
end;
|
||||
|
||||
// TLS 1.0: get IV from encrypted block
|
||||
if UseIV then
|
||||
if IsTLS10(ProtocolVersion) then
|
||||
tls10UpdateIV(BufP^, BufPLeft, NextIV, IVSize);
|
||||
|
||||
// TLS 1.1: IV is first encrypted block
|
||||
|
||||
// decrypt from Buffer to BufCipher
|
||||
TLSCipherBuf(CipherState,
|
||||
BufP^, BufPLeft,
|
||||
BufCipher, SizeOf(BufCipher),
|
||||
CipherSize,
|
||||
IVBufPtr, IVSize);
|
||||
|
||||
// decode decrypted Buffer
|
||||
BufQ := @BufCipher;
|
||||
BufQLeft := CipherSize;
|
||||
|
||||
// TLS 1.1: skip over IV field
|
||||
if UseIV then
|
||||
if IsTLS11(ProtocolVersion) then
|
||||
begin
|
||||
Move(BufQ^, IVBufPtr^, IVSize);
|
||||
Inc(BufQ, IVSize);
|
||||
Dec(BufQLeft, IVSize);
|
||||
end;
|
||||
|
||||
// TLS 1.0: update IV
|
||||
if UseIV then
|
||||
if IsTLS10(ProtocolVersion) then
|
||||
Move(NextIV, IVBufPtr^, IVSize);
|
||||
|
||||
// decode padding
|
||||
if IsBlockCipher then
|
||||
begin
|
||||
PadSize := DecodeTLSGenericBlockCipherPadding(BufQ^, BufQLeft);
|
||||
Dec(BufQLeft, PadSize);
|
||||
end;
|
||||
|
||||
// update size for MAC
|
||||
MACSize := CipherSuiteDetails.HashInfo^.HashSize div 8;
|
||||
Dec(BufQLeft, MACSize);
|
||||
|
||||
// compressed content
|
||||
RecContent := BufQ;
|
||||
ComprSize := BufQLeft;
|
||||
|
||||
// Calculate MAC
|
||||
InitTLSRecordHeader(ComprHdr, RecHeader^._type, RecHeader^.version, ComprSize);
|
||||
GenerateRecordPayloadMAC(
|
||||
ProtocolVersion,
|
||||
CipherSuiteDetails,
|
||||
MACKey, MACKeySize,
|
||||
SequenceNumber,
|
||||
@ComprHdr,
|
||||
RecContent^, ComprSize,
|
||||
CalcMAC, MACSize);
|
||||
|
||||
// get MAC
|
||||
Inc(BufQ, ComprSize);
|
||||
RecMAC := BufQ;
|
||||
|
||||
// validate MAC
|
||||
P := @CalcMAC;
|
||||
Q := RecMAC;
|
||||
MACOk := True;
|
||||
for MACIdx := 0 to MACSize - 1 do
|
||||
if P^ <> Q^ then
|
||||
begin
|
||||
MACOk := False;
|
||||
break;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Inc(P);
|
||||
Inc(Q);
|
||||
end;
|
||||
if not MACOk then
|
||||
raise ETLSError.Create(TLSError_DecodeError);
|
||||
end
|
||||
else
|
||||
begin
|
||||
Move(Buffer, BufCipher, Size);
|
||||
RecContent := @BufCipher;
|
||||
ComprSize := Size;
|
||||
end;
|
||||
|
||||
// decompress from BufCipher to BufPlain
|
||||
TLSDecompressFragment(
|
||||
CompressionMethod,
|
||||
RecContent^, ComprSize,
|
||||
BufPlain, SizeOf(BufPlain),
|
||||
PlainSize);
|
||||
|
||||
// plain text
|
||||
Move(BufPlain, ContentBuffer, PlainSize);
|
||||
ContentSize := PlainSize;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test cases }
|
||||
{ }
|
||||
//// TBytes
|
||||
{$IFDEF TLS_TEST}
|
||||
{$ASSERTIONS ON}
|
||||
procedure SelfTestPayloadMAC;
|
||||
const
|
||||
MACWriteKey = RawByteString(#$85#$F0#$56#$F8#$07#$1D#$B1#$89#$89#$D0#$E1#$33#$3C#$CA#$63#$F9);
|
||||
|
||||
var S, T, D : RawByteString;
|
||||
L : Integer;
|
||||
begin
|
||||
|
||||
// //
|
||||
|
||||
// Example from http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/ReadDebug.html //
|
||||
|
||||
// //
|
||||
|
||||
T := MACWriteKey;
|
||||
|
||||
D := RawByteString(
|
||||
#$00#$00#$00#$00#$00#$00#$00#$00 + // seq_num
|
||||
#$16#$03#$01#$00#$10 + // compressed hdr
|
||||
#$14#$00#$00#$0C#$F2#$62#$42#$AA#$7C#$7C#$CC#$E7#$49#$0F#$ED#$AC); // handshake msg
|
||||
SetLength(S, 256);
|
||||
L := GenerateTLSRecordPayloadMAC(tlsmaHMAC_MD5, T[1], Length(T), D[1], Length(D), S[1], Length(S));
|
||||
Assert(L = 16);
|
||||
SetLength(S, L);
|
||||
Assert(S = #$FA#$06#$3C#$9F#$8C#$41#$1D#$ED#$2B#$06#$D0#$5A#$ED#$31#$F2#$80);
|
||||
end;
|
||||
|
||||
procedure Test;
|
||||
begin
|
||||
Assert(TLSContentTypeSize = 1);
|
||||
Assert(TLSRecordHeaderSize = 5);
|
||||
SelfTestPayloadMAC;
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
140
contrib/fundamentals/TLS/flcTLSSessionID.pas
Normal file
140
contrib/fundamentals/TLS/flcTLSSessionID.pas
Normal file
@@ -0,0 +1,140 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSSessionID.pas }
|
||||
{ File version: 5.02 }
|
||||
{ Description: TLS Session ID }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2020/05/09 5.02 Create flcTLSSessionID unit from flcTLSUtils unit. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSSessionID;
|
||||
|
||||
interface
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ SessionID }
|
||||
{ }
|
||||
const
|
||||
TLSSessionIDMaxLen = 32;
|
||||
|
||||
type
|
||||
TTLSSessionID = record
|
||||
Len : Byte;
|
||||
Data : array[0..TLSSessionIDMaxLen - 1] of Byte;
|
||||
end;
|
||||
|
||||
procedure InitTLSSessionID(var SessionID: TTLSSessionID; const A: RawByteString);
|
||||
function EncodeTLSSessionID(var Buffer; const Size: Integer; const SessionID: TTLSSessionID): Integer;
|
||||
function DecodeTLSSessionID(const Buffer; const Size: Integer; var SessionID: TTLSSessionID): Integer;
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{ TLS }
|
||||
|
||||
flcTLSErrors;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ SessionID }
|
||||
|
||||
{ length : Byte; }
|
||||
{ SessionID : <0..32>; }
|
||||
{ }
|
||||
procedure InitTLSSessionID(var SessionID: TTLSSessionID; const A: RawByteString);
|
||||
var
|
||||
L : Integer;
|
||||
begin
|
||||
L := Length(A);
|
||||
if L > TLSSessionIDMaxLen then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter, 'Invalid SessionID length');
|
||||
SessionID.Len := Byte(L);
|
||||
FillChar(SessionID.Data[0], TLSSessionIDMaxLen, 0);
|
||||
if L > 0 then
|
||||
Move(A[1], SessionID.Data[0], L);
|
||||
end;
|
||||
|
||||
function EncodeTLSSessionID(var Buffer; const Size: Integer; const SessionID: TTLSSessionID): Integer;
|
||||
var L : Byte;
|
||||
N : Integer;
|
||||
P : PByte;
|
||||
begin
|
||||
L := SessionID.Len;
|
||||
N := L + 1;
|
||||
if Size < N then
|
||||
raise ETLSError.CreateAlertBufferEncode;
|
||||
P := @Buffer;
|
||||
P^ := L;
|
||||
Inc(P);
|
||||
if L > 0 then
|
||||
Move(SessionID.Data[0], P^, L);
|
||||
Result := N;
|
||||
end;
|
||||
|
||||
function DecodeTLSSessionID(const Buffer; const Size: Integer; var SessionID: TTLSSessionID): Integer;
|
||||
var L : Byte;
|
||||
P : PByte;
|
||||
begin
|
||||
if Size < 1 then
|
||||
raise ETLSError.CreateAlertBufferDecode;
|
||||
P := @Buffer;
|
||||
L := P^;
|
||||
if L = 0 then
|
||||
begin
|
||||
SessionID.Len := 0;
|
||||
Result := 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if Size < 1 + L then
|
||||
raise ETLSError.CreateAlertBufferDecode;
|
||||
if L > TLSSessionIDMaxLen then
|
||||
raise ETLSError.CreateAlertBufferDecode; // invalid length
|
||||
SessionID.Len := L;
|
||||
Inc(P);
|
||||
Move(P^, SessionID.Data[0], L);
|
||||
Result := 1 + L;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
|
303
contrib/fundamentals/TLS/flcTLSTestCertificates.pas
Normal file
303
contrib/fundamentals/TLS/flcTLSTestCertificates.pas
Normal file
@@ -0,0 +1,303 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSTestCertificates.pas }
|
||||
{ File version: 5.05 }
|
||||
{ Description: TLS Test Certificates }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2020/05/11 5.01 Initial certificates: RSA768, RSA2048, ECDSA-Secp256k1, }
|
||||
{ DSA512, DSA2048 and RSA-STunnel. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSTestCertificates;
|
||||
|
||||
interface
|
||||
|
||||
|
||||
|
||||
{$IFDEF TLS_TEST}
|
||||
const
|
||||
// rsa768-example.com-1
|
||||
RSA768_ExampleCom_1_PrivateKeyRSAPEM =
|
||||
'MIIB5QIBADANBgkqhkiG9w0BAQEFAASCAc8wggHLAgEAAmEAoO3RSQnutJfvT56L' +
|
||||
'85saXYZQi5zCzt5YUb75z3T/WsN1oaWt7NR1Bd1+xBxdmHOSRfSm0CsBw/gkt9YI' +
|
||||
'Vyjl6IbclBbhgIGzS3bkoVCvbG6SKtxGJPJcf9BOV8J9DqqXAgMBAAECYQCJz14b' +
|
||||
'h+/soveCXSlH8ZjAYlbzV8jTUkCbsElIyM4rsZo4VSL93mpgHW+DDS9xb/WFPtdk' +
|
||||
'CadzB+mnK8/Hul0OteOFFT5gn9vRzlFPS6WzPTeoeaKtqrwX8RyU+xLgREECMQDQ' +
|
||||
'+yAK8LF/v9yJ55A7Tfcq9XDr+eEjZ2DkaytvRX4HlMV9uCccCkISxxdBIbZMeIcC' +
|
||||
'MQDFIv8ikcJ5VjYaEr83Jof5bcH7qHeHV1WY2017cV/7ISVxwPL7rACKer+RWhnv' +
|
||||
'kXECMHzYiZv/jwqypB3+qLvFKBQR7RQMg+OSrt/G5nvjGBePWSxyB2tI9ZAiQFI4' +
|
||||
'wZ+NoQIwBhaWmpK11tl6wkNh9GoUOPfSzdreFif0VMwxEGbn9/GGHoU++9bMDXrM' +
|
||||
'/8gwlN2BAjEAsBKVdwN9HHE6uu8YoSxudy5Tcwa+bj8yxLiS6EwRs5WwzvaLv88p' +
|
||||
'ES7nd5PO2txL';
|
||||
|
||||
RSA768_ExampleCom_1_CertificatePEM =
|
||||
'MIICtzCCAkGgAwIBAgIUZQggmdgFQ6iq5DQGqcgDcL7jj4EwDQYJKoZIhvcNAQEL' +
|
||||
'BQAwgY8xCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQH' +
|
||||
'DAhMb2NhbGl0eTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRQw' +
|
||||
'EgYDVQQDDAtleGFtcGxlLmNvbTEfMB0GCSqGSIb3DQEJARYQaW5mb0BleGFtcGxl' +
|
||||
'LmNvbTAeFw0yMDA1MTExODI5NTlaFw0zMDA1MDkxODI5NTlaMIGPMQswCQYDVQQG' +
|
||||
'EwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UEBwwITG9jYWxpdHkxITAf' +
|
||||
'BgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwLZXhhbXBs' +
|
||||
'ZS5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9AZXhhbXBsZS5jb20wfDANBgkqhkiG' +
|
||||
'9w0BAQEFAANrADBoAmEAoO3RSQnutJfvT56L85saXYZQi5zCzt5YUb75z3T/WsN1' +
|
||||
'oaWt7NR1Bd1+xBxdmHOSRfSm0CsBw/gkt9YIVyjl6IbclBbhgIGzS3bkoVCvbG6S' +
|
||||
'KtxGJPJcf9BOV8J9DqqXAgMBAAGjUzBRMB0GA1UdDgQWBBRKImmf1879CQy/aFl/' +
|
||||
'miDQp00BJDAfBgNVHSMEGDAWgBRKImmf1879CQy/aFl/miDQp00BJDAPBgNVHRMB' +
|
||||
'Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA2EAZ2mFxf4DNHrmVMbvyGVXzzPmmGoz' +
|
||||
'vNdPeSQH16cgl1Q/Ass+52pSLjeIgiSpJcQtG5YzZY/t1m8LPcGqASYg9azce8fo' +
|
||||
'b34G260PvXX4FUrOSBZ2Owx59R5Cl1r238oj';
|
||||
|
||||
|
||||
|
||||
// rsa2048-example.com-1
|
||||
RSA2048_ExampleCom_1_PrivateKeyRSAPEM =
|
||||
'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDe6cFTj4ciladG' +
|
||||
'pHE9r0ytDfmWKVnnJZYLR2DLPVg6LVkEeykusfUSpf4pYwKOuToLD24iZpK5x3CY' +
|
||||
'UR348OXkFT2ytQwIcyRhK91N5x06WbmtCSl2Fx0GVBaKwfgx73LNfwtGvcOQVOQy' +
|
||||
'hozHm0TkhBHVplJ57hD3YGTH98WSiRP0fS1yV595wP72nYAvPAp61bVYpRNJDjFZ' +
|
||||
'QESubigYB5ufLUfGntlOasNd1CuICFFkSpRi1cd/r6qvq4ehhH7ypGTBjbPQ3Zg9' +
|
||||
'vpjR5B3NCKtH2n90fKy+Fuxfcm73GUinjR1C66Ve0CHovoskEROCcbCoi1VT2+oy' +
|
||||
'+cqOExfFAgMBAAECggEBANzZNyK0lqwbHOmOTmtQ3GSv7dFqEppB0NBH3Yw+sMSi' +
|
||||
'3QjlhL2wrh/VuWQDpisFNI50sSb//Op2wAUIiOt0sC8zJDeDy/IrMaXcMZvXGEwR' +
|
||||
'TTY0V5GaALWeZd7/ogjHNTSHZAKoS7MZiCTOzXeNS8ojVxAXgqsuxDxykibUQjiU' +
|
||||
'IVdKTN5KVANu1iL6FX9cXjbTncYmvMdtVqLccs4uFaazhWw756or1rk2rQQIEdXX' +
|
||||
'HisZ0iQeOmZILXy8HZI3EH/Vz8CDC9T3xJG76PiDP6I5wbM2WcOLAZcop+hWi/+U' +
|
||||
'KtTlIMFLYHSOwKjJmc4xkLRKRtoHUUtofAHSvh7CgZkCgYEA9dhhtfCskvw6mZcx' +
|
||||
'BuPNoN6Ge9+m56Z2dhSRVs5mzNSDjuVa+HFXAAramrJ6avc7fDm8S8j/AD9b2XnW' +
|
||||
'x4z4SFn9tTZyuUPEPAQAmwxFS2QHUA1fxDDvDh407iiSzXBO9ehke3b65YM6zjPl' +
|
||||
'WK72OG11dbFfctD4MIjK/0kFo9sCgYEA6B7iZkI/uiLQ0fqz07oOasvsGjtFja6F' +
|
||||
'2uNVZkZo0iYnXzdWGWeLlLQ3bme4kylpIyj2hh2EHQzrjJ6NCgU/W/QvDMFuyJbQ' +
|
||||
'wtUhWEFjlgqgjigRGDm3kMj0+hYbnS5g3rVpmfDsKT8fwCoMXwDCEgMpDe5CnwJf' +
|
||||
'ucgm/Njo1N8CgYAIoLttIzErR2bXFRNHZp9E0gpuNn8pChKGOlqPbVb2QU8MqMf0' +
|
||||
'iCXBfqAFZdYeAuc3iN8u2bL5Uz/p9fivsCbWgzIANhT4o4QzhwBucJPN/Yi0KoP9' +
|
||||
'4qnBGRZKdWoRg6uBvdIo8xgDDgP2UKPv5NQHTvAcXUk4QlUzftmA9BMamQKBgDFa' +
|
||||
'D6zKPR5oNJnQgddsYZBXVxWksH8VMiR93TRnl/XGYuydqVKxbz3oqzhwGRBA57ew' +
|
||||
'B+ov8Fz02EgHldkhkH0Oh8pgfhtr5WrnQbWwAWpvS/+tiSTrcJn6AAwEE07yA2qW' +
|
||||
'i6NNVAjZAPksd4Djel+2CE6L7+I68PthENkFjUtlAoGAX+TvpFV9b7O+HxpKtljz' +
|
||||
'DrCoN54myazIAbkEkQTHoCQcqdnvS4pnCTi+j7Gcvncbw1DHqCUadV4MG+9BNLjp' +
|
||||
'ZuKNEqVcjdKyVC1ZO8o58/PC/jKf46BZf0KPZ2njYN/HhTsYKW+cS8BqQ03z05Vx' +
|
||||
'mIRN6htJ2rDNYLnPKuFxW1s=';
|
||||
|
||||
RSA2048_ExampleCom_1_CertificatePEM =
|
||||
'MIID2TCCAsGgAwIBAgIUDjajQu/92DMG5roEQ0G4WkQ49pQwDQYJKoZIhvcNAQEL' +
|
||||
'BQAwfDELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM' +
|
||||
'GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwLZXhhbXBsZS5jb20x' +
|
||||
'HzAdBgkqhkiG9w0BCQEWEGluZm9AZXhhbXBsZS5jb20wHhcNMjAwNTExMTgyNzE2' +
|
||||
'WhcNMzAwNTA5MTgyNzE2WjB8MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1T' +
|
||||
'dGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRQwEgYDVQQD' +
|
||||
'DAtleGFtcGxlLmNvbTEfMB0GCSqGSIb3DQEJARYQaW5mb0BleGFtcGxlLmNvbTCC' +
|
||||
'ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN7pwVOPhyKVp0akcT2vTK0N' +
|
||||
'+ZYpWecllgtHYMs9WDotWQR7KS6x9RKl/iljAo65OgsPbiJmkrnHcJhRHfjw5eQV' +
|
||||
'PbK1DAhzJGEr3U3nHTpZua0JKXYXHQZUForB+DHvcs1/C0a9w5BU5DKGjMebROSE' +
|
||||
'EdWmUnnuEPdgZMf3xZKJE/R9LXJXn3nA/vadgC88CnrVtVilE0kOMVlARK5uKBgH' +
|
||||
'm58tR8ae2U5qw13UK4gIUWRKlGLVx3+vqq+rh6GEfvKkZMGNs9DdmD2+mNHkHc0I' +
|
||||
'q0faf3R8rL4W7F9ybvcZSKeNHULrpV7QIei+iyQRE4JxsKiLVVPb6jL5yo4TF8UC' +
|
||||
'AwEAAaNTMFEwHQYDVR0OBBYEFBPFygrc+d52rGccjTlh0lRXhn7VMB8GA1UdIwQY' +
|
||||
'MBaAFBPFygrc+d52rGccjTlh0lRXhn7VMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI' +
|
||||
'hvcNAQELBQADggEBAJqY4EARd0fHRYTtQA7antfIGSSDYH0S5E3mVSQEKKNR029h' +
|
||||
'XJNUKi93kheAwMAQlgKqFWWIPRGvEg8rVux3T6tSm14v7aEYmC6z/XdidYo1hA6F' +
|
||||
'f4hAC2eBkhzEcql1FAbt+s1crBmLkfRWxeI8E7/xYmFYP99QJdv+BkxD48Rf+bE3' +
|
||||
'hRIq2X2yOq1oC1zGR75fWcL7+6418bwYQfeOrn4bSHuWiOq19kELlzUQbSmjPnmF' +
|
||||
'zSErKEU8hezaVX5Z6mwYgV1P4Y4CPHaoK/Tl55Lr0KSLEc2U5Ff3SBKvkgkW968q' +
|
||||
'JYTt4/thw9MVT9/AO63iAIiYF79e8C5ZTYa6J/s=';
|
||||
|
||||
|
||||
|
||||
// ecdsa-secp256k1-example.com-1
|
||||
ECDSA_Secp256k1_ExampleCom_1_PrivateKeyPEM =
|
||||
'MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgH1iT7iOnhczYKDnUnd0T' +
|
||||
'01m31q2wwDouonax6KF04r2hRANCAATQcPezFewJYlOYPDSYuy46Bu9SAfU8qo7a' +
|
||||
'OYCFgN/WmiFckB/oi+sEqnYxsgPMN77+c9EjSjvl1zKCQhEP4nf1';
|
||||
|
||||
ECDSA_Secp256k1_ExampleCom_1_CertificatePEM =
|
||||
'MIICSzCCAfCgAwIBAgIUMknQUnv2p2k+F2ATArxlu9STJuwwCgYIKoZIzj0EAwIw' +
|
||||
'fDELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu' +
|
||||
'dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwLZXhhbXBsZS5jb20xHzAd' +
|
||||
'BgkqhkiG9w0BCQEWEGluZm9AZXhhbXBsZS5jb20wHhcNMjAwNTExMTg0MTE4WhcN' +
|
||||
'MzAwNTA5MTg0MTE4WjB8MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0' +
|
||||
'ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRQwEgYDVQQDDAtl' +
|
||||
'eGFtcGxlLmNvbTEfMB0GCSqGSIb3DQEJARYQaW5mb0BleGFtcGxlLmNvbTBWMBAG' +
|
||||
'ByqGSM49AgEGBSuBBAAKA0IABNBw97MV7AliU5g8NJi7LjoG71IB9Tyqjto5gIWA' +
|
||||
'39aaIVyQH+iL6wSqdjGyA8w3vv5z0SNKO+XXMoJCEQ/id/WjUzBRMB0GA1UdDgQW' +
|
||||
'BBRa68KZXd4PMT2ujfRcGelXVYT5RTAfBgNVHSMEGDAWgBRa68KZXd4PMT2ujfRc' +
|
||||
'GelXVYT5RTAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDjOYWa' +
|
||||
'geEf616bxFlOq6GTqzHNdAsoYcllkvdTH7oGrAIhAMx/D4pikimc/8PKt2RROqU2' +
|
||||
'1pYBYY4q+WNHi/FkP1Rb';
|
||||
|
||||
|
||||
|
||||
// dsa-512-example.com-1
|
||||
DSA512_ExampleCom_1_DSAParamsPEM =
|
||||
'MIGdAkEAy7pVdOq2xqDKhJVOK3yjEcBdngaCsng6nahCzR/YkOY1OS+Eb4ED+vv7' +
|
||||
'bjWxjZzQxknRzcgMqAwLEabjoxNIGwIVAOveBUI43583wCYz0nUtdEtRAaEpAkEA' +
|
||||
'uDkymWK9Bcy+YF+x4+xOyM1XGvyXb43TjkvwH+lTrH8jyeNpOfID07cW7xIBR/pz' +
|
||||
'r7sf6aFr0VqBWli+T+5KZQ==';
|
||||
|
||||
DSA512_ExampleCom_1_PrivateKeyPEM =
|
||||
'MIH5AgEAAkEAy7pVdOq2xqDKhJVOK3yjEcBdngaCsng6nahCzR/YkOY1OS+Eb4ED' +
|
||||
'+vv7bjWxjZzQxknRzcgMqAwLEabjoxNIGwIVAOveBUI43583wCYz0nUtdEtRAaEp' +
|
||||
'AkEAuDkymWK9Bcy+YF+x4+xOyM1XGvyXb43TjkvwH+lTrH8jyeNpOfID07cW7xIB' +
|
||||
'R/pzr7sf6aFr0VqBWli+T+5KZQJBAIVwoK42Ydy2m7mtij2NLZ0Bom8l65+XQ62+' +
|
||||
'BmV2+2SPZaLOP3R+6p3voWbimxLr1dHqnaPLxcoNvtLk0QVsAqECFETKnDMulFrC' +
|
||||
'pWeRddos5U5WJNzC';
|
||||
|
||||
DSA512_ExampleCom_1_CertificatePEM =
|
||||
'MIIC0TCCAo6gAwIBAgIUfVSUaT4wpDU2h5Czdf+zJPqtVQYwCwYJYIZIAWUDBAMC' +
|
||||
'MHwxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJ' +
|
||||
'bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFDASBgNVBAMMC2V4YW1wbGUuY29tMR8w' +
|
||||
'HQYJKoZIhvcNAQkBFhBpbmZvQGV4YW1wbGUuY29tMB4XDTIwMDUxMTE5NTEyOFoX' +
|
||||
'DTMwMDUwOTE5NTEyOFowfDELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3Rh' +
|
||||
'dGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwL' +
|
||||
'ZXhhbXBsZS5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9AZXhhbXBsZS5jb20wgfIw' +
|
||||
'gakGByqGSM44BAEwgZ0CQQDLulV06rbGoMqElU4rfKMRwF2eBoKyeDqdqELNH9iQ' +
|
||||
'5jU5L4RvgQP6+/tuNbGNnNDGSdHNyAyoDAsRpuOjE0gbAhUA694FQjjfnzfAJjPS' +
|
||||
'dS10S1EBoSkCQQC4OTKZYr0FzL5gX7Hj7E7IzVca/JdvjdOOS/Af6VOsfyPJ42k5' +
|
||||
'8gPTtxbvEgFH+nOvux/poWvRWoFaWL5P7kplA0QAAkEAvsRAbx3gJSKdOAmD6922' +
|
||||
'L/akoJiyT6hkz/9/D+oHvfdD6C5djg9E7ldBxu2y4G0RT6hrBgucnaY5EKRQ4Qa3' +
|
||||
'aqNTMFEwHQYDVR0OBBYEFN8uO0Y+73h43EIYn10VZvHY28/iMB8GA1UdIwQYMBaA' +
|
||||
'FN8uO0Y+73h43EIYn10VZvHY28/iMA8GA1UdEwEB/wQFMAMBAf8wCwYJYIZIAWUD' +
|
||||
'BAMCAzAAMC0CFQDJuGO19W778E8nVcowcu6INt4++gIUURUMEWm/dRO+4ti8GoHD' +
|
||||
'X4xdmkI=';
|
||||
|
||||
|
||||
|
||||
// dsa-2048-example.com-1
|
||||
DSA2048_ExampleCom_1_DSAParamsPEM =
|
||||
'MIICLAKCAQEA0SWakCcmMvfxKFGQZkRCYDvaCIVu1PVuDTzclYdvWMLRajxpO3jK' +
|
||||
'paekYV9kh/beE6aRtyhEvNbEo9YmWPM8PSYwN5OBp8mW+gxaO7yrr/SVNXrF+xsK' +
|
||||
'dXle7UE4gP5JXtY4Tnl0u0BBGyrhl5rnBKfxJllhC4c+YEoEb+IWuJcal9Qhv1S7' +
|
||||
'dxVqB7KJ1PG8IOe4ainWjM7bnqjoHd5JpqfNami9CKKoV5EAdiQcVPEVcf1uKU+F' +
|
||||
'E6TzAqep60MTdi6K7l+xfTHKt15aZlcAS/93rkA6BiguUK/JV8JFGUvY2Zu2hNh0' +
|
||||
'FlJfGIShRbScrf8jIelzFeCdZc6EujSrQQIhAOTD9z+JcF8PGCRmyHDAdUEDnlXw' +
|
||||
'lobq80CtiTeabSwLAoIBABQTvKuqZNNbhMw6jwjwrVLhbRxVcaLxRHKVGS4b7+zN' +
|
||||
'j6zBANZ+OD0ds9XFpy5XIAkwgOiFCK3A/QC+1/eSRqSpzaBb6NwN9poAsxh5TzQe' +
|
||||
'0j1FmvUGDzjHgPSCZXCaEqgFtwqzn188oeOAWsGDNHfEeEIzM735AEyOfIEtDNwE' +
|
||||
'r5xaUpJa0m0q1TRule90VySR+1JMOJBdl6rDXeUe5YgdjW0oXBoZ7Ejlbzz8bjwk' +
|
||||
'LZaxipq4iScHar6gNIXSH5NRmhKRANg9/IRdzdduC0iyCwvANlQXjNqv6qxONvnK' +
|
||||
'Eeud+U0qeOzXQpFunX7jk0pWhXJsrHYoYE8JEF+t2TE=';
|
||||
|
||||
DSA2048_ExampleCom_1_PrivateKeyPEM =
|
||||
'MIIDVgIBAAKCAQEA0SWakCcmMvfxKFGQZkRCYDvaCIVu1PVuDTzclYdvWMLRajxp' +
|
||||
'O3jKpaekYV9kh/beE6aRtyhEvNbEo9YmWPM8PSYwN5OBp8mW+gxaO7yrr/SVNXrF' +
|
||||
'+xsKdXle7UE4gP5JXtY4Tnl0u0BBGyrhl5rnBKfxJllhC4c+YEoEb+IWuJcal9Qh' +
|
||||
'v1S7dxVqB7KJ1PG8IOe4ainWjM7bnqjoHd5JpqfNami9CKKoV5EAdiQcVPEVcf1u' +
|
||||
'KU+FE6TzAqep60MTdi6K7l+xfTHKt15aZlcAS/93rkA6BiguUK/JV8JFGUvY2Zu2' +
|
||||
'hNh0FlJfGIShRbScrf8jIelzFeCdZc6EujSrQQIhAOTD9z+JcF8PGCRmyHDAdUED' +
|
||||
'nlXwlobq80CtiTeabSwLAoIBABQTvKuqZNNbhMw6jwjwrVLhbRxVcaLxRHKVGS4b' +
|
||||
'7+zNj6zBANZ+OD0ds9XFpy5XIAkwgOiFCK3A/QC+1/eSRqSpzaBb6NwN9poAsxh5' +
|
||||
'TzQe0j1FmvUGDzjHgPSCZXCaEqgFtwqzn188oeOAWsGDNHfEeEIzM735AEyOfIEt' +
|
||||
'DNwEr5xaUpJa0m0q1TRule90VySR+1JMOJBdl6rDXeUe5YgdjW0oXBoZ7Ejlbzz8' +
|
||||
'bjwkLZaxipq4iScHar6gNIXSH5NRmhKRANg9/IRdzdduC0iyCwvANlQXjNqv6qxO' +
|
||||
'NvnKEeud+U0qeOzXQpFunX7jk0pWhXJsrHYoYE8JEF+t2TECggEAbafGARPAM0KD' +
|
||||
'9DNoJTKn94GXQPJcHMqE8i8IZtDTtn2jFNcz5p+Ee9n7Tz0fPeNQuaQLUF3GK7wT' +
|
||||
'82D1JxEyFmWXysIyDa45iwXfFUMb44DxOZh6PNcH7pn/ZTQg9LeXFOSqpIUdEzAC' +
|
||||
'0feCbfaWT081vnJFEq6ZZ4TKNTiYo/pFRs6d6KxlJGHtuR1FvFcR2HmK9wff0W7t' +
|
||||
'wA3+D7rqE1eJd6GiAf2WGYkdwt/Jbyqtn3hQyO6++23qsE9yStaweL5lGxsyzpZ1' +
|
||||
'dyaKg9yQNZZGGIey7EPTZ02bpceADxx0beWg3QhSXMzk35+AA2o4wyL6jWujy7zR' +
|
||||
'xIDYYdGsCwIhAINGDcB6W3IQCCe/XSHrJ9uXEQ7zcytzmBbPBJW7L2Gr';
|
||||
|
||||
DSA2048_ExampleCom_1_CertificatePEM =
|
||||
'MIIFPjCCBOOgAwIBAgIURBEKc3eR4RfSATcwzqCG4zr2rvowCwYJYIZIAWUDBAMC' +
|
||||
'MHwxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJ' +
|
||||
'bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFDASBgNVBAMMC2V4YW1wbGUuY29tMR8w' +
|
||||
'HQYJKoZIhvcNAQkBFhBpbmZvQGV4YW1wbGUuY29tMB4XDTIwMDUxMTE4Mzc0MFoX' +
|
||||
'DTMwMDUwOTE4Mzc0MFowfDELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3Rh' +
|
||||
'dGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwL' +
|
||||
'ZXhhbXBsZS5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9AZXhhbXBsZS5jb20wggNG' +
|
||||
'MIICOQYHKoZIzjgEATCCAiwCggEBANElmpAnJjL38ShRkGZEQmA72giFbtT1bg08' +
|
||||
'3JWHb1jC0Wo8aTt4yqWnpGFfZIf23hOmkbcoRLzWxKPWJljzPD0mMDeTgafJlvoM' +
|
||||
'Wju8q6/0lTV6xfsbCnV5Xu1BOID+SV7WOE55dLtAQRsq4Zea5wSn8SZZYQuHPmBK' +
|
||||
'BG/iFriXGpfUIb9Uu3cVageyidTxvCDnuGop1ozO256o6B3eSaanzWpovQiiqFeR' +
|
||||
'AHYkHFTxFXH9bilPhROk8wKnqetDE3Yuiu5fsX0xyrdeWmZXAEv/d65AOgYoLlCv' +
|
||||
'yVfCRRlL2NmbtoTYdBZSXxiEoUW0nK3/IyHpcxXgnWXOhLo0q0ECIQDkw/c/iXBf' +
|
||||
'DxgkZshwwHVBA55V8JaG6vNArYk3mm0sCwKCAQAUE7yrqmTTW4TMOo8I8K1S4W0c' +
|
||||
'VXGi8URylRkuG+/szY+swQDWfjg9HbPVxacuVyAJMIDohQitwP0Avtf3kkakqc2g' +
|
||||
'W+jcDfaaALMYeU80HtI9RZr1Bg84x4D0gmVwmhKoBbcKs59fPKHjgFrBgzR3xHhC' +
|
||||
'MzO9+QBMjnyBLQzcBK+cWlKSWtJtKtU0bpXvdFckkftSTDiQXZeqw13lHuWIHY1t' +
|
||||
'KFwaGexI5W88/G48JC2WsYqauIknB2q+oDSF0h+TUZoSkQDYPfyEXc3XbgtIsgsL' +
|
||||
'wDZUF4zar+qsTjb5yhHrnflNKnjs10KRbp1+45NKVoVybKx2KGBPCRBfrdkxA4IB' +
|
||||
'BQACggEAbafGARPAM0KD9DNoJTKn94GXQPJcHMqE8i8IZtDTtn2jFNcz5p+Ee9n7' +
|
||||
'Tz0fPeNQuaQLUF3GK7wT82D1JxEyFmWXysIyDa45iwXfFUMb44DxOZh6PNcH7pn/' +
|
||||
'ZTQg9LeXFOSqpIUdEzAC0feCbfaWT081vnJFEq6ZZ4TKNTiYo/pFRs6d6KxlJGHt' +
|
||||
'uR1FvFcR2HmK9wff0W7twA3+D7rqE1eJd6GiAf2WGYkdwt/Jbyqtn3hQyO6++23q' +
|
||||
'sE9yStaweL5lGxsyzpZ1dyaKg9yQNZZGGIey7EPTZ02bpceADxx0beWg3QhSXMzk' +
|
||||
'35+AA2o4wyL6jWujy7zRxIDYYdGsC6NTMFEwHQYDVR0OBBYEFC+/k77yRQlGFqpI' +
|
||||
'unC/qriSkUcoMB8GA1UdIwQYMBaAFC+/k77yRQlGFqpIunC/qriSkUcoMA8GA1Ud' +
|
||||
'EwEB/wQFMAMBAf8wCwYJYIZIAWUDBAMCA0gAMEUCIQCzQ2pv8wajCK9V/0DL4WVE' +
|
||||
'9bPgwloEdmFzoxMxeHfePwIgKjeEa1eIgbzQhMqaejjp/XsuATHUZ6cPU3A3uDWs' +
|
||||
'ezo=';
|
||||
|
||||
|
||||
// rsa-stunnel
|
||||
// from stunnel pem file
|
||||
RSA_STunnel_PrivateKeyRSAPEM =
|
||||
'MIICXAIBAAKBgQCxUFMuqJJbI9KnB8VtwSbcvwNOltWBtWyaSmp7yEnqwWel5TFf' +
|
||||
'cOObCuLZ69sFi1ELi5C91qRaDMow7k5Gj05DZtLDFfICD0W1S+n2Kql2o8f2RSvZ' +
|
||||
'qD2W9l8i59XbCz1oS4l9S09L+3RTZV9oer/Unby/QmicFLNM0WgrVNiKywIDAQAB' +
|
||||
'AoGAKX4KeRipZvpzCPMgmBZi6bUpKPLS849o4pIXaO/tnCm1/3QqoZLhMB7UBvrS' +
|
||||
'PfHj/Tejn0jjHM9xYRHi71AJmAgzI+gcN1XQpHiW6kATNDz1r3yftpjwvLhuOcp9' +
|
||||
'tAOblojtImV8KrAlVH/21rTYQI+Q0m9qnWKKCoUsX9Yu8UECQQDlbHL38rqBvIMk' +
|
||||
'zK2wWJAbRvVf4Fs47qUSef9pOo+p7jrrtaTqd99irNbVRe8EWKbSnAod/B04d+cQ' +
|
||||
'ci8W+nVtAkEAxdqPOnCISW4MeS+qHSVtaGv2kwvfxqfsQw+zkwwHYqa+ueg4wHtG' +
|
||||
'/9+UgxcXyCXrj0ciYCqURkYhQoPbWP82FwJAWWkjgTgqsYcLQRs3kaNiPg8wb7Yb' +
|
||||
'NxviX0oGXTdCaAJ9GgGHjQ08lNMxQprnpLT8BtZjJv5rUOeBuKoXagggHQJAaUAF' +
|
||||
'91GLvnwzWHg5p32UgPsF1V14siX8MgR1Q6EfgKQxS5Y0Mnih4VXfnAi51vgNIk/2' +
|
||||
'AnBEJkoCQW8BTYueCwJBALvz2JkaUfCJc18E7jCP7qLY4+6qqsq+wr0t18+ogOM9' +
|
||||
'JIY9r6e1qwNxQ/j1Mud6gn6cRrObpRtEad5z2FtcnwY=';
|
||||
|
||||
RSA_STunnel_CertificatePEM =
|
||||
'MIICDzCCAXigAwIBAgIBADANBgkqhkiG9w0BAQQFADBCMQswCQYDVQQGEwJQTDEf' +
|
||||
'MB0GA1UEChMWU3R1bm5lbCBEZXZlbG9wZXJzIEx0ZDESMBAGA1UEAxMJbG9jYWxo' +
|
||||
'b3N0MB4XDTk5MDQwODE1MDkwOFoXDTAwMDQwNzE1MDkwOFowQjELMAkGA1UEBhMC' +
|
||||
'UEwxHzAdBgNVBAoTFlN0dW5uZWwgRGV2ZWxvcGVycyBMdGQxEjAQBgNVBAMTCWxv' +
|
||||
'Y2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsVBTLqiSWyPSpwfF' +
|
||||
'bcEm3L8DTpbVgbVsmkpqe8hJ6sFnpeUxX3Djmwri2evbBYtRC4uQvdakWgzKMO5O' +
|
||||
'Ro9OQ2bSwxXyAg9FtUvp9iqpdqPH9kUr2ag9lvZfIufV2ws9aEuJfUtPS/t0U2Vf' +
|
||||
'aHq/1J28v0JonBSzTNFoK1TYissCAwEAAaMVMBMwEQYJYIZIAYb4QgEBBAQDAgZA' +
|
||||
'MA0GCSqGSIb3DQEBBAUAA4GBAAhYFTngWc3tuMjVFhS4HbfFF/vlOgTu44/rv2F+' +
|
||||
'ya1mEB93htfNxx3ofRxcjCdorqONZFwEba6xZ8/UujYfVmIGCBy4X8+aXd83TJ9A' +
|
||||
'eSjTzV9UayOoGtmg8Dv2aj/5iabNeK1Qf35ouvlcTezVZt2ZeJRhqUHcGaE+apCN' +
|
||||
'TC9Y';
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
|
||||
|
||||
end.
|
||||
|
413
contrib/fundamentals/TLS/flcTLSTests.pas
Normal file
413
contrib/fundamentals/TLS/flcTLSTests.pas
Normal file
@@ -0,0 +1,413 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSTests.pas }
|
||||
{ File version: 5.05 }
|
||||
{ Description: TLS tests }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2010/12/15 0.02 Client/Server test case. }
|
||||
{ 2010/12/17 0.03 Client/Server test cases for TLS 1.0, 1.1 and 1.2. }
|
||||
{ 2018/07/17 5.04 Revised for Fundamentals 5. }
|
||||
{ 2020/05/11 5.05 Use client options. }
|
||||
{ }
|
||||
{ References: }
|
||||
{ }
|
||||
{ SSL 3 - www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt }
|
||||
{ RFC 2246 - The TLS Protocol Version 1.0 }
|
||||
{ RFC 4346 - The TLS Protocol Version 1.1 }
|
||||
{ RFC 5246 - The TLS Protocol Version 1.2 }
|
||||
{ RFC 4366 - Transport Layer Security (TLS) Extensions }
|
||||
{ www.mozilla.org/projects/security/pki/nss/ssl/traces/trc-clnt-ex.html }
|
||||
{ RFC 4492 - Elliptic Curve Cryptography (ECC) Cipher Suites }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
// ----------------------------------------------------- -------------------------------------------
|
||||
// CIPHER SUITE ClientServer Test
|
||||
// ----------------------------------------------------- -------------------------------------------
|
||||
// RSA_WITH_RC4_128_MD5 TESTED OK
|
||||
// RSA_WITH_RC4_128_SHA TESTED OK
|
||||
// RSA_WITH_DES_CBC_SHA TESTED OK
|
||||
// RSA_WITH_AES_128_CBC_SHA TESTED OK
|
||||
// RSA_WITH_AES_256_CBC_SHA TESTED OK
|
||||
// RSA_WITH_AES_128_CBC_SHA256 TESTED OK TLS 1.2 only
|
||||
// RSA_WITH_AES_256_CBC_SHA256 TESTED OK TLS 1.2 only
|
||||
// NULL_WITH_NULL_NULL UNTESTED
|
||||
// RSA_WITH_NULL_MD5 UNTESTED
|
||||
// RSA_WITH_NULL_SHA UNTESTED
|
||||
// RSA_WITH_IDEA_CBC_SHA UNTESTED
|
||||
// RSA_WITH_3DES_EDE_CBC_SHA ERROR: SERVER DECRYPTION FAILED
|
||||
// RSA_WITH_NULL_SHA256 ERROR
|
||||
// DHE_RSA_WITH_AES_256_CBC_SHA TESTED OK TLS 1.2
|
||||
// ----------------------------------------------------- -------------------------------------------
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
{$DEFINE TLS_TEST_LOG_TO_CONSOLE}
|
||||
|
||||
{$DEFINE Cipher_SupportEC}
|
||||
|
||||
unit flcTLSTests;
|
||||
|
||||
interface
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test }
|
||||
{ }
|
||||
{$IFDEF TLS_TEST}
|
||||
procedure Test;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{ System }
|
||||
|
||||
SysUtils,
|
||||
SyncObjs,
|
||||
|
||||
{ Utils }
|
||||
|
||||
flcStdTypes,
|
||||
flcBase64,
|
||||
flcStrings,
|
||||
flcPEM,
|
||||
flcASN1,
|
||||
flcX509Certificate,
|
||||
flcHugeInt,
|
||||
|
||||
{ Cipher }
|
||||
|
||||
flcCipherAES,
|
||||
flcCipherRSA,
|
||||
flcCipherDH,
|
||||
{$IFDEF Cipher_SupportEC}
|
||||
flcCipherEllipticCurve,
|
||||
{$ENDIF}
|
||||
|
||||
{ TLS }
|
||||
|
||||
flcTLSConsts,
|
||||
flcTLSProtocolVersion,
|
||||
flcTLSRecord,
|
||||
flcTLSAlert,
|
||||
flcTLSAlgorithmTypes,
|
||||
flcTLSRandom,
|
||||
flcTLSCertificate,
|
||||
flcTLSHandshake,
|
||||
flcTLSCipher,
|
||||
flcTLSPRF,
|
||||
flcTLSKeys,
|
||||
flcTLSTransportTypes,
|
||||
flcTLSTransportConnection,
|
||||
flcTLSTransportClient,
|
||||
flcTLSTransportServer,
|
||||
flcTLSTestCertificates;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test }
|
||||
{ }
|
||||
{$IFDEF TLS_TEST}
|
||||
type
|
||||
TTLSClientServerTester = class
|
||||
Lock : TCriticalSection;
|
||||
Sr : TTLSServer;
|
||||
Cl : TTLSClient;
|
||||
SCl : TTLSServerClient;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
procedure ServerTLSendProc(Server: TTLSServer; Client: TTLSServerClient; const Buffer; const Size: Integer);
|
||||
procedure ClientTLSendProc(const Sender: TTLSConnection; const Buffer; const Size: Integer);
|
||||
procedure Log(Msg: String);
|
||||
procedure ClientLog(Sender: TTLSConnection; LogType: TTLSLogType; LogMsg: String; LogLevel: Integer);
|
||||
procedure ServerLog(Sender: TTLSServer; LogType: TTLSLogType; LogMsg: String; LogLevel: Integer);
|
||||
end;
|
||||
|
||||
constructor TTLSClientServerTester.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
Lock := TCriticalSection.Create;
|
||||
Sr := TTLSServer.Create(ServerTLSendProc);
|
||||
Sr.OnLog := ServerLog;
|
||||
Cl := TTLSClient.Create(ClientTLSendProc);
|
||||
Cl.OnLog := ClientLog;
|
||||
end;
|
||||
|
||||
destructor TTLSClientServerTester.Destroy;
|
||||
begin
|
||||
FreeAndNil(Cl);
|
||||
FreeAndNil(Sr);
|
||||
FreeAndNil(Lock);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TTLSClientServerTester.ServerTLSendProc(Server: TTLSServer; Client: TTLSServerClient; const Buffer; const Size: Integer);
|
||||
begin
|
||||
Assert(Assigned(Cl));
|
||||
Cl.ProcessTransportLayerReceivedData(Buffer, Size);
|
||||
end;
|
||||
|
||||
procedure TTLSClientServerTester.ClientTLSendProc(const Sender: TTLSConnection; const Buffer; const Size: Integer);
|
||||
begin
|
||||
Assert(Assigned(SCl));
|
||||
SCl.ProcessTransportLayerReceivedData(Buffer, Size);
|
||||
end;
|
||||
|
||||
{$IFDEF TLS_TEST_LOG_TO_CONSOLE}
|
||||
procedure TTLSClientServerTester.Log(Msg: String);
|
||||
var S : String;
|
||||
begin
|
||||
S := FormatDateTime('hh:nn:ss.zzz', Now) + ' ' + Msg;
|
||||
Lock.Acquire;
|
||||
try
|
||||
Writeln(S);
|
||||
finally
|
||||
Lock.Release;
|
||||
end;
|
||||
end;
|
||||
{$ELSE}
|
||||
procedure TTLSClientServerTester.Log(Msg: String);
|
||||
begin
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
procedure TTLSClientServerTester.ClientLog(Sender: TTLSConnection; LogType: TTLSLogType; LogMsg: String; LogLevel: Integer);
|
||||
begin
|
||||
Log(IntToStr(LogLevel) + ' C:' + LogMsg);
|
||||
end;
|
||||
|
||||
procedure TTLSClientServerTester.ServerLog(Sender: TTLSServer; LogType: TTLSLogType; LogMsg: String; LogLevel: Integer);
|
||||
begin
|
||||
Log(IntToStr(LogLevel) + ' S:' + LogMsg);
|
||||
end;
|
||||
|
||||
procedure TestClientServer(
|
||||
const ClientOptions : TTLSClientOptions = [];
|
||||
const VersionOptions : TTLSVersionOptions = DefaultTLSClientVersionOptions;
|
||||
const KeyExchangeOptions : TTLSKeyExchangeOptions = DefaultTLSClientKeyExchangeOptions;
|
||||
const CipherOptions : TTLSCipherOptions = DefaultTLSClientCipherOptions;
|
||||
const HashOptions : TTLSHashOptions = DefaultTLSClientHashOptions
|
||||
);
|
||||
const
|
||||
LargeBlockSize = TLS_PLAINTEXT_FRAGMENT_MAXSIZE * 8;
|
||||
var CS : TTLSClientServerTester;
|
||||
CtL : TTLSCertificateList;
|
||||
S : RawByteString;
|
||||
I, L : Integer;
|
||||
begin
|
||||
CS := TTLSClientServerTester.Create;
|
||||
try
|
||||
// initialise client
|
||||
CS.Cl.ClientOptions := ClientOptions;
|
||||
// initialise server
|
||||
CS.Sr.PrivateKeyRSAPEM := RSA_STunnel_PrivateKeyRSAPEM;
|
||||
TLSCertificateListAppend(CtL,
|
||||
MIMEBase64Decode(RSA_STunnel_CertificatePEM));
|
||||
CS.Sr.CertificateList := CtL;
|
||||
CS.Sr.DHKeySize := 512;
|
||||
// start server
|
||||
CS.Sr.Start;
|
||||
Assert(CS.Sr.State = tlssActive);
|
||||
// start connection
|
||||
CS.SCl := CS.Sr.AddClient(nil);
|
||||
CS.SCl.Start;
|
||||
CS.Cl.Start;
|
||||
// negotiated
|
||||
Assert(CS.Cl.IsReadyState);
|
||||
Assert(CS.SCl.IsReadyState);
|
||||
// application data (small block)
|
||||
S := 'Fundamentals';
|
||||
CS.Cl.Write(S[1], Length(S));
|
||||
Assert(CS.SCl.AvailableToRead = 12);
|
||||
S := '1234567890';
|
||||
Assert(CS.SCl.Read(S[1], 3) = 3);
|
||||
Assert(CS.SCl.AvailableToRead = 9);
|
||||
Assert(S = 'Fun4567890');
|
||||
Assert(CS.SCl.Read(S[1], 9) = 9);
|
||||
Assert(CS.SCl.AvailableToRead = 0);
|
||||
Assert(S = 'damentals0');
|
||||
S := 'Fundamentals';
|
||||
CS.SCl.Write(S[1], Length(S));
|
||||
Assert(CS.Cl.AvailableToRead = 12);
|
||||
S := '123456789012';
|
||||
Assert(CS.Cl.Read(S[1], 12) = 12);
|
||||
Assert(CS.Cl.AvailableToRead = 0);
|
||||
Assert(S = 'Fundamentals');
|
||||
// application data (large blocks)
|
||||
for L := LargeBlockSize - 1 to LargeBlockSize + 1 do
|
||||
begin
|
||||
SetLength(S, L);
|
||||
FillChar(S[1], L, #1);
|
||||
CS.Cl.Write(S[1], L);
|
||||
Assert(CS.SCl.AvailableToRead = L);
|
||||
FillChar(S[1], L, #0);
|
||||
CS.SCl.Read(S[1], L);
|
||||
for I := 1 to L do
|
||||
Assert(S[I] = #1);
|
||||
Assert(CS.SCl.AvailableToRead = 0);
|
||||
CS.SCl.Write(S[1], L);
|
||||
Assert(CS.Cl.AvailableToRead = L);
|
||||
FillChar(S[1], L, #0);
|
||||
Assert(CS.Cl.Read(S[1], L) = L);
|
||||
for I := 1 to L do
|
||||
Assert(S[I] = #1);
|
||||
Assert(CS.Cl.AvailableToRead = 0);
|
||||
end;
|
||||
// close
|
||||
CS.Cl.Close;
|
||||
Assert(CS.Cl.IsFinishedState);
|
||||
Assert(CS.SCl.IsFinishedState);
|
||||
// stop
|
||||
CS.Sr.RemoveClient(CS.SCl);
|
||||
CS.Sr.Stop;
|
||||
finally
|
||||
FreeAndNil(CS);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure Test_Units_Dependencies;
|
||||
begin
|
||||
flcPEM.Test;
|
||||
flcASN1.Test;
|
||||
flcX509Certificate.Test;
|
||||
|
||||
flcHugeInt.Test;
|
||||
|
||||
flcCipherAES.Test;
|
||||
flcCipherRSA.Test;
|
||||
flcCipherDH.Test;
|
||||
{$IFDEF Cipher_SupportEC}
|
||||
flcCipherEllipticCurve.Test;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure Test_Units_TLS;
|
||||
begin
|
||||
flcTLSAlert.Test;
|
||||
flcTLSAlgorithmTypes.Test;
|
||||
flcTLSRandom.Test;
|
||||
flcTLSCipher.Test;
|
||||
flcTLSHandshake.Test;
|
||||
flcTLSKeys.Test;
|
||||
flcTLSProtocolVersion.Test;
|
||||
flcTLSPRF.Test;
|
||||
flcTLSRecord.Test;
|
||||
end;
|
||||
|
||||
procedure Test_ClientServer_TLSVersions;
|
||||
begin
|
||||
// TLS 1.2
|
||||
TestClientServer([], [tlsvoTLS12]);
|
||||
// TLS 1.1
|
||||
TestClientServer([], [tlsvoTLS11]);
|
||||
// TLS 1.0
|
||||
TestClientServer([], [tlsvoTLS10]);
|
||||
Sleep(100);
|
||||
// SSL 3
|
||||
// Fails with invalid parameter
|
||||
//SelfTestClientServer([], [tlsvoSSL3]);
|
||||
end;
|
||||
|
||||
procedure Test_ClientServer_KeyExchangeAlgos;
|
||||
begin
|
||||
// TLS 1.2 RSA
|
||||
TestClientServer([], [tlsvoTLS12], [tlskeoRSA]);
|
||||
// TLS 1.2 DHE_RSA
|
||||
TestClientServer([], [tlsvoTLS12], [tlskeoDHE_RSA]);
|
||||
// TLS 1.2 DH_anon
|
||||
// Under development/testing
|
||||
//SelfTestClientServer([], [tlsvoTLS12], [tlskeoDH_Anon]);
|
||||
end;
|
||||
|
||||
procedure Test_ClientServer_CipherAlgos;
|
||||
begin
|
||||
// TLS 1.2 RC4
|
||||
TestClientServer([], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions,
|
||||
[tlscoRC4]);
|
||||
// TLS 1.2 AES128
|
||||
TestClientServer([], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions,
|
||||
[tlscoAES128]);
|
||||
// TLS 1.2 AES256
|
||||
TestClientServer([], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions,
|
||||
[tlscoAES256]);
|
||||
// TLS 1.2 DES
|
||||
TestClientServer([], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions,
|
||||
[tlscoDES]);
|
||||
// TLS 1.2 3DES
|
||||
// No Cipher Suite
|
||||
{SelfTestClientServer([], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions,
|
||||
[tlsco3DES]);}
|
||||
end;
|
||||
|
||||
procedure Test_ClientServer_HashAlgos;
|
||||
begin
|
||||
// TLS 1.2 SHA256
|
||||
TestClientServer(
|
||||
[], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions, DefaultTLSClientCipherOptions,
|
||||
[tlshoSHA256]);
|
||||
// TLS 1.2 SHA1
|
||||
TestClientServer(
|
||||
[], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions, DefaultTLSClientCipherOptions,
|
||||
[tlshoSHA1]);
|
||||
// TLS 1.2 MD5
|
||||
TestClientServer(
|
||||
[], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions, DefaultTLSClientCipherOptions,
|
||||
[tlshoMD5]);
|
||||
end;
|
||||
|
||||
procedure Test_ClientServer;
|
||||
begin
|
||||
Test_ClientServer_TLSVersions;
|
||||
Test_ClientServer_KeyExchangeAlgos;
|
||||
Test_ClientServer_CipherAlgos;
|
||||
Test_ClientServer_HashAlgos;
|
||||
end;
|
||||
|
||||
procedure Test;
|
||||
begin
|
||||
Test_Units_Dependencies;
|
||||
Test_Units_TLS;
|
||||
Test_ClientServer;
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
||||
end.
|
||||
|
875
contrib/fundamentals/TLS/flcTLSTransportClient.pas
Normal file
875
contrib/fundamentals/TLS/flcTLSTransportClient.pas
Normal file
@@ -0,0 +1,875 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSTransportClient.pas }
|
||||
{ File version: 5.08 }
|
||||
{ Description: TLS Transport Client }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2010/11/26 0.02 Protocol messages. }
|
||||
{ 2010/11/30 0.03 Encrypted messages. }
|
||||
{ 2010/12/03 0.04 Connection base class. }
|
||||
{ 2016/01/08 0.05 String changes. }
|
||||
{ 2018/07/17 5.06 Revised for Fundamentals 5. }
|
||||
{ 2020/05/11 5.07 VersionOptions, KeyExchangeOptions, CipherOptions and }
|
||||
{ HashOptions. }
|
||||
{ 2020/05/19 5.08 Verify RSA authentication signature for DHE_RSA. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSTransportClient;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
SysUtils,
|
||||
|
||||
{ Utils }
|
||||
|
||||
flcStdTypes,
|
||||
|
||||
{ Cipher }
|
||||
|
||||
flcCipherRSA,
|
||||
flcCipherDH,
|
||||
|
||||
{ X509 }
|
||||
|
||||
flcX509Certificate,
|
||||
|
||||
{ TLS }
|
||||
|
||||
flcTLSProtocolVersion,
|
||||
flcTLSAlgorithmTypes,
|
||||
flcTLSRandom,
|
||||
flcTLSCipherSuite,
|
||||
flcTLSRecord,
|
||||
flcTLSAlert,
|
||||
flcTLSKeyExchangeParams,
|
||||
flcTLSCertificate,
|
||||
flcTLSKeys,
|
||||
flcTLSHandshake,
|
||||
flcTLSTransportTypes,
|
||||
flcTLSTransportConnection;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ TLS Client }
|
||||
{ }
|
||||
type
|
||||
TTLSClientOption = (
|
||||
tlscloNone
|
||||
);
|
||||
|
||||
TTLSClientOptions = set of TTLSClientOption;
|
||||
|
||||
const
|
||||
DefaultTLSClientOptions = [];
|
||||
DefaultTLSClientVersionOptions = AllTLSVersionOptions - [tlsvoSSL3];
|
||||
DefaultTLSClientKeyExchangeOptions = AllTLSKeyExchangeOptions;
|
||||
DefaultTLSClientCipherOptions = AllTLSCipherOptions;
|
||||
DefaultTLSClientHashOptions = AllTLSHashOptions;
|
||||
|
||||
type
|
||||
TTLSClient = class;
|
||||
|
||||
TTLSClientNotifyEvent = procedure (Sender: TTLSClient) of object;
|
||||
|
||||
TTLSClientState = (
|
||||
tlsclInit,
|
||||
tlsclHandshakeAwaitingServerHello,
|
||||
tlsclHandshakeAwaitingServerHelloDone,
|
||||
tlsclHandshakeClientKeyExchange,
|
||||
tlsclConnection
|
||||
);
|
||||
|
||||
TTLSClient = class(TTLSConnection)
|
||||
protected
|
||||
FClientOptions : TTLSClientOptions;
|
||||
FVersionOptions : TTLSVersionOptions;
|
||||
FKeyExchangeOptions : TTLSKeyExchangeOptions;
|
||||
FCipherOptions : TTLSCipherOptions;
|
||||
FHashOptions : TTLSHashOptions;
|
||||
FResumeSessionID : RawByteString;
|
||||
|
||||
FClientState : TTLSClientState;
|
||||
FClientProtocolVersion : TTLSProtocolVersion;
|
||||
FServerProtocolVersion : TTLSProtocolVersion;
|
||||
FClientHello : TTLSClientHello;
|
||||
FClientHelloRandomStr : RawByteString;
|
||||
FServerHello : TTLSServerHello;
|
||||
FServerHelloRandomStr : RawByteString;
|
||||
FServerCertificateList : TTLSCertificateList;
|
||||
FServerX509Certs : TX509CertificateArray;
|
||||
FServerKeyExchange : TTLSServerKeyExchange;
|
||||
FCertificateRequest : TTLSCertificateRequest;
|
||||
FCertificateRequested : Boolean;
|
||||
FClientKeyExchange : TTLSClientKeyExchange;
|
||||
FServerRSAPublicKey : TRSAPublicKey;
|
||||
FDHState : PDHState;
|
||||
FPreMasterSecretStr : RawByteString;
|
||||
FMasterSecret : RawByteString;
|
||||
|
||||
procedure Init; override;
|
||||
|
||||
procedure SetClientState(const AState: TTLSClientState);
|
||||
procedure CheckNotActive;
|
||||
|
||||
procedure SetClientOptions(const AClientOptions: TTLSClientOptions);
|
||||
procedure SetVersionOptions(const AVersionOptions: TTLSVersionOptions);
|
||||
procedure SetCipherOptions(const ACipherOptions: TTLSCipherOptions);
|
||||
procedure SetKeyExchangeOptions(const AKeyExchangeOptions: TTLSKeyExchangeOptions);
|
||||
procedure SetHashOptions(const AHashOptions: TTLSHashOptions);
|
||||
|
||||
procedure InitInitialProtocolVersion;
|
||||
procedure InitSessionProtocolVersion;
|
||||
procedure InitClientHelloCipherSuites;
|
||||
procedure InitDHState;
|
||||
|
||||
procedure InitHandshakeClientHello;
|
||||
procedure InitServerPublicKey_RSA;
|
||||
procedure InitHandshakeClientKeyExchange;
|
||||
|
||||
procedure SendHandshakeClientHello;
|
||||
procedure SendHandshakeCertificate;
|
||||
procedure SendHandshakeClientKeyExchange;
|
||||
procedure SendHandshakeCertificateVerify;
|
||||
procedure SendHandshakeFinished;
|
||||
|
||||
procedure HandleHandshakeHelloRequest(const Buffer; const Size: Integer);
|
||||
procedure HandleHandshakeServerHello(const Buffer; const Size: Integer);
|
||||
procedure HandleHandshakeCertificate(const Buffer; const Size: Integer);
|
||||
procedure HandleHandshakeServerKeyExchange(const Buffer; const Size: Integer);
|
||||
procedure HandleHandshakeCertificateRequest(const Buffer; const Size: Integer);
|
||||
procedure HandleHandshakeServerHelloDone(const Buffer; const Size: Integer);
|
||||
procedure HandleHandshakeFinished(const Buffer; const Size: Integer);
|
||||
procedure HandleHandshakeMessage(const MsgType: TTLSHandshakeType; const Buffer; const Size: Integer); override;
|
||||
|
||||
procedure InitCipherSpecNone;
|
||||
procedure InitCipherSpecNewFromServerHello;
|
||||
|
||||
procedure DoStart;
|
||||
|
||||
public
|
||||
constructor Create(const ATransportLayerSendProc: TTLSConnectionTransportLayerSendProc);
|
||||
destructor Destroy; override;
|
||||
|
||||
property ClientOptions: TTLSClientOptions read FClientOptions write SetClientOptions default DefaultTLSClientOptions;
|
||||
property VersionOptions: TTLSVersionOptions read FVersionOptions write SetVersionOptions default DefaultTLSClientVersionOptions;
|
||||
property KeyExchangeOptions: TTLSKeyExchangeOptions read FKeyExchangeOptions write SetKeyExchangeOptions default DefaultTLSClientKeyExchangeOptions;
|
||||
property CipherOptions: TTLSCipherOptions read FCipherOptions write SetCipherOptions default DefaultTLSClientCipherOptions;
|
||||
property HashOptions: TTLSHashOptions read FHashOptions write SetHashOptions default DefaultTLSClientHashOptions;
|
||||
|
||||
property ResumeSessionID: RawByteString read FResumeSessionID write FResumeSessionID;
|
||||
|
||||
// property OnValidateCertificate
|
||||
|
||||
property ClientState: TTLSClientState read FClientState;
|
||||
|
||||
procedure Start;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{ Utils }
|
||||
|
||||
flcHugeInt,
|
||||
flcASN1,
|
||||
|
||||
{ Cipher }
|
||||
|
||||
flcCipherUtils,
|
||||
|
||||
{ TLS }
|
||||
|
||||
flcTLSErrors,
|
||||
flcTLSCompress,
|
||||
flcTLSCipher;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ TLS Client }
|
||||
{ }
|
||||
const
|
||||
STLSClientState: array[TTLSClientState] of String = (
|
||||
'Init',
|
||||
'HandshakeAwaitingServerHello',
|
||||
'HandshakeAwaitingServerHelloDone',
|
||||
'HandshakeClientKeyExchange',
|
||||
'Connection');
|
||||
|
||||
constructor TTLSClient.Create(const ATransportLayerSendProc: TTLSConnectionTransportLayerSendProc);
|
||||
begin
|
||||
inherited Create(ATransportLayerSendProc);
|
||||
end;
|
||||
|
||||
destructor TTLSClient.Destroy;
|
||||
begin
|
||||
if Assigned(FDHState) then
|
||||
begin
|
||||
DHStateFinalise(FDHState^);
|
||||
Dispose(FDHState);
|
||||
FDHState := nil;
|
||||
end;
|
||||
RSAPublicKeyFinalise(FServerRSAPublicKey);
|
||||
SecureClearStr(FMasterSecret);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TTLSClient.Init;
|
||||
begin
|
||||
inherited Init;
|
||||
|
||||
RSAPublicKeyInit(FServerRSAPublicKey);
|
||||
|
||||
FClientOptions := DefaultTLSClientOptions;
|
||||
FVersionOptions := DefaultTLSClientVersionOptions;
|
||||
FKeyExchangeOptions := DefaultTLSClientKeyExchangeOptions;
|
||||
FCipherOptions := DefaultTLSClientCipherOptions;
|
||||
FHashOptions := DefaultTLSClientHashOptions;
|
||||
|
||||
FClientState := tlsclInit;
|
||||
end;
|
||||
|
||||
procedure TTLSClient.SetClientState(const AState: TTLSClientState);
|
||||
begin
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'State:%s', [STLSClientState[AState]]);
|
||||
{$ENDIF}
|
||||
|
||||
FClientState := AState;
|
||||
end;
|
||||
|
||||
procedure TTLSClient.CheckNotActive;
|
||||
begin
|
||||
if FClientState <> tlsclInit then
|
||||
raise ETLSError.Create(TLSError_InvalidState, 'Operation not allowed while active');
|
||||
end;
|
||||
|
||||
procedure TTLSClient.SetClientOptions(const AClientOptions: TTLSClientOptions);
|
||||
begin
|
||||
if AClientOptions = FClientOptions then
|
||||
exit;
|
||||
CheckNotActive;
|
||||
FClientOptions := AClientOptions;
|
||||
end;
|
||||
|
||||
procedure TTLSClient.SetVersionOptions(const AVersionOptions: TTLSVersionOptions);
|
||||
begin
|
||||
if AVersionOptions = FVersionOptions then
|
||||
exit;
|
||||
CheckNotActive;
|
||||
if AVersionOptions = [] then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter, 'Invalid version options');
|
||||
FVersionOptions := AVersionOptions;
|
||||
end;
|
||||
|
||||
procedure TTLSClient.SetCipherOptions(const ACipherOptions: TTLSCipherOptions);
|
||||
begin
|
||||
if ACipherOptions = FCipherOptions then
|
||||
exit;
|
||||
CheckNotActive;
|
||||
if ACipherOptions = [] then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter, 'Invalid cipher options');
|
||||
FCipherOptions := ACipherOptions;
|
||||
end;
|
||||
|
||||
procedure TTLSClient.SetKeyExchangeOptions(const AKeyExchangeOptions: TTLSKeyExchangeOptions);
|
||||
begin
|
||||
if AKeyExchangeOptions = FKeyExchangeOptions then
|
||||
exit;
|
||||
CheckNotActive;
|
||||
if AKeyExchangeOptions = [] then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter, 'Invalid key exchange options');
|
||||
FKeyExchangeOptions := AKeyExchangeOptions;
|
||||
end;
|
||||
|
||||
procedure TTLSClient.SetHashOptions(const AHashOptions: TTLSHashOptions);
|
||||
begin
|
||||
if AHashOptions = FHashOptions then
|
||||
exit;
|
||||
CheckNotActive;
|
||||
if AHashOptions = [] then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter, 'Invalid hash options');
|
||||
FHashOptions := AHashOptions;
|
||||
end;
|
||||
|
||||
procedure TTLSClient.InitInitialProtocolVersion;
|
||||
begin
|
||||
// set highest allowable protocol version
|
||||
if tlsvoTLS12 in FVersionOptions then
|
||||
InitTLSProtocolVersion12(FProtocolVersion) else
|
||||
if tlsvoTLS11 in FVersionOptions then
|
||||
InitTLSProtocolVersion11(FProtocolVersion) else
|
||||
if tlsvoTLS10 in FVersionOptions then
|
||||
InitTLSProtocolVersion10(FProtocolVersion) else
|
||||
if tlsvoSSL3 in FVersionOptions then
|
||||
InitSSLProtocolVersion30(FProtocolVersion)
|
||||
else
|
||||
raise ETLSError.Create(TLSError_InvalidParameter, 'Invalid version options');
|
||||
FClientProtocolVersion := FProtocolVersion;
|
||||
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'InitialProtocolVersion:%s', [TLSProtocolVersionName(FProtocolVersion)]);
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure TTLSClient.InitSessionProtocolVersion;
|
||||
begin
|
||||
FProtocolVersion := FServerProtocolVersion;
|
||||
if IsTLS12(FProtocolVersion) and not (tlsvoTLS12 in FVersionOptions) then
|
||||
InitTLSProtocolVersion11(FProtocolVersion);
|
||||
if IsTLS11(FProtocolVersion) and not (tlsvoTLS11 in FVersionOptions) then
|
||||
InitTLSProtocolVersion10(FProtocolVersion);
|
||||
if IsTLS10(FProtocolVersion) and not (tlsvoTLS10 in FVersionOptions) then
|
||||
InitSSLProtocolVersion30(FProtocolVersion);
|
||||
if IsSSL3(FProtocolVersion) and not (tlsvoSSL3 in FVersionOptions) then
|
||||
raise ETLSError.CreateAlertBadProtocolVersion; // no allowable protocol version
|
||||
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'SessionProtocolVersion:%s', [TLSProtocolVersionName(FProtocolVersion)]);
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure TTLSClient.InitClientHelloCipherSuites;
|
||||
var
|
||||
C : TTLSCipherSuites;
|
||||
I : TTLSCipherSuite;
|
||||
P : PTLSCipherSuiteInfo;
|
||||
R : Boolean;
|
||||
begin
|
||||
C := [];
|
||||
for I := Low(I) to High(I) do
|
||||
begin
|
||||
P := @TLSCipherSuiteInfo[I];
|
||||
R := P^.ClientSupport;
|
||||
if R then
|
||||
if not (tlscoRC4 in FCipherOptions) then
|
||||
if P^.Cipher in [tlscscRC4_40, tlscscRC4_56, tlscscRC4_128] then
|
||||
R := False;
|
||||
if R then
|
||||
if not (tlscoDES in FCipherOptions) then
|
||||
if P^.Cipher in [tlscscDES_CBC] then
|
||||
R := False;
|
||||
if R then
|
||||
if not (tlsco3DES in FCipherOptions) then
|
||||
if P^.Cipher in [tlscsc3DES_EDE_CBC] then
|
||||
R := False;
|
||||
if R then
|
||||
if not (tlscoAES128 in FCipherOptions) then
|
||||
if P^.Cipher in [tlscscAES_128_CBC] then
|
||||
R := False;
|
||||
if R then
|
||||
if not (tlscoAES256 in FCipherOptions) then
|
||||
if P^.Cipher in [tlscscAES_256_CBC] then
|
||||
R := False;
|
||||
if R then
|
||||
if not (tlshoMD5 in FHashOptions) then
|
||||
if P^.Hash in [tlscshMD5] then
|
||||
R := False;
|
||||
if R then
|
||||
if not (tlshoSHA1 in FHashOptions) then
|
||||
if P^.Hash in [tlscshSHA] then
|
||||
R := False;
|
||||
if R then
|
||||
if not (tlshoSHA256 in FHashOptions) then
|
||||
if P^.Hash in [tlscshSHA256] then
|
||||
R := False;
|
||||
if R then
|
||||
if not (tlshoSHA384 in FHashOptions) then
|
||||
if P^.Hash in [tlscshSHA384] then
|
||||
R := False;
|
||||
if R then
|
||||
if not (tlskeoRSA in FKeyExchangeOptions) then
|
||||
if P^.KeyExchange in [tlscskeRSA] then
|
||||
R := False;
|
||||
if R then
|
||||
if not (tlskeoDH_Anon in FKeyExchangeOptions) then
|
||||
if P^.KeyExchange in [tlscskeDH_anon] then
|
||||
R := False;
|
||||
if R then
|
||||
if not (tlskeoDH_RSA in FKeyExchangeOptions) then
|
||||
if P^.KeyExchange in [tlscskeDH_RSA] then
|
||||
R := False;
|
||||
if R then
|
||||
if not (tlskeoDHE_RSA in FKeyExchangeOptions) then
|
||||
if P^.KeyExchange in [tlscskeDHE_RSA] then
|
||||
R := False;
|
||||
if R then
|
||||
if not (tlskeoECDH_RSA in FKeyExchangeOptions) then
|
||||
if P^.KeyExchange in [tlscskeECDH_RSA] then
|
||||
R := False;
|
||||
if R then
|
||||
if not (tlskeoECDHE_RSA in FKeyExchangeOptions) then
|
||||
if P^.KeyExchange in [tlscskeECDHE_RSA] then
|
||||
R := False;
|
||||
if R then
|
||||
Include(C, I);
|
||||
end;
|
||||
if C = [] then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter, 'No allowable cipher suite');
|
||||
FClientHello.CipherSuites := C;
|
||||
end;
|
||||
|
||||
procedure TTLSClient.InitDHState;
|
||||
begin
|
||||
New(FDHState);
|
||||
DHStateInit(FDHState^);
|
||||
DHInitHashAlgorithm(FDHState^, dhhSHA1);
|
||||
end;
|
||||
|
||||
procedure TTLSClient.InitHandshakeClientHello;
|
||||
begin
|
||||
InitTLSClientHello(FClientHello,
|
||||
FClientProtocolVersion,
|
||||
FResumeSessionID);
|
||||
|
||||
{$IFDEF TLS_TEST_NO_RANDOM_HELLO}
|
||||
FClientHello.Random.gmt_unix_time := 123;
|
||||
FillChar(FClientHello.Random.random_bytes, 28, 117);
|
||||
{$ENDIF}
|
||||
|
||||
InitClientHelloCipherSuites;
|
||||
FClientHello.CompressionMethods := [tlscmNull];
|
||||
FClientHelloRandomStr := TLSRandomToStr(FClientHello.Random);
|
||||
end;
|
||||
|
||||
procedure TTLSClient.InitServerPublicKey_RSA;
|
||||
begin
|
||||
GetCertificateRSAPublicKey(FServerX509Certs,
|
||||
FServerRSAPublicKey);
|
||||
end;
|
||||
|
||||
procedure TTLSClient.InitHandshakeClientKeyExchange;
|
||||
var
|
||||
S : RawByteString;
|
||||
PMS : TTLSPreMasterSecret;
|
||||
DHXC : HugeWord;
|
||||
DHYC : HugeWord;
|
||||
DHP : HugeWord;
|
||||
DHG : HugeWord;
|
||||
DHYS : HugeWord;
|
||||
ZZ : HugeWord;
|
||||
begin
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'InitHandshakeClientKeyExchange:%s', [
|
||||
TLSKeyExchangeAlgorithmInfo[FCipherSpecNew.KeyExchangeAlgorithm].Name]);
|
||||
{$ENDIF}
|
||||
|
||||
case FCipherSpecNew.KeyExchangeAlgorithm of
|
||||
tlskeaRSA :
|
||||
begin
|
||||
{ RFC 5246: When RSA is used for server authentication and key exchange, a 48- }
|
||||
{ byte pre_master_secret is generated by the client, encrypted under }
|
||||
{ the server's public key, and sent to the server. The server uses its }
|
||||
{ private key to decrypt the pre_master_secret. Both parties then }
|
||||
{ convert the pre_master_secret into the master_secret, as specified above. }
|
||||
|
||||
InitTLSPreMasterSecret_Random(PMS, FClientHello.ProtocolVersion);
|
||||
FPreMasterSecretStr := TLSPreMasterSecretToStr(PMS);
|
||||
|
||||
InitServerPublicKey_RSA;
|
||||
|
||||
InitTLSEncryptedPreMasterSecret_RSA(S, PMS, FServerRSAPublicKey);
|
||||
FClientKeyExchange.EncryptedPreMasterSecret := S;
|
||||
end;
|
||||
tlskeaDHE_DSS,
|
||||
tlskeaDHE_RSA,
|
||||
tlskeaDH_Anon :
|
||||
begin
|
||||
//Assert(Assigned(FDHState));
|
||||
|
||||
{ RFC 5246: A conventional Diffie-Hellman computation is performed. The }
|
||||
{ negotiated key (Z) is used as the pre_master_secret, and is converted }
|
||||
{ into the master_secret, as specified above. Leading bytes of Z that }
|
||||
{ contain all zero bits are stripped before it is used as the }
|
||||
{ pre_master_secret }
|
||||
|
||||
InitTLSPreMasterSecret_Random(PMS, FClientHello.ProtocolVersion);
|
||||
|
||||
HugeWordInit(DHXC);
|
||||
HugeWordInit(DHYC);
|
||||
HugeWordInit(DHP);
|
||||
HugeWordInit(DHG);
|
||||
HugeWordInit(DHYS);
|
||||
HugeWordInit(ZZ);
|
||||
try
|
||||
DHHugeWordKeyDecodeBytes(DHP, FServerKeyExchange.DHParams.dh_p);
|
||||
DHHugeWordKeyDecodeBytes(DHG, FServerKeyExchange.DHParams.dh_g);
|
||||
DHHugeWordKeyDecodeBytes(DHYS, FServerKeyExchange.DHParams.dh_Ys);
|
||||
|
||||
//HugeWordSetSize(DHXC, (SizeOf(PMS) + 3) div 4); //// size? 384 bits in SBA. use q size.
|
||||
//Move(PMS, DHXC.Data^, SizeOf(PMS));
|
||||
|
||||
repeat
|
||||
HugeWordRandom(DHXC, HugeWordGetSize(DHP)); /////
|
||||
if SizeOf(PMS) <= DHXC.Used * 4 then
|
||||
Move(PMS, DHXC.Data^, SizeOf(PMS))
|
||||
else
|
||||
Move(PMS, DHXC.Data^, DHXC.Used * 4);
|
||||
until HugeWordCompare(DHXC, DHP) < 0;
|
||||
|
||||
HugeWordPowerAndMod(DHYC, DHG, DHXC, DHP); // yc = (g ^ xc) mod p
|
||||
|
||||
FClientKeyExchange.ClientDiffieHellmanPublic.PublicValueEncodingExplicit := True;
|
||||
FClientKeyExchange.ClientDiffieHellmanPublic.dh_Yc := DHHugeWordKeyEncodeBytes(DHYC);
|
||||
|
||||
HugeWordPowerAndMod(ZZ, DHYs, DHXC, DHP); // ZZ = (ys ^ xc) mod p
|
||||
|
||||
FPreMasterSecretStr := DHHugeWordKeyEncodeBytes(ZZ);
|
||||
finally
|
||||
//// Secure clear
|
||||
HugeWordFinalise(ZZ);
|
||||
HugeWordFinalise(DHYS);
|
||||
HugeWordFinalise(DHG);
|
||||
HugeWordFinalise(DHP);
|
||||
HugeWordFinalise(DHYC);
|
||||
HugeWordFinalise(DHXC);
|
||||
end;
|
||||
end;
|
||||
tlskeaDH_DSS,
|
||||
tlskeaDH_RSA :
|
||||
begin
|
||||
FClientKeyExchange.ClientDiffieHellmanPublic.PublicValueEncodingExplicit := False;
|
||||
FClientKeyExchange.ClientDiffieHellmanPublic.dh_Yc := '';
|
||||
end;
|
||||
end;
|
||||
|
||||
case FCipherSpecNew.KeyExchangeAlgorithm of
|
||||
tlskeaRSA,
|
||||
tlskeaDHE_DSS,
|
||||
tlskeaDHE_RSA,
|
||||
tlskeaDH_Anon :
|
||||
begin
|
||||
Assert(FPreMasterSecretStr <> '');
|
||||
FMasterSecret := TLSMasterSecret(FProtocolVersion, FPreMasterSecretStr,
|
||||
FClientHelloRandomStr, FServerHelloRandomStr);
|
||||
SecureClearStr(FPreMasterSecretStr);
|
||||
|
||||
GenerateTLSKeys(FProtocolVersion,
|
||||
FCipherSpecNew.CipherSuiteDetails.HashInfo^.KeyLength,
|
||||
FCipherSpecNew.CipherSuiteDetails.CipherInfo^.KeyBits,
|
||||
FCipherSpecNew.CipherSuiteDetails.CipherInfo^.IVSize * 8,
|
||||
FMasterSecret,
|
||||
FServerHelloRandomStr,
|
||||
FClientHelloRandomStr,
|
||||
FKeys);
|
||||
GenerateFinalTLSKeys(FProtocolVersion,
|
||||
FCipherSpecNew.CipherSuiteDetails.CipherInfo^.Exportable,
|
||||
FCipherSpecNew.CipherSuiteDetails.CipherInfo^.ExpKeyMat * 8,
|
||||
FServerHelloRandomStr,
|
||||
FClientHelloRandomStr,
|
||||
FKeys);
|
||||
|
||||
SetEncodeKeys(FKeys.ClientMACKey, FKeys.ClientEncKey, FKeys.ClientIV);
|
||||
SetDecodeKeys(FKeys.ServerMACKey, FKeys.ServerEncKey, FKeys.ServerIV);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
const
|
||||
MaxHandshakeClientHelloSize = 16384;
|
||||
MaxHandshakeCertificateSize = 65536;
|
||||
MaxHandshakeClientKeyExchangeSize = 2048;
|
||||
MaxHandshakeCertificateVerifySize = 16384;
|
||||
MaxHandshakeFinishedSize = 2048;
|
||||
|
||||
procedure TTLSClient.SendHandshakeClientHello;
|
||||
var
|
||||
Buf : array[0..MaxHandshakeClientHelloSize - 1] of Byte;
|
||||
Size : Integer;
|
||||
begin
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'T:Handshake:ClientHello');
|
||||
{$ENDIF}
|
||||
|
||||
InitHandshakeClientHello;
|
||||
Size := EncodeTLSHandshakeClientHello(Buf, SizeOf(Buf), FClientHello);
|
||||
SendHandshake(Buf, Size);
|
||||
end;
|
||||
|
||||
procedure TTLSClient.SendHandshakeCertificate;
|
||||
var
|
||||
Buf : array[0..MaxHandshakeCertificateSize - 1] of Byte;
|
||||
Size : Integer;
|
||||
begin
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'T:Handshake:Certificate');
|
||||
{$ENDIF}
|
||||
|
||||
Size := EncodeTLSHandshakeCertificate(Buf, SizeOf(Buf), nil);
|
||||
SendHandshake(Buf, Size);
|
||||
end;
|
||||
|
||||
procedure TTLSClient.SendHandshakeClientKeyExchange;
|
||||
var
|
||||
Buf : array[0..MaxHandshakeClientKeyExchangeSize - 1] of Byte;
|
||||
Size : Integer;
|
||||
begin
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'T:Handshake:ClientKeyExchange');
|
||||
{$ENDIF}
|
||||
|
||||
InitHandshakeClientKeyExchange;
|
||||
Size := EncodeTLSHandshakeClientKeyExchange(
|
||||
Buf, SizeOf(Buf),
|
||||
FCipherSpecNew.KeyExchangeAlgorithm,
|
||||
FClientKeyExchange);
|
||||
SendHandshake(Buf, Size);
|
||||
end;
|
||||
|
||||
procedure TTLSClient.SendHandshakeCertificateVerify;
|
||||
var
|
||||
Buf : array[0..MaxHandshakeCertificateVerifySize - 1] of Byte;
|
||||
Size : Integer;
|
||||
begin
|
||||
Size := EncodeTLSHandshakeCertificateVerify(Buf, SizeOf(Buf));
|
||||
SendHandshake(Buf, Size);
|
||||
end;
|
||||
|
||||
procedure TTLSClient.SendHandshakeFinished;
|
||||
var
|
||||
Buf : array[0..MaxHandshakeFinishedSize - 1] of Byte;
|
||||
Size : Integer;
|
||||
begin
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'T:Handshake:Finished:%s', [TLSProtocolVersionName(FProtocolVersion)]);
|
||||
{$ENDIF}
|
||||
|
||||
Size := EncodeTLSHandshakeFinished(Buf, SizeOf(Buf), FMasterSecret, FProtocolVersion, FVerifyHandshakeData, True);
|
||||
SendHandshake(Buf, Size);
|
||||
end;
|
||||
|
||||
procedure TTLSClient.HandleHandshakeHelloRequest(const Buffer; const Size: Integer);
|
||||
begin
|
||||
if IsNegotiatingState then
|
||||
exit; // ignore while negotiating
|
||||
if FConnectionState = tlscoApplicationData then
|
||||
SendAlert(tlsalWarning, tlsadNo_renegotiation); // client does not support renegotiation, notify server
|
||||
end;
|
||||
|
||||
procedure TTLSClient.HandleHandshakeServerHello(const Buffer; const Size: Integer);
|
||||
begin
|
||||
if not (FClientState in [tlsclHandshakeAwaitingServerHello]) or
|
||||
not (FConnectionState in [tlscoStart, tlscoHandshaking]) then
|
||||
raise ETLSError.CreateAlertUnexpectedMessage;
|
||||
|
||||
DecodeTLSServerHello(Buffer, Size, FServerHello);
|
||||
FServerProtocolVersion := FServerHello.ProtocolVersion;
|
||||
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'ServerProtocolVersion:%s', [TLSProtocolVersionName(FServerProtocolVersion)]);
|
||||
{$ENDIF}
|
||||
|
||||
FServerHelloRandomStr := TLSRandomToStr(FServerHello.Random);
|
||||
if not IsTLSProtocolVersion(FServerProtocolVersion, FProtocolVersion) then // different protocol version
|
||||
begin
|
||||
if IsPostTLS12(FServerProtocolVersion) then
|
||||
raise ETLSError.CreateAlert(TLSError_BadProtocol, tlsadProtocol_version); // unsupported future version of TLS
|
||||
if not IsKnownTLSVersion(FServerProtocolVersion) then
|
||||
raise ETLSError.CreateAlert(TLSError_BadProtocol, tlsadProtocol_version); // unknown past TLS version
|
||||
end;
|
||||
InitSessionProtocolVersion;
|
||||
InitCipherSpecNewFromServerHello;
|
||||
SetClientState(tlsclHandshakeAwaitingServerHelloDone);
|
||||
end;
|
||||
|
||||
procedure TTLSClient.HandleHandshakeCertificate(const Buffer; const Size: Integer);
|
||||
begin
|
||||
if FClientState <> tlsclHandshakeAwaitingServerHelloDone then
|
||||
raise ETLSError.CreateAlertUnexpectedMessage;
|
||||
|
||||
DecodeTLSCertificate(Buffer, Size, FServerCertificateList);
|
||||
ParseX509Certificates(FServerCertificateList, FServerX509Certs);
|
||||
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'R:Handshake:Certificate:Count=%d', [Length(FServerX509Certs)]);
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure TTLSClient.HandleHandshakeServerKeyExchange(const Buffer; const Size: Integer);
|
||||
//var
|
||||
// R : HugeWord;
|
||||
begin
|
||||
if FClientState <> tlsclHandshakeAwaitingServerHelloDone then
|
||||
raise ETLSError.CreateAlertUnexpectedMessage;
|
||||
|
||||
DecodeTLSServerKeyExchange(Buffer, Size, FCipherSpecNew.KeyExchangeAlgorithm,
|
||||
FServerKeyExchange);
|
||||
|
||||
case FCipherSpecNew.KeyExchangeAlgorithm of
|
||||
tlskeaDHE_DSS,
|
||||
tlskeaDHE_RSA,
|
||||
tlskeaDH_Anon :
|
||||
begin
|
||||
{
|
||||
//// Validate
|
||||
//DHHugeWordKeyDecodeBytes(DHP, FServerKeyExchange.DHParams.dh_p);
|
||||
//DHHugeWordKeyDecodeBytes(DHG, FServerKeyExchange.DHParams.dh_g);
|
||||
//DHHugeWordKeyDecodeBytes(DHYS, FServerKeyExchange.DHParams.dh_Ys);
|
||||
|
||||
InitDHState;
|
||||
DHHugeWordKeyDecodeBytes(FDHState^.P, FServerKeyExchange.DHParams.dh_p);
|
||||
DHHugeWordKeyDecodeBytes(FDHState^.G, FServerKeyExchange.DHParams.dh_g);
|
||||
FDHState^.PrimePBitCount := HugeWordGetSizeInBits(FDHState^.P);
|
||||
FDHState^.PrimeQBitCount := DHQBitCount(FDHState^.PrimePBitCount);
|
||||
|
||||
DHDeriveKeysFromGroupParametersPG(FDHState^, dhhSHA1,
|
||||
FDHState^.PrimeQBitCount,
|
||||
FDHState^.PrimePBitCount,
|
||||
FDHState^.P,
|
||||
FDHState^.G);
|
||||
|
||||
HugeWordInit(R);
|
||||
DHHugeWordKeyDecodeBytes(R, FServerKeyExchange.DHParams.dh_Ys);
|
||||
|
||||
DHGenerateSharedSecretZZ(FDHState^, HugeWordGetSizeInBits(R), R);
|
||||
HugeWordFinalise(R);
|
||||
}
|
||||
|
||||
if FCipherSpecNew.KeyExchangeAlgorithm = tlskeaDHE_RSA then
|
||||
begin
|
||||
InitServerPublicKey_RSA;
|
||||
if not VerifyTLSServerKeyExchangeDH_RSA(FServerKeyExchange,
|
||||
PTLSClientServerRandom(@FClientHello.Random)^,
|
||||
PTLSClientServerRandom(@FServerHello.Random)^,
|
||||
FServerRSAPublicKey) then
|
||||
raise ETLSError.CreateAlert(TLSError_BadProtocol, tlsadHandshake_failure);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTLSClient.HandleHandshakeCertificateRequest(const Buffer; const Size: Integer);
|
||||
begin
|
||||
if FClientState <> tlsclHandshakeAwaitingServerHelloDone then
|
||||
raise ETLSError.CreateAlertUnexpectedMessage;
|
||||
|
||||
DecodeTLSCertificateRequest(Buffer, Size, FCertificateRequest);
|
||||
FCertificateRequested := True;
|
||||
end;
|
||||
|
||||
procedure TTLSClient.HandleHandshakeServerHelloDone(const Buffer; const Size: Integer);
|
||||
begin
|
||||
if FClientState <> tlsclHandshakeAwaitingServerHelloDone then
|
||||
raise ETLSError.CreateAlertUnexpectedMessage;
|
||||
|
||||
SetClientState(tlsclHandshakeClientKeyExchange);
|
||||
if FCertificateRequested then
|
||||
SendHandshakeCertificate;
|
||||
SendHandshakeClientKeyExchange;
|
||||
// TODO SendHandshakeCertificateVerify;
|
||||
SendChangeCipherSpec;
|
||||
ChangeEncryptCipherSpec;
|
||||
SendHandshakeFinished;
|
||||
end;
|
||||
|
||||
procedure TTLSClient.HandleHandshakeFinished(const Buffer; const Size: Integer);
|
||||
begin
|
||||
if FClientState <> tlsclHandshakeClientKeyExchange then
|
||||
raise ETLSError.CreateAlertUnexpectedMessage;
|
||||
|
||||
SetClientState(tlsclConnection);
|
||||
SetConnectionState(tlscoApplicationData);
|
||||
TriggerHandshakeFinished;
|
||||
end;
|
||||
|
||||
procedure TTLSClient.HandleHandshakeMessage(const MsgType: TTLSHandshakeType; const Buffer; const Size: Integer);
|
||||
begin
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'R:Handshake:%s:%db', [TLSHandshakeTypeToStr(MsgType), Size]);
|
||||
{$ENDIF}
|
||||
|
||||
case MsgType of
|
||||
tlshtHello_request : HandleHandshakeHelloRequest(Buffer, Size);
|
||||
tlshtClient_hello : ShutdownBadProtocol(tlsadUnexpected_message);
|
||||
tlshtServer_hello : HandleHandshakeServerHello(Buffer, Size);
|
||||
tlshtCertificate : HandleHandshakeCertificate(Buffer, Size);
|
||||
tlshtServer_key_exchange : HandleHandshakeServerKeyExchange(Buffer, Size);
|
||||
tlshtCertificate_request : HandleHandshakeCertificateRequest(Buffer, Size);
|
||||
tlshtServer_hello_done : HandleHandshakeServerHelloDone(Buffer, Size);
|
||||
tlshtCertificate_verify : ShutdownBadProtocol(tlsadUnexpected_message);
|
||||
tlshtClient_key_exchange : ShutdownBadProtocol(tlsadUnexpected_message);
|
||||
tlshtFinished : HandleHandshakeFinished(Buffer, Size);
|
||||
else
|
||||
ShutdownBadProtocol(tlsadUnexpected_message);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTLSClient.InitCipherSpecNone;
|
||||
begin
|
||||
InitTLSSecurityParametersNone(FCipherEncryptSpec);
|
||||
InitTLSSecurityParametersNone(FCipherDecryptSpec);
|
||||
TLSCipherInitNone(FCipherEncryptState, tlscoEncrypt);
|
||||
TLSCipherInitNone(FCipherDecryptState, tlscoDecrypt);
|
||||
end;
|
||||
|
||||
procedure TTLSClient.InitCipherSpecNewFromServerHello;
|
||||
begin
|
||||
InitTLSSecurityParameters(
|
||||
FCipherSpecNew,
|
||||
FServerHello.CompressionMethod,
|
||||
GetCipherSuiteByRec(FServerHello.CipherSuite.B1, FServerHello.CipherSuite.B2));
|
||||
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'CipherSpec:%s', [FCipherSpecNew.CipherSuiteDetails.CipherSuiteInfo^.Name]);
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure TTLSClient.DoStart;
|
||||
begin
|
||||
SetConnectionState(tlscoStart);
|
||||
InitInitialProtocolVersion;
|
||||
InitCipherSpecNone;
|
||||
SetConnectionState(tlscoHandshaking);
|
||||
SetClientState(tlsclHandshakeAwaitingServerHello);
|
||||
SendHandshakeClientHello;
|
||||
end;
|
||||
|
||||
procedure TTLSClient.Start;
|
||||
begin
|
||||
Assert(FConnectionState = tlscoInit);
|
||||
Assert(FClientState = tlsclInit);
|
||||
DoStart;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
end.
|
||||
|
861
contrib/fundamentals/TLS/flcTLSTransportConnection.pas
Normal file
861
contrib/fundamentals/TLS/flcTLSTransportConnection.pas
Normal file
@@ -0,0 +1,861 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSTransportConnection.pas }
|
||||
{ File version: 5.06 }
|
||||
{ Description: TLS Transport Connection }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2008/01/18 0.01 Initial development. }
|
||||
{ 2010/11/26 0.02 Protocol messages. }
|
||||
{ 2010/11/30 0.03 Encrypted messages. }
|
||||
{ 2010/12/03 0.04 Revision. }
|
||||
{ 2011/06/18 0.05 Allow multiple handshakes in a record. }
|
||||
{ 2018/07/17 5.06 Revised for Fundamentals 5. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSTransportConnection;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
{ Utils }
|
||||
|
||||
flcStdTypes,
|
||||
|
||||
{ TLS }
|
||||
|
||||
flcTLSErrors,
|
||||
flcTLSProtocolVersion,
|
||||
flcTLSAlgorithmTypes,
|
||||
flcTLSPRF,
|
||||
flcTLSCipherSuite,
|
||||
flcTLSCipher,
|
||||
flcTLSRecord,
|
||||
flcTLSAlert,
|
||||
flcTLSHandshake,
|
||||
flcTLSBuffer,
|
||||
flcTLSKeys,
|
||||
flcTLSTransportTypes;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ TLS security parameters }
|
||||
{ }
|
||||
type
|
||||
TTLSSecurityParameters = record
|
||||
PrfAlgorithm : TTLSPRFAlgorithm;
|
||||
CipherSuite : TTLSCipherSuite;
|
||||
CipherSuiteDetails : TTLSCipherSuiteDetails;
|
||||
CipherSuiteCipherCipherInfo : PTLSCipherSuiteCipherCipherInfo;
|
||||
Compression : TTLSCompressionMethod;
|
||||
KeyExchangeAlgorithm : TTLSKeyExchangeAlgorithm;
|
||||
KeyExchangeAlgorithmInfo : PTLSKeyExchangeAlgorithmInfo;
|
||||
end;
|
||||
PTLSSecurityParameters = ^TTLSSecurityParameters;
|
||||
|
||||
procedure InitTLSSecurityParameters(var A: TTLSSecurityParameters;
|
||||
const CompressionMethod: TTLSCompressionMethod;
|
||||
const CipherSuite: TTLSCipherSuite);
|
||||
procedure InitTLSSecurityParametersNone(var A: TTLSSecurityParameters);
|
||||
procedure InitTLSSecurityParametersNULL(var A: TTLSSecurityParameters);
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ TLS connection }
|
||||
{ }
|
||||
type
|
||||
TTLSConnection = class;
|
||||
|
||||
TTLSConnectionTransportLayerSendProc =
|
||||
procedure (const Sender: TTLSConnection; const Buffer; const Size: Integer) of object;
|
||||
|
||||
TTLSConnectionState = (
|
||||
tlscoInit,
|
||||
tlscoStart,
|
||||
tlscoHandshaking,
|
||||
tlscoApplicationData,
|
||||
tlscoErrorBadProtocol,
|
||||
tlscoCancelled,
|
||||
tlscoClosed
|
||||
);
|
||||
|
||||
TTLSConnectionLogEvent = procedure (Sender: TTLSConnection; LogType: TTLSLogType; LogMsg: String; LogLevel: Integer) of object;
|
||||
TTLSConnectionStateChangeEvent = procedure (Sender: TTLSConnection; State: TTLSConnectionState) of object;
|
||||
TTLSConnectionAlertEvent = procedure (Sender: TTLSConnection; Level: TTLSAlertLevel; Description: TTLSAlertDescription) of object;
|
||||
TTLSConnectionNotifyEvent = procedure (Sender: TTLSConnection) of object;
|
||||
|
||||
TTLSConnection = class
|
||||
protected
|
||||
FTransportLayerSendProc : TTLSConnectionTransportLayerSendProc;
|
||||
FOnLog : TTLSConnectionLogEvent;
|
||||
FOnStateChange : TTLSConnectionStateChangeEvent;
|
||||
FOnAlert : TTLSConnectionAlertEvent;
|
||||
FOnHandshakeFinished : TTLSConnectionNotifyEvent;
|
||||
FConnectionState : TTLSConnectionState;
|
||||
FConnectionErrorMessage : String;
|
||||
FInBuf : TTLSBuffer;
|
||||
FOutBuf : TTLSBuffer;
|
||||
FProtocolVersion : TTLSProtocolVersion;
|
||||
FReadSeqNo : Int64;
|
||||
FWriteSeqNo : Int64;
|
||||
FKeys : TTLSKeys;
|
||||
FEncMACKey : RawByteString;
|
||||
FEncCipherKey : RawByteString;
|
||||
FEncIV : RawByteString;
|
||||
FDecMACKey : RawByteString;
|
||||
FDecCipherKey : RawByteString;
|
||||
FDecIV : RawByteString;
|
||||
FVerifyHandshakeData : RawByteString;
|
||||
FCipherEncryptSpec : TTLSSecurityParameters;
|
||||
FCipherEncryptState : TTLSCipherState;
|
||||
FCipherDecryptSpec : TTLSSecurityParameters;
|
||||
FCipherDecryptState : TTLSCipherState;
|
||||
FCipherSpecNew : TTLSSecurityParameters;
|
||||
|
||||
procedure Init; virtual;
|
||||
|
||||
procedure Log(const LogType: TTLSLogType; const LogMsg: String; const LogLevel: Integer = 0); overload;
|
||||
procedure Log(const LogType: TTLSLogType; const LogMsg: String; const LogArgs: array of const; const LogLevel: Integer = 0); overload;
|
||||
|
||||
procedure TriggerLog(const LogType: TTLSLogType; const LogMsg: String; const LogLevel: Integer); virtual;
|
||||
procedure TriggerConnectionStateChange; virtual;
|
||||
procedure TriggerAlert(const Level: TTLSAlertLevel; const Description: TTLSAlertDescription); virtual;
|
||||
procedure TriggerHandshakeFinished; virtual;
|
||||
|
||||
procedure SetConnectionState(const State: TTLSConnectionState);
|
||||
procedure SetClosed;
|
||||
procedure SetErrorBadProtocol;
|
||||
|
||||
procedure SetEncodeKeys(const MACKey, CipherKey, IV: RawByteString);
|
||||
procedure SetDecodeKeys(const MACKey, CipherKey, IV: RawByteString);
|
||||
|
||||
procedure TransportLayerSend(const Buffer; const Size: Integer);
|
||||
procedure SendContent(const ContentType: TTLSContentType; const Buffer; const Size: Integer);
|
||||
|
||||
procedure SendAlert(const Level: TTLSAlertLevel; const Description: TTLSAlertDescription);
|
||||
procedure SendAlertCloseNotify;
|
||||
procedure SendAlertUnexpectedMessage;
|
||||
procedure SendAlertIllegalParameter;
|
||||
procedure SendAlertDecodeError;
|
||||
procedure SendAlertProtocolVersion;
|
||||
procedure SendAlertInternalError;
|
||||
|
||||
procedure SendApplicationData(const Buffer; const Size: Integer);
|
||||
procedure SendChangeCipherSpec;
|
||||
procedure SendHandshake(const Buf; const Size: Integer);
|
||||
|
||||
procedure ShutdownBadProtocol(const AlertDescription: TTLSAlertDescription);
|
||||
procedure AddVerifyHandshakeData(const Buffer; const Size: Integer);
|
||||
procedure DoClose;
|
||||
|
||||
procedure ChangeEncryptCipherSpec;
|
||||
procedure ChangeDecryptCipherSpec;
|
||||
|
||||
procedure HandleAlertCloseNotify;
|
||||
procedure HandleAlertProtocolVersion;
|
||||
procedure HandleAlertProtocolFailure(const Alert: TTLSAlert);
|
||||
procedure HandleAlertCertificateError(const Alert: TTLSAlert);
|
||||
procedure HandleAlertSecurityError(const Alert: TTLSAlert);
|
||||
procedure HandleAlertUserCancelled;
|
||||
procedure HandleAlertNoRenegotiation;
|
||||
procedure HandleAlertUnknown(const Alert: TTLSAlert);
|
||||
procedure HandleProtocolAlert(const Buffer; const Size: Integer);
|
||||
|
||||
procedure HandleProtocolChangeCipherSpec(const Buffer; const Size: Integer);
|
||||
procedure HandleProtocolApplicationData(const Buffer; const Size: Integer);
|
||||
|
||||
procedure HandleHandshakeMessage(const MsgType: TTLSHandshakeType; const Buffer; const Size: Integer); virtual; abstract;
|
||||
procedure HandleProtocolHandshake(const Buffer; const Size: Integer);
|
||||
|
||||
procedure ProcessTransportLayerData;
|
||||
|
||||
public
|
||||
constructor Create(const ATransportLayerSendProc: TTLSConnectionTransportLayerSendProc);
|
||||
destructor Destroy; override;
|
||||
|
||||
property OnLog: TTLSConnectionLogEvent read FOnLog write FOnLog;
|
||||
property OnStateChange: TTLSConnectionStateChangeEvent read FOnStateChange write FOnStateChange;
|
||||
property OnAlert: TTLSConnectionAlertEvent read FOnAlert write FOnAlert;
|
||||
property OnHandshakeFinished: TTLSConnectionNotifyEvent read FOnHandshakeFinished write FOnHandshakeFinished;
|
||||
|
||||
property ConnectionState: TTLSConnectionState read FConnectionState;
|
||||
property ConnectionErrorMessage: String read FConnectionErrorMessage;
|
||||
|
||||
function IsNegotiatingState: Boolean;
|
||||
function IsReadyState: Boolean;
|
||||
function IsFinishedState: Boolean;
|
||||
|
||||
procedure ProcessTransportLayerReceivedData(const Buffer; const Size: Integer);
|
||||
|
||||
function AvailableToRead: Integer;
|
||||
function Read(var Buffer; const Size: Integer): Integer;
|
||||
procedure Write(const Buffer; const Size: Integer);
|
||||
procedure Close;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{ System }
|
||||
|
||||
SysUtils,
|
||||
|
||||
{ Cipher }
|
||||
|
||||
flcCipherUtils,
|
||||
|
||||
{ TLS }
|
||||
|
||||
flcTLSConsts;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Security Parameters }
|
||||
{ }
|
||||
procedure InitTLSSecurityParameters(var A: TTLSSecurityParameters;
|
||||
const CompressionMethod: TTLSCompressionMethod;
|
||||
const CipherSuite: TTLSCipherSuite);
|
||||
var C : PTLSCipherSuiteInfo;
|
||||
begin
|
||||
C := @TLSCipherSuiteInfo[CipherSuite];
|
||||
A.Compression := CompressionMethod;
|
||||
A.CipherSuite := CipherSuite;
|
||||
InitTLSCipherSuiteDetails(A.CipherSuiteDetails, CipherSuite);
|
||||
A.KeyExchangeAlgorithm := TLSCipherSuiteKeyExchangeInfo[C^.KeyExchange].Algorithm;
|
||||
A.KeyExchangeAlgorithmInfo := @TLSKeyExchangeAlgorithmInfo[A.KeyExchangeAlgorithm];
|
||||
end;
|
||||
|
||||
procedure InitTLSSecurityParametersNone(var A: TTLSSecurityParameters);
|
||||
begin
|
||||
InitTLSSecurityParameters(A, tlscmNull, tlscsNone);
|
||||
end;
|
||||
|
||||
procedure InitTLSSecurityParametersNULL(var A: TTLSSecurityParameters);
|
||||
begin
|
||||
InitTLSSecurityParameters(A, tlscmNull, tlscsNULL_WITH_NULL_NULL);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ TLS connection }
|
||||
{ }
|
||||
constructor TTLSConnection.Create(const ATransportLayerSendProc: TTLSConnectionTransportLayerSendProc);
|
||||
begin
|
||||
inherited Create;
|
||||
Init;
|
||||
if not Assigned(ATransportLayerSendProc) then
|
||||
raise ETLSError.Create(TLSError_InvalidParameter);
|
||||
FTransportLayerSendProc := ATransportLayerSendProc;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.Init;
|
||||
begin
|
||||
FConnectionState := tlscoInit;
|
||||
TLSBufferInitialise(FInBuf);
|
||||
TLSBufferInitialise(FOutBuf);
|
||||
end;
|
||||
|
||||
destructor TTLSConnection.Destroy;
|
||||
begin
|
||||
SecureClearStr(FEncMACKey);
|
||||
SecureClearStr(FEncCipherKey);
|
||||
SecureClearStr(FEncIV);
|
||||
SecureClearStr(FDecMACKey);
|
||||
SecureClearStr(FDecCipherKey);
|
||||
SecureClearStr(FDecIV);
|
||||
SecureClearStr(FVerifyHandshakeData);
|
||||
TLSBufferFinalise(FOutBuf);
|
||||
TLSBufferFinalise(FInBuf);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.Log(const LogType: TTLSLogType; const LogMsg: String; const LogLevel: Integer);
|
||||
begin
|
||||
TriggerLog(LogType, LogMsg, LogLevel);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.Log(const LogType: TTLSLogType; const LogMsg: String; const LogArgs: array of const; const LogLevel: Integer);
|
||||
begin
|
||||
Log(LogType, Format(LogMsg, LogArgs), LogLevel);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.TriggerLog(const LogType: TTLSLogType; const LogMsg: String; const LogLevel: Integer);
|
||||
begin
|
||||
if Assigned(FOnLog) then
|
||||
FOnLog(self, LogType, LogMsg, LogLevel);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.TriggerConnectionStateChange;
|
||||
begin
|
||||
if Assigned(FOnStateChange) then
|
||||
FOnStateChange(self, FConnectionState);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.TriggerAlert(const Level: TTLSAlertLevel; const Description: TTLSAlertDescription);
|
||||
begin
|
||||
if Assigned(FOnAlert) then
|
||||
FOnAlert(self, Level, Description);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.TriggerHandshakeFinished;
|
||||
begin
|
||||
if Assigned(FOnHandshakeFinished) then
|
||||
FOnHandshakeFinished(self);
|
||||
end;
|
||||
|
||||
const
|
||||
TLSConnectionStateStr : array[TTLSConnectionState] of String = (
|
||||
'Init',
|
||||
'Start',
|
||||
'Handshaking',
|
||||
'ApplicationData',
|
||||
'ErrorBadProtocol',
|
||||
'Cancelled',
|
||||
'Closed');
|
||||
|
||||
procedure TTLSConnection.SetConnectionState(const State: TTLSConnectionState);
|
||||
begin
|
||||
FConnectionState := State;
|
||||
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'ConnectionState:%s', [TLSConnectionStateStr[State]]);
|
||||
{$ENDIF}
|
||||
|
||||
TriggerConnectionStateChange;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.SetClosed;
|
||||
begin
|
||||
SetConnectionState(tlscoClosed);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.SetErrorBadProtocol;
|
||||
begin
|
||||
SetConnectionState(tlscoErrorBadProtocol);
|
||||
end;
|
||||
|
||||
function TTLSConnection.IsNegotiatingState: Boolean;
|
||||
begin
|
||||
Result := FConnectionState in [
|
||||
tlscoStart,
|
||||
tlscoHandshaking];
|
||||
end;
|
||||
|
||||
function TTLSConnection.IsReadyState: Boolean;
|
||||
begin
|
||||
Result := FConnectionState = tlscoApplicationData;
|
||||
end;
|
||||
|
||||
function TTLSConnection.IsFinishedState: Boolean;
|
||||
begin
|
||||
Result := FConnectionState in [
|
||||
tlscoErrorBadProtocol,
|
||||
tlscoCancelled,
|
||||
tlscoClosed];
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.SetEncodeKeys(const MACKey, CipherKey, IV: RawByteString);
|
||||
begin
|
||||
FEncMACKey := MACKey;
|
||||
FEncCipherKey := CipherKey;
|
||||
FEncIV := IV;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.SetDecodeKeys(const MACKey, CipherKey, IV: RawByteString);
|
||||
begin
|
||||
FDecMACKey := MACKey;
|
||||
FDecCipherKey := CipherKey;
|
||||
FDecIV := IV;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.TransportLayerSend(const Buffer; const Size: Integer);
|
||||
begin
|
||||
Assert(Assigned(FTransportLayerSendProc));
|
||||
Assert(Assigned(@Buffer));
|
||||
Assert(Size >= 0);
|
||||
|
||||
FTransportLayerSendProc(self, Buffer, Size);
|
||||
end;
|
||||
|
||||
const
|
||||
TLS_CLIENT_RECORDBUF_MAXSIZE = TLS_PLAINTEXT_FRAGMENT_MAXSIZE * 2;
|
||||
|
||||
procedure TTLSConnection.SendContent(
|
||||
const ContentType: TTLSContentType;
|
||||
const Buffer; const Size: Integer);
|
||||
var P : PByte;
|
||||
L : Integer;
|
||||
BufMsg : array[0..TLS_CLIENT_RECORDBUF_MAXSIZE - 1] of Byte;
|
||||
M, RecSize : Integer;
|
||||
begin
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'T:%s:%db', [TLSContentTypeToStr(ContentType), Size]);
|
||||
{$ENDIF}
|
||||
|
||||
P := @Buffer;
|
||||
L := Size;
|
||||
while L > 0 do
|
||||
begin
|
||||
M := L;
|
||||
if M > TLS_PLAINTEXT_FRAGMENT_MAXSIZE then
|
||||
M := TLS_PLAINTEXT_FRAGMENT_MAXSIZE;
|
||||
|
||||
RecSize := EncodeTLSRecord(
|
||||
BufMsg, SizeOf(BufMsg),
|
||||
FProtocolVersion,
|
||||
ContentType,
|
||||
P^, M,
|
||||
FCipherEncryptSpec.Compression,
|
||||
FCipherEncryptSpec.CipherSuiteDetails,
|
||||
FWriteSeqNo,
|
||||
Pointer(FEncMACKey)^, Length(FEncMACKey),
|
||||
FCipherEncryptState,
|
||||
Pointer(FEncIV), Length(FEncIV));
|
||||
|
||||
Inc(FWriteSeqNo);
|
||||
TransportLayerSend(BufMsg, RecSize);
|
||||
|
||||
Dec(L, M);
|
||||
Inc(P, M);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.SendAlert(const Level: TTLSAlertLevel; const Description: TTLSAlertDescription);
|
||||
var B : TTLSAlert;
|
||||
begin
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'T:Alert:%s:%s', [TLSAlertLevelToStr(Level), TLSAlertDescriptionToStr(Description)]);
|
||||
{$ENDIF}
|
||||
|
||||
InitTLSAlert(B, Level, Description);
|
||||
SendContent(tlsctAlert, B, TLSAlertSize);
|
||||
|
||||
if Level = tlsalFatal then
|
||||
FConnectionErrorMessage :=
|
||||
TLSAlertLevelToStr(Level) + ':' +
|
||||
TLSAlertDescriptionToStr(Description);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.SendAlertCloseNotify;
|
||||
begin
|
||||
SendAlert(tlsalWarning, tlsadClose_notify);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.SendAlertUnexpectedMessage;
|
||||
begin
|
||||
SendAlert(tlsalFatal, tlsadUnexpected_message);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.SendAlertIllegalParameter;
|
||||
begin
|
||||
SendAlert(tlsalFatal, tlsadIllegal_parameter);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.SendAlertDecodeError;
|
||||
begin
|
||||
SendAlert(tlsalFatal, tlsadDecode_error);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.SendAlertProtocolVersion;
|
||||
begin
|
||||
SendAlert(tlsalFatal, tlsadDecode_error);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.SendAlertInternalError;
|
||||
begin
|
||||
SendAlert(tlsalFatal, tlsadInternal_error);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.SendApplicationData(const Buffer; const Size: Integer);
|
||||
begin
|
||||
Assert(FConnectionState = tlscoApplicationData);
|
||||
SendContent(tlsctApplication_data, Buffer, Size);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.SendHandshake(const Buf; const Size: Integer);
|
||||
begin
|
||||
SendContent(tlsctHandshake, Buf, Size);
|
||||
AddVerifyHandshakeData(Buf, Size);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.SendChangeCipherSpec;
|
||||
var B : TTLSChangeCipherSpec;
|
||||
begin
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'T:ChangeCipherSpec');
|
||||
{$ENDIF}
|
||||
|
||||
InitTLSChangeCipherSpec(B);
|
||||
SendContent(tlsctChange_cipher_spec, B, TLSChangeCipherSpecSize);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.ShutdownBadProtocol(const AlertDescription: TTLSAlertDescription);
|
||||
begin
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'ShutdownBadProtocol:%s', [TLSAlertDescriptionToStr(AlertDescription)]);
|
||||
{$ENDIF}
|
||||
|
||||
SendAlert(tlsalFatal, AlertDescription);
|
||||
SetErrorBadProtocol;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.AddVerifyHandshakeData(const Buffer; const Size: Integer);
|
||||
var S : RawByteString;
|
||||
begin
|
||||
Assert(Size > 0);
|
||||
SetLength(S, Size);
|
||||
Move(Buffer, S[1], Size);
|
||||
FVerifyHandshakeData := FVerifyHandshakeData + S;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.DoClose;
|
||||
begin
|
||||
if FConnectionState = tlscoApplicationData then
|
||||
SendAlertCloseNotify;
|
||||
SetClosed;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.ChangeEncryptCipherSpec;
|
||||
begin
|
||||
FCipherEncryptSpec := FCipherSpecNew;
|
||||
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'EncryptCipherSpec:%s', [FCipherEncryptSpec.CipherSuiteDetails.CipherSuiteInfo^.Name]);
|
||||
{$ENDIF}
|
||||
|
||||
FWriteSeqNo := 0;
|
||||
TLSCipherFinalise(FCipherEncryptState);
|
||||
TLSCipherInit(
|
||||
FCipherEncryptState,
|
||||
tlscoEncrypt,
|
||||
FCipherEncryptSpec.CipherSuiteDetails.CipherSuiteInfo^.Cipher,
|
||||
FEncCipherKey[1], Length(FEncCipherKey));
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.ChangeDecryptCipherSpec;
|
||||
begin
|
||||
FCipherDecryptSpec := FCipherSpecNew;
|
||||
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'DecryptCipherSpec:%s', [
|
||||
FCipherDecryptSpec.CipherSuiteDetails.CipherSuiteInfo^.Name]);
|
||||
{$ENDIF}
|
||||
|
||||
FReadSeqNo := 0;
|
||||
TLSCipherFinalise(FCipherDecryptState);
|
||||
TLSCipherInit(
|
||||
FCipherDecryptState,
|
||||
tlscoDecrypt,
|
||||
FCipherDecryptSpec.CipherSuiteDetails.CipherSuiteInfo^.Cipher,
|
||||
FDecCipherKey[1], Length(FDecCipherKey));
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.HandleAlertCloseNotify;
|
||||
begin
|
||||
SetClosed;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.HandleAlertProtocolVersion;
|
||||
begin
|
||||
SetErrorBadProtocol;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.HandleAlertProtocolFailure(const Alert: TTLSAlert);
|
||||
begin
|
||||
SetErrorBadProtocol;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.HandleAlertCertificateError(const Alert: TTLSAlert);
|
||||
begin
|
||||
SetErrorBadProtocol;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.HandleAlertSecurityError(const Alert: TTLSAlert);
|
||||
begin
|
||||
SetErrorBadProtocol;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.HandleAlertUserCancelled;
|
||||
begin
|
||||
SetConnectionState(tlscoCancelled);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.HandleAlertNoRenegotiation;
|
||||
begin
|
||||
SetErrorBadProtocol;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.HandleAlertUnknown(const Alert: TTLSAlert);
|
||||
begin
|
||||
if Alert.level = tlsalFatal then
|
||||
SetErrorBadProtocol;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.HandleProtocolAlert(const Buffer; const Size: Integer);
|
||||
var Alert : PTLSAlert;
|
||||
begin
|
||||
Alert := @Buffer;
|
||||
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'R:Alert:%s:%s', [TLSAlertLevelToStr(Alert^.level),
|
||||
TLSAlertDescriptionToStr(Alert^.description)]);
|
||||
{$ENDIF}
|
||||
|
||||
if Alert^.level = tlsalFatal then
|
||||
FConnectionErrorMessage :=
|
||||
TLSAlertLevelToStr(Alert^.level) + ':' +
|
||||
TLSAlertDescriptionToStr(Alert^.description);
|
||||
|
||||
case Alert^.description of
|
||||
tlsadClose_notify : HandleAlertCloseNotify;
|
||||
tlsadProtocol_version : HandleAlertProtocolVersion;
|
||||
tlsadUnexpected_message,
|
||||
tlsadBad_record_mac,
|
||||
tlsadDecryption_failed,
|
||||
tlsadRecord_overflow,
|
||||
tlsadDecompression_failure,
|
||||
tlsadHandshake_failure,
|
||||
tlsadInternal_error,
|
||||
tlsadIllegal_parameter,
|
||||
tlsadDecode_error,
|
||||
tlsadDecrypt_error,
|
||||
tlsadUnsupported_extention : HandleAlertProtocolFailure(Alert^);
|
||||
tlsadNo_certificate,
|
||||
tlsadBad_certificate,
|
||||
tlsadUnsupported_certificate,
|
||||
tlsadCertificate_revoked,
|
||||
tlsadCertificate_expired,
|
||||
tlsadCertificate_unknown,
|
||||
tlsadUnknown_ca : HandleAlertCertificateError(Alert^);
|
||||
tlsadAccess_denied,
|
||||
tlsadExport_restriction,
|
||||
tlsadInsufficient_security : HandleAlertSecurityError(Alert^);
|
||||
tlsadUser_canceled : HandleAlertUserCancelled;
|
||||
tlsadNo_renegotiation : HandleAlertNoRenegotiation;
|
||||
/////
|
||||
else
|
||||
HandleAlertUnknown(Alert^);
|
||||
end;
|
||||
|
||||
TriggerAlert(Alert^.level, Alert^.description);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.HandleProtocolChangeCipherSpec(const Buffer; const Size: Integer);
|
||||
begin
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'R:ChangeCipherSpec');
|
||||
{$ENDIF}
|
||||
|
||||
ChangeDecryptCipherSpec;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.HandleProtocolApplicationData(const Buffer; const Size: Integer);
|
||||
begin
|
||||
TLSBufferAddBuf(FOutBuf, Buffer, Size);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.HandleProtocolHandshake(const Buffer; const Size: Integer);
|
||||
var P : PByte;
|
||||
N : Integer;
|
||||
MsgType : TTLSHandshakeType;
|
||||
Len : Integer;
|
||||
begin
|
||||
try
|
||||
P := @Buffer;
|
||||
N := Size;
|
||||
repeat
|
||||
DecodeTLSHandshakeHeader(PTLSHandshakeHeader(P)^, MsgType, Len);
|
||||
if MsgType <> tlshtHello_request then
|
||||
AddVerifyHandshakeData(P^, TLSHandshakeHeaderSize + Len);
|
||||
Inc(P, TLSHandshakeHeaderSize);
|
||||
Dec(N, TLSHandshakeHeaderSize);
|
||||
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'R:Handshake:[%s]:%db', [TLSHandshakeTypeToStr(MsgType), Len]);
|
||||
{$ENDIF}
|
||||
|
||||
HandleHandshakeMessage(MsgType, P^, Len);
|
||||
Inc(P, Len);
|
||||
Dec(N, Len);
|
||||
until N <= 0;
|
||||
except
|
||||
on E : ETLSError do
|
||||
ShutdownBadProtocol(E.AlertDescription)
|
||||
else
|
||||
ShutdownBadProtocol(tlsadHandshake_failure);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.ProcessTransportLayerData;
|
||||
var P, Q : PByte;
|
||||
RecHeader : PTLSRecordHeader;
|
||||
ContentType : TTLSContentType;
|
||||
ProtocolVersion : TTLSProtocolVersion;
|
||||
RecLength : Word;
|
||||
PlainSize : Integer;
|
||||
PlainBuf : array[0..TLS_CLIENT_RECORDBUF_MAXSIZE - 1] of Byte;
|
||||
begin
|
||||
while TLSBufferUsed(FInBuf) >= TLSRecordHeaderSize do
|
||||
begin
|
||||
P := TLSBufferPtr(FInBuf);
|
||||
|
||||
// decode header
|
||||
RecHeader := PTLSRecordHeader(P);
|
||||
DecodeTLSRecordHeader(RecHeader^, ContentType, ProtocolVersion, RecLength);
|
||||
|
||||
// validate header
|
||||
if not (ContentType in [
|
||||
tlsctHandshake,
|
||||
tlsctAlert,
|
||||
tlsctApplication_data,
|
||||
tlsctChange_cipher_spec]) then
|
||||
ShutdownBadProtocol(tlsadUnexpected_message);
|
||||
|
||||
// wait for complete record
|
||||
if TLSBufferUsed(FInBuf) < TLSRecordHeaderSize + RecLength then
|
||||
exit;
|
||||
|
||||
// record received
|
||||
{$IFDEF TLS_DEBUG}
|
||||
Log(tlsltDebug, 'R:Record:[%s]:%db', [TLSContentTypeToStr(ContentType), RecLength]);
|
||||
{$ENDIF}
|
||||
|
||||
try
|
||||
Inc(P, TLSRecordHeaderSize);
|
||||
DecodeTLSRecord(
|
||||
RecHeader,
|
||||
P^, RecLength,
|
||||
FProtocolVersion,
|
||||
FCipherDecryptSpec.Compression,
|
||||
FCipherDecryptSpec.CipherSuiteDetails,
|
||||
FReadSeqNo,
|
||||
Pointer(FDecMACKey)^, Length(FDecMACKey),
|
||||
FCipherDecryptState,
|
||||
Pointer(FDecIV), Length(FDecIV),
|
||||
PlainBuf, SizeOf(PlainBuf), PlainSize);
|
||||
TLSBufferDiscard(FInBuf, TLSRecordHeaderSize + RecLength);
|
||||
Inc(FReadSeqNo);
|
||||
|
||||
// process
|
||||
Q := @PlainBuf;
|
||||
case ContentType of
|
||||
tlsctHandshake : HandleProtocolHandshake(Q^, PlainSize);
|
||||
tlsctAlert : HandleProtocolAlert(Q^, PlainSize);
|
||||
tlsctApplication_data : HandleProtocolApplicationData(Q^, PlainSize);
|
||||
tlsctChange_cipher_spec : HandleProtocolChangeCipherSpec(Q^, PlainSize);
|
||||
else
|
||||
ShutdownBadProtocol(tlsadUnexpected_message);
|
||||
end;
|
||||
except
|
||||
on E : ETLSError do
|
||||
if E.AlertDescription = tlsadMax then
|
||||
ShutdownBadProtocol(tlsadDecode_error)
|
||||
else
|
||||
ShutdownBadProtocol(E.AlertDescription);
|
||||
else
|
||||
ShutdownBadProtocol(tlsadDecode_error);
|
||||
end;
|
||||
if IsFinishedState then
|
||||
exit;
|
||||
end;
|
||||
SecureClear(PlainBuf, SizeOf(PlainBuf));
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.ProcessTransportLayerReceivedData(const Buffer; const Size: Integer);
|
||||
begin
|
||||
TLSBufferAddBuf(FInBuf, Buffer, Size);
|
||||
if IsFinishedState then
|
||||
raise ETLSError.Create(TLSError_InvalidState); // tls session finished
|
||||
|
||||
ProcessTransportLayerData;
|
||||
end;
|
||||
|
||||
function TTLSConnection.AvailableToRead: Integer;
|
||||
begin
|
||||
Result := TLSBufferUsed(FOutBuf);
|
||||
end;
|
||||
|
||||
function TTLSConnection.Read(var Buffer; const Size: Integer): Integer;
|
||||
var L, N : Integer;
|
||||
begin
|
||||
if Size <= 0 then
|
||||
begin
|
||||
Result := 0;
|
||||
exit;
|
||||
end;
|
||||
N := TLSBufferUsed(FOutBuf);
|
||||
if N = 0 then
|
||||
begin
|
||||
Result := 0;
|
||||
exit;
|
||||
end;
|
||||
if Size > N then
|
||||
L := N
|
||||
else
|
||||
L := Size;
|
||||
Result := TLSBufferRemove(FOutBuf, Buffer, L);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.Write(const Buffer; const Size: Integer);
|
||||
begin
|
||||
if Size <= 0 then
|
||||
exit;
|
||||
if IsFinishedState then
|
||||
raise ETLSError.Create(TLSError_InvalidState); // tls session finished
|
||||
|
||||
if FConnectionState <> tlscoApplicationData then
|
||||
raise ETLSError.Create(TLSError_InvalidState); // cannot accept application data yet.. todo: buffer until negotiation finished?
|
||||
|
||||
SendApplicationData(Buffer, Size);
|
||||
end;
|
||||
|
||||
procedure TTLSConnection.Close;
|
||||
begin
|
||||
if IsFinishedState then
|
||||
raise ETLSError.Create(TLSError_InvalidState); // not open
|
||||
|
||||
DoClose;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
end.
|
||||
|
1126
contrib/fundamentals/TLS/flcTLSTransportServer.pas
Normal file
1126
contrib/fundamentals/TLS/flcTLSTransportServer.pas
Normal file
File diff suppressed because it is too large
Load Diff
151
contrib/fundamentals/TLS/flcTLSTransportTypes.pas
Normal file
151
contrib/fundamentals/TLS/flcTLSTransportTypes.pas
Normal file
@@ -0,0 +1,151 @@
|
||||
{******************************************************************************}
|
||||
{ }
|
||||
{ Library: Fundamentals TLS }
|
||||
{ File name: flcTLSTransportTypes.pas }
|
||||
{ File version: 5.01 }
|
||||
{ Description: TLS Transport Types }
|
||||
{ }
|
||||
{ Copyright: Copyright (c) 2008-2020, David J Butler }
|
||||
{ All rights reserved. }
|
||||
{ Redistribution and use in source and binary forms, with }
|
||||
{ or without modification, are permitted provided that }
|
||||
{ the following conditions are met: }
|
||||
{ Redistributions of source code must retain the above }
|
||||
{ copyright notice, this list of conditions and the }
|
||||
{ following disclaimer. }
|
||||
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
||||
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
|
||||
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
|
||||
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
|
||||
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
|
||||
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
|
||||
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
|
||||
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
|
||||
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
|
||||
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
|
||||
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
|
||||
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
|
||||
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
|
||||
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
|
||||
{ POSSIBILITY OF SUCH DAMAGE. }
|
||||
{ }
|
||||
{ Github: https://github.com/fundamentalslib }
|
||||
{ E-mail: fundamentals.library at gmail.com }
|
||||
{ }
|
||||
{ Revision history: }
|
||||
{ }
|
||||
{ 2020/05/01 5.01 Initial version: Options. }
|
||||
{ }
|
||||
{******************************************************************************}
|
||||
|
||||
{$INCLUDE flcTLS.inc}
|
||||
|
||||
unit flcTLSTransportTypes;
|
||||
|
||||
interface
|
||||
|
||||
|
||||
|
||||
type
|
||||
TTLSLogType = (
|
||||
tlsltDebug,
|
||||
tlsltParameter,
|
||||
tlsltInfo,
|
||||
tlsltWarning,
|
||||
tlsltError
|
||||
);
|
||||
|
||||
|
||||
|
||||
type
|
||||
TTLSVersionOption = (
|
||||
tlsvoSSL3,
|
||||
tlsvoTLS10,
|
||||
tlsvoTLS11,
|
||||
tlsvoTLS12
|
||||
);
|
||||
|
||||
TTLSVersionOptions = set of TTLSVersionOption;
|
||||
|
||||
const
|
||||
AllTLSVersionOptions = [
|
||||
tlsvoSSL3,
|
||||
tlsvoTLS10,
|
||||
tlsvoTLS11,
|
||||
tlsvoTLS12
|
||||
];
|
||||
|
||||
|
||||
|
||||
type
|
||||
TTLSKeyExchangeOption = (
|
||||
tlskeoRSA,
|
||||
tlskeoDH_Anon,
|
||||
tlskeoDH_RSA,
|
||||
tlskeoDHE_RSA,
|
||||
tlskeoECDH_RSA,
|
||||
tlskeoECDHE_RSA
|
||||
);
|
||||
|
||||
TTLSKeyExchangeOptions = set of TTLSKeyExchangeOption;
|
||||
|
||||
const
|
||||
AllTLSKeyExchangeOptions = [
|
||||
tlskeoRSA,
|
||||
tlskeoDH_Anon,
|
||||
tlskeoDH_RSA,
|
||||
tlskeoDHE_RSA,
|
||||
tlskeoECDH_RSA,
|
||||
tlskeoECDHE_RSA
|
||||
];
|
||||
|
||||
|
||||
|
||||
type
|
||||
TTLSCipherOption = (
|
||||
tlscoRC4,
|
||||
tlscoDES,
|
||||
tlsco3DES,
|
||||
tlscoAES128,
|
||||
tlscoAES256
|
||||
);
|
||||
|
||||
TTLSCipherOptions = set of TTLSCipherOption;
|
||||
|
||||
const
|
||||
AllTLSCipherOptions = [
|
||||
tlscoRC4,
|
||||
tlscoDES,
|
||||
tlsco3DES,
|
||||
tlscoAES128,
|
||||
tlscoAES256
|
||||
];
|
||||
|
||||
|
||||
|
||||
type
|
||||
TTLSHashOption = (
|
||||
tlshoMD5,
|
||||
tlshoSHA1,
|
||||
tlshoSHA256,
|
||||
tlshoSHA384
|
||||
);
|
||||
|
||||
TTLSHashOptions = set of TTLSHashOption;
|
||||
|
||||
const
|
||||
AllTLSHashOptions = [
|
||||
tlshoMD5,
|
||||
tlshoSHA1,
|
||||
tlshoSHA256,
|
||||
tlshoSHA384
|
||||
];
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
|
||||
|
||||
end.
|
||||
|
Reference in New Issue
Block a user