openssl_csr: fix idempotency problems (#55142)

* Add test for generating a CSR with everything, and testing idempotency.

* Proper SAN normalization before comparison.

* Fix check in cryptography backend.

* Convert SANs to text. Update comments.

* Add changelog.
This commit is contained in:
Felix Fontein 2019-04-15 09:15:08 +02:00 committed by Martin Krizek
parent 91e808eed2
commit cb5c57bcd5
5 changed files with 209 additions and 7 deletions

View file

@ -554,6 +554,16 @@ class CertificateSigningRequestPyOpenSSL(CertificateSigningRequestBase):
except crypto_utils.OpenSSLBadPassphraseError as exc:
raise CertificateSigningRequestError(exc)
def _normalize_san(self, san):
# apperently openssl returns 'IP address' not 'IP' as specifier when converting the subjectAltName to string
# although it won't accept this specifier when generating the CSR. (https://github.com/openssl/openssl/issues/4004)
if san.startswith('IP Address:'):
san = 'IP:' + san[len('IP Address:'):]
if san.startswith('IP:'):
ip = ipaddress.ip_address(san[3:])
san = 'IP:{0}'.format(ip.compressed)
return san
def _check_csr(self):
def _check_subject(csr):
subject = [(OpenSSL._util.lib.OBJ_txt2nid(to_bytes(sub[0])), to_bytes(sub[1])) for sub in self.subject]
@ -565,12 +575,11 @@ class CertificateSigningRequestPyOpenSSL(CertificateSigningRequestBase):
def _check_subjectAltName(extensions):
altnames_ext = next((ext for ext in extensions if ext.get_short_name() == b'subjectAltName'), '')
altnames = [altname.strip() for altname in str(altnames_ext).split(',') if altname.strip()]
# apperently openssl returns 'IP address' not 'IP' as specifier when converting the subjectAltName to string
# although it won't accept this specifier when generating the CSR. (https://github.com/openssl/openssl/issues/4004)
altnames = [name if not name.startswith('IP Address:') else "IP:" + name.split(':', 1)[1] for name in altnames]
altnames = [self._normalize_san(altname.strip()) for altname in
to_text(altnames_ext, errors='surrogate_or_strict').split(',') if altname.strip()]
if self.subjectAltName:
if set(altnames) != set(self.subjectAltName) or altnames_ext.get_critical() != self.subjectAltName_critical:
if (set(altnames) != set([self._normalize_san(to_text(name)) for name in self.subjectAltName]) or
altnames_ext.get_critical() != self.subjectAltName_critical):
return False
else:
if altnames:
@ -761,8 +770,8 @@ class CertificateSigningRequestCryptography(CertificateSigningRequestBase):
def _check_basicConstraints(extensions):
bc_ext = _find_extension(extensions, cryptography.x509.BasicConstraints)
current_ca = bc_ext.ca if bc_ext else False
current_path_length = bc_ext.path_length if bc_ext else None
current_ca = bc_ext.value.ca if bc_ext else False
current_path_length = bc_ext.value.path_length if bc_ext else None
ca, path_length = crypto_utils.cryptography_get_basic_constraints(self.basicConstraints)
# Check CA flag
if ca != current_ca: