diff --git a/tlslite/handshakesettings.py b/tlslite/handshakesettings.py index 38e560a2..ea0bbc0b 100644 --- a/tlslite/handshakesettings.py +++ b/tlslite/handshakesettings.py @@ -396,6 +396,11 @@ def _init_misc_extensions(self): # resumed connections (as tickets are single-use in TLS 1.3 self.ticket_count = 2 self.record_size_limit = 2**14 + 1 # TLS 1.3 includes content type + # data needed for the signature algorithms cert extension + self.more_sig_schemes_cert = list(SIGNATURE_SCHEMES) + self.ecdsa_sig_hashes_cert = list(ECDSA_SIGNATURE_HASHES) + self.rsa_sig_hashes_cert = list(RSA_SIGNATURE_HASHES) + self.rsa_sig_schemes_cert = list(RSA_SCHEMES) def __init__(self): """Initialise default values for settings.""" @@ -675,6 +680,11 @@ def _copy_extension_settings(self, other): other.max_early_data = self.max_early_data other.ticket_count = self.ticket_count other.record_size_limit = self.record_size_limit + # signature algorithms cert + other.more_sig_schemes_cert = self.more_sig_schemes_cert + other.ecdsa_sig_hashes_cert = self.ecdsa_sig_hashes_cert + other.rsa_sig_hashes_cert = self.rsa_sig_hashes_cert + other.rsa_sig_schemes_cert = self.rsa_sig_schemes_cert @staticmethod def _remove_all_matches(values, needle): diff --git a/tlslite/tlsconnection.py b/tlslite/tlsconnection.py index 582097a7..38e12ae1 100644 --- a/tlslite/tlsconnection.py +++ b/tlslite/tlsconnection.py @@ -2830,9 +2830,15 @@ def _serverTLS13Handshake(self, settings, clientHello, cipherSuite, cr_settings.dsaSigHashes = [] valid_sig_algs = self._sigHashesToList(cr_settings) assert valid_sig_algs - + valid_sig_algs_cert = self._sigHashesToList(cr_settings, + sig_algs_cert=True) certificate_request = CertificateRequest(self.version) certificate_request.create(context=ctx, sig_algs=valid_sig_algs) + # if there is no difference the extension can be omitted + if set(valid_sig_algs_cert) != set(valid_sig_algs): + sig_algs_cert_ext = SignatureAlgorithmsCertExtension() + sig_algs_cert_ext.create(valid_sig_algs_cert) + certificate_request.addExtension(sig_algs_cert_ext) self._queue_message(certificate_request) certificate = Certificate(CertificateType.x509, self.version) @@ -4668,7 +4674,7 @@ def _pickServerKeyExchangeSig(settings, clientHello, certList=None, @staticmethod def _sigHashesToList(settings, privateKey=None, certList=None, - version=(3, 3)): + version=(3, 3), sig_algs_cert=False): """Convert list of valid signature hashes to array of tuples""" certType = None publicKey = None @@ -4679,7 +4685,9 @@ def _sigHashesToList(settings, privateKey=None, certList=None, sigAlgs = [] if not certType or certType == "Ed25519" or certType == "Ed448": - for sig_scheme in settings.more_sig_schemes: + sig_schemes = settings.more_sig_schemes if not sig_algs_cert else \ + settings.more_sig_schemes_cert + for sig_scheme in sig_schemes: if version < (3, 3): # EdDSA is supported only in TLS 1.2 and 1.3 continue @@ -4688,9 +4696,11 @@ def _sigHashesToList(settings, privateKey=None, certList=None, sigAlgs.append(getattr(SignatureScheme, sig_scheme.lower())) if not certType or certType == "ecdsa": - for hashName in settings.ecdsaSigHashes: + hash_names = settings.ecdsaSigHashes if not sig_algs_cert else \ + settings.ecdsa_sig_hashes_cert + for hash_name in hash_names: # only SHA256, SHA384 and SHA512 are allowed in TLS 1.3 - if version > (3, 3) and hashName in ("sha1", "sha224"): + if version > (3, 3) and hash_name in ("sha1", "sha224"): continue # in TLS 1.3 ECDSA key curve is bound to hash @@ -4698,35 +4708,38 @@ def _sigHashesToList(settings, privateKey=None, certList=None, curve = publicKey.curve_name matching_hash = TLSConnection._curve_name_to_hash_name( curve) - if hashName != matching_hash: + if hash_name != matching_hash: continue - sigAlgs.append((getattr(HashAlgorithm, hashName), + sigAlgs.append((getattr(HashAlgorithm, hash_name), SignatureAlgorithm.ecdsa)) if not certType or certType == "dsa": - for hashName in settings.dsaSigHashes: + for hash_name in settings.dsaSigHashes: if version > (3, 3): continue - sigAlgs.append((getattr(HashAlgorithm, hashName), + sigAlgs.append((getattr(HashAlgorithm, hash_name), SignatureAlgorithm.dsa)) if not certType or certType in ("rsa", "rsa-pss"): - for schemeName in settings.rsaSchemes: + rsa_schemes = settings.rsaSchemes if not sig_algs_cert else \ + settings.rsa_sig_schemes_cert + for scheme_name in rsa_schemes: # pkcs#1 v1.5 signatures are not allowed in TLS 1.3 - if version > (3, 3) and schemeName == "pkcs1": + if version > (3, 3) and scheme_name == "pkcs1": continue - - for hashName in settings.rsaSigHashes: + rsa_sig_hashes = settings.rsaSigHashes if not sig_algs_cert else \ + settings.rsa_sig_hashes_cert + for hash_name in rsa_sig_hashes: # rsa-pss certificates can't be used to make PKCS#1 v1.5 # signatures - if certType == "rsa-pss" and schemeName == "pkcs1": + if certType == "rsa-pss" and scheme_name == "pkcs1": continue try: # 1024 bit keys are too small to create valid # rsa-pss-SHA512 signatures - if schemeName == 'pss' and hashName == 'sha512'\ + if scheme_name == 'pss' and hash_name == 'sha512'\ and privateKey and privateKey.n < 2**2047: continue # advertise support for both rsaEncryption and RSA-PSS OID @@ -4734,14 +4747,16 @@ def _sigHashesToList(settings, privateKey=None, certList=None, if certType != 'rsa-pss': sigAlgs.append(getattr(SignatureScheme, "rsa_{0}_rsae_{1}" - .format(schemeName, hashName))) + .format(scheme_name, + hash_name))) if certType != 'rsa': sigAlgs.append(getattr(SignatureScheme, "rsa_{0}_pss_{1}" - .format(schemeName, hashName))) + .format(scheme_name, + hash_name))) except AttributeError: - if schemeName == 'pkcs1': - sigAlgs.append((getattr(HashAlgorithm, hashName), + if scheme_name == 'pkcs1': + sigAlgs.append((getattr(HashAlgorithm, hash_name), SignatureAlgorithm.rsa)) continue return sigAlgs