diff --git a/Source/TLS/flcTLS.inc b/Source/TLS/flcTLS.inc index fa8ce7b..6d6ce48 100644 --- a/Source/TLS/flcTLS.inc +++ b/Source/TLS/flcTLS.inc @@ -2,16 +2,15 @@ { } { Library: Fundamentals TLS } { File name: flcTLS.inc } -{ File version: 5.04 } { Description: TLS library defines } +{ Last updated: 2020/05/19 } { } {******************************************************************************} -{.DEFINE DEBUG} -{.DEFINE SELFTEST} - {$INCLUDE ..\flcInclude.inc} +{$DEFINE TLS} + {$IFDEF DEBUG} {$DEFINE TLS_DEBUG} {$ENDIF} @@ -19,10 +18,9 @@ {$IFDEF DEBUG} {$IFDEF TEST} {$DEFINE TLS_TEST} + {.DEFINE TLS_TEST_NO_RANDOM_HELLO} {$ENDIF} {$ENDIF} -{$IFNDEF MSWIN} - {$DEFINE TLS_ZLIB_DISABLE} -{$ENDIF} +{$DEFINE TLS_ZLIB_DISABLE} diff --git a/Source/TLS/flcTLSAlert.pas b/Source/TLS/flcTLSAlert.pas index 2a355d9..0ecba00 100644 --- a/Source/TLS/flcTLSAlert.pas +++ b/Source/TLS/flcTLSAlert.pas @@ -1,204 +1,210 @@ -{******************************************************************************} -{ } -{ Library: Fundamentals TLS } -{ File name: flcTLSAlert.pas } -{ File version: 5.03 } -{ Description: TLS alert protocol } -{ } -{ 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 Additional alerts from RFC 4366. } -{ 2018/07/17 5.03 Revised for Fundamentals 5. } -{ } -{******************************************************************************} - -{$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 - 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 - 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 - 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 - tlsadUnsupported_extention = 110, // TLS 1.2 - tlsadCertificate_unobtainable = 111, // RFC 4366 - tlsadUnrecognized_name = 112, // RFC 4366 - tlsadBad_certificate_status_response = 113, // RFC 4366 - tlsadBad_certificate_hash_value = 114, // RFC 4366 - 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_SELFTEST} -procedure SelfTest; -{$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'; - 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'; - 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 cases } -{ } -{$IFDEF TLS_SELFTEST} -{$ASSERTIONS ON} -procedure SelfTest; -begin - Assert(TLSAlertSize = 2); -end; -{$ENDIF} - - - -end. - +{******************************************************************************} +{ } +{ 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} + + + +end. + diff --git a/Source/TLS/flcTLSAlgorithmTypes.pas b/Source/TLS/flcTLSAlgorithmTypes.pas new file mode 100644 index 0000000..1b81c2f --- /dev/null +++ b/Source/TLS/flcTLSAlgorithmTypes.pas @@ -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 + ); + + + +{ } +{ Test } +{ } +{$IFDEF TLS_TEST} +procedure Test; +{$ENDIF} + + + +implementation + +uses + { System } + + SysUtils; + + + +{ } +{ HashAlgorithm } +{ } +function HashAlgorithmToStr(const A: TTLSHashAlgorithm): String; +begin + case A of + tlshaNone : Result := 'None'; + tlshaMD5 : Result := 'MD5'; + tlshaSHA1 : Result := 'SHA1'; + tlshaSHA224 : Result := 'SHA224'; + tlshaSHA256 : Result := 'SHA256'; + tlshaSHA384 : Result := 'SHA384'; + tlshaSHA512 : Result := 'SHA512'; + else + Result := 'Hash#' + IntToStr(Ord(A)); + end; +end; + + + +{ } +{ Test } +{ } +{$IFDEF TLS_TEST} +{$ASSERTIONS ON} +procedure Test; +begin + Assert(TLSCompressionMethodSize = 1); +end; +{$ENDIF} + + + +end. diff --git a/Source/TLS/flcTLSBuffer.pas b/Source/TLS/flcTLSBuffer.pas index c15cf43..e20cd3a 100644 --- a/Source/TLS/flcTLSBuffer.pas +++ b/Source/TLS/flcTLSBuffer.pas @@ -5,7 +5,7 @@ { File version: 5.02 } { Description: TLS buffer } { } -{ Copyright: Copyright (c) 2008-2018, David J Butler } +{ 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 } @@ -98,7 +98,8 @@ implementation uses { TLS } - flcTLSUtils; + + flcTLSErrors; diff --git a/Source/TLS/flcTLSCertificate.pas b/Source/TLS/flcTLSCertificate.pas new file mode 100644 index 0000000..1f552b1 --- /dev/null +++ b/Source/TLS/flcTLSCertificate.pas @@ -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. + diff --git a/Source/TLS/flcTLSCipher.pas b/Source/TLS/flcTLSCipher.pas index 7672175..5aa40b2 100644 --- a/Source/TLS/flcTLSCipher.pas +++ b/Source/TLS/flcTLSCipher.pas @@ -49,8 +49,11 @@ interface uses { Cipher } + flcCipher, + { TLS } + flcTLSCipherSuite; @@ -105,7 +108,7 @@ TTLSCipherSuiteCipherCipherInfo = record CipherMode : cmCBC; Padding : cpNone), ( // 3DES_EDE_CBC - CipherType : ctTripleDESEDE; + CipherType : ctTripleDES3EDE; //// TripleDESEDE or TripleDES3EDE ? CipherMode : cmCBC; Padding : cpNone), ( // AES_128_CBC @@ -181,11 +184,13 @@ procedure Test; implementation uses - { Fundamentals } + { Utils } + flcStdTypes, - + { TLS } - flcTLSUtils; + + flcTLSErrors; diff --git a/Source/TLS/flcTLSCipherSuite.pas b/Source/TLS/flcTLSCipherSuite.pas index 34e0d09..2cc6215 100644 --- a/Source/TLS/flcTLSCipherSuite.pas +++ b/Source/TLS/flcTLSCipherSuite.pas @@ -2,10 +2,10 @@ { } { Library: Fundamentals TLS } { File name: flcTLSCipherSuite.pas } -{ File version: 5.02 } +{ File version: 5.04 } { Description: TLS cipher suite } { } -{ Copyright: Copyright (c) 2008-2018, David J Butler } +{ 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 } @@ -35,11 +35,14 @@ { References: } { } { http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml } +{ https://ldapwiki.com/wiki/Known%20Cipher%20Suites } { } { Revision history: } { } -{ 2008/01/18 0.01 Initial version } +{ 2008/01/18 0.01 Initial development. } { 2018/07/17 5.02 Revised for Fundamentals 5. } +{ 2020/05/09 5.03 Populate CipherSuiteInfo.Auhtentication. } +{ 2020/05/19 5.04 Enable support for DHE_RSA_WITH_AES suites. } { } {******************************************************************************} @@ -50,10 +53,14 @@ interface uses - { Fundamentals } + { Utils } + flcStdTypes, + { TLS } - flcTLSUtils; + + flcTLSProtocolVersion, + flcTLSAlgorithmTypes; @@ -71,6 +78,8 @@ interface tlscsDH_Anon_EXPORT_WITH_DES40_CBC_SHA, tlscsDH_Anon_WITH_DES_CBC_SHA, tlscsDH_Anon_WITH_3DES_EDE_CBC_SHA, + tlscsDH_Anon_WITH_AES_128_CBC_SHA256, + tlscsDH_Anon_WITH_AES_256_CBC_SHA256, tlscsDH_DSS_EXPORT_WITH_DES40_CBC_SHA, tlscsDH_DSS_WITH_DES_CBC_SHA, tlscsDH_DSS_WITH_3DES_EDE_CBC_SHA, @@ -96,13 +105,13 @@ interface tlscsRSA_EXPORT1024_WITH_DES_CBC_SHA, // draft-ietf-tls-56-bit-ciphersuites-01 tlscsRSA_EXPORT1024_WITH_RC4_56_SHA, // draft-ietf-tls-56-bit-ciphersuites-01 tlscsRSA_WITH_NULL_SHA256, - tlscsRSA_WITH_AES_128_CBC_SHA, + tlscsRSA_WITH_AES_128_CBC_SHA, // mandatory for tls 1.2 (rfc 5246) tlscsRSA_WITH_AES_256_CBC_SHA, tlscsRSA_WITH_AES_128_CBC_SHA256, tlscsRSA_WITH_AES_256_CBC_SHA256, tlscsDHE_DSS_EXPORT_WITH_DES40_CBC_SHA, tlscsDHE_DSS_WITH_DES_CBC_SHA, - tlscsDHE_DSS_WITH_3DES_EDE_CBC_SHA, // required + tlscsDHE_DSS_WITH_3DES_EDE_CBC_SHA, tlscsDHE_DSS_WITH_RC4_128_SHA, // draft-ietf-tls-56-bit-ciphersuites-01 tlscsDHE_RSA_EXPORT_WITH_DES40_CBC_SHA, tlscsDHE_RSA_WITH_DES_CBC_SHA, @@ -114,7 +123,15 @@ interface tlscsDHE_RSA_WITH_AES_128_CBC_SHA, tlscsDHE_RSA_WITH_AES_256_CBC_SHA, tlscsDHE_RSA_WITH_AES_128_CBC_SHA256, - tlscsDHE_RSA_WITH_AES_256_CBC_SHA256 + tlscsDHE_RSA_WITH_AES_256_CBC_SHA256, + tlscsECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // rfc 5289 + tlscsECDHE_ECDSA_WITH_AES_256_CBC_SHA384, // rfc 5289 + tlscsECDH_ECDSA_WITH_AES_128_CBC_SHA256, // rfc 5289 + tlscsECDH_ECDSA_WITH_AES_256_CBC_SHA384, // rfc 5289 + tlscsECDHE_RSA_WITH_AES_128_CBC_SHA256, // rfc 5289 + tlscsECDHE_RSA_WITH_AES_256_CBC_SHA384, // rfc 5289 + tlscsECDH_RSA_WITH_AES_128_CBC_SHA256, // rfc 5289 + tlscsECDH_RSA_WITH_AES_256_CBC_SHA384 // rfc 5289 ); TTLSCipherSuites = set of TTLSCipherSuite; @@ -133,9 +150,22 @@ interface tlscskeDHE_RSA_EXPORT, tlscskeDHE_RSA, tlscskeDH_anon_EXPORT, - tlscskeDH_anon + tlscskeDH_anon, + tlscskeECDHE_ECDSA, + tlscskeECDH_ECDSA, + tlscskeECDHE_RSA, + tlscskeECDH_RSA ); + TTLSCipherSuiteAuthentication = ( + tlscsaNone, + tlscsaAnon, + tlscsaRSA, + tlscsaDSS, + tlscsaPSK, + tlscsaECDSA + ); + TTLSCipherSuiteCipher = ( tlscscNone, tlscscNULL, @@ -156,6 +186,7 @@ interface tlscshNULL, tlscshSHA, tlscshSHA256, + tlscshSHA384, tlscshMD5 ); @@ -170,507 +201,661 @@ interface type TTLSCipherSuiteInfo = record - Name : RawByteString; - KeyExchange : TTLSCipherSuiteKeyExchange; - Cipher : TTLSCipherSuiteCipher; - Hash : TTLSCipherSuiteHash; - Rec : TTLSCipherSuiteRec; - ServerSupport : Boolean; - ClientSupport : Boolean; - MinVersion : TTLSProtocolVersion; + Name : RawByteString; + KeyExchange : TTLSCipherSuiteKeyExchange; + Authentication : TTLSCipherSuiteAuthentication; + Cipher : TTLSCipherSuiteCipher; + Hash : TTLSCipherSuiteHash; + Rec : TTLSCipherSuiteRec; + ServerSupport : Boolean; + ClientSupport : Boolean; + MinVersion : TTLSProtocolVersion; end; PTLSCipherSuiteInfo = ^TTLSCipherSuiteInfo; const TLSCipherSuiteInfo : array[TTLSCipherSuite] of TTLSCipherSuiteInfo = ( ( // None - Name : ''; - KeyExchange : tlscskeNone; - Cipher : tlscscNone; - Hash : tlscshNone; - Rec : (B1: $FF; B2: $FF); - ServerSupport : False; - ClientSupport : False; - MinVersion : (major: 0; minor: 0); + Name : ''; + KeyExchange : tlscskeNone; + Authentication : tlscsaNone; + Cipher : tlscscNone; + Hash : tlscshNone; + Rec : (B1: $FF; B2: $FF); + ServerSupport : False; + ClientSupport : False; + MinVersion : (major: 0; minor: 0); ), ( // NULL_WITH_NULL_NULL - Name : 'NULL_WITH_NULL_NULL'; - KeyExchange : tlscskeNULL; - Cipher : tlscscNULL; - Hash : tlscshNULL; - Rec : (B1: $00; B2: $00); - ServerSupport : False; - ClientSupport : False; - MinVersion : (major: 0; minor: 0); + Name : 'NULL_WITH_NULL_NULL'; + KeyExchange : tlscskeNULL; + Authentication : tlscsaNone; + Cipher : tlscscNULL; + Hash : tlscshNULL; + Rec : (B1: $00; B2: $00); + ServerSupport : False; + ClientSupport : False; + MinVersion : (major: 0; minor: 0); ), ( // RSA_WITH_NULL_MD5 - Name : 'RSA_WITH_NULL_MD5'; - KeyExchange : tlscskeRSA; - Cipher : tlscscNULL; - Hash : tlscshMD5; - Rec : (B1: $00; B2: $01); - ServerSupport : False; - ClientSupport : False; + Name : 'RSA_WITH_NULL_MD5'; + KeyExchange : tlscskeRSA; + Authentication : tlscsaAnon; + Cipher : tlscscNULL; + Hash : tlscshMD5; + Rec : (B1: $00; B2: $01); + ServerSupport : False; + ClientSupport : False; ), ( // RSA_WITH_NULL_SHA - Name : 'RSA_WITH_NULL_SHA'; - KeyExchange : tlscskeRSA; - Cipher : tlscscNULL; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $02); - ServerSupport : False; - ClientSupport : False; + Name : 'RSA_WITH_NULL_SHA'; + KeyExchange : tlscskeRSA; + Authentication : tlscsaAnon; + Cipher : tlscscNULL; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $02); + ServerSupport : False; + ClientSupport : False; ), ( // DH_anon_EXPORT_WITH_RC4_40_MD5 - Name : 'DH_anon_EXPORT_WITH_RC4_40_MD5'; - KeyExchange : tlscskeDH_anon_EXPORT; - Cipher : tlscscRC4_40; - Hash : tlscshMD5; - Rec : (B1: $00; B2: $17); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_anon_EXPORT_WITH_RC4_40_MD5'; + KeyExchange : tlscskeDH_anon_EXPORT; + Authentication : tlscsaAnon; + Cipher : tlscscRC4_40; + Hash : tlscshMD5; + Rec : (B1: $00; B2: $17); + ServerSupport : False; + ClientSupport : False; ), ( // DH_anon_WITH_RC4_128_MD5 - Name : 'DH_anon_WITH_RC4_128_MD5'; - KeyExchange : tlscskeDH_anon; - Cipher : tlscscRC4_128; - Hash : tlscshMD5; - Rec : (B1: $00; B2: $18); - ServerSupport : False; // Under development - ClientSupport : False; // Under development + Name : 'DH_anon_WITH_RC4_128_MD5'; + KeyExchange : tlscskeDH_anon; + Authentication : tlscsaAnon; + Cipher : tlscscRC4_128; + Hash : tlscshMD5; + Rec : (B1: $00; B2: $18); + ServerSupport : False; + ClientSupport : False; ), ( // DH_anon_EXPORT_WITH_DES40_CBC_SHA - Name : 'DH_anon_EXPORT_WITH_DES40_CBC_SHA'; - KeyExchange : tlscskeDH_anon_EXPORT; - Cipher : tlscscDES40_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $19); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_anon_EXPORT_WITH_DES40_CBC_SHA'; + KeyExchange : tlscskeDH_anon_EXPORT; + Authentication : tlscsaAnon; + Cipher : tlscscDES40_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $19); + ServerSupport : False; + ClientSupport : False; ), ( // DH_anon_WITH_DES_CBC_SHA - Name : 'DH_anon_WITH_DES_CBC_SHA'; - KeyExchange : tlscskeDH_anon; - Cipher : tlscscDES_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $1A); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_anon_WITH_DES_CBC_SHA'; + KeyExchange : tlscskeDH_anon; + Authentication : tlscsaAnon; + Cipher : tlscscDES_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $1A); + ServerSupport : False; + ClientSupport : False; ), ( // DH_anon_WITH_3DES_EDE_CBC_SHA - Name : 'DH_anon_WITH_3DES_EDE_CBC_SHA'; - KeyExchange : tlscskeDH_anon; - Cipher : tlscsc3DES_EDE_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $1B); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_anon_WITH_3DES_EDE_CBC_SHA'; + KeyExchange : tlscskeDH_anon; + Authentication : tlscsaAnon; + Cipher : tlscsc3DES_EDE_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $1B); + ServerSupport : False; + ClientSupport : False; + ), + ( // DH_anon_WITH_AES_128_CBC_SHA256 + Name : 'DH_anon_WITH_AES_128_CBC_SHA256'; + KeyExchange : tlscskeDH_anon; + Authentication : tlscsaAnon; + Cipher : tlscscAES_128_CBC; + Hash : tlscshSHA256; + Rec : (B1: $00; B2: $6C); + ServerSupport : False; + ClientSupport : False; + ), + ( // DH_anon_WITH_AES_256_CBC_SHA256 + Name : 'DH_anon_WITH_AES_256_CBC_SHA256'; + KeyExchange : tlscskeDH_anon; + Authentication : tlscsaAnon; + Cipher : tlscscAES_256_CBC; + Hash : tlscshSHA256; + Rec : (B1: $00; B2: $6D); + ServerSupport : False; + ClientSupport : False; ), ( // DH_DSS_EXPORT_WITH_DES40_CBC_SHA - Name : 'DH_DSS_EXPORT_WITH_DES40_CBC_SHA'; - KeyExchange : tlscskeDH_DSS_EXPORT; - Cipher : tlscscDES40_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $0B); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_DSS_EXPORT_WITH_DES40_CBC_SHA'; + KeyExchange : tlscskeDH_DSS_EXPORT; + Authentication : tlscsaDSS; + Cipher : tlscscDES40_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $0B); + ServerSupport : False; + ClientSupport : False; ), ( // DH_DSS_WITH_DES_CBC_SHA - Name : 'DH_DSS_WITH_DES_CBC_SHA'; - KeyExchange : tlscskeDH_DSS; - Cipher : tlscscDES_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $0C); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_DSS_WITH_DES_CBC_SHA'; + KeyExchange : tlscskeDH_DSS; + Authentication : tlscsaDSS; + Cipher : tlscscDES_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $0C); + ServerSupport : False; + ClientSupport : False; ), ( // DH_DSS_WITH_3DES_EDE_CBC_SHA - Name : 'DH_DSS_WITH_3DES_EDE_CBC_SHA'; - KeyExchange : tlscskeDH_DSS; - Cipher : tlscsc3DES_EDE_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $0D); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_DSS_WITH_3DES_EDE_CBC_SHA'; + KeyExchange : tlscskeDH_DSS; + Authentication : tlscsaDSS; + Cipher : tlscsc3DES_EDE_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $0D); + ServerSupport : False; + ClientSupport : False; ), ( // DH_RSA_EXPORT_WITH_DES40_CBC_SHA - Name : 'DH_RSA_EXPORT_WITH_DES40_CBC_SHA'; - KeyExchange : tlscskeDH_RSA_EXPORT; - Cipher : tlscscDES40_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $0E); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_RSA_EXPORT_WITH_DES40_CBC_SHA'; + KeyExchange : tlscskeDH_RSA_EXPORT; + Authentication : tlscsaAnon; + Cipher : tlscscDES40_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $0E); + ServerSupport : False; + ClientSupport : False; ), ( // DH_RSA_WITH_DES_CBC_SHA - Name : 'DH_RSA_WITH_DES_CBC_SHA'; - KeyExchange : tlscskeDH_RSA; - Cipher : tlscscDES_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $0F); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_RSA_WITH_DES_CBC_SHA'; + KeyExchange : tlscskeDH_RSA; + Authentication : tlscsaRSA; + Cipher : tlscscDES_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $0F); + ServerSupport : False; + ClientSupport : False; ), ( // DH_RSA_WITH_3DES_EDE_CBC_SHA - Name : 'DH_RSA_WITH_3DES_EDE_CBC_SHA'; - KeyExchange : tlscskeDH_RSA; - Cipher : tlscsc3DES_EDE_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $10); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_RSA_WITH_3DES_EDE_CBC_SHA'; + KeyExchange : tlscskeDH_RSA; + Authentication : tlscsaRSA; + Cipher : tlscsc3DES_EDE_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $10); + ServerSupport : False; + ClientSupport : False; ), ( // DH_DSS_WITH_AES_128_CBC_SHA - Name : 'DH_DSS_WITH_AES_128_CBC_SHA'; - KeyExchange : tlscskeDH_DSS; - Cipher : tlscscAES_128_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $30); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_DSS_WITH_AES_128_CBC_SHA'; + KeyExchange : tlscskeDH_DSS; + Authentication : tlscsaDSS; + Cipher : tlscscAES_128_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $30); + ServerSupport : False; + ClientSupport : False; ), ( // DH_DSS_WITH_AES_256_CBC_SHA - Name : 'DH_DSS_WITH_AES_256_CBC_SHA'; - KeyExchange : tlscskeDH_DSS; - Cipher : tlscscAES_256_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $36); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_DSS_WITH_AES_256_CBC_SHA'; + KeyExchange : tlscskeDH_DSS; + Authentication : tlscsaDSS; + Cipher : tlscscAES_256_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $36); + ServerSupport : False; + ClientSupport : False; ), ( // DH_DSS_WITH_AES_128_CBC_SHA256 - Name : 'DH_DSS_WITH_AES_128_CBC_SHA256'; - KeyExchange : tlscskeDH_DSS; - Cipher : tlscscAES_128_CBC; - Hash : tlscshSHA256; - Rec : (B1: $00; B2: $3E); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_DSS_WITH_AES_128_CBC_SHA256'; + KeyExchange : tlscskeDH_DSS; + Authentication : tlscsaDSS; + Cipher : tlscscAES_128_CBC; + Hash : tlscshSHA256; + Rec : (B1: $00; B2: $3E); + ServerSupport : False; + ClientSupport : False; ), ( // DH_DSS_WITH_AES_256_CBC_SHA256 - Name : 'DH_DSS_WITH_AES_256_CBC_SHA256'; - KeyExchange : tlscskeDH_DSS; - Cipher : tlscscAES_256_CBC; - Hash : tlscshSHA256; - Rec : (B1: $00; B2: $68); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_DSS_WITH_AES_256_CBC_SHA256'; + KeyExchange : tlscskeDH_DSS; + Authentication : tlscsaDSS; + Cipher : tlscscAES_256_CBC; + Hash : tlscshSHA256; + Rec : (B1: $00; B2: $68); + ServerSupport : False; + ClientSupport : False; ), ( // DH_RSA_WITH_AES_128_CBC_SHA - Name : 'DH_RSA_WITH_AES_128_CBC_SHA'; - KeyExchange : tlscskeDH_RSA; - Cipher : tlscscAES_128_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $31); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_RSA_WITH_AES_128_CBC_SHA'; + KeyExchange : tlscskeDH_RSA; + Authentication : tlscsaRSA; + Cipher : tlscscAES_128_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $31); + ServerSupport : False; + ClientSupport : False; ), ( // DH_RSA_WITH_AES_256_CBC_SHA - Name : 'DH_RSA_WITH_AES_256_CBC_SHA'; - KeyExchange : tlscskeDH_RSA; - Cipher : tlscscAES_256_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $37); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_RSA_WITH_AES_256_CBC_SHA'; + KeyExchange : tlscskeDH_RSA; + Authentication : tlscsaRSA; + Cipher : tlscscAES_256_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $37); + ServerSupport : False; + ClientSupport : False; ), ( // DH_RSA_WITH_AES_128_CBC_SHA256 - Name : 'DH_RSA_WITH_AES_128_CBC_SHA256'; - KeyExchange : tlscskeDH_RSA; - Cipher : tlscscAES_128_CBC; - Hash : tlscshSHA256; - Rec : (B1: $00; B2: $3F); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_RSA_WITH_AES_128_CBC_SHA256'; + KeyExchange : tlscskeDH_RSA; + Authentication : tlscsaRSA; + Cipher : tlscscAES_128_CBC; + Hash : tlscshSHA256; + Rec : (B1: $00; B2: $3F); + ServerSupport : False; + ClientSupport : False; ), ( // DH_RSA_WITH_AES_256_CBC_SHA256 - Name : 'DH_RSA_WITH_AES_256_CBC_SHA256'; - KeyExchange : tlscskeDH_RSA; - Cipher : tlscscAES_256_CBC; - Hash : tlscshSHA256; - Rec : (B1: $00; B2: $69); - ServerSupport : False; - ClientSupport : False; + Name : 'DH_RSA_WITH_AES_256_CBC_SHA256'; + KeyExchange : tlscskeDH_RSA; + Authentication : tlscsaRSA; + Cipher : tlscscAES_256_CBC; + Hash : tlscshSHA256; + Rec : (B1: $00; B2: $69); + ServerSupport : False; + ClientSupport : False; ), ( // RSA_EXPORT_WITH_RC4_40_MD5 - Name : 'RSA_EXPORT_WITH_RC4_40_MD5'; - KeyExchange : tlscskeRSA_EXPORT; - Cipher : tlscscRC4_40; - Hash : tlscshMD5; - Rec : (B1: $00; B2: $03); - ServerSupport : False; - ClientSupport : False; - MinVersion : (major: 3; minor: 0); // SSL 3 + Name : 'RSA_EXPORT_WITH_RC4_40_MD5'; + KeyExchange : tlscskeRSA_EXPORT; + Authentication : tlscsaAnon; + Cipher : tlscscRC4_40; + Hash : tlscshMD5; + Rec : (B1: $00; B2: $03); + ServerSupport : False; + ClientSupport : False; + MinVersion : (major: 3; minor: 0); // SSL 3 ), ( // RSA_WITH_RC4_128_MD5 - Name : 'RSA_WITH_RC4_128_MD5'; - KeyExchange : tlscskeRSA; - Cipher : tlscscRC4_128; - Hash : tlscshMD5; - Rec : (B1: $00; B2: $04); - ServerSupport : True; - ClientSupport : True; - MinVersion : (major: 3; minor: 0); // SSL 3 + Name : 'RSA_WITH_RC4_128_MD5'; + KeyExchange : tlscskeRSA; + Authentication : tlscsaAnon; + Cipher : tlscscRC4_128; + Hash : tlscshMD5; + Rec : (B1: $00; B2: $04); + ServerSupport : True; + ClientSupport : True; + MinVersion : (major: 3; minor: 0); // SSL 3 ), ( // RSA_WITH_RC4_128_SHA - Name : 'RSA_WITH_RC4_128_SHA'; - KeyExchange : tlscskeRSA; - Cipher : tlscscRC4_128; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $05); - ServerSupport : True; - ClientSupport : True; - MinVersion : (major: 3; minor: 0); // SSL 3 + Name : 'RSA_WITH_RC4_128_SHA'; + KeyExchange : tlscskeRSA; + Authentication : tlscsaAnon; + Cipher : tlscscRC4_128; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $05); + ServerSupport : True; + ClientSupport : True; + MinVersion : (major: 3; minor: 0); // SSL 3 ), ( // RSA_EXPORT_WITH_RC2_CBC_40_MD5 - Name : 'RSA_EXPORT_WITH_RC2_CBC_40_MD5'; - KeyExchange : tlscskeRSA_EXPORT; - Cipher : tlscscRC2_CBC_40; - Hash : tlscshMD5; - Rec : (B1: $00; B2: $06); - ServerSupport : False; - ClientSupport : False; - MinVersion : (major: 3; minor: 0); // SSL 3 + Name : 'RSA_EXPORT_WITH_RC2_CBC_40_MD5'; + KeyExchange : tlscskeRSA_EXPORT; + Authentication : tlscsaAnon; + Cipher : tlscscRC2_CBC_40; + Hash : tlscshMD5; + Rec : (B1: $00; B2: $06); + ServerSupport : False; + ClientSupport : False; + MinVersion : (major: 3; minor: 0); // SSL 3 ), ( // RSA_WITH_IDEA_CBC_SHA - Name : 'RSA_WITH_IDEA_CBC_SHA'; - KeyExchange : tlscskeRSA; - Cipher : tlscscIDEA_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $07); - ServerSupport : False; - ClientSupport : False; + Name : 'RSA_WITH_IDEA_CBC_SHA'; + KeyExchange : tlscskeRSA; + Authentication : tlscsaAnon; + Cipher : tlscscIDEA_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $07); + ServerSupport : False; + ClientSupport : False; ), ( // RSA_EXPORT_WITH_DES40_CBC_SHA - Name : 'RSA_EXPORT_WITH_DES40_CBC_SHA'; - KeyExchange : tlscskeRSA_EXPORT; - Cipher : tlscscDES40_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $08); - ServerSupport : False; - ClientSupport : False; + Name : 'RSA_EXPORT_WITH_DES40_CBC_SHA'; + KeyExchange : tlscskeRSA_EXPORT; + Authentication : tlscsaAnon; + Cipher : tlscscDES40_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $08); + ServerSupport : False; + ClientSupport : False; ), ( // RSA_WITH_DES_CBC_SHA - Name : 'RSA_WITH_DES_CBC_SHA'; - KeyExchange : tlscskeRSA; - Cipher : tlscscDES_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $09); - ServerSupport : True; - ClientSupport : True; - MinVersion : (major: 3; minor: 0); // SSL 3 + Name : 'RSA_WITH_DES_CBC_SHA'; + KeyExchange : tlscskeRSA; + Authentication : tlscsaAnon; + Cipher : tlscscDES_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $09); + ServerSupport : True; + ClientSupport : True; + MinVersion : (major: 3; minor: 0); // SSL 3 ), ( // RSA_WITH_3DES_EDE_CBC_SHA - Name : 'RSA_WITH_3DES_EDE_CBC_SHA'; - KeyExchange : tlscskeRSA; - Cipher : tlscsc3DES_EDE_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $0A); - ServerSupport : False; - ClientSupport : False; - MinVersion : (major: 3; minor: 0); // SSL 3 + Name : 'RSA_WITH_3DES_EDE_CBC_SHA'; + KeyExchange : tlscskeRSA; + Authentication : tlscsaAnon; + Cipher : tlscsc3DES_EDE_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $0A); + ServerSupport : False; + ClientSupport : False; + MinVersion : (major: 3; minor: 0); // SSL 3 ), ( // RSA_EXPORT1024_WITH_DES_CBC_SHA - Name : 'RSA_EXPORT1024_WITH_DES_CBC_SHA'; - KeyExchange : tlscskeRSA_EXPORT1024; - Cipher : tlscscDES_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $62); - ServerSupport : False; - ClientSupport : False; - MinVersion : (major: 3; minor: 0); // SSL 3 + Name : 'RSA_EXPORT1024_WITH_DES_CBC_SHA'; + KeyExchange : tlscskeRSA_EXPORT1024; + Authentication : tlscsaAnon; + Cipher : tlscscDES_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $62); + ServerSupport : False; + ClientSupport : False; + MinVersion : (major: 3; minor: 0); // SSL 3 ), ( // RSA_EXPORT1024_WITH_RC4_56_SHA - Name : 'RSA_EXPORT1024_WITH_RC4_56_SHA'; - KeyExchange : tlscskeRSA_EXPORT1024; - Cipher : tlscscRC4_56; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $64); - ServerSupport : False; - ClientSupport : False; - MinVersion : (major: 3; minor: 0); // SSL 3 + Name : 'RSA_EXPORT1024_WITH_RC4_56_SHA'; + KeyExchange : tlscskeRSA_EXPORT1024; + Authentication : tlscsaAnon; + Cipher : tlscscRC4_56; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $64); + ServerSupport : False; + ClientSupport : False; + MinVersion : (major: 3; minor: 0); // SSL 3 ), ( // RSA_WITH_NULL_SHA256 - Name : 'RSA_WITH_NULL_SHA256'; - KeyExchange : tlscskeRSA; - Cipher : tlscscNULL; - Hash : tlscshSHA256; - Rec : (B1: $00; B2: $3B); - ServerSupport : False; - ClientSupport : False; + Name : 'RSA_WITH_NULL_SHA256'; + KeyExchange : tlscskeRSA; + Authentication : tlscsaAnon; + Cipher : tlscscNULL; + Hash : tlscshSHA256; + Rec : (B1: $00; B2: $3B); + ServerSupport : False; + ClientSupport : False; ), ( // RSA_WITH_AES_128_CBC_SHA - Name : 'RSA_WITH_AES_128_CBC_SHA'; - KeyExchange : tlscskeRSA; - Cipher : tlscscAES_128_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $2F); - ServerSupport : True; - ClientSupport : True; + Name : 'RSA_WITH_AES_128_CBC_SHA'; + KeyExchange : tlscskeRSA; + Authentication : tlscsaAnon; + Cipher : tlscscAES_128_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $2F); + ServerSupport : True; + ClientSupport : True; ), ( // RSA_WITH_AES_256_CBC_SHA - Name : 'RSA_WITH_AES_256_CBC_SHA'; - KeyExchange : tlscskeRSA; - Cipher : tlscscAES_256_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $35); - ServerSupport : True; - ClientSupport : True; + Name : 'RSA_WITH_AES_256_CBC_SHA'; + KeyExchange : tlscskeRSA; + Authentication : tlscsaAnon; + Cipher : tlscscAES_256_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $35); + ServerSupport : True; + ClientSupport : True; ), ( // RSA_WITH_AES_128_CBC_SHA256 - Name : 'RSA_WITH_AES_128_CBC_SHA256'; - KeyExchange : tlscskeRSA; - Cipher : tlscscAES_128_CBC; - Hash : tlscshSHA256; - Rec : (B1: $00; B2: $3C); - ServerSupport : True; - ClientSupport : True; - MinVersion : (major: 3; minor: 3); // TLS 1.2 + Name : 'RSA_WITH_AES_128_CBC_SHA256'; + KeyExchange : tlscskeRSA; + Authentication : tlscsaAnon; + Cipher : tlscscAES_128_CBC; + Hash : tlscshSHA256; + Rec : (B1: $00; B2: $3C); + ServerSupport : True; + ClientSupport : True; + MinVersion : (major: 3; minor: 3); // TLS 1.2 ), ( // RSA_WITH_AES_256_CBC_SHA256 - Name : 'RSA_WITH_AES_256_CBC_SHA256'; - KeyExchange : tlscskeRSA; - Cipher : tlscscAES_256_CBC; - Hash : tlscshSHA256; - Rec : (B1: $00; B2: $3D); - ServerSupport : True; - ClientSupport : True; - MinVersion : (major: 3; minor: 3); // TLS 1.2 + Name : 'RSA_WITH_AES_256_CBC_SHA256'; + KeyExchange : tlscskeRSA; + Authentication : tlscsaAnon; + Cipher : tlscscAES_256_CBC; + Hash : tlscshSHA256; + Rec : (B1: $00; B2: $3D); + ServerSupport : True; + ClientSupport : True; + MinVersion : (major: 3; minor: 3); // TLS 1.2 ), ( // DHE_DSS_EXPORT_WITH_DES40_CBC_SHA - Name : 'DHE_DSS_EXPORT_WITH_DES40_CBC_SHA'; - KeyExchange : tlscskeDHE_DSS_EXPORT; - Cipher : tlscscDES40_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $11); - ServerSupport : False; - ClientSupport : False; + Name : 'DHE_DSS_EXPORT_WITH_DES40_CBC_SHA'; + KeyExchange : tlscskeDHE_DSS_EXPORT; + Authentication : tlscsaDSS; + Cipher : tlscscDES40_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $11); + ServerSupport : False; + ClientSupport : False; ), ( // DHE_DSS_WITH_DES_CBC_SHA - Name : 'DHE_DSS_WITH_DES_CBC_SHA'; - KeyExchange : tlscskeDHE_DSS; - Cipher : tlscscDES_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $12); - ServerSupport : False; - ClientSupport : False; + Name : 'DHE_DSS_WITH_DES_CBC_SHA'; + KeyExchange : tlscskeDHE_DSS; + Authentication : tlscsaDSS; + Cipher : tlscscDES_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $12); + ServerSupport : False; + ClientSupport : False; ), ( // DHE_DSS_WITH_3DES_EDE_CBC_SHA - Name : 'DHE_DSS_WITH_3DES_EDE_CBC_SHA'; - KeyExchange : tlscskeDHE_DSS; - Cipher : tlscsc3DES_EDE_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $13); - ServerSupport : False; - ClientSupport : False; + Name : 'DHE_DSS_WITH_3DES_EDE_CBC_SHA'; + KeyExchange : tlscskeDHE_DSS; + Authentication : tlscsaDSS; + Cipher : tlscsc3DES_EDE_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $13); + ServerSupport : False; + ClientSupport : False; ), ( // DHE_DSS_WITH_RC4_128_SHA - Name : 'DHE_DSS_WITH_RC4_128_SHA'; - KeyExchange : tlscskeDHE_DSS; - Cipher : tlscscRC4_128; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $66); - ServerSupport : False; - ClientSupport : False; + Name : 'DHE_DSS_WITH_RC4_128_SHA'; + KeyExchange : tlscskeDHE_DSS; + Authentication : tlscsaDSS; + Cipher : tlscscRC4_128; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $66); + ServerSupport : False; + ClientSupport : False; ), ( // DHE_RSA_EXPORT_WITH_DES40_CBC_SHA - Name : 'DHE_RSA_EXPORT_WITH_DES40_CBC_SHA'; - KeyExchange : tlscskeDHE_RSA_EXPORT; - Cipher : tlscscDES40_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $14); - ServerSupport : False; - ClientSupport : False; + Name : 'DHE_RSA_EXPORT_WITH_DES40_CBC_SHA'; + KeyExchange : tlscskeDHE_RSA_EXPORT; + Authentication : tlscsaRSA; + Cipher : tlscscDES40_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $14); + ServerSupport : False; + ClientSupport : False; ), ( // DHE_RSA_WITH_DES_CBC_SHA - Name : 'DHE_RSA_WITH_DES_CBC_SHA'; - KeyExchange : tlscskeDHE_RSA; - Cipher : tlscscDES_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $15); - ServerSupport : False; - ClientSupport : False; + Name : 'DHE_RSA_WITH_DES_CBC_SHA'; + KeyExchange : tlscskeDHE_RSA; + Authentication : tlscsaRSA; + Cipher : tlscscDES_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $15); + ServerSupport : True; + ClientSupport : True; ), ( // DHE_RSA_WITH_3DES_EDE_CBC_SHA - Name : 'DHE_RSA_WITH_3DES_EDE_CBC_SHA'; - KeyExchange : tlscskeDHE_RSA; - Cipher : tlscsc3DES_EDE_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $16); - ServerSupport : False; - ClientSupport : False; + Name : 'DHE_RSA_WITH_3DES_EDE_CBC_SHA'; + KeyExchange : tlscskeDHE_RSA; + Authentication : tlscsaRSA; + Cipher : tlscsc3DES_EDE_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $16); + ServerSupport : False; + ClientSupport : False; ), ( // DHE_DSS_WITH_AES_128_CBC_SHA - Name : 'DHE_DSS_WITH_AES_128_CBC_SHA '; - KeyExchange : tlscskeDHE_DSS; - Cipher : tlscscAES_128_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $32); - ServerSupport : False; - ClientSupport : False; + Name : 'DHE_DSS_WITH_AES_128_CBC_SHA '; + KeyExchange : tlscskeDHE_DSS; + Authentication : tlscsaDSS; + Cipher : tlscscAES_128_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $32); + ServerSupport : False; + ClientSupport : False; ), ( // DHE_DSS_WITH_AES_256_CBC_SHA - Name : 'DHE_DSS_WITH_AES_256_CBC_SHA'; - KeyExchange : tlscskeDHE_DSS; - Cipher : tlscscAES_256_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $38); - ServerSupport : False; - ClientSupport : False; + Name : 'DHE_DSS_WITH_AES_256_CBC_SHA'; + KeyExchange : tlscskeDHE_DSS; + Authentication : tlscsaDSS; + Cipher : tlscscAES_256_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $38); + ServerSupport : False; + ClientSupport : False; ), ( // DHE_DSS_WITH_AES_128_CBC_SHA256 - Name : 'DHE_DSS_WITH_AES_128_CBC_SHA256'; - KeyExchange : tlscskeDHE_DSS; - Cipher : tlscscAES_128_CBC; - Hash : tlscshSHA256; - Rec : (B1: $00; B2: $40); - ServerSupport : False; - ClientSupport : False; + Name : 'DHE_DSS_WITH_AES_128_CBC_SHA256'; + KeyExchange : tlscskeDHE_DSS; + Authentication : tlscsaDSS; + Cipher : tlscscAES_128_CBC; + Hash : tlscshSHA256; + Rec : (B1: $00; B2: $40); + ServerSupport : False; + ClientSupport : False; ), ( // DHE_DSS_WITH_AES_256_CBC_SHA256 - Name : 'DHE_DSS_WITH_AES_256_CBC_SHA256'; - KeyExchange : tlscskeDHE_DSS; - Cipher : tlscscAES_256_CBC; - Hash : tlscshSHA256; - Rec : (B1: $00; B2: $6A); - ServerSupport : False; - ClientSupport : False; + Name : 'DHE_DSS_WITH_AES_256_CBC_SHA256'; + KeyExchange : tlscskeDHE_DSS; + Authentication : tlscsaDSS; + Cipher : tlscscAES_256_CBC; + Hash : tlscshSHA256; + Rec : (B1: $00; B2: $6A); + ServerSupport : False; + ClientSupport : False; ), ( // DHE_RSA_WITH_AES_128_CBC_SHA - Name : 'DHE_RSA_WITH_AES_128_CBC_SHA'; - KeyExchange : tlscskeDHE_RSA; - Cipher : tlscscAES_128_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $33); - ServerSupport : False; - ClientSupport : False; + Name : 'DHE_RSA_WITH_AES_128_CBC_SHA'; + KeyExchange : tlscskeDHE_RSA; + Authentication : tlscsaRSA; + Cipher : tlscscAES_128_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $33); + ServerSupport : True; + ClientSupport : True; ), ( // DHE_RSA_WITH_AES_256_CBC_SHA - Name : 'DHE_RSA_WITH_AES_256_CBC_SHA'; - KeyExchange : tlscskeDHE_RSA; - Cipher : tlscscAES_256_CBC; - Hash : tlscshSHA; - Rec : (B1: $00; B2: $39); - ServerSupport : False; - ClientSupport : False; + Name : 'DHE_RSA_WITH_AES_256_CBC_SHA'; + KeyExchange : tlscskeDHE_RSA; + Authentication : tlscsaRSA; + Cipher : tlscscAES_256_CBC; + Hash : tlscshSHA; + Rec : (B1: $00; B2: $39); + ServerSupport : True; + ClientSupport : True; ), ( // DHE_RSA_WITH_AES_128_CBC_SHA256 - Name : 'DHE_RSA_WITH_AES_128_CBC_SHA256'; - KeyExchange : tlscskeDHE_RSA; - Cipher : tlscscAES_128_CBC; - Hash : tlscshSHA256; - Rec : (B1: $00; B2: $67); - ServerSupport : False; - ClientSupport : False; + Name : 'DHE_RSA_WITH_AES_128_CBC_SHA256'; + KeyExchange : tlscskeDHE_RSA; + Authentication : tlscsaRSA; + Cipher : tlscscAES_128_CBC; + Hash : tlscshSHA256; + Rec : (B1: $00; B2: $67); + ServerSupport : True; + ClientSupport : True; ), ( // DHE_RSA_WITH_AES_256_CBC_SHA256 - Name : 'DHE_RSA_WITH_AES_256_CBC_SHA256'; - KeyExchange : tlscskeDHE_RSA; - Cipher : tlscscAES_256_CBC; - Hash : tlscshSHA256; - Rec : (B1: $00; B2: $6B); - ServerSupport : False; - ClientSupport : False; + Name : 'DHE_RSA_WITH_AES_256_CBC_SHA256'; + KeyExchange : tlscskeDHE_RSA; + Authentication : tlscsaRSA; + Cipher : tlscscAES_256_CBC; + Hash : tlscshSHA256; + Rec : (B1: $00; B2: $6B); + ServerSupport : True; + ClientSupport : True; + ), + ( // ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + Name : 'ECDHE_ECDSA_WITH_AES_128_CBC_SHA256'; + KeyExchange : tlscskeECDHE_ECDSA; + Authentication : tlscsaECDSA; + Cipher : tlscscAES_128_CBC; + Hash : tlscshSHA256; + Rec : (B1: $C0; B2: $23); + ServerSupport : False; + ClientSupport : False; + ), + ( // ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + Name : 'ECDHE_ECDSA_WITH_AES_256_CBC_SHA384'; + KeyExchange : tlscskeECDHE_ECDSA; + Authentication : tlscsaECDSA; + Cipher : tlscscAES_256_CBC; + Hash : tlscshSHA384; + Rec : (B1: $C0; B2: $24); + ServerSupport : False; + ClientSupport : False; + ), + ( // ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + Name : 'ECDH_ECDSA_WITH_AES_128_CBC_SHA256'; + KeyExchange : tlscskeECDH_ECDSA; + Authentication : tlscsaECDSA; + Cipher : tlscscAES_128_CBC; + Hash : tlscshSHA256; + Rec : (B1: $C0; B2: $25); + ServerSupport : False; + ClientSupport : False; + ), + ( // ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + Name : 'ECDH_ECDSA_WITH_AES_256_CBC_SHA384'; + KeyExchange : tlscskeECDH_ECDSA; + Authentication : tlscsaECDSA; + Cipher : tlscscAES_256_CBC; + Hash : tlscshSHA384; + Rec : (B1: $C0; B2: $26); + ServerSupport : False; + ClientSupport : False; + ), + ( // ECDHE_RSA_WITH_AES_128_CBC_SHA256 + Name : 'ECDHE_RSA_WITH_AES_128_CBC_SHA256'; + KeyExchange : tlscskeECDHE_RSA; + Authentication : tlscsaRSA; + Cipher : tlscscAES_128_CBC; + Hash : tlscshSHA256; + Rec : (B1: $C0; B2: $27); + ServerSupport : False; + ClientSupport : False; + ), + ( // ECDHE_RSA_WITH_AES_256_CBC_SHA384 + Name : 'ECDHE_RSA_WITH_AES_256_CBC_SHA384'; + KeyExchange : tlscskeECDHE_RSA; + Authentication : tlscsaRSA; + Cipher : tlscscAES_256_CBC; + Hash : tlscshSHA384; + Rec : (B1: $C0; B2: $28); + ServerSupport : False; + ClientSupport : False; + ), + ( // ECDH_RSA_WITH_AES_128_CBC_SHA256 + Name : 'ECDH_RSA_WITH_AES_128_CBC_SHA256'; + KeyExchange : tlscskeECDH_RSA; + Authentication : tlscsaRSA; + Cipher : tlscscAES_128_CBC; + Hash : tlscshSHA256; + Rec : (B1: $C0; B2: $29); + ServerSupport : False; + ClientSupport : False; + ), + ( // ECDH_RSA_WITH_AES_256_CBC_SHA384 + Name : 'ECDH_RSA_WITH_AES_256_CBC_SHA384'; + KeyExchange : tlscskeECDH_RSA; + Authentication : tlscsaRSA; + Cipher : tlscscAES_256_CBC; + Hash : tlscshSHA384; + Rec : (B1: $C0; B2: $2A); + ServerSupport : False; + ClientSupport : False; ) ); @@ -682,7 +867,6 @@ TTLSCipherSuiteKeyExchangeInfo = record Name : RawByteString; Algorithm : TTLSKeyExchangeAlgorithm; Exportable : Boolean; - Supported : Boolean; // Not used end; PTLSCipherSuiteKeyExchangeInfo = ^TTLSCipherSuiteKeyExchangeInfo; @@ -692,92 +876,98 @@ TTLSCipherSuiteKeyExchangeInfo = record Name : ''; Algorithm : tlskeaNone; Exportable : True; - Supported : False; ), ( // NULL Name : 'NULL'; Algorithm : tlskeaNULL; Exportable : True; - Supported : False; ), ( // RSA Name : 'RSA'; Algorithm : tlskeaRSA; Exportable : False; - Supported : True; ), ( // RSA_EXPORT Name : 'RSA_EXPORT'; Algorithm : tlskeaRSA; Exportable : True; - Supported : False; ), ( // RSA_EXPORT1024 Name : 'RSA_EXPORT1024'; Algorithm : tlskeaRSA; Exportable : True; - Supported : False; ), ( // DH_DSS_EXPORT Name : 'DH_DSS_EXPORT'; Algorithm : tlskeaDH_DSS; Exportable : True; - Supported : False; ), ( // DH_DSS Name : 'DH_DSS'; Algorithm : tlskeaDH_DSS; Exportable : False; - Supported : False; ), ( // DH_RSA_EXPORT Name : 'DH_RSA_EXPORT'; Algorithm : tlskeaDH_RSA; Exportable : True; - Supported : False; ), ( // DH_RSA Name : 'DH_RSA'; Algorithm : tlskeaDH_RSA; Exportable : False; - Supported : False; ), ( // DHE_DSS_EXPORT Name : 'DHE_DSS_EXPORT'; Algorithm : tlskeaDHE_DSS; Exportable : True; - Supported : False; ), ( // DHE_DSS Name : 'DHE_DSS'; Algorithm : tlskeaDHE_DSS; Exportable : False; - Supported : False; ), ( // DHE_RSA_EXPORT Name : 'DHE_RSA_EXPORT'; Algorithm : tlskeaDHE_RSA; Exportable : True; - Supported : False; ), ( // DHE_RSA Name : 'DHE_RSA'; Algorithm : tlskeaDHE_RSA; Exportable : False; - Supported : False; ), ( // DH_anon_EXPORT Name : 'DH_anon_EXPORT'; Algorithm : tlskeaDH_Anon; Exportable : True; - Supported : False; ), ( // DH_anon Name : 'DH_anon'; Algorithm : tlskeaDH_Anon; Exportable : False; - Supported : False; - )); + ), + ( // ECDHE_ECDSA + Name : 'ECDHE_ECDSA'; + Algorithm : tlskeaECDHE_ECDSA; + Exportable : False; + ), + ( // ECDH_ECDSA + Name : 'ECDH_ECDSA'; + Algorithm : tlskeaECDH_ECDSA; + Exportable : False; + ), + ( // ECDHE_RSA + Name : 'ECDHE_RSA'; + Algorithm : tlskeaECDHE_RSA; + Exportable : False; + ), + ( // ECDH_RSA + Name : 'ECDH_RSA'; + Algorithm : tlskeaECDH_RSA; + Exportable : False; + ) + ); @@ -789,7 +979,8 @@ TTLSCipherSuiteKeyExchangeInfo = record tlscsctNone, tlscsctNULL, tlscsctStream, - tlscsctBlock); + tlscsctBlock + ); TTLSCipherSuiteBulkCipher = ( tlscsbcNone, @@ -801,7 +992,7 @@ TTLSCipherSuiteKeyExchangeInfo = record tlscsbcIDEA, tlscsbcDES40, tlscsbcAES - ); + ); TTLSCipherSuiteCipherInfo = record Name : RawByteString; @@ -1013,6 +1204,13 @@ TTLSCipherSuiteHashInfo = record MACAlgorithm : tlsmaHMAC_SHA256; Supported : True; ), + ( // SHA384 + Name : 'SHA384'; + HashSize : 384; + KeyLength : 384; + MACAlgorithm : tlsmaHMAC_SHA384; + Supported : True; + ), ( // MD5 Name : 'MD5'; HashSize : 128; diff --git a/Source/TLS/flcTLSCompress.pas b/Source/TLS/flcTLSCompress.pas index 5436395..d017f19 100644 --- a/Source/TLS/flcTLSCompress.pas +++ b/Source/TLS/flcTLSCompress.pas @@ -5,7 +5,7 @@ { File version: 5.03 } { Description: TLS compression } { } -{ Copyright: Copyright (c) 2008-2018, David J Butler } +{ 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 } @@ -34,7 +34,7 @@ { } { Revision history: } { } -{ 2008/01/18 0.01 Initial version. } +{ 2008/01/18 0.01 Initial development. } { 2010/11/30 0.02 Revision. } { 2018/07/17 5.03 Revised for Fundamentals 5. } { } @@ -54,7 +54,10 @@ interface uses { TLS } - flcTLSUtils; + + flcTLSConsts, + flcTLSErrors, + flcTLSAlgorithmTypes; @@ -79,7 +82,7 @@ implementation {$IFDEF TLS_COMPRESS_ZLIB} uses - { Fundamentals } + { Utils } flcZLib; {$ENDIF} diff --git a/Source/TLS/flcTLSConsts.pas b/Source/TLS/flcTLSConsts.pas new file mode 100644 index 0000000..7fa8550 --- /dev/null +++ b/Source/TLS/flcTLSConsts.pas @@ -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. diff --git a/Source/TLS/flcTLSErrors.pas b/Source/TLS/flcTLSErrors.pas new file mode 100644 index 0000000..be2fca4 --- /dev/null +++ b/Source/TLS/flcTLSErrors.pas @@ -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. + diff --git a/Source/TLS/flcTLSHandshake.pas b/Source/TLS/flcTLSHandshake.pas index b917298..9ca2b80 100644 --- a/Source/TLS/flcTLSHandshake.pas +++ b/Source/TLS/flcTLSHandshake.pas @@ -5,7 +5,7 @@ { File version: 5.04 } { Description: TLS handshake protocol } { } -{ Copyright: Copyright (c) 2008-2018, David J Butler } +{ 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 } @@ -48,12 +48,24 @@ interface uses - { Fundamentals } + { Utils } + flcStdTypes, + + { Cipher } + flcCipherRSA, + { TLS } - flcTLSUtils, - flcTLSCipherSuite; + + flcTLSProtocolVersion, + flcTLSAlgorithmTypes, + flcTLSRandom, + flcTLSCipherSuite, + flcTLSSessionID, + flcTLSKeyExchangeParams, + flcTLSCertificate, + flcTLSHandshakeExtension; @@ -62,19 +74,24 @@ interface { } type TTLSHandshakeType = ( - tlshtHello_request = 0, - tlshtClient_hello = 1, - tlshtServer_hello = 2, - tlshtCertificate = 11, - tlshtServer_key_exchange = 12, - tlshtCertificate_request = 13, - tlshtServer_hello_done = 14, - tlshtCertificate_verify = 15, - tlshtClient_key_exchange = 16, - tlshtFinished = 20, - tlshtCertificate_url = 21, // RFC 6066 - tlshtCertificate_status = 22, // RFC 6066 - tlshtMax = 255 + tlshtHello_request = 0, // Not used in TLS 1.3 + tlshtClient_hello = 1, + tlshtServer_hello = 2, + tlshtNew_session_ticket = 4, // TLS 1.3 + tlshtEnd_of_early_data = 5, // TLS 1.3 + tlshtEncrypted_extensions = 8, // TLS 1.3 + tlshtCertificate = 11, + tlshtServer_key_exchange = 12, // Not used in TLS 1.3 + tlshtCertificate_request = 13, + tlshtServer_hello_done = 14, // Not used in TLS 1.3 + tlshtCertificate_verify = 15, + tlshtClient_key_exchange = 16, // Not used in TLS 1.3 + tlshtFinished = 20, + tlshtCertificate_url = 21, // RFC 6066 // Not used in TLS 1.3 + tlshtCertificate_status = 22, // RFC 6066 // Not used in TLS 1.3 + tlshtKey_update = 24, // TLS 1.3 + tlshtMessage_hash = 254, // TLS 1.3 + tlshtMax = 255 ); TTLSHandshakeHeader = packed record @@ -124,22 +141,25 @@ TTLSClientHello = record CompressionMethods : TTLSCompressionMethods; Random : TTLSRandom; ExtensionsPresent : Boolean; + SignAndHashAlgos : TTLSSignatureAndHashAlgorithmArray; end; procedure InitTLSClientHello( var ClientHello: TTLSClientHello; const ProtocolVersion: TTLSProtocolVersion; const SessionID: RawByteString); + function EncodeTLSClientHello( var Buffer; const Size: Integer; - const ClientHello: TTLSClientHello): Integer; + var ClientHello: TTLSClientHello): Integer; + function DecodeTLSClientHello( const Buffer; const Size: Integer; var ClientHello: TTLSClientHello): Integer; function EncodeTLSHandshakeClientHello( var Buffer; const Size: Integer; - const ClientHello: TTLSClientHello): Integer; + var ClientHello: TTLSClientHello): Integer; @@ -161,9 +181,11 @@ procedure InitTLSServerHello( const SessionID: RawByteString; const CipherSuite: TTLSCipherSuiteRec; const CompressionMethod: TTLSCompressionMethod); + function EncodeTLSServerHello( var Buffer; const Size: Integer; const ServerHello: TTLSServerHello): Integer; + function DecodeTLSServerHello( const Buffer; const Size: Integer; var ServerHello: TTLSServerHello): Integer; @@ -177,88 +199,15 @@ function EncodeTLSHandshakeServerHello( { } { 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; - function EncodeTLSHandshakeCertificate( var Buffer; const Size: Integer; const CertificateList: TTLSCertificateList): Integer; -{ } -{ ServerDHParams } -{ } -type - TTLSServerDHParams = record - dh_p : RawByteString; - dh_g : RawByteString; - dh_Ys : RawByteString; - end; - -procedure InitTLSServerDHParams_None(var ServerDHParams: TTLSServerDHParams); -procedure InitTLSServerDHParams(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; - - - -{ } -{ SignedParams } -{ } -type - TTLSSignedParams = record - client_random : array[0..31] of Byte; - server_random : array[0..31] of Byte; - params : TTLSServerDHParams; - end; - -procedure InitTLSSignedParams(var SignedParams: TTLSSignedParams); - -function EncodeTLSSignedParams( - var Buffer; const Size: Integer; - const SignedParams: TTLSSignedParams): Integer; -function DecodeTLSSignedParams( - const Buffer; const Size: Integer; - var SignedParams: TTLSSignedParams): Integer; - - - { } { ServerKeyExchange } { } -type - TTLSServerKeyExchange = record - Params : TTLSServerDHParams; - SignedParams : TTLSSignedParams; - end; - -procedure InitTLSServerKeyExchange(var ServerKeyExchange: TTLSServerKeyExchange); - -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; - function EncodeTLSHandshakeServerKeyExchange( var Buffer; const Size: Integer; const KeyExchangeAlgorithm: TTLSKeyExchangeAlgorithm; @@ -270,16 +219,6 @@ function EncodeTLSHandshakeServerKeyExchange( { CertificateRequest } { } 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, - tlscctMax = 255 - ); TTLSClientCertificateTypeArray = array of TTLSClientCertificateType; TTLSCertificateRequest = record @@ -291,6 +230,7 @@ TTLSCertificateRequest = record function EncodeTLSCertificateRequest( var Buffer; const Size: Integer; const CertificateRequest: TTLSCertificateRequest): Integer; + function DecodeTLSCertificateRequest( const Buffer; const Size: Integer; var CertificateRequest: TTLSCertificateRequest): Integer; @@ -340,51 +280,14 @@ procedure InitTLSEncryptedPreMasterSecret_RSA( - -{ } -{ 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 EncodeTLSHandshakeClientKeyExchange( 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; - { } @@ -410,14 +313,14 @@ function EncodeTLSHandshakeFinished(var Buffer; const Size: Integer; PTLSChangeCipherSpec = ^TTLSChangeCipherSpec; const - TLSChangeCipherSpecSize = Sizeof(TTLSChangeCipherSpec); + TLSChangeCipherSpecSize = SizeOf(TTLSChangeCipherSpec); procedure InitTLSChangeCipherSpec(var ChangeCipherSpec: TTLSChangeCipherSpec); { } -{ Unit test } +{ Test } { } {$IFDEF TLS_TEST} procedure Test; @@ -429,144 +332,24 @@ implementation uses { System } - SysUtils, - { Fundamentals } - flcStrings, - flcHash, - flcCipherRandom; - - - -{ } -{ Helper functions } -{ } -function EncodeTLSLen16(var Buffer; const Size: Integer; const Len: Integer): Integer; -var P : PByte; -begin - Assert(Len >= 0); - Assert(Len <= $FFFF); - if Size < 2 then - raise ETLSError.Create(TLSError_InvalidBuffer); - P := @Buffer; - P^ := (Len and $FF00) shr 8; - Inc(P); - P^ := (Len and $00FF); - Result := 2; -end; -function EncodeTLSLen24(var Buffer; const Size: Integer; const Len: Integer): Integer; -var P : PByte; -begin - Assert(Len >= 0); - Assert(Len <= $FFFFFF); - if Size < 3 then - raise ETLSError.Create(TLSError_InvalidBuffer); - P := @Buffer; - P^ := (Len and $FF0000) shr 16; - Inc(P); - P^ := (Len and $00FF00) shr 8; - Inc(P); - P^ := (Len and $0000FF); - Result := 3; -end; + SysUtils, -function DecodeTLSLen16(const Buffer; const Size: Integer; var Len: Integer): Integer; -var P : PByte; -begin - if Size < 2 then - raise ETLSError.Create(TLSError_InvalidBuffer); - P := @Buffer; - Len := P^ shl 8; - Inc(P); - Inc(Len, P^); - Result := 2; -end; + { Utils } -function DecodeTLSLen24(const Buffer; const Size: Integer; var Len: Integer): Integer; -var P : PByte; -begin - if Size < 3 then - raise ETLSError.Create(TLSError_InvalidBuffer); - P := @Buffer; - Len := P^ shl 16; - Inc(P); - Inc(Len, P^ shl 8); - Inc(P); - Inc(Len, P^); - Result := 3; -end; + flcStrings, + flcHash, -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.Create(TLSError_InvalidBuffer); - if L > 0 then - Move(A[1], P^, L); - Result := Size - N; -end; + { Cipher } -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.Create(TLSError_InvalidBuffer); - if L > 0 then - Move(A[1], P^, L); - Result := Size - N; -end; + flcCipherRandom, -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.Create(TLSError_InvalidBuffer); - SetLength(A, L); - if L > 0 then - Move(P^, A[1], L); - Result := Size - N; -end; + { TLS } -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.Create(TLSError_InvalidBuffer); - SetLength(A, L); - if L > 0 then - Move(P^, A[1], L); - Result := Size - N; -end; + flcTLSAlert, + flcTLSErrors, + flcTLSPRF, + flcTLSOpaqueEncoding; @@ -647,7 +430,7 @@ function EncodeTLSHandshake( P := @Buffer; L := TLSHandshakeHeaderSize + MsgSize; if not Assigned(P) or (Size < L) then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferEncode; EncodeTLSHandshakeHeader(PTLSHandshakeHeader(P)^, MsgType, MsgSize); Result := L; end; @@ -689,12 +472,13 @@ procedure InitTLSClientHello( function EncodeTLSClientHello( var Buffer; const Size: Integer; - const ClientHello: TTLSClientHello): Integer; -var P : PByte; - L, N : Integer; - C : TTLSCipherSuite; - D : TTLSCompressionMethod; - Suite : TTLSCipherSuiteRec; + var ClientHello: TTLSClientHello): Integer; +var P : PByte; + L, N : Integer; + C : TTLSCipherSuite; + D : TTLSCompressionMethod; + Suite : TTLSCipherSuiteRec; + SignRSA : Boolean; begin Assert(Assigned(@Buffer)); @@ -704,13 +488,13 @@ function EncodeTLSClientHello( // client_version Dec(N, TLSProtocolVersionSize); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferEncode; PTLSProtocolVersion(P)^ := ClientHello.ProtocolVersion; Inc(P, TLSProtocolVersionSize); // random Dec(N, TLSRandomSize); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferEncode; PTLSRandom(P)^ := ClientHello.Random; Inc(P, TLSRandomSize); // session_id @@ -727,7 +511,8 @@ function EncodeTLSClientHello( Inc(P, 2); Dec(N, 2 + L * TLSCipherSuiteRecSize); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferEncode; + SignRSA := False; for C := Low(TTLSCipherSuite) to High(TTLSCipherSuite) do if C in ClientHello.CipherSuites then begin @@ -735,6 +520,8 @@ function EncodeTLSClientHello( Suite.B2 := TLSCipherSuiteInfo[C].Rec.B2; PTLSCipherSuiteRec(P)^ := Suite; Inc(P, TLSCipherSuiteRecSize); + if TLSCipherSuiteInfo[C].Authentication = tlscsaRSA then + SignRSA := True; end; // compression_methods L := 0; @@ -744,7 +531,7 @@ function EncodeTLSClientHello( Assert(L <= $FF); Dec(N, 1 + L); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferEncode; P^ := L; Inc(P); for D := Low(TTLSCompressionMethod) to High(TTLSCompressionMethod) do @@ -753,7 +540,27 @@ function EncodeTLSClientHello( P^ := Ord(D); Inc(P); end; - + // extensions + { + if IsTLS12(ClientHello.ProtocolVersion) then + if SignRSA then + begin + SetLength(ClientHello.SignAndHashAlgos, 5); + ClientHello.SignAndHashAlgos[0].Hash := tlshaSHA1; + ClientHello.SignAndHashAlgos[0].Signature := tlssaRSA; + ClientHello.SignAndHashAlgos[1].Hash := tlshaSHA224; + ClientHello.SignAndHashAlgos[1].Signature := tlssaRSA; + ClientHello.SignAndHashAlgos[2].Hash := tlshaSHA256; + ClientHello.SignAndHashAlgos[2].Signature := tlssaRSA; + ClientHello.SignAndHashAlgos[3].Hash := tlshaSHA384; + ClientHello.SignAndHashAlgos[3].Signature := tlssaRSA; + ClientHello.SignAndHashAlgos[4].Hash := tlshaSHA512; + ClientHello.SignAndHashAlgos[4].Signature := tlssaRSA; + ClientHello.ExtensionsPresent := True; + L := EncodeTLSClientHelloExtension_SignatureAlgorithms(P^, N, ClientHello); + Dec(N, L); + end; + } Result := Size - N; end; @@ -761,7 +568,7 @@ function DecodeTLSClientHello( const Buffer; const Size: Integer; var ClientHello: TTLSClientHello): Integer; var P : PByte; - L, N, C : Integer; + L, N, C, ExtType, ExtLen : Integer; I : Word; E : TTLSCipherSuite; F : TTLSCipherSuiteRec; @@ -776,13 +583,13 @@ function DecodeTLSClientHello( // client_version Dec(N, TLSProtocolVersionSize); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferDecode; ClientHello.ProtocolVersion := PTLSProtocolVersion(P)^; Inc(P, TLSProtocolVersionSize); // random Dec(N, TLSRandomSize); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferDecode; ClientHello.Random := PTLSRandom(P)^; Inc(P, TLSRandomSize); // session_id @@ -796,7 +603,7 @@ function DecodeTLSClientHello( Inc(P, L); Dec(N, C); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferDecode; C := C div TLSCipherSuiteRecSize; for I := 0 to C - 1 do begin @@ -808,13 +615,13 @@ function DecodeTLSClientHello( // compression_methods Dec(N); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferDecode; ClientHello.CompressionMethods := []; C := P^; Inc(P); Dec(N, C); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferDecode; for I := 0 to C - 1 do begin D := PTLSCompressionMethod(P)^; @@ -823,13 +630,28 @@ function DecodeTLSClientHello( end; // extensions ClientHello.ExtensionsPresent := N > 0; - + while N > 0 do + begin + if N < 4 then + raise ETLSError.CreateAlertBufferDecode; + DecodeTLSWord16(P^, N, ExtType); + Inc(P, 2); + Dec(N, 2); + DecodeTLSLen16(P^, N, ExtLen); + Inc(P, 2); + Dec(N, 2); + Dec(N, ExtLen); + if N < 0 then + raise ETLSError.CreateAlertBufferDecode; + Inc(P, ExtLen); + end; + Result := Size - N; end; function EncodeTLSHandshakeClientHello( var Buffer; const Size: Integer; - const ClientHello: TTLSClientHello): Integer; + var ClientHello: TTLSClientHello): Integer; var P : Pointer; N, L : Integer; begin @@ -879,13 +701,13 @@ function EncodeTLSServerHello( // server_version Dec(N, TLSProtocolVersionSize); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferEncode; PTLSProtocolVersion(P)^ := ServerHello.ProtocolVersion; Inc(P, TLSProtocolVersionSize); // random Dec(N, TLSRandomSize); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferEncode; PTLSRandom(P)^ := ServerHello.Random; Inc(P, TLSRandomSize); // session_id @@ -895,13 +717,13 @@ function EncodeTLSServerHello( // cipher_suite Dec(N, TLSCipherSuiteRecSize); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferEncode; PTLSCipherSuiteRec(P)^ := ServerHello.CipherSuite; Inc(P, TLSCipherSuiteRecSize); // compression_method Dec(N, TLSCompressionMethodSize); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferEncode; PTLSCompressionMethod(P)^ := ServerHello.CompressionMethod; Result := Size - N; @@ -921,13 +743,13 @@ function DecodeTLSServerHello( // server_version Dec(N, TLSProtocolVersionSize); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferDecode; ServerHello.ProtocolVersion := PTLSProtocolVersion(P)^; Inc(P, TLSProtocolVersionSize); // random Dec(N, TLSRandomSize); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferDecode; ServerHello.Random := PTLSRandom(P)^; Inc(P, TLSRandomSize); // session_id @@ -937,13 +759,13 @@ function DecodeTLSServerHello( // cipher_suite Dec(N, TLSCipherSuiteRecSize); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferDecode; ServerHello.CipherSuite := PTLSCipherSuiteRec(P)^; Inc(P, TLSCipherSuiteRecSize); // compression_method Dec(N, TLSCompressionMethodSize); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferDecode; ServerHello.CompressionMethod := PTLSCompressionMethod(P)^; Result := Size - N; @@ -968,76 +790,6 @@ function EncodeTLSHandshakeServerHello( { } { 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; - function EncodeTLSHandshakeCertificate( var Buffer; const Size: Integer; const CertificateList: TTLSCertificateList): Integer; @@ -1051,221 +803,10 @@ function EncodeTLSHandshakeCertificate( -{ } -{ ServerDHParams } -{ Ephemeral DH parameters } -{ } -{ dh_p : opaque <1..2^16-1>; } -{ dh_g : opaque <1..2^16-1>; } -{ dh_Ys : opaque <1..2^16-1>; } -{ } -procedure InitTLSServerDHParams_None(var ServerDHParams: TTLSServerDHParams); -begin - ServerDHParams.dh_p := ''; - ServerDHParams.dh_g := ''; - ServerDHParams.dh_Ys := ''; -end; - -procedure InitTLSServerDHParams(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; - - -{ } -{ TTLSSignedParams } -{ signed_params = digitally-signed struct ( } -{ client_random : opaque [32]; } -{ server_random : opaque [32]; } -{ params : ServerDHParams ; } -{ ); } -{ } -procedure InitTLSSignedParams(var SignedParams: TTLSSignedParams); -begin - FillChar(SignedParams.client_random, SizeOf(SignedParams.client_random), 0); - FillChar(SignedParams.server_random, SizeOf(SignedParams.server_random), 0); - InitTLSServerDHParams_None(SignedParams.params); -end; - -function EncodeTLSSignedParams( - var Buffer; const Size: Integer; - const SignedParams: TTLSSignedParams): 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(SignedParams.client_random, P^, 32); - Inc(P, 32); - Move(SignedParams.server_random, P^, 32); - Inc(P, 32); - L := EncodeTLSServerDHParams(P^, N, SignedParams.params); - Dec(N, L); - Result := Size - N; -end; - -function DecodeTLSSignedParams( - const Buffer; const Size: Integer; - var SignedParams: TTLSSignedParams): 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(P^, SignedParams.client_random, 32); - Inc(P, 32); - Move(P^, SignedParams.server_random, 32); - Inc(P, 32); - L := DecodeTLSServerDHParams(P^, N, SignedParams.params); - Dec(N, L); - Result := Size - N; -end; - - { } -{ Server Key Exchange } +{ ServerKeyExchange } { } -{ 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 (); } -{ } -procedure InitTLSServerKeyExchange(var ServerKeyExchange: TTLSServerKeyExchange); -begin - InitTLSServerDHParams_None(ServerKeyExchange.Params); - InitTLSSignedParams(ServerKeyExchange.SignedParams); -end; - -function EncodeTLSServerKeyExchange( - var Buffer; const Size: Integer; - const KeyExchangeAlgorithm: TTLSKeyExchangeAlgorithm; - const ServerKeyExchange: TTLSServerKeyExchange): Integer; -var P : PByte; - N, L : Integer; -begin - N := Size; - P := @Buffer; - case KeyExchangeAlgorithm of - tlskeaDH_Anon : - begin - L := EncodeTLSServerDHParams(P^, N, ServerKeyExchange.Params); - Dec(N, L); - end; - tlskeaDHE_DSS, - tlskeaDHE_RSA : - begin - L := EncodeTLSServerDHParams(P^, N, ServerKeyExchange.Params); - Dec(N, L); - Inc(P, L); - L := EncodeTLSSignedParams(P^, N, ServerKeyExchange.SignedParams); - Dec(N, L); - end; - 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.Params); - Dec(N, L); - end; - tlskeaDHE_DSS, - tlskeaDHE_RSA : - begin - L := DecodeTLSServerDHParams(P^, N, ServerKeyExchange.Params); - Dec(N, L); - Inc(P, L); - L := DecodeTLSSignedParams(P^, N, ServerKeyExchange.SignedParams); - Dec(N, L); - end; - tlskeaRSA, - tlskeaDH_DSS, - tlskeaDH_RSA : ; - end; - Result := Size - N; -end; - function EncodeTLSHandshakeServerKeyExchange( var Buffer; const Size: Integer; const KeyExchangeAlgorithm: TTLSKeyExchangeAlgorithm; @@ -1344,12 +885,12 @@ function DecodeTLSCertificateRequest( // certificate_types Dec(N); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferDecode; L := P^; Inc(P); Dec(N, L); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferDecode; SetLength(CertificateRequest.CertificateTypes, L); for I := 0 to L - 1 do begin @@ -1363,7 +904,7 @@ function DecodeTLSCertificateRequest( Inc(P, 2); Dec(N, 2 + L * TLSSignatureAndHashAlgorithmSize); if N < 0 then - raise ETLSError.Create(TLSError_InvalidBuffer); + raise ETLSError.CreateAlertBufferDecode; SetLength(CertificateRequest.SupportedSignatureAlgorithms, L); for I := 0 to L - 1 do begin @@ -1440,7 +981,7 @@ procedure InitTLSEncryptedPreMasterSecret_RSA( var B : array[0..1023] of Byte; L : Integer; begin - L := RSAEncrypt(rsaetPKCS1, RSAPublicKey, PreMasterSecret, SizeOf(PreMasterSecret), + L := RSAEncrypt(rsaetRSAES_PKCS1, RSAPublicKey, PreMasterSecret, SizeOf(PreMasterSecret), B, SizeOf(B)); SetLength(EncryptedPreMasterSecret, L + 2); EncodeTLSLen16(EncryptedPremasterSecret[1], L + 2, L); @@ -1449,91 +990,17 @@ procedure InitTLSEncryptedPreMasterSecret_RSA( -{ } -{ 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; - - - { } { ClientKeyExchange } { } { select (KeyExchangeAlgorithm) } -{ case rsa : EncryptedPreMasterSecret; } +{ 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 EncodeTLSHandshakeClientKeyExchange( var Buffer; const Size: Integer; const KeyExchangeAlgorithm: TTLSKeyExchangeAlgorithm; @@ -1546,40 +1013,6 @@ function EncodeTLSHandshakeClientKeyExchange( Result := EncodeTLSHandshake(Buffer, Size, tlshtClient_key_exchange, L); 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; - { } @@ -1652,7 +1085,8 @@ procedure CalcSSLVerifyData( const SenderIsClient: Boolean; var md5_hash: TSSLFinishedMD5Hash; var sha_hash: TSSLFinishedSHAHash); -var M, S, T : RawByteString; +var + M, S, T : RawByteString; begin if SenderIsClient then T := #$43#$4C#$4E#$54 diff --git a/Source/TLS/flcTLSHandshakeExtension.pas b/Source/TLS/flcTLSHandshakeExtension.pas new file mode 100644 index 0000000..296dae0 --- /dev/null +++ b/Source/TLS/flcTLSHandshakeExtension.pas @@ -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. diff --git a/Source/TLS/flcTLSKeyExchangeParams.pas b/Source/TLS/flcTLSKeyExchangeParams.pas new file mode 100644 index 0000000..71808c6 --- /dev/null +++ b/Source/TLS/flcTLSKeyExchangeParams.pas @@ -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. + diff --git a/Source/TLS/flcTLSKeys.pas b/Source/TLS/flcTLSKeys.pas new file mode 100644 index 0000000..242a050 --- /dev/null +++ b/Source/TLS/flcTLSKeys.pas @@ -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 + // // + // Example from http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/ReadDebug.html // + // // + Assert(tls10MasterSecret(PreMasterSecret, ClientRandom, ServerRandom) = MasterSecret); + S := tls10KeyBlock(MasterSecret, ServerRandom, ClientRandom, 64); + Assert(Copy(S, 1, 48) = + MACWriteKey + + #$1E#$4D#$D1#$D3#$0A#$78#$EE#$B7#$4F#$EC#$15#$79#$B2#$59#$18#$40 + + #$10#$D0#$D6#$C2#$D9#$B7#$62#$CB#$2C#$74#$BF#$5F#$85#$3C#$6F#$E7); +end; + +procedure Test; + begin + TestKeyBlock; + end; + {$ENDIF} + + + + end. diff --git a/Source/TLS/flcTLSOpaqueEncoding.pas b/Source/TLS/flcTLSOpaqueEncoding.pas new file mode 100644 index 0000000..b64c63b --- /dev/null +++ b/Source/TLS/flcTLSOpaqueEncoding.pas @@ -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. + diff --git a/Source/TLS/flcTLSPRF.pas b/Source/TLS/flcTLSPRF.pas new file mode 100644 index 0000000..a70857b --- /dev/null +++ b/Source/TLS/flcTLSPRF.pas @@ -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_(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 + + #$40#$d4#$d8#$98); +end; +{$ENDIF} + + + + end. + diff --git a/Source/TLS/flcTLSProtocolVersion.pas b/Source/TLS/flcTLSProtocolVersion.pas new file mode 100644 index 0000000..a00fa71 --- /dev/null +++ b/Source/TLS/flcTLSProtocolVersion.pas @@ -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'); + Assert(TLSProtocolVersionName(TLSProtocolVersion11) = 'TLS1.1'); + Assert(TLSProtocolVersionName(TLSProtocolVersion12) = 'TLS1.2'); + end; + {$ENDIF} + + + +end. diff --git a/Source/TLS/flcTLSRandom.pas b/Source/TLS/flcTLSRandom.pas new file mode 100644 index 0000000..6cb5eb3 --- /dev/null +++ b/Source/TLS/flcTLSRandom.pas @@ -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 + Assert(TLSRandomSize = 32); + end; + {$ENDIF} + + + +end. diff --git a/Source/TLS/flcTLSRecord.pas b/Source/TLS/flcTLSRecord.pas index 562d4de..1e09d32 100644 --- a/Source/TLS/flcTLSRecord.pas +++ b/Source/TLS/flcTLSRecord.pas @@ -5,7 +5,7 @@ { File version: 5.08 } { Description: TLS records } { } -{ Copyright: Copyright (c) 2008-2018, David J Butler } +{ 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 } @@ -34,7 +34,7 @@ { } { Revision history: } { } -{ 2008/01/18 0.01 Initial version. } +{ 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. } @@ -53,7 +53,9 @@ interface uses { TLS } - flcTLSUtils, + + flcTLSProtocolVersion, + flcTLSAlgorithmTypes, flcTLSCipherSuite, flcTLSCipher; @@ -64,10 +66,12 @@ interface { } type TTLSContentType = ( + tlsctInvalid = 0, tlsctChange_cipher_spec = 20, tlsctAlert = 21, tlsctHandshake = 22, tlsctApplication_data = 23, + tlsctHeartbeat = 24, // RFC 6520 tlsctMax = 255 ); PTLSContentType = ^TTLSContentType; @@ -176,13 +180,22 @@ implementation uses { System } + SysUtils, - { Fundamentals } + + { Utils } + flcStdTypes, - flcStrings, flcHash, + + { Cipher } + flcCipherRandom, + { TLS } + + flcTLSConsts, + flcTLSErrors, flcTLSCompress; @@ -193,10 +206,12 @@ implementation 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; @@ -208,7 +223,8 @@ function IsKnownTLSContentType(const A: TTLSContentType): Boolean; tlsctChange_cipher_spec, tlsctAlert, tlsctHandshake, - tlsctApplication_data]; + tlsctApplication_data, + tlsctHeartbeat]; end; @@ -912,6 +928,7 @@ procedure DecodeTLSRecord( { } { Test cases } { } +//// TBytes {$IFDEF TLS_TEST} {$ASSERTIONS ON} procedure SelfTestPayloadMAC; @@ -947,3 +964,5 @@ procedure Test; end. + + diff --git a/Source/TLS/flcTLSSessionID.pas b/Source/TLS/flcTLSSessionID.pas new file mode 100644 index 0000000..ceb698f --- /dev/null +++ b/Source/TLS/flcTLSSessionID.pas @@ -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; + + + + end. diff --git a/Source/TLS/flcTLSTestCertificates.pas b/Source/TLS/flcTLSTestCertificates.pas new file mode 100644 index 0000000..12117a0 --- /dev/null +++ b/Source/TLS/flcTLSTestCertificates.pas @@ -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. + diff --git a/Source/TLS/flcTLSTests.pas b/Source/TLS/flcTLSTests.pas index 032666e..8ea1b6f 100644 --- a/Source/TLS/flcTLSTests.pas +++ b/Source/TLS/flcTLSTests.pas @@ -2,10 +2,10 @@ { } { Library: Fundamentals TLS } { File name: flcTLSTests.pas } -{ File version: 5.04 } +{ File version: 5.05 } { Description: TLS tests } { } -{ Copyright: Copyright (c) 2008-2018, David J Butler } +{ 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 } @@ -34,10 +34,11 @@ { } { Revision history: } { } -{ 2008/01/18 0.01 Initial version. } -{ 2010/12/15 0.02 Client/Server test case. ] +{ 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: } { } @@ -47,15 +48,35 @@ { 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 } { } -{ Todo: } -{ - Test compression. } {******************************************************************************} +// ----------------------------------------------------- ------------------------------------------- +// 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 @@ -63,7 +84,7 @@ interface { } -{ Test cases } +{ Test } { } {$IFDEF TLS_TEST} procedure Test; @@ -74,28 +95,53 @@ procedure Test; implementation uses + { System } + SysUtils, SyncObjs, - { Fundamentals } + + { Utils } + flcStdTypes, - flcUtils, flcBase64, flcStrings, + flcPEM, + flcASN1, flcX509Certificate, + flcHugeInt, + + { Cipher } + + flcCipherAES, + flcCipherRSA, + flcCipherDH, + {$IFDEF Cipher_SupportEC} + flcCipherEllipticCurve, + {$ENDIF} + { TLS } - flcTLSUtils, + + flcTLSConsts, + flcTLSProtocolVersion, flcTLSRecord, flcTLSAlert, + flcTLSAlgorithmTypes, + flcTLSRandom, + flcTLSCertificate, flcTLSHandshake, flcTLSCipher, - flcTLSConnection, - flcTLSClient, - flcTLSServer; + flcTLSPRF, + flcTLSKeys, + flcTLSTransportTypes, + flcTLSTransportConnection, + flcTLSTransportClient, + flcTLSTransportServer, + flcTLSTestCertificates; { } -{ Test cases } +{ Test } { } {$IFDEF TLS_TEST} type @@ -171,7 +217,13 @@ procedure TTLSClientServerTester.ServerLog(Sender: TTLSServer; LogType: TTLSLogT Log(IntToStr(LogLevel) + ' S:' + LogMsg); end; -procedure SelfTestClientServer(const ClientOptions: TTLSClientOptions); +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; @@ -184,36 +236,11 @@ procedure SelfTestClientServer(const ClientOptions: TTLSClientOptions); // initialise client CS.Cl.ClientOptions := ClientOptions; // initialise server - CS.Sr.PrivateKeyRSAPEM := // from stunnel pem file - '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='; + CS.Sr.PrivateKeyRSAPEM := RSA_STunnel_PrivateKeyRSAPEM; TLSCertificateListAppend(CtL, - MIMEBase64Decode( // from stunnel pem file - 'MIICDzCCAXigAwIBAgIBADANBgkqhkiG9w0BAQQFADBCMQswCQYDVQQGEwJQTDEf' + - 'MB0GA1UEChMWU3R1bm5lbCBEZXZlbG9wZXJzIEx0ZDESMBAGA1UEAxMJbG9jYWxo' + - 'b3N0MB4XDTk5MDQwODE1MDkwOFoXDTAwMDQwNzE1MDkwOFowQjELMAkGA1UEBhMC' + - 'UEwxHzAdBgNVBAoTFlN0dW5uZWwgRGV2ZWxvcGVycyBMdGQxEjAQBgNVBAMTCWxv' + - 'Y2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsVBTLqiSWyPSpwfF' + - 'bcEm3L8DTpbVgbVsmkpqe8hJ6sFnpeUxX3Djmwri2evbBYtRC4uQvdakWgzKMO5O' + - 'Ro9OQ2bSwxXyAg9FtUvp9iqpdqPH9kUr2ag9lvZfIufV2ws9aEuJfUtPS/t0U2Vf' + - 'aHq/1J28v0JonBSzTNFoK1TYissCAwEAAaMVMBMwEQYJYIZIAYb4QgEBBAQDAgZA' + - 'MA0GCSqGSIb3DQEBBAUAA4GBAAhYFTngWc3tuMjVFhS4HbfFF/vlOgTu44/rv2F+' + - 'ya1mEB93htfNxx3ofRxcjCdorqONZFwEba6xZ8/UujYfVmIGCBy4X8+aXd83TJ9A' + - 'eSjTzV9UayOoGtmg8Dv2aj/5iabNeK1Qf35ouvlcTezVZt2ZeJRhqUHcGaE+apCN' + - 'TC9Y')); + MIMEBase64Decode(RSA_STunnel_CertificatePEM)); CS.Sr.CertificateList := CtL; - CS.Sr.DHKeySize := 256; + CS.Sr.DHKeySize := 512; // start server CS.Sr.Start; Assert(CS.Sr.State = tlssActive); @@ -274,77 +301,111 @@ procedure SelfTestClientServer(const ClientOptions: TTLSClientOptions); end; end; -procedure Test; +procedure Test_Units_Dependencies; begin - flcTLSUtils.Test; - flcTLSRecord.Test; - flcTLSHandshake.Test; + 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; - // TLS version tests +procedure Test_ClientServer_TLSVersions; +begin // TLS 1.2 - SelfTestClientServer([tlscoDisableSSL3, tlscoDisableTLS10, tlscoDisableTLS11]); + TestClientServer([], [tlsvoTLS12]); // TLS 1.1 - SelfTestClientServer([tlscoDisableSSL3, tlscoDisableTLS10, tlscoDisableTLS12]); + TestClientServer([], [tlsvoTLS11]); // TLS 1.0 - SelfTestClientServer([tlscoDisableSSL3, tlscoDisableTLS11, tlscoDisableTLS12]); + TestClientServer([], [tlsvoTLS10]); + Sleep(100); // SSL 3 // Fails with invalid parameter - // SelfTestClientServer([tlscoDisableTLS10, tlscoDisableTLS11, tlscoDisableTLS12]); + //SelfTestClientServer([], [tlsvoSSL3]); +end; - // TLS cipher tests - // TLS 1.2 RC4_128 - SelfTestClientServer([tlscoDisableSSL3, tlscoDisableTLS10, tlscoDisableTLS11, - tlscoDisableCipherAES128, tlscoDisableCipherAES256, tlscoDisableCipherDES]); +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 - SelfTestClientServer([tlscoDisableSSL3, tlscoDisableTLS10, tlscoDisableTLS11, - tlscoDisableCipherAES256, tlscoDisableCipherRC4_128, tlscoDisableCipherDES]); + TestClientServer([], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions, + [tlscoAES128]); // TLS 1.2 AES256 - SelfTestClientServer([tlscoDisableSSL3, tlscoDisableTLS10, tlscoDisableTLS11, - tlscoDisableCipherAES128, tlscoDisableCipherRC4_128, tlscoDisableCipherDES]); + TestClientServer([], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions, + [tlscoAES256]); // TLS 1.2 DES - SelfTestClientServer([tlscoDisableSSL3, tlscoDisableTLS10, tlscoDisableTLS11, - tlscoDisableCipherAES128, tlscoDisableCipherAES256, tlscoDisableCipherRC4_128]); + TestClientServer([], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions, + [tlscoDES]); + // TLS 1.2 3DES + // No Cipher Suite + {SelfTestClientServer([], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions, + [tlsco3DES]);} +end; - // TLS hash tests +procedure Test_ClientServer_HashAlgos; +begin // TLS 1.2 SHA256 - SelfTestClientServer([tlscoDisableSSL3, tlscoDisableTLS10, tlscoDisableTLS11, - tlscoDisableHashMD5, tlscoDisableHashSHA1]); + TestClientServer( + [], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions, DefaultTLSClientCipherOptions, + [tlshoSHA256]); // TLS 1.2 SHA1 - SelfTestClientServer([tlscoDisableSSL3, tlscoDisableTLS10, tlscoDisableTLS11, - tlscoDisableHashMD5, tlscoDisableHashSHA256]); + TestClientServer( + [], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions, DefaultTLSClientCipherOptions, + [tlshoSHA1]); // TLS 1.2 MD5 - SelfTestClientServer([tlscoDisableSSL3, tlscoDisableTLS10, tlscoDisableTLS11, - tlscoDisableHashSHA1, tlscoDisableHashSHA256]); + TestClientServer( + [], [tlsvoTLS12], DefaultTLSClientKeyExchangeOptions, DefaultTLSClientCipherOptions, + [tlshoMD5]); +end; - // TLS key exchange tests - // TLS 1.2 RSA - SelfTestClientServer([tlscoDisableSSL3, tlscoDisableTLS10, tlscoDisableTLS11, - tlscoDisableKeyExchangeDH_Anon, tlscoDisableKeyExchangeDH_RSA]); - // TLS 1.2 DH_RSA - // Not implemented - // SelfTestClientServer([tlscoDisableSSL3, tlscoDisableTLS10, tlscoDisableTLS11, - // tlscoDisableKeyExchangeDH_Anon, tlscoDisableKeyExchangeRSA]); - // TLS 1.2 DH_anon - // Under development/testing - // SelfTestClientServer([tlscoDisableSSL3, tlscoDisableTLS10, tlscoDisableTLS11, - // tlscoDisableKeyExchangeDH_RSA, tlscoDisableKeyExchangeRSA]); +procedure Test_ClientServer; +begin + Test_ClientServer_TLSVersions; + Test_ClientServer_KeyExchangeAlgos; + Test_ClientServer_CipherAlgos; + Test_ClientServer_HashAlgos; end; -{$ENDIF} -// tlscsRSA_WITH_RC4_128_MD5, // TESTED OK -// tlscsRSA_WITH_RC4_128_SHA, // TESTED OK -// tlscsRSA_WITH_DES_CBC_SHA, // TESTED OK -// tlscsRSA_WITH_AES_128_CBC_SHA, // TESTED OK -// tlscsRSA_WITH_AES_256_CBC_SHA, // TESTED OK -// tlscsRSA_WITH_AES_128_CBC_SHA256, // TESTED OK, TLS 1.2 only -// tlscsRSA_WITH_AES_256_CBC_SHA256 // TESTED OK, TLS 1.2 only -// tlscsNULL_WITH_NULL_NULL // UNTESTED -// tlscsRSA_WITH_NULL_MD5 // UNTESTED -// tlscsRSA_WITH_NULL_SHA // UNTESTED -// tlscsRSA_WITH_IDEA_CBC_SHA // UNTESTED -// tlscsRSA_WITH_3DES_EDE_CBC_SHA // ERROR: SERVER DECRYPTION FAILED -// tlscsRSA_WITH_NULL_SHA256 // ERROR +procedure Test; +begin + Test_Units_Dependencies; + Test_Units_TLS; + Test_ClientServer; +end; +{$ENDIF} diff --git a/Source/TLS/flcTLSClient.pas b/Source/TLS/flcTLSTransportClient.pas similarity index 62% rename from Source/TLS/flcTLSClient.pas rename to Source/TLS/flcTLSTransportClient.pas index a756773..78ae1df 100644 --- a/Source/TLS/flcTLSClient.pas +++ b/Source/TLS/flcTLSTransportClient.pas @@ -1,11 +1,11 @@ {******************************************************************************} { } { Library: Fundamentals TLS } -{ File name: flcTLSClient.pas } -{ File version: 5.06 } -{ Description: TLS client } +{ File name: flcTLSTransportClient.pas } +{ File version: 5.08 } +{ Description: TLS Transport Client } { } -{ Copyright: Copyright (c) 2008-2018, David J Butler } +{ 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 } @@ -40,72 +40,88 @@ { 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. } { } -{ Todo: } -{ - OnClientStateChange event } -{ - Send connection close alert } -{ - SecureClear memory } -{ - Option to set allowable ciphers/hashes. } {******************************************************************************} {$INCLUDE flcTLS.inc} -unit flcTLSClient; +unit flcTLSTransportClient; interface uses - { Fundamentals } + SysUtils, + + { Utils } + flcStdTypes, + { Cipher } + flcCipherRSA, flcCipherDH, + { X509 } + flcX509Certificate, + { TLS } - flcTLSUtils, + + flcTLSProtocolVersion, + flcTLSAlgorithmTypes, + flcTLSRandom, flcTLSCipherSuite, flcTLSRecord, flcTLSAlert, + flcTLSKeyExchangeParams, + flcTLSCertificate, + flcTLSKeys, flcTLSHandshake, - flcTLSConnection; + 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; - TTLSClientOptions = set of ( - tlscoDisableSSL3, - tlscoDisableTLS10, - tlscoDisableTLS11, - tlscoDisableTLS12, - tlscoDisableCipherRC4_128, - tlscoDisableCipherDES, - tlscoDisableCipherAES128, - tlscoDisableCipherAES256, - tlscoDisableHashMD5, - tlscoDisableHashSHA1, - tlscoDisableHashSHA256, - tlscoDisableKeyExchangeRSA, - tlscoDisableKeyExchangeDH_Anon, - tlscoDisableKeyExchangeDH_RSA); - TTLSClientState = ( - tlsclInit, - tlsclHandshakeAwaitingServerHello, - tlsclHandshakeAwaitingServerHelloDone, - tlsclHandshakeClientKeyExchange, - tlsclConnection); + tlsclInit, + tlsclHandshakeAwaitingServerHello, + tlsclHandshakeAwaitingServerHelloDone, + tlsclHandshakeClientKeyExchange, + tlsclConnection + ); TTLSClient = class(TTLSConnection) protected FClientOptions : TTLSClientOptions; + FVersionOptions : TTLSVersionOptions; + FKeyExchangeOptions : TTLSKeyExchangeOptions; + FCipherOptions : TTLSCipherOptions; + FHashOptions : TTLSHashOptions; FResumeSessionID : RawByteString; FClientState : TTLSClientState; @@ -123,16 +139,19 @@ TTLSClient = class(TTLSConnection) FClientKeyExchange : TTLSClientKeyExchange; FServerRSAPublicKey : TRSAPublicKey; FDHState : PDHState; - FPreMasterSecret : TTLSPreMasterSecret; FPreMasterSecretStr : RawByteString; FMasterSecret : RawByteString; procedure Init; override; - procedure SetClientState(const State: TTLSClientState); + procedure SetClientState(const AState: TTLSClientState); procedure CheckNotActive; - procedure SetClientOptions(const ClientOptions: TTLSClientOptions); + 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; @@ -164,13 +183,21 @@ TTLSClient = class(TTLSConnection) procedure DoStart; public - constructor Create(const TransportLayerSendProc: TTLSConnectionTransportLayerSendProc); + constructor Create(const ATransportLayerSendProc: TTLSConnectionTransportLayerSendProc); destructor Destroy; override; - property ClientOptions: TTLSClientOptions read FClientOptions write SetClientOptions; + 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; @@ -179,11 +206,18 @@ TTLSClient = class(TTLSConnection) implementation uses - { Fundamentals } + { Utils } + flcHugeInt, flcASN1, + + { Cipher } + flcCipherUtils, + { TLS } + + flcTLSErrors, flcTLSCompress, flcTLSCipher; @@ -200,9 +234,9 @@ implementation 'HandshakeClientKeyExchange', 'Connection'); -constructor TTLSClient.Create(const TransportLayerSendProc: TTLSConnectionTransportLayerSendProc); +constructor TTLSClient.Create(const ATransportLayerSendProc: TTLSConnectionTransportLayerSendProc); begin - inherited Create(TransportLayerSendProc); + inherited Create(ATransportLayerSendProc); end; destructor TTLSClient.Destroy; @@ -221,18 +255,25 @@ destructor TTLSClient.Destroy; procedure TTLSClient.Init; begin inherited Init; + RSAPublicKeyInit(FServerRSAPublicKey); - FClientOptions := [tlscoDisableSSL3]; + + FClientOptions := DefaultTLSClientOptions; + FVersionOptions := DefaultTLSClientVersionOptions; + FKeyExchangeOptions := DefaultTLSClientKeyExchangeOptions; + FCipherOptions := DefaultTLSClientCipherOptions; + FHashOptions := DefaultTLSClientHashOptions; + FClientState := tlsclInit; end; -procedure TTLSClient.SetClientState(const State: TTLSClientState); +procedure TTLSClient.SetClientState(const AState: TTLSClientState); begin {$IFDEF TLS_DEBUG} - Log(tlsltDebug, 'State:%s', [STLSClientState[State]]); + Log(tlsltDebug, 'State:%s', [STLSClientState[AState]]); {$ENDIF} - FClientState := State; + FClientState := AState; end; procedure TTLSClient.CheckNotActive; @@ -241,27 +282,64 @@ procedure TTLSClient.CheckNotActive; raise ETLSError.Create(TLSError_InvalidState, 'Operation not allowed while active'); end; -procedure TTLSClient.SetClientOptions(const ClientOptions: TTLSClientOptions); +procedure TTLSClient.SetClientOptions(const AClientOptions: TTLSClientOptions); begin - if ClientOptions = FClientOptions then + if AClientOptions = FClientOptions then exit; CheckNotActive; - if ClientOptions * [tlscoDisableSSL3, tlscoDisableTLS10, tlscoDisableTLS11, tlscoDisableTLS12] = - [tlscoDisableSSL3, tlscoDisableTLS10, tlscoDisableTLS11, tlscoDisableTLS12] then + 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'); - FClientOptions := ClientOptions; + 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 not (tlscoDisableTLS12 in FClientOptions) then + if tlsvoTLS12 in FVersionOptions then InitTLSProtocolVersion12(FProtocolVersion) else - if not (tlscoDisableTLS11 in FClientOptions) then + if tlsvoTLS11 in FVersionOptions then InitTLSProtocolVersion11(FProtocolVersion) else - if not (tlscoDisableTLS10 in FClientOptions) then + if tlsvoTLS10 in FVersionOptions then InitTLSProtocolVersion10(FProtocolVersion) else - if not (tlscoDisableSSL3 in FClientOptions) then + if tlsvoSSL3 in FVersionOptions then InitSSLProtocolVersion30(FProtocolVersion) else raise ETLSError.Create(TLSError_InvalidParameter, 'Invalid version options'); @@ -275,14 +353,14 @@ procedure TTLSClient.InitInitialProtocolVersion; procedure TTLSClient.InitSessionProtocolVersion; begin FProtocolVersion := FServerProtocolVersion; - if IsTLS12(FProtocolVersion) and (tlscoDisableTLS12 in FClientOptions)then + if IsTLS12(FProtocolVersion) and not (tlsvoTLS12 in FVersionOptions) then InitTLSProtocolVersion11(FProtocolVersion); - if IsTLS11(FProtocolVersion) and (tlscoDisableTLS11 in FClientOptions) then + if IsTLS11(FProtocolVersion) and not (tlsvoTLS11 in FVersionOptions) then InitTLSProtocolVersion10(FProtocolVersion); - if IsTLS10(FProtocolVersion) and (tlscoDisableTLS10 in FClientOptions) then + if IsTLS10(FProtocolVersion) and not (tlsvoTLS10 in FVersionOptions) then InitSSLProtocolVersion30(FProtocolVersion); - if IsSSL3(FProtocolVersion) and (tlscoDisableSSL3 in FClientOptions) then - raise ETLSAlertError.Create(tlsadProtocol_version); // no allowable protocol version + 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)]); @@ -290,10 +368,11 @@ procedure TTLSClient.InitSessionProtocolVersion; end; procedure TTLSClient.InitClientHelloCipherSuites; -var C : TTLSCipherSuites; - I : TTLSCipherSuite; - P : PTLSCipherSuiteInfo; - R : Boolean; +var + C : TTLSCipherSuites; + I : TTLSCipherSuite; + P : PTLSCipherSuiteInfo; + R : Boolean; begin C := []; for I := Low(I) to High(I) do @@ -301,45 +380,65 @@ procedure TTLSClient.InitClientHelloCipherSuites; P := @TLSCipherSuiteInfo[I]; R := P^.ClientSupport; if R then - if tlscoDisableCipherRC4_128 in FClientOptions then - if P^.Cipher in [tlscscRC4_128] then + if not (tlscoRC4 in FCipherOptions) then + if P^.Cipher in [tlscscRC4_40, tlscscRC4_56, tlscscRC4_128] then R := False; if R then - if tlscoDisableCipherDES in FClientOptions then + if not (tlscoDES in FCipherOptions) then if P^.Cipher in [tlscscDES_CBC] then R := False; if R then - if tlscoDisableCipherAES128 in FClientOptions 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 tlscoDisableCipherAES256 in FClientOptions then + if not (tlscoAES256 in FCipherOptions) then if P^.Cipher in [tlscscAES_256_CBC] then R := False; if R then - if tlscoDisableHashMD5 in FClientOptions then + if not (tlshoMD5 in FHashOptions) then if P^.Hash in [tlscshMD5] then R := False; if R then - if tlscoDisableHashSHA1 in FClientOptions then + if not (tlshoSHA1 in FHashOptions) then if P^.Hash in [tlscshSHA] then R := False; if R then - if tlscoDisableHashSHA256 in FClientOptions then + if not (tlshoSHA256 in FHashOptions) then if P^.Hash in [tlscshSHA256] then R := False; if R then - if tlscoDisableKeyExchangeRSA in FClientOptions 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 tlscoDisableKeyExchangeDH_Anon in FClientOptions then + if not (tlskeoDH_Anon in FKeyExchangeOptions) then if P^.KeyExchange in [tlscskeDH_anon] then R := False; if R then - if tlscoDisableKeyExchangeDH_RSA in FClientOptions 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; @@ -360,47 +459,33 @@ procedure TTLSClient.InitHandshakeClientHello; 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; -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(FServerX509Certs); - for I := 0 to L - 1 do - begin - C := @FServerX509Certs[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 - exit; - N1 := NormaliseX509IntKeyBuf(PKR.Modulus); - N2 := NormaliseX509IntKeyBuf(PKR.PublicExponent); - if N2 > N1 then - N1 := N2; - // initialise RSA public key - RSAPublicKeyAssignBuf(FServerRSAPublicKey, N1 * 8, - PKR.Modulus[1], Length(PKR.Modulus), - PKR.PublicExponent[1], Length(PKR.PublicExponent), True); +begin + GetCertificateRSAPublicKey(FServerX509Certs, + FServerRSAPublicKey); end; procedure TTLSClient.InitHandshakeClientKeyExchange; -var S : RawByteString; +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', [ @@ -416,19 +501,19 @@ procedure TTLSClient.InitHandshakeClientKeyExchange; { 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(FPreMasterSecret, FClientHello.ProtocolVersion); - FPreMasterSecretStr := TLSPreMasterSecretToStr(FPreMasterSecret); + InitTLSPreMasterSecret_Random(PMS, FClientHello.ProtocolVersion); + FPreMasterSecretStr := TLSPreMasterSecretToStr(PMS); InitServerPublicKey_RSA; - InitTLSEncryptedPreMasterSecret_RSA(S, FPreMasterSecret, FServerRSAPublicKey); + InitTLSEncryptedPreMasterSecret_RSA(S, PMS, FServerRSAPublicKey); FClientKeyExchange.EncryptedPreMasterSecret := S; end; tlskeaDHE_DSS, tlskeaDHE_RSA, tlskeaDH_Anon : begin - Assert(Assigned(FDHState)); + //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 } @@ -436,10 +521,47 @@ procedure TTLSClient.InitHandshakeClientKeyExchange; { contain all zero bits are stripped before it is used as the } { pre_master_secret } - FClientKeyExchange.ClientDiffieHellmanPublic.PublicValueEncodingExplicit := True; - FClientKeyExchange.ClientDiffieHellmanPublic.dh_Yc := DHHugeWordKeyEncodeBytes(FDHState^.Y); - - FPreMasterSecretStr := DHHugeWordKeyEncodeBytes(FDHState^.ZZ); + 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 : @@ -489,64 +611,69 @@ procedure TTLSClient.InitHandshakeClientKeyExchange; MaxHandshakeFinishedSize = 2048; procedure TTLSClient.SendHandshakeClientHello; -var B : array[0..MaxHandshakeClientHelloSize - 1] of Byte; - L : Integer; +var + Buf : array[0..MaxHandshakeClientHelloSize - 1] of Byte; + Size : Integer; begin {$IFDEF TLS_DEBUG} Log(tlsltDebug, 'T:Handshake:ClientHello'); {$ENDIF} InitHandshakeClientHello; - L := EncodeTLSHandshakeClientHello(B, SizeOf(B), FClientHello); - SendHandshake(B, L); + Size := EncodeTLSHandshakeClientHello(Buf, SizeOf(Buf), FClientHello); + SendHandshake(Buf, Size); end; procedure TTLSClient.SendHandshakeCertificate; -var B : array[0..MaxHandshakeCertificateSize - 1] of Byte; - L : Integer; +var + Buf : array[0..MaxHandshakeCertificateSize - 1] of Byte; + Size : Integer; begin {$IFDEF TLS_DEBUG} Log(tlsltDebug, 'T:Handshake:Certificate'); {$ENDIF} - L := EncodeTLSHandshakeCertificate(B, SizeOf(B), nil); - SendHandshake(B, L); + Size := EncodeTLSHandshakeCertificate(Buf, SizeOf(Buf), nil); + SendHandshake(Buf, Size); end; procedure TTLSClient.SendHandshakeClientKeyExchange; -var B : array[0..MaxHandshakeClientKeyExchangeSize - 1] of Byte; - L : Integer; +var + Buf : array[0..MaxHandshakeClientKeyExchangeSize - 1] of Byte; + Size : Integer; begin {$IFDEF TLS_DEBUG} Log(tlsltDebug, 'T:Handshake:ClientKeyExchange'); {$ENDIF} InitHandshakeClientKeyExchange; - L := EncodeTLSHandshakeClientKeyExchange( - B, SizeOf(B), + Size := EncodeTLSHandshakeClientKeyExchange( + Buf, SizeOf(Buf), FCipherSpecNew.KeyExchangeAlgorithm, FClientKeyExchange); - SendHandshake(B, L); + SendHandshake(Buf, Size); end; procedure TTLSClient.SendHandshakeCertificateVerify; -var B : array[0..MaxHandshakeCertificateVerifySize - 1] of Byte; - L : Integer; +var + Buf : array[0..MaxHandshakeCertificateVerifySize - 1] of Byte; + Size : Integer; begin - L := EncodeTLSHandshakeCertificateVerify(B, SizeOf(B)); - SendHandshake(B, L); + Size := EncodeTLSHandshakeCertificateVerify(Buf, SizeOf(Buf)); + SendHandshake(Buf, Size); end; procedure TTLSClient.SendHandshakeFinished; -var B : array[0..MaxHandshakeFinishedSize - 1] of Byte; - L : Integer; +var + Buf : array[0..MaxHandshakeFinishedSize - 1] of Byte; + Size : Integer; begin {$IFDEF TLS_DEBUG} Log(tlsltDebug, 'T:Handshake:Finished:%s', [TLSProtocolVersionName(FProtocolVersion)]); {$ENDIF} - L := EncodeTLSHandshakeFinished(B, SizeOf(B), FMasterSecret, FProtocolVersion, FVerifyHandshakeData, True); - SendHandshake(B, L); + Size := EncodeTLSHandshakeFinished(Buf, SizeOf(Buf), FMasterSecret, FProtocolVersion, FVerifyHandshakeData, True); + SendHandshake(Buf, Size); end; procedure TTLSClient.HandleHandshakeHelloRequest(const Buffer; const Size: Integer); @@ -561,7 +688,8 @@ procedure TTLSClient.HandleHandshakeServerHello(const Buffer; const Size: Intege begin if not (FClientState in [tlsclHandshakeAwaitingServerHello]) or not (FConnectionState in [tlscoStart, tlscoHandshaking]) then - raise ETLSAlertError.Create(tlsadUnexpected_message); + raise ETLSError.CreateAlertUnexpectedMessage; + DecodeTLSServerHello(Buffer, Size, FServerHello); FServerProtocolVersion := FServerHello.ProtocolVersion; @@ -572,10 +700,10 @@ procedure TTLSClient.HandleHandshakeServerHello(const Buffer; const Size: Intege FServerHelloRandomStr := TLSRandomToStr(FServerHello.Random); if not IsTLSProtocolVersion(FServerProtocolVersion, FProtocolVersion) then // different protocol version begin - if IsFutureTLSVersion(FServerProtocolVersion) then - raise ETLSAlertError.Create(tlsadProtocol_version); // unsupported future version of TLS + if IsPostTLS12(FServerProtocolVersion) then + raise ETLSError.CreateAlert(TLSError_BadProtocol, tlsadProtocol_version); // unsupported future version of TLS if not IsKnownTLSVersion(FServerProtocolVersion) then - raise ETLSAlertError.Create(tlsadProtocol_version); // unknown past TLS version + raise ETLSError.CreateAlert(TLSError_BadProtocol, tlsadProtocol_version); // unknown past TLS version end; InitSessionProtocolVersion; InitCipherSpecNewFromServerHello; @@ -583,52 +711,67 @@ procedure TTLSClient.HandleHandshakeServerHello(const Buffer; const Size: Intege end; procedure TTLSClient.HandleHandshakeCertificate(const Buffer; const Size: Integer); -var I, L : Integer; - C : RawByteString; begin if FClientState <> tlsclHandshakeAwaitingServerHelloDone then - raise ETLSAlertError.Create(tlsadUnexpected_message); + raise ETLSError.CreateAlertUnexpectedMessage; + DecodeTLSCertificate(Buffer, Size, FServerCertificateList); - L := Length(FServerCertificateList); - SetLength(FServerX509Certs, L); - for I := 0 to L - 1 do - begin - C := FServerCertificateList[I]; - InitX509Certificate(FServerX509Certs[I]); - if C <> '' then - ParseX509Certificate(C[1], Length(C), FServerX509Certs[I]); - end; + ParseX509Certificates(FServerCertificateList, FServerX509Certs); {$IFDEF TLS_DEBUG} - Log(tlsltDebug, 'R:Handshake:Certificate:Count=%d', [L]); + Log(tlsltDebug, 'R:Handshake:Certificate:Count=%d', [Length(FServerX509Certs)]); {$ENDIF} end; procedure TTLSClient.HandleHandshakeServerKeyExchange(const Buffer; const Size: Integer); -var - R : HugeWord; +//var +// R : HugeWord; begin if FClientState <> tlsclHandshakeAwaitingServerHelloDone then - raise ETLSAlertError.Create(tlsadUnexpected_message); + 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.Params.dh_p); - DHHugeWordKeyDecodeBytes(FDHState^.G, FServerKeyExchange.Params.dh_g); + DHHugeWordKeyDecodeBytes(FDHState^.P, FServerKeyExchange.DHParams.dh_p); + DHHugeWordKeyDecodeBytes(FDHState^.G, FServerKeyExchange.DHParams.dh_g); FDHState^.PrimePBitCount := HugeWordGetSizeInBits(FDHState^.P); FDHState^.PrimeQBitCount := DHQBitCount(FDHState^.PrimePBitCount); - DHGeneratePrivateKeyX(FDHState^); - DHGeneratePublicKeyY(FDHState^); + + DHDeriveKeysFromGroupParametersPG(FDHState^, dhhSHA1, + FDHState^.PrimeQBitCount, + FDHState^.PrimePBitCount, + FDHState^.P, + FDHState^.G); HugeWordInit(R); - DHHugeWordKeyDecodeBytes(R, FServerKeyExchange.Params.dh_Ys); + 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; @@ -636,7 +779,8 @@ procedure TTLSClient.HandleHandshakeServerKeyExchange(const Buffer; const Size: procedure TTLSClient.HandleHandshakeCertificateRequest(const Buffer; const Size: Integer); begin if FClientState <> tlsclHandshakeAwaitingServerHelloDone then - raise ETLSAlertError.Create(tlsadUnexpected_message); + raise ETLSError.CreateAlertUnexpectedMessage; + DecodeTLSCertificateRequest(Buffer, Size, FCertificateRequest); FCertificateRequested := True; end; @@ -644,7 +788,8 @@ procedure TTLSClient.HandleHandshakeCertificateRequest(const Buffer; const Size: procedure TTLSClient.HandleHandshakeServerHelloDone(const Buffer; const Size: Integer); begin if FClientState <> tlsclHandshakeAwaitingServerHelloDone then - raise ETLSAlertError.Create(tlsadUnexpected_message); + raise ETLSError.CreateAlertUnexpectedMessage; + SetClientState(tlsclHandshakeClientKeyExchange); if FCertificateRequested then SendHandshakeCertificate; @@ -658,7 +803,8 @@ procedure TTLSClient.HandleHandshakeServerHelloDone(const Buffer; const Size: In procedure TTLSClient.HandleHandshakeFinished(const Buffer; const Size: Integer); begin if FClientState <> tlsclHandshakeClientKeyExchange then - raise ETLSAlertError.Create(tlsadUnexpected_message); + raise ETLSError.CreateAlertUnexpectedMessage; + SetClientState(tlsclConnection); SetConnectionState(tlscoApplicationData); TriggerHandshakeFinished; diff --git a/Source/TLS/flcTLSConnection.pas b/Source/TLS/flcTLSTransportConnection.pas similarity index 91% rename from Source/TLS/flcTLSConnection.pas rename to Source/TLS/flcTLSTransportConnection.pas index 77761f5..50ade8b 100644 --- a/Source/TLS/flcTLSConnection.pas +++ b/Source/TLS/flcTLSTransportConnection.pas @@ -1,11 +1,11 @@ {******************************************************************************} { } { Library: Fundamentals TLS } -{ File name: flcTLSConnection.pas } +{ File name: flcTLSTransportConnection.pas } { File version: 5.06 } -{ Description: TLS connection } +{ Description: TLS Transport Connection } { } -{ Copyright: Copyright (c) 2008-2018, David J Butler } +{ 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 } @@ -45,22 +45,29 @@ {$INCLUDE flcTLS.inc} -unit flcTLSConnection; +unit flcTLSTransportConnection; interface uses - { Fundamentals } + { Utils } + flcStdTypes, - + { TLS } - flcTLSUtils, + + flcTLSErrors, + flcTLSProtocolVersion, + flcTLSAlgorithmTypes, + flcTLSPRF, flcTLSCipherSuite, flcTLSCipher, flcTLSRecord, flcTLSAlert, flcTLSHandshake, - flcTLSBuffer; + flcTLSBuffer, + flcTLSKeys, + flcTLSTransportTypes; @@ -87,20 +94,6 @@ procedure InitTLSSecurityParametersNULL(var A: TTLSSecurityParameters); -{ } -{ TLS alert error } -{ } -type - ETLSAlertError = class(ETLSError) - private - FDescription : TTLSAlertDescription; - public - constructor Create(const Description: TTLSAlertDescription; const TLSError: Integer = TLSError_BadProtocol; const Msg: String = ''); - property Description: TTLSAlertDescription read FDescription; - end; - - - { } { TLS connection } { } @@ -111,18 +104,14 @@ TTLSConnection = class; procedure (const Sender: TTLSConnection; const Buffer; const Size: Integer) of object; TTLSConnectionState = ( - tlscoInit, - tlscoStart, - tlscoHandshaking, - tlscoApplicationData, - tlscoErrorBadProtocol, - tlscoCancelled, - tlscoClosed); - - TTLSLogType = ( - tlsltDebug, - tlsltInfo, - tlsltError); + 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; @@ -137,6 +126,7 @@ TTLSConnection = class FOnAlert : TTLSConnectionAlertEvent; FOnHandshakeFinished : TTLSConnectionNotifyEvent; FConnectionState : TTLSConnectionState; + FConnectionErrorMessage : String; FInBuf : TTLSBuffer; FOutBuf : TTLSBuffer; FProtocolVersion : TTLSProtocolVersion; @@ -214,7 +204,7 @@ TTLSConnection = class procedure ProcessTransportLayerData; public - constructor Create(const TransportLayerSendProc: TTLSConnectionTransportLayerSendProc); + constructor Create(const ATransportLayerSendProc: TTLSConnectionTransportLayerSendProc); destructor Destroy; override; property OnLog: TTLSConnectionLogEvent read FOnLog write FOnLog; @@ -223,6 +213,8 @@ TTLSConnection = class 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; @@ -241,9 +233,16 @@ implementation uses { System } + SysUtils, + { Cipher } - flcCipherUtils; + + flcCipherUtils, + + { TLS } + + flcTLSConsts; @@ -275,27 +274,16 @@ procedure InitTLSSecurityParametersNULL(var A: TTLSSecurityParameters); -{ } -{ TLS alert error } -{ } -constructor ETLSAlertError.Create(const Description: TTLSAlertDescription; const TLSError: Integer; const Msg: String); -begin - FDescription := Description; - inherited Create(TLSError, Msg); -end; - - - { } { TLS connection } { } -constructor TTLSConnection.Create(const TransportLayerSendProc: TTLSConnectionTransportLayerSendProc); +constructor TTLSConnection.Create(const ATransportLayerSendProc: TTLSConnectionTransportLayerSendProc); begin inherited Create; Init; - if not Assigned(TransportLayerSendProc) then + if not Assigned(ATransportLayerSendProc) then raise ETLSError.Create(TLSError_InvalidParameter); - FTransportLayerSendProc := TransportLayerSendProc; + FTransportLayerSendProc := ATransportLayerSendProc; end; procedure TTLSConnection.Init; @@ -479,6 +467,11 @@ procedure TTLSConnection.SendAlert(const Level: TTLSAlertLevel; const Descriptio InitTLSAlert(B, Level, Description); SendContent(tlsctAlert, B, TLSAlertSize); + + if Level = tlsalFatal then + FConnectionErrorMessage := + TLSAlertLevelToStr(Level) + ':' + + TLSAlertDescriptionToStr(Description); end; procedure TTLSConnection.SendAlertCloseNotify; @@ -646,6 +639,11 @@ procedure TTLSConnection.HandleProtocolAlert(const Buffer; const Size: Integer); 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; @@ -672,6 +670,7 @@ procedure TTLSConnection.HandleProtocolAlert(const Buffer; const Size: Integer); tlsadInsufficient_security : HandleAlertSecurityError(Alert^); tlsadUser_canceled : HandleAlertUserCancelled; tlsadNo_renegotiation : HandleAlertNoRenegotiation; + ///// else HandleAlertUnknown(Alert^); end; @@ -699,23 +698,30 @@ procedure TTLSConnection.HandleProtocolHandshake(const Buffer; const Size: Integ MsgType : TTLSHandshakeType; Len : Integer; begin - 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); + 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} + {$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; + 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; @@ -779,8 +785,13 @@ procedure TTLSConnection.ProcessTransportLayerData; ShutdownBadProtocol(tlsadUnexpected_message); end; except - on E : ETLSAlertError do ShutdownBadProtocol(E.FDescription); - else ShutdownBadProtocol(tlsadDecode_error); + 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; @@ -793,6 +804,7 @@ procedure TTLSConnection.ProcessTransportLayerReceivedData(const Buffer; const S TLSBufferAddBuf(FInBuf, Buffer, Size); if IsFinishedState then raise ETLSError.Create(TLSError_InvalidState); // tls session finished + ProcessTransportLayerData; end; @@ -828,8 +840,10 @@ procedure TTLSConnection.Write(const Buffer; const Size: Integer); 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; @@ -837,6 +851,7 @@ procedure TTLSConnection.Close; begin if IsFinishedState then raise ETLSError.Create(TLSError_InvalidState); // not open + DoClose; end; diff --git a/Source/TLS/flcTLSServer.pas b/Source/TLS/flcTLSTransportServer.pas similarity index 70% rename from Source/TLS/flcTLSServer.pas rename to Source/TLS/flcTLSTransportServer.pas index fbc7cd0..68f76e3 100644 --- a/Source/TLS/flcTLSServer.pas +++ b/Source/TLS/flcTLSTransportServer.pas @@ -1,11 +1,11 @@ {******************************************************************************} { } { Library: Fundamentals TLS } -{ File name: flcTLSServer.pas } +{ File name: flcTLSTransportServer.pas } { File version: 5.04 } -{ Description: TLS server } +{ Description: TLS Transport Server } { } -{ Copyright: Copyright (c) 2008-2018, David J Butler } +{ 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 } @@ -38,42 +38,66 @@ { 2010/12/15 0.02 Development. Simple client server test case. } { 2016/01/08 0.03 String changes. } { 2018/07/17 5.04 Revised for Fundamentals 5. } +{ 2020/05/19 5.08 Sign RSA authentication signature for DHE_RSA. } { } -{ Todo: } -{ - Server options for cipher and compression selection. } -{ - SSL3 can only select SHA1 and MD5 hash. } {******************************************************************************} {$INCLUDE flcTLS.inc} -unit flcTLSServer; +unit flcTLSTransportServer; interface uses { System } + SyncObjs, - { Fundamentals } + + { Utils } + flcStdTypes, + { Cipher } + flcCipherRSA, flcCipherDH, + { X509 } + flcX509Certificate, + { PEM } + flcPEM, + { TLS } - flcTLSUtils, + + flcTLSProtocolVersion, + flcTLSAlgorithmTypes, + flcTLSRandom, flcTLSCipherSuite, flcTLSAlert, + flcTLSKeyExchangeParams, + flcTLSCertificate, + flcTLSKeys, flcTLSHandshake, - flcTLSConnection; + flcTLSTransportTypes, + flcTLSTransportConnection; { } { TLS Server } { } +const + DefaultTLSServerOptions = []; + DefaultTLSServerVersionOptions = AllTLSVersionOptions - [tlsvoSSL3]; + DefaultTLSServerKeyExchangeOptions = AllTLSKeyExchangeOptions; + DefaultTLSServerCipherOptions = AllTLSCipherOptions; + DefaultTLSServerHashOptions = AllTLSHashOptions; + + + type TTLSServer = class; @@ -82,7 +106,8 @@ TTLSServer = class; tlsscHandshakeAwaitingClientHello, tlsscHandshakeAwaitingClientKeyExchange, tlsscHandshakeAwaitingFinish, - tlsscConnection); + tlsscConnection + ); TTLSServerClient = class(TTLSConnection) protected @@ -140,7 +165,7 @@ TTLSServerClient = class(TTLSConnection) procedure DoStart; public - constructor Create(const Server: TTLSServer; const UserObj: TObject); + constructor Create(const AServer: TTLSServer; const AUserObj: TObject); destructor Destroy; override; property UserObj: TObject read FUserObj; @@ -148,15 +173,14 @@ TTLSServerClient = class(TTLSConnection) end; TTLSServerOptions = set of ( - tlssoDontUseSSL3, - tlssoDontUseTLS10, - tlssoDontUseTLS11, - tlssoDontUseTLS12); + tlssoNone + ); TTLSServerState = ( tlssInit, tlssActive, - tlssStopped); + tlssStopped + ); TTLSServerTransportLayerSendProc = procedure (Server: TTLSServer; Client: TTLSServerClient; const Buffer; const Size: Integer) of object; TTLSServerNotifyEvent = procedure (Sender: TTLSServer) of object; @@ -171,7 +195,11 @@ TTLSServer = class FOnClientAlert : TTLSServerClientAlertEvent; FOnClientHandshakeFinished : TTLSServerClientEvent; FTransportLayerSendProc : TTLSServerTransportLayerSendProc; - FOptions : TTLSServerOptions; + FServerOptions : TTLSServerOptions; + FVersionOptions : TTLSVersionOptions; + FKeyExchangeOptions : TTLSKeyExchangeOptions; + FCipherOptions : TTLSCipherOptions; + FHashOptions : TTLSHashOptions; FCertificateList : TTLSCertificateList; FPrivateKeyRSA : RawByteString; FPEMFileName : String; @@ -196,14 +224,19 @@ TTLSServer = class procedure CheckNotActive; procedure CheckActive; - procedure SetOptions(const Options: TTLSServerOptions); + procedure SetServerOptions(const AServerOptions: TTLSServerOptions); + procedure SetVersionOptions(const AVersionOptions: TTLSVersionOptions); + procedure SetCipherOptions(const ACipherOptions: TTLSCipherOptions); + procedure SetKeyExchangeOptions(const AKeyExchangeOptions: TTLSKeyExchangeOptions); + procedure SetHashOptions(const AHashOptions: TTLSHashOptions); + procedure SetCertificateList(const List: TTLSCertificateList); - procedure SetPrivateKeyRSA(const PrivateKeyRSA: RawByteString); + procedure SetPrivateKeyRSA(const APrivateKeyRSA: RawByteString); function GetPrivateKeyRSAPEM: RawByteString; - procedure SetPrivateKeyRSAPEM(const PrivateKeyRSAPEM: RawByteString); - procedure SetPEMFileName(const PEMFileName: String); - procedure SetPEMText(const PEMText: RawByteString); - procedure SetDHKeySize(const DHKeySize: Integer); + procedure SetPrivateKeyRSAPEM(const APrivateKeyRSAPEM: RawByteString); + procedure SetPEMFileName(const APEMFileName: String); + procedure SetPEMText(const APEMText: RawByteString); + procedure SetDHKeySize(const ADHKeySize: Integer); procedure ClientLog(const Client: TTLSServerClient; const LogType: TTLSLogType; const LogMsg: String; const LogLevel: Integer); procedure ClientStateChange(const Client: TTLSServerClient); @@ -225,7 +258,7 @@ TTLSServer = class procedure DoStop; public - constructor Create(const TransportLayerSendProc: TTLSServerTransportLayerSendProc); + constructor Create(const ATransportLayerSendProc: TTLSServerTransportLayerSendProc); destructor Destroy; override; property OnLog: TTLSServerLogEvent read FOnLog write FOnLog; @@ -233,7 +266,12 @@ TTLSServer = class property OnClientStateChange: TTLSServerClientEvent read FOnClientStateChange write FOnClientStateChange; property OnClientHandshakeFinished: TTLSServerClientEvent read FOnClientHandshakeFinished write FOnClientHandshakeFinished; - property Options: TTLSServerOptions read FOptions write SetOptions; + property ServerOptions: TTLSServerOptions read FServerOptions write SetServerOptions default DefaultTLSServerOptions; + property VersionOptions: TTLSVersionOptions read FVersionOptions write SetVersionOptions default DefaultTLSServerVersionOptions; + property KeyExchangeOptions: TTLSKeyExchangeOptions read FKeyExchangeOptions write SetKeyExchangeOptions default DefaultTLSServerKeyExchangeOptions; + property CipherOptions: TTLSCipherOptions read FCipherOptions write SetCipherOptions default DefaultTLSServerCipherOptions; + property HashOptions: TTLSHashOptions read FHashOptions write SetHashOptions default DefaultTLSServerHashOptions; + property CertificateList: TTLSCertificateList read FCertificateList write SetCertificateList; property PrivateKeyRSA: RawByteString read FPrivateKeyRSA write SetPrivateKeyRSA; property PrivateKeyRSAPEM: RawByteString read GetPrivateKeyRSAPEM write SetPrivateKeyRSAPEM; @@ -250,7 +288,9 @@ TTLSServer = class function AddClient(const UserObj: TObject): TTLSServerClient; procedure RemoveClient(const Client: TTLSServerClient); - procedure ProcessTransportLayerReceivedData(const Client: TTLSServerClient; const Buffer; const Size: Integer); + procedure ProcessTransportLayerReceivedData( + const AClient: TTLSServerClient; + const Buffer; const Size: Integer); end; @@ -260,13 +300,18 @@ implementation uses { System } SysUtils, + { Utils } flcBase64, flcHugeInt, + { Cipher } flcCipherUtils, flcCipherRandom, + { TLS } + flcTLSErrors, + flcTLSSessionID, flcTLSCipher; @@ -274,12 +319,12 @@ implementation { } { TLS Server Client } { } -constructor TTLSServerClient.Create(const Server: TTLSServer; const UserObj: TObject); +constructor TTLSServerClient.Create(const AServer: TTLSServer; const AUserObj: TObject); begin - Assert(Assigned(Server)); + Assert(Assigned(AServer)); inherited Create(TransportLayerSendProc); - FServer := Server; - FUserObj := UserObj; + FServer := AServer; + FUserObj := AUserObj; end; destructor TTLSServerClient.Destroy; @@ -333,8 +378,9 @@ procedure TTLSServerClient.SelectCompression(var Compression: TTLSCompressionMet end; procedure TTLSServerClient.SelectCipherSuite(var CipherSuite: TTLSCipherSuite); -var I : TTLSCipherSuite; - C : PTLSCipherSuiteInfo; +var + I : TTLSCipherSuite; + C : PTLSCipherSuiteInfo; begin for I := High(TTLSCipherSuite) downto Low(TTLSCipherSuite) do if (I <> tlscsNone) and (I in FClientHello.CipherSuites) then @@ -354,18 +400,52 @@ procedure TTLSServerClient.InitDHState; New(FDHState); DHStateInit(FDHState^); - DHGenerateKeys(FDHState^, dhhSHA1, DHQBitCount(FServer.FDHKeySize), FServer.FDHKeySize); + (* + P = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF' + G = '00000002' + *) + +{ HugeWordToHexB(FDHState^.Q); + HugeWordToHexB(FDHState^.X); + HugeWordToHexB(FDHState^.Y); +} + +(* + DHInitHashAlgorithm(FDHState^, dhhSHA1); + + HexToHugeWordB('FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF', + FDHState^.P); + HexToHugeWordB('00000002', FDHState^.G); + + HexToHugeWordB('AF2FCC0B5ADD8F623266378ADBF72664D5913FFF', FDHState^.Q); + HexToHugeWordB('8E62C571E6ECCC720CF65E432FA779BE56EFAB46', FDHState^.X); + HexToHugeWordB('A37CCB97CAB7AC5C3C2B59FC7C33007B2CDD9FA6C616D8BA4A202EC901FE5F37F790295D5DAA990E22121C154B78E2201B36AB4A8944E61D34ADA541221653B49E432B782A5A59806E87ADBCC57033385FB9197CEC137170DD80466D82F431BA', + FDHState^.Y); + + FDHState^.PrimePBitCount := DHWellKnownGroup[0].PBitCount; + FDHState^.PrimeQBitCount := DHWellKnownGroup[0].QBitCount; +*) + + //DHGenerateKeys(FDHState^, dhhSHA1, DHQBitCount(FServer.FDHKeySize), FServer.FDHKeySize); + //// Use well known pairs + //// x/prikey is a random nr + + HexToHugeWordB(DHWellKnownGroup[0].P_Hex, FDHState^.P); + HexToHugeWordB(DHWellKnownGroup[0].G_Hex, FDHState^.G); + DHDeriveKeysFromGroupParametersPG( + FDHState^, dhhSHA1, DHWellKnownGroup[0].QBitCount, DHWellKnownGroup[0].PBitCount, + FDHState^.P, FDHState^.G); end; procedure TTLSServerClient.InitProtocolVersion; begin FProtocolVersion := FClientHello.ProtocolVersion; if IsSSL2(FProtocolVersion) then - raise ETLSAlertError.Create(tlsadProtocol_version); // SSL2 not supported - if IsFutureTLSVersion(FProtocolVersion) then + raise ETLSError.CreateAlertBadProtocolVersion; // SSL2 not supported + if IsPostTLS12(FProtocolVersion) then FProtocolVersion := TLSProtocolVersion12; if not IsKnownTLSVersion(FProtocolVersion) then - raise ETLSAlertError.Create(tlsadProtocol_version); // unknown SSL version + raise ETLSError.CreateAlertBadProtocolVersion; // unknown SSL version end; procedure TTLSServerClient.InitHandshakeServerHello; @@ -375,6 +455,12 @@ procedure TTLSServerClient.InitHandshakeServerHello; FSessionID, FCipherSpecNew.CipherSuiteDetails.CipherSuiteInfo^.Rec, FCompression); + + {$IFDEF TLS_TEST_NO_RANDOM_HELLO} + FClientHello.Random.gmt_unix_time := 123; + FillChar(FServerHello.Random.random_bytes, 28, 117); + {$ENDIF} + FServerHelloRandomStr := TLSRandomToStr(FServerHello.Random); end; @@ -388,10 +474,18 @@ procedure TTLSServerClient.InitHandshakeServerKeyExchange; tlskeaDH_Anon : begin InitDHState; - InitTLSServerDHParams(FServerKeyExchange.Params, + + AssignTLSServerKeyExchangeDHParams( + FServerKeyExchange, DHHugeWordKeyEncodeBytes(FDHState^.P), DHHugeWordKeyEncodeBytes(FDHState^.G), - DHHugeWordKeyEncodeBytes(FDHState^.Y)); + DHHugeWordKeyEncodeBytes(FDHState^.Y)); ///////// + + SignTLSServerKeyExchangeDH_RSA( + FServerKeyExchange, + PTLSClientServerRandom(@FClientHello.Random)^, + PTLSClientServerRandom(@FServerHello.Random)^, + FServer.FRSAPrivateKey); end; end; end; @@ -406,69 +500,76 @@ procedure TTLSServerClient.InitHandshakeServerKeyExchange; MaxHandshakeFinishedSize = 2048; procedure TTLSServerClient.SendHandshakeHelloRequest; -var B : array[0..MaxHandshakeHelloRequestSize - 1] of Byte; - L : Integer; +var + Buf : array[0..MaxHandshakeHelloRequestSize - 1] of Byte; + Size : Integer; begin - L := EncodeTLSHandshakeHelloRequest(B, SizeOf(B)); - SendHandshake(B, L); + Size := EncodeTLSHandshakeHelloRequest(Buf, SizeOf(Buf)); + SendHandshake(Buf, Size); end; procedure TTLSServerClient.SendHandshakeServerHello; -var B : array[0..MaxHandshakeServerHelloSize - 1] of Byte; - L : Integer; +var + Buf : array[0..MaxHandshakeServerHelloSize - 1] of Byte; + Size : Integer; begin InitHandshakeServerHello; - L := EncodeTLSHandshakeServerHello(B, SizeOf(B), FServerHello); - SendHandshake(B, L); + Size := EncodeTLSHandshakeServerHello(Buf, SizeOf(Buf), FServerHello); + SendHandshake(Buf, Size); end; procedure TTLSServerClient.SendHandshakeCertificate; -var B : array[0..MaxHandshakeCertificateSize - 1] of Byte; - L : Integer; +var + Buf : array[0..MaxHandshakeCertificateSize - 1] of Byte; + Size : Integer; begin - L := EncodeTLSHandshakeCertificate(B, SizeOf(B), FServer.FCertificateList); - SendHandshake(B, L); + Size := EncodeTLSHandshakeCertificate(Buf, SizeOf(Buf), FServer.FCertificateList); + SendHandshake(Buf, Size); end; procedure TTLSServerClient.SendHandshakeServerKeyExchange; -var B : array[0..MaxHandshakeServerKeyExchangeSize - 1] of Byte; - L : Integer; +var + Buf : array[0..MaxHandshakeServerKeyExchangeSize - 1] of Byte; + Size : Integer; begin InitHandshakeServerKeyExchange; - L := EncodeTLSHandshakeServerKeyExchange(B, SizeOf(B), + Size := EncodeTLSHandshakeServerKeyExchange(Buf, SizeOf(Buf), FCipherSpecNew.KeyExchangeAlgorithm, FServerKeyExchange); - SendHandshake(B, L); + SendHandshake(Buf, Size); end; procedure TTLSServerClient.SendHandshakeCertificateRequest; -var B : array[0..MaxHandshakeCertificateRequestSize - 1] of Byte; - L : Integer; - R : TTLSCertificateRequest; +var + Buf : array[0..MaxHandshakeCertificateRequestSize - 1] of Byte; + Size : Integer; + CReq : TTLSCertificateRequest; begin - L := EncodeTLSHandshakeCertificateRequest(B, SizeOf(B), R); - SendHandshake(B, L); + Size := EncodeTLSHandshakeCertificateRequest(Buf, SizeOf(Buf), CReq); + SendHandshake(Buf, Size); end; procedure TTLSServerClient.SendHandshakeServerHelloDone; -var B : array[0..MaxHandshakeServerHelloDoneSize - 1] of Byte; - L : Integer; +var + Buf : array[0..MaxHandshakeServerHelloDoneSize - 1] of Byte; + Size : Integer; begin - L := EncodeTLSHandshakeServerHelloDone(B, SizeOf(B)); - SendHandshake(B, L); + Size := EncodeTLSHandshakeServerHelloDone(Buf, SizeOf(Buf)); + SendHandshake(Buf, Size); end; procedure TTLSServerClient.SendHandshakeFinished; -var B : array[0..MaxHandshakeFinishedSize - 1] of Byte; - L : Integer; +var + Buf : array[0..MaxHandshakeFinishedSize - 1] of Byte; + Size : Integer; begin - L := EncodeTLSHandshakeFinished(B, SizeOf(B), FMasterSecret, FProtocolVersion, FVerifyHandshakeData, False); - SendHandshake(B, L); + Size := EncodeTLSHandshakeFinished(Buf, SizeOf(Buf), FMasterSecret, FProtocolVersion, FVerifyHandshakeData, False); + SendHandshake(Buf, Size); end; procedure TTLSServerClient.HandleHandshakeClientHello(const Buffer; const Size: Integer); begin if FClientState <> tlsscHandshakeAwaitingClientHello then - raise ETLSAlertError.Create(tlsadUnexpected_message); + raise ETLSError.CreateAlertUnexpectedMessage; DecodeTLSClientHello(Buffer, Size, FClientHello); FClientHelloRandomStr := TLSRandomToStr(FClientHello.Random); @@ -487,28 +588,45 @@ procedure TTLSServerClient.HandleHandshakeClientHello(const Buffer; const Size: Log(tlsltDebug, 'CipherSuite:%s', [TLSCipherSuiteInfo[FCipherSuite].Name]); {$ENDIF} if FCipherSuite = tlscsNone then - raise ETLSAlertError.Create(tlsadHandshake_failure); + raise ETLSError.CreateAlert(TLSError_BadProtocol, tlsadHandshake_failure); InitTLSSecurityParameters(FCipherSpecNew, FCompression, FCipherSuite); SetClientState(tlsscHandshakeAwaitingClientKeyExchange); SendHandshakeServerHello; SendHandshakeCertificate; - SendHandshakeServerKeyExchange; + + { The ServerKeyExchange message is sent by the server only when the ServerCertificate message (if sent) } + { does not contain enough data to allow the user-agent to exchange a premaster secret. } + { This is true for the following key exchange methods: } + { RSA_EXPORT (if the public key in the server certificate is longer than 512 bits) } + { DHE_DSS, DHE_DSS_EXPORT, DHE_RSA, DHE_RSA_EXPORT, DH_anon } + { It is not legal to send the server key exchange message for the following key exchange methods: } + { RSA, DH_DSS, DH_RSA, } + { RSA_EXPORT (when the public key in the server certificate is less than or equal to 512 bits in length) } + { Additionally, a ServerKeyExchange message may be sent, if it is required (e.g., if the server has no } + { certificate, or if its certificate is for signing only). If the server is authenticated, it may } + { request a certificate from the client. } + + if FCipherSpecNew.KeyExchangeAlgorithm in [tlskeaDHE_DSS, tlskeaDHE_RSA, tlskeaDH_Anon] then + SendHandshakeServerKeyExchange; + SendHandshakeServerHelloDone; end; procedure TTLSServerClient.HandleHandshakeCertificateVerify(const Buffer; const Size: Integer); begin if FClientState <> tlsscHandshakeAwaitingClientKeyExchange then - raise ETLSAlertError.Create(tlsadUnexpected_message); + raise ETLSError.CreateAlertUnexpectedMessage; end; procedure TTLSServerClient.HandleHandshakeClientKeyExchange(const Buffer; const Size: Integer); -var R : HugeWord; +var + Yc : HugeWord; + ZZ : HugeWord; begin if FClientState <> tlsscHandshakeAwaitingClientKeyExchange then - raise ETLSAlertError.Create(tlsadUnexpected_message); + raise ETLSError.CreateAlertUnexpectedMessage; DecodeTLSClientKeyExchange(Buffer, Size, FCipherSpecNew.KeyExchangeAlgorithm, @@ -526,7 +644,7 @@ procedure TTLSServerClient.HandleHandshakeClientKeyExchange(const Buffer; const { private key to decrypt the pre_master_secret. Both parties then } { convert the pre_master_secret into the master_secret, as specified above. } - FPreMasterSecret := RSADecryptStr(rsaetPKCS1, FServer.FRSAPrivateKey, + FPreMasterSecret := RSADecryptStr(rsaetRSAES_PKCS1, FServer.FRSAPrivateKey, FClientKeyExchange.EncryptedPreMasterSecret); end; tlskeaDHE_DSS, @@ -541,15 +659,18 @@ procedure TTLSServerClient.HandleHandshakeClientKeyExchange(const Buffer; const { contain all zero bits are stripped before it is used as the } { pre_master_secret } - HugeWordInit(R); - DHHugeWordKeyDecodeBytes(R, FClientKeyExchange.ClientDiffieHellmanPublic.dh_Yc); - DHGenerateSharedSecretZZ(FDHState^, HugeWordGetSizeInBits(R), R); - HugeWordFinalise(R); + HugeWordInit(Yc); + HugeWordInit(ZZ); + DHHugeWordKeyDecodeBytes(Yc, FClientKeyExchange.ClientDiffieHellmanPublic.dh_Yc); + HugeWordPowerAndMod(ZZ, Yc, FDHState^.X, FDHState^.P); + + FPreMasterSecret := DHHugeWordKeyEncodeBytes(ZZ); - FPreMasterSecret := DHHugeWordKeyEncodeBytes(FDHState^.ZZ); + HugeWordFinalise(ZZ); + HugeWordFinalise(Yc); end; else - raise ETLSAlertError.Create(tlsadHandshake_failure); + raise ETLSError.CreateAlert(TLSError_BadProtocol, tlsadHandshake_failure); end; case FCipherSpecNew.KeyExchangeAlgorithm of @@ -589,7 +710,7 @@ procedure TTLSServerClient.HandleHandshakeClientKeyExchange(const Buffer; const procedure TTLSServerClient.HandleHandshakeFinished(const Buffer; const Size: Integer); begin if FClientState <> tlsscHandshakeAwaitingFinish then - raise ETLSAlertError.Create(tlsadUnexpected_message); + raise ETLSError.CreateAlertUnexpectedMessage; SendChangeCipherSpec; ChangeEncryptCipherSpec; @@ -650,18 +771,23 @@ procedure TTLSServerClient.Start; { } { TLS Server } { } -constructor TTLSServer.Create(const TransportLayerSendProc: TTLSServerTransportLayerSendProc); +constructor TTLSServer.Create(const ATransportLayerSendProc: TTLSServerTransportLayerSendProc); begin inherited Create; Init; - if not Assigned(TransportLayerSendProc) then + if not Assigned(ATransportLayerSendProc) then raise ETLSError.Create(TLSError_InvalidParameter); - FTransportLayerSendProc := TransportLayerSendProc; + FTransportLayerSendProc := ATransportLayerSendProc; end; procedure TTLSServer.Init; begin - FOptions := []; + FServerOptions := DefaultTLSServerOptions; + FVersionOptions := DefaultTLSServerVersionOptions; + FKeyExchangeOptions := DefaultTLSServerKeyExchangeOptions; + FCipherOptions := DefaultTLSServerCipherOptions; + FHashOptions := DefaultTLSServerHashOptions; + FState := tlssInit; FLock := TCriticalSection.Create; RSAPrivateKeyInit(FRSAPrivateKey); @@ -712,12 +838,52 @@ procedure TTLSServer.CheckActive; raise ETLSError.Create(TLSError_InvalidState, 'Operation not allowed while not active'); end; -procedure TTLSServer.SetOptions(const Options: TTLSServerOptions); +procedure TTLSServer.SetServerOptions(const AServerOptions: TTLSServerOptions); +begin + if AServerOptions = FServerOptions then + exit; + CheckNotActive; + FServerOptions := AServerOptions; +end; + +procedure TTLSServer.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 TTLSServer.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 TTLSServer.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 TTLSServer.SetHashOptions(const AHashOptions: TTLSHashOptions); begin - if Options = FOptions then + if AHashOptions = FHashOptions then exit; CheckNotActive; - FOptions := Options; + if AHashOptions = [] then + raise ETLSError.Create(TLSError_InvalidParameter, 'Invalid hash options'); + FHashOptions := AHashOptions; end; procedure TTLSServer.SetCertificateList(const List: TTLSCertificateList); @@ -726,12 +892,12 @@ procedure TTLSServer.SetCertificateList(const List: TTLSCertificateList); FCertificateList := Copy(List); end; -procedure TTLSServer.SetPrivateKeyRSA(const PrivateKeyRSA: RawByteString); +procedure TTLSServer.SetPrivateKeyRSA(const APrivateKeyRSA: RawByteString); begin - if PrivateKeyRSA = FPrivateKeyRSA then + if APrivateKeyRSA = FPrivateKeyRSA then exit; CheckNotActive; - FPrivateKeyRSA := PrivateKeyRSA; + FPrivateKeyRSA := APrivateKeyRSA; end; function TTLSServer.GetPrivateKeyRSAPEM: RawByteString; @@ -739,33 +905,33 @@ function TTLSServer.GetPrivateKeyRSAPEM: RawByteString; Result := MIMEBase64Encode(PrivateKeyRSA); end; -procedure TTLSServer.SetPrivateKeyRSAPEM(const PrivateKeyRSAPEM: RawByteString); +procedure TTLSServer.SetPrivateKeyRSAPEM(const APrivateKeyRSAPEM: RawByteString); begin - SetPrivateKeyRSA(MIMEBase64Decode(PrivateKeyRSAPEM)); + SetPrivateKeyRSA(MIMEBase64Decode(APrivateKeyRSAPEM)); end; -procedure TTLSServer.SetPEMFileName(const PEMFileName: String); +procedure TTLSServer.SetPEMFileName(const APEMFileName: String); begin - if PEMFileName = FPEMFileName then + if APEMFileName = FPEMFileName then exit; CheckNotActive; - FPEMFileName := PEMFileName; + FPEMFileName := APEMFileName; end; -procedure TTLSServer.SetPEMText(const PEMText: RawByteString); +procedure TTLSServer.SetPEMText(const APEMText: RawByteString); begin - if PEMText = FPEMText then + if APEMText = FPEMText then exit; CheckNotActive; - FPEMText := PEMText; + FPEMText := APEMText; end; -procedure TTLSServer.SetDHKeySize(const DHKeySize: Integer); +procedure TTLSServer.SetDHKeySize(const ADHKeySize: Integer); begin - if DHKeySize = FDHKeySize then + if ADHKeySize = FDHKeySize then exit; CheckNotActive; - FDHKeySize := DHKeySize; + FDHKeySize := ADHKeySize; end; procedure TTLSServer.ClientLog(const Client: TTLSServerClient; const LogType: TTLSLogType; const LogMsg: String; const LogLevel: Integer); @@ -866,11 +1032,11 @@ procedure TTLSServer.ClientTransportLayerSend(const Sender: TTLSServerClient; co FTransportLayerSendProc(self, Sender, Buffer, Size); end; -procedure TTLSServer.ProcessTransportLayerReceivedData(const Client: TTLSServerClient; const Buffer; const Size: Integer); +procedure TTLSServer.ProcessTransportLayerReceivedData(const AClient: TTLSServerClient; const Buffer; const Size: Integer); begin - if not Assigned(Client) then + if not Assigned(AClient) then raise ETLSError.Create(TLSError_InvalidParameter); - Client.ProcessTransportLayerReceivedData(Buffer, Size); + AClient.ProcessTransportLayerReceivedData(Buffer, Size); end; procedure TTLSServer.InitFromPEM; diff --git a/Source/TLS/flcTLSTransportTypes.pas b/Source/TLS/flcTLSTransportTypes.pas new file mode 100644 index 0000000..088b10b --- /dev/null +++ b/Source/TLS/flcTLSTransportTypes.pas @@ -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. + diff --git a/Source/TLS/flcTLSUtils.pas b/Source/TLS/flcTLSUtils.pas deleted file mode 100644 index 3963a2f..0000000 --- a/Source/TLS/flcTLSUtils.pas +++ /dev/null @@ -1,1249 +0,0 @@ -{******************************************************************************} -{ } -{ Library: Fundamentals TLS } -{ File name: flcTLSUtils.pas } -{ File version: 5.05 } -{ Description: TLS utilities } -{ } -{ 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. } -{ 2011/10/13 0.03 Fix SSL3 keyblock. } -{ 2016/01/07 0.04 String changes. } -{ 2018/07/17 5.05 Revised for Fundamentals 5. } -{ } -{******************************************************************************} - -{$INCLUDE flcTLS.inc} - -unit flcTLSUtils; - -interface - -uses - { System } - SysUtils, - { Fundamentals } - flcStdTypes; - - - -{ } -{ TLS library } -{ } -const - TLSLibraryVersion = '1.00'; - - - -{ } -{ 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; - public - constructor Create(const TLSError: Integer; const Msg: String = ''); - property TLSError: Integer read FTLSError; - end; - - - -{ } -{ 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); - -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 IsTLS10OrLater(const A: TTLSProtocolVersion): Boolean; -function IsTLS11OrLater(const A: TTLSProtocolVersion): Boolean; -function IsTLS12OrLater(const A: TTLSProtocolVersion): Boolean; -function IsFutureTLSVersion(const A: TTLSProtocolVersion): Boolean; -function IsKnownTLSVersion(const A: TTLSProtocolVersion): Boolean; -function TLSProtocolVersionToStr(const A: TTLSProtocolVersion): String; -function TLSProtocolVersionName(const A: TTLSProtocolVersion): String; - - - -{ } -{ CompressionMethod } -{ } -type - TTLSCompressionMethod = ( - tlscmNull = 0, - tlscmDeflate = 1, - tlscmMax = 255); - PTLSCompressionMethod = ^TTLSCompressionMethod; - - TTLSCompressionMethods = set of TTLSCompressionMethod; - -const - TLSCompressionMethodSize = Sizeof(TTLSCompressionMethod); - - - -{ } -{ 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; - - - -{ } -{ 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; - - - -{ } -{ HashAlgorithm } -{ } -type - TTLSHashAlgorithm = ( - tlshaNone = 0, - tlshaMD5 = 1, - tlshaSHA1 = 2, - tlshaSHA224 = 3, - tlshaSHA256 = 4, - tlshaSHA384 = 5, - tlshaSHA512 = 6, - tlshaMax = 255); - TTLSHashAlgorithms = set of TTLSHashAlgorithm; - - - -{ } -{ SignatureAlgorithm } -{ } -type - TTLSSignatureAlgorithm = ( - tlssaAnonymous = 0, - 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); - - - - { } - { KeyExchangeAlgorithm } -{ } -type - TTLSKeyExchangeAlgorithm = ( - tlskeaNone, - tlskeaNULL, - tlskeaDHE_DSS, - tlskeaDHE_RSA, - tlskeaDH_Anon, - tlskeaRSA, - tlskeaDH_DSS, - tlskeaDH_RSA); - - TTLSKeyExchangeMethod = ( - tlskemNone, - tlskemNULL, - tlskemDHE, - tlskemDH_Anon, - tlskemRSA, - tlskemDH); - - TTLSKeyExchangeCertificateKeyType = ( - tlskecktNone, - tlskecktDSS, - tlskecktRSA); - - TTLSKeyExchangeAlgorithmInfo = record - Name : RawByteString; - Method : TTLSKeyExchangeMethod; - KeyType : TTLSKeyExchangeCertificateKeyType; - Supported : Boolean; // Not used - end; - PTLSKeyExchangeAlgorithmInfo = ^TTLSKeyExchangeAlgorithmInfo; - -const - TLSKeyExchangeAlgorithmInfo: array[TTLSKeyExchangeAlgorithm] of TTLSKeyExchangeAlgorithmInfo = ( - ( // None - Name : ''; - Method : tlskemNone; - KeyType : tlskecktNone; - Supported : False; - ), - ( // NULL - Name : 'NULL'; - Method : tlskemNULL; - KeyType : tlskecktNone; - Supported : True; - ), - ( // DHE_DSS - Name : 'DHE_DSS'; - Method : tlskemDHE; - KeyType : tlskecktDSS; - Supported : False; - ), - ( // DHE_RSA - Name : 'DHE_RSA'; - Method : tlskemDHE; - KeyType : tlskecktRSA; - Supported : False; - ), - ( // DH_Anon - Name : 'DH_Anon'; - Method : tlskemDH_Anon; - KeyType : tlskecktNone; - Supported : False; - ), - ( // RSA - Name : 'RSA'; - Method : tlskemRSA; - KeyType : tlskecktRSA; - Supported : True; - ), - ( // DH_DSS - Name : 'DH_DSS'; - Method : tlskemDH; - KeyType : tlskecktDSS; - Supported : False; - ), - ( // DH_RSA - Name : 'DH_RSA'; - Method : tlskemDH; - KeyType : tlskecktRSA; - Supported : False; - ) - ); - - - -{ } -{ MACAlgorithm } -{ } -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; - - - - { } -{ 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; - - - -{ } -{ 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); - - - -{ } -{ TLS Limits } -{ } -const - TLS_PLAINTEXT_FRAGMENT_MAXSIZE = 16384 - 1; // 2^14 - 1 - TLS_COMPRESSED_FRAGMENT_MAXSIZE = 16384 + 1024; // 2^14 + 1024 - - - -{ } -{ Unit test } -{ } -{$IFDEF TLS_TEST} - procedure Test; - {$ENDIF} - - - - implementation - -uses - { Fundamentals } - flcStrings, - flcHash, - flcCipherRandom; - - - -{ } -{ 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 TLSError: Integer; const Msg: String); -var S : String; -begin - FTLSError := TLSError; - if Msg = '' then - S := TLSErrorMessage(TLSError) - else - S := Msg; - inherited Create(S); -end; - - - -{ } -{ 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 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 IsFutureTLSVersion(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 := - (A.major = 3) and - (A.minor <= 3); -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 - Result := '[TLS' + TLSProtocolVersionToStr(A) + ']'; -end; - - - -{ } -{ 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, 28); -end; - - function TLSRandomToStr(const Random: TTLSRandom): RawByteString; - begin - SetLength(Result, TLSRandomSize); - Move(Random, Result[1], TLSRandomSize); - end; - - - - { } - { 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.Create(TLSError_InvalidBuffer); - 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.Create(TLSError_InvalidBuffer); - P := @Buffer; - L := P^; - if L = 0 then - begin - SessionID.Len := 0; - Result := 1; - end - else - begin - if Size < 1 + L then - raise ETLSError.Create(TLSError_InvalidBuffer); - if L > TLSSessionIDMaxLen then - raise ETLSError.Create(TLSError_DecodeError); // invalid length - SessionID.Len := L; - Inc(P); - Move(P^, SessionID.Data[0], L); - Result := 1 + L; - end; -end; - - - - { } - { 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_(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; - - - -{ } -{ 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; - - - -{ } -{ Unit test } -{ } -{$IFDEF TLS_TEST} -{$ASSERTIONS ON} -procedure TestProtocolVersion; -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'); - Assert(TLSProtocolVersionName(TLSProtocolVersion11) = 'TLS1.1'); - Assert(TLSProtocolVersionName(TLSProtocolVersion12) = 'TLS1.2'); - end; - - procedure TestPRF; -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 + - #$40#$d4#$d8#$98); -end; - -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 - // // - // Example from http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/ReadDebug.html // - // // - Assert(tls10MasterSecret(PreMasterSecret, ClientRandom, ServerRandom) = MasterSecret); - S := tls10KeyBlock(MasterSecret, ServerRandom, ClientRandom, 64); - Assert(Copy(S, 1, 48) = - MACWriteKey + - #$1E#$4D#$D1#$D3#$0A#$78#$EE#$B7#$4F#$EC#$15#$79#$B2#$59#$18#$40 + - #$10#$D0#$D6#$C2#$D9#$B7#$62#$CB#$2C#$74#$BF#$5F#$85#$3C#$6F#$E7); -end; - -procedure Test; - begin - Assert(TLSCompressionMethodSize = 1); - Assert(TLSRandomSize = 32); - - TestProtocolVersion; - TestPRF; - TestKeyBlock; - end; - {$ENDIF} - - - -end. -