mirror of
https://github.com/saymrwulf/cryptography.git
synced 2026-05-14 20:37:55 +00:00
Accept combined PEM files with multiple sections (#6365)
* accept combined PEM files with multiple sections * pass error messages into `find_in_pem`
This commit is contained in:
parent
4feca6d03b
commit
703de3afa0
5 changed files with 178 additions and 21 deletions
|
|
@ -205,6 +205,10 @@ X.509
|
|||
* ``cryptography.io.old_header.pem`` - A leaf certificate issued by RapidSSL
|
||||
for the cryptography website. This certificate uses the ``X509 CERTIFICATE``
|
||||
legacy PEM header format.
|
||||
* ``cryptography.io.repeated_twice.pem`` - The same as ``cryptography.io.pem``,
|
||||
but the certificate is repeated twice.
|
||||
* ``cryptography.io.with_garbage.pem`` - The same as ``cryptography.io.pem``,
|
||||
but with other sections and text around it.
|
||||
* ``rapidssl_sha256_ca_g3.pem`` - The intermediate CA that issued the
|
||||
``cryptography.io.pem`` certificate.
|
||||
* ``cryptography.io.precert.pem`` - A pre-certificate with the CT poison
|
||||
|
|
|
|||
|
|
@ -389,16 +389,40 @@ fn cert_version(py: pyo3::Python<'_>, version: u8) -> Result<&pyo3::PyAny, PyAsn
|
|||
}
|
||||
}
|
||||
|
||||
#[pyo3::prelude::pyfunction]
|
||||
fn load_pem_x509_certificate(py: pyo3::Python<'_>, data: &[u8]) -> PyAsn1Result<Certificate> {
|
||||
let parsed = pem::parse(data)?;
|
||||
// We support both PEM header strings that OpenSSL does
|
||||
// https://github.com/openssl/openssl/blob/5e2d22d53ed322a7124e26a4fbd116a8210eb77a/include/openssl/pem.h#L32-L33
|
||||
if parsed.tag != "CERTIFICATE" && parsed.tag != "X509 CERTIFICATE" {
|
||||
/// parse all sections in a PEM file and return the only matching section.
|
||||
/// If no or multiple matching sections are found, return an error.
|
||||
fn find_in_pem(
|
||||
data: &[u8],
|
||||
filter_fn: fn(&pem::Pem) -> bool,
|
||||
no_match_err: &'static str,
|
||||
multiple_match_err: &'static str,
|
||||
) -> Result<pem::Pem, PyAsn1Error> {
|
||||
let all_sections = pem::parse_many(data)?;
|
||||
if all_sections.is_empty() {
|
||||
return Err(PyAsn1Error::from(pem::PemError::MalformedFraming));
|
||||
}
|
||||
let matching_sections: Vec<pem::Pem> = all_sections.into_iter().filter(filter_fn).collect();
|
||||
if matching_sections.len() > 1 {
|
||||
return Err(PyAsn1Error::from(pyo3::exceptions::PyValueError::new_err(
|
||||
"Valid PEM but no BEGIN CERTIFICATE/END CERTIFICATE delimiters. Are you sure this is a certificate?"
|
||||
multiple_match_err,
|
||||
)));
|
||||
}
|
||||
matching_sections
|
||||
.into_iter()
|
||||
.next()
|
||||
.ok_or_else(|| PyAsn1Error::from(pyo3::exceptions::PyValueError::new_err(no_match_err)))
|
||||
}
|
||||
|
||||
#[pyo3::prelude::pyfunction]
|
||||
fn load_pem_x509_certificate(py: pyo3::Python<'_>, data: &[u8]) -> PyAsn1Result<Certificate> {
|
||||
// We support both PEM header strings that OpenSSL does
|
||||
// https://github.com/openssl/openssl/blob/5e2d22d53ed322a7124e26a4fbd116a8210eb77a/include/openssl/pem.h#L32-L33
|
||||
let parsed = find_in_pem(
|
||||
data,
|
||||
|p| p.tag == "CERTIFICATE" || p.tag == "X509 CERTIFICATE",
|
||||
"Valid PEM but no BEGIN CERTIFICATE/END CERTIFICATE delimiters. Are you sure this is a certificate?",
|
||||
"Valid PEM but multiple BEGIN CERTIFICATE/END CERTIFICATE delimiters."
|
||||
)?;
|
||||
load_der_x509_certificate(py, &parsed.contents)
|
||||
}
|
||||
|
||||
|
|
@ -672,16 +696,14 @@ impl CertificateSigningRequest {
|
|||
|
||||
#[pyo3::prelude::pyfunction]
|
||||
fn load_pem_x509_csr(py: pyo3::Python<'_>, data: &[u8]) -> PyAsn1Result<CertificateSigningRequest> {
|
||||
let parsed = pem::parse(data)?;
|
||||
// We support both PEM header strings that OpenSSL does
|
||||
// https://github.com/openssl/openssl/blob/5e2d22d53ed322a7124e26a4fbd116a8210eb77a/include/openssl/pem.h#L35-L36
|
||||
if parsed.tag != "CERTIFICATE REQUEST" && parsed.tag != "NEW CERTIFICATE REQUEST" {
|
||||
// TODO: The old errors had the following URL:
|
||||
// See https://cryptography.io/en/latest/faq.html#why-can-t-i-import-my-pem-file for more details.
|
||||
return Err(PyAsn1Error::from(pyo3::exceptions::PyValueError::new_err(
|
||||
"Valid PEM but no BEGIN CERTIFICATE REQUEST/END CERTIFICATE REQUEST delimiters. Are you sure this is a CSR?"
|
||||
)));
|
||||
}
|
||||
let parsed = find_in_pem(
|
||||
data,
|
||||
|p| p.tag == "CERTIFICATE REQUEST" || p.tag == "NEW CERTIFICATE REQUEST",
|
||||
"Valid PEM but no BEGIN CERTIFICATE REQUEST/END CERTIFICATE REQUEST delimiters. Are you sure this is a CSR?",
|
||||
"Valid PEM but multiple BEGIN CERTIFICATE REQUEST/END CERTIFICATE REQUEST delimiters.",
|
||||
)?;
|
||||
load_der_x509_csr(py, &parsed.contents)
|
||||
}
|
||||
|
||||
|
|
@ -719,12 +741,12 @@ fn load_pem_x509_crl(
|
|||
py: pyo3::Python<'_>,
|
||||
data: &[u8],
|
||||
) -> Result<CertificateRevocationList, PyAsn1Error> {
|
||||
let block = pem::parse(data)?;
|
||||
if block.tag != "X509 CRL" {
|
||||
return Err(PyAsn1Error::from(pyo3::exceptions::PyValueError::new_err(
|
||||
"Valid PEM but no BEGIN X509 CRL/END X509 delimiters. Are you sure this is a CRL?",
|
||||
)));
|
||||
}
|
||||
let block = find_in_pem(
|
||||
data,
|
||||
|p| p.tag == "X509 CRL",
|
||||
"Valid PEM but no BEGIN X509 CRL/END X509 delimiters. Are you sure this is a CRL?",
|
||||
"Valid PEM but multiple BEGIN X509 CRL/END X509 delimiters.",
|
||||
)?;
|
||||
// TODO: Produces an extra copy
|
||||
load_der_x509_crl(py, &block.contents)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -694,6 +694,22 @@ class TestRSACertificate(object):
|
|||
)
|
||||
assert isinstance(cert, x509.Certificate)
|
||||
|
||||
def test_load_with_other_sections(self, backend):
|
||||
cert = _load_cert(
|
||||
os.path.join("x509", "cryptography.io.with_garbage.pem"),
|
||||
x509.load_pem_x509_certificate,
|
||||
backend,
|
||||
)
|
||||
assert isinstance(cert, x509.Certificate)
|
||||
|
||||
def test_load_multiple_sections(self, backend):
|
||||
with pytest.raises(ValueError, match="Valid PEM but multiple"):
|
||||
_load_cert(
|
||||
os.path.join("x509", "cryptography.io.repeated_twice.pem"),
|
||||
x509.load_pem_x509_certificate,
|
||||
backend,
|
||||
)
|
||||
|
||||
def test_negative_serial_number(self, backend):
|
||||
with pytest.raises(ValueError, match="TbsCertificate::serial"):
|
||||
_load_cert(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIFvTCCBKWgAwIBAgICPyAwDQYJKoZIhvcNAQELBQAwRzELMAkGA1UEBhMCVVMx
|
||||
FjAUBgNVBAoTDUdlb1RydXN0IEluYy4xIDAeBgNVBAMTF1JhcGlkU1NMIFNIQTI1
|
||||
NiBDQSAtIEczMB4XDTE0MTAxNTEyMDkzMloXDTE4MTExNjAxMTUwM1owgZcxEzAR
|
||||
BgNVBAsTCkdUNDg3NDI5NjUxMTAvBgNVBAsTKFNlZSB3d3cucmFwaWRzc2wuY29t
|
||||
L3Jlc291cmNlcy9jcHMgKGMpMTQxLzAtBgNVBAsTJkRvbWFpbiBDb250cm9sIFZh
|
||||
bGlkYXRlZCAtIFJhcGlkU1NMKFIpMRwwGgYDVQQDExN3d3cuY3J5cHRvZ3JhcGh5
|
||||
LmlvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAom/FebKJIot7Sp3s
|
||||
itG1sicpe3thCssjI+g1JDAS7I3GLVNmbms1DOdIIqwf01gZkzzXBN2+9sOnyRaR
|
||||
PPfCe1jTr3dk2y6rPE559vPa1nZQkhlzlhMhlPyjaT+S7g4Tio4qV2sCBZU01DZJ
|
||||
CaksfohN+5BNVWoJzTbOcrHOEJ+M8B484KlBCiSxqf9cyNQKru4W3bHaCVNVJ8eu
|
||||
6i6KyhzLa0L7yK3LXwwXVs583C0/vwFhccGWsFODqD/9xHUzsBIshE8HKjdjDi7Y
|
||||
3BFQzVUQFjBB50NSZfAA/jcdt1blxJouc7z9T8Oklh+V5DDBowgAsrT4b6Z2Fq6/
|
||||
r7D1GqivLK/ypUQmxq2WXWAUBb/Q6xHgxASxI4Br+CByIUQJsm8L2jzc7k+mF4hW
|
||||
ltAIUkbo8fGiVnat0505YJgxWEDKOLc4Gda6d/7GVd5AvKrz242bUqeaWo6e4MTx
|
||||
diku2Ma3rhdcr044Qvfh9hGyjqNjvhWY/I+VRWgihU7JrYvgwFdJqsQ5eiKT4OHi
|
||||
gsejvWwkZzDtiQ+aQTrzM1FsY2swJBJsLSX4ofohlVRlIJCn/ME+XErj553431Lu
|
||||
YQ5SzMd3nXzN78Vj6qzTfMUUY72UoT1/AcFiUMobgIqrrmwuNxfrkbVE2b6Bga74
|
||||
FsJX63prvrJ41kuHK/16RQBM7fcCAwEAAaOCAWAwggFcMB8GA1UdIwQYMBaAFMOc
|
||||
8/zTRgg0u85Gf6B8W/PiCMtZMFcGCCsGAQUFBwEBBEswSTAfBggrBgEFBQcwAYYT
|
||||
aHR0cDovL2d2LnN5bWNkLmNvbTAmBggrBgEFBQcwAoYaaHR0cDovL2d2LnN5bWNi
|
||||
LmNvbS9ndi5jcnQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB
|
||||
BggrBgEFBQcDAjAvBgNVHREEKDAmghN3d3cuY3J5cHRvZ3JhcGh5Lmlvgg9jcnlw
|
||||
dG9ncmFwaHkuaW8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL2d2LnN5bWNiLmNv
|
||||
bS9ndi5jcmwwDAYDVR0TAQH/BAIwADBFBgNVHSAEPjA8MDoGCmCGSAGG+EUBBzYw
|
||||
LDAqBggrBgEFBQcCARYeaHR0cHM6Ly93d3cucmFwaWRzc2wuY29tL2xlZ2FsMA0G
|
||||
CSqGSIb3DQEBCwUAA4IBAQAzIYO2jx7h17FBT74tJ2zbV9OKqGb7QF8y3wUtP4xc
|
||||
dH80vprI/Cfji8s86kr77aAvAqjDjaVjHn7UzebhSUivvRPmfzRgyWBacomnXTSt
|
||||
Xlt2dp2nDQuwGyK2vB7dMfKnQAkxwq1sYUXznB8i0IhhCAoXp01QGPKq51YoIlnF
|
||||
7DRMk6iEaL1SJbkIrLsCQyZFDf0xtfW9DqXugMMLoxeCsBhZJQzNyS2ryirrv9LH
|
||||
aK3+6IZjrcyy9bkpz/gzJucyhU+75c4My/mnRCrtItRbCQuiI5pd5poDowm+HH9i
|
||||
GVI9+0lAFwxOUnOnwsoI40iOoxjLMGB+CgFLKCGUcWxP
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFvTCCBKWgAwIBAgICPyAwDQYJKoZIhvcNAQELBQAwRzELMAkGA1UEBhMCVVMx
|
||||
FjAUBgNVBAoTDUdlb1RydXN0IEluYy4xIDAeBgNVBAMTF1JhcGlkU1NMIFNIQTI1
|
||||
NiBDQSAtIEczMB4XDTE0MTAxNTEyMDkzMloXDTE4MTExNjAxMTUwM1owgZcxEzAR
|
||||
BgNVBAsTCkdUNDg3NDI5NjUxMTAvBgNVBAsTKFNlZSB3d3cucmFwaWRzc2wuY29t
|
||||
L3Jlc291cmNlcy9jcHMgKGMpMTQxLzAtBgNVBAsTJkRvbWFpbiBDb250cm9sIFZh
|
||||
bGlkYXRlZCAtIFJhcGlkU1NMKFIpMRwwGgYDVQQDExN3d3cuY3J5cHRvZ3JhcGh5
|
||||
LmlvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAom/FebKJIot7Sp3s
|
||||
itG1sicpe3thCssjI+g1JDAS7I3GLVNmbms1DOdIIqwf01gZkzzXBN2+9sOnyRaR
|
||||
PPfCe1jTr3dk2y6rPE559vPa1nZQkhlzlhMhlPyjaT+S7g4Tio4qV2sCBZU01DZJ
|
||||
CaksfohN+5BNVWoJzTbOcrHOEJ+M8B484KlBCiSxqf9cyNQKru4W3bHaCVNVJ8eu
|
||||
6i6KyhzLa0L7yK3LXwwXVs583C0/vwFhccGWsFODqD/9xHUzsBIshE8HKjdjDi7Y
|
||||
3BFQzVUQFjBB50NSZfAA/jcdt1blxJouc7z9T8Oklh+V5DDBowgAsrT4b6Z2Fq6/
|
||||
r7D1GqivLK/ypUQmxq2WXWAUBb/Q6xHgxASxI4Br+CByIUQJsm8L2jzc7k+mF4hW
|
||||
ltAIUkbo8fGiVnat0505YJgxWEDKOLc4Gda6d/7GVd5AvKrz242bUqeaWo6e4MTx
|
||||
diku2Ma3rhdcr044Qvfh9hGyjqNjvhWY/I+VRWgihU7JrYvgwFdJqsQ5eiKT4OHi
|
||||
gsejvWwkZzDtiQ+aQTrzM1FsY2swJBJsLSX4ofohlVRlIJCn/ME+XErj553431Lu
|
||||
YQ5SzMd3nXzN78Vj6qzTfMUUY72UoT1/AcFiUMobgIqrrmwuNxfrkbVE2b6Bga74
|
||||
FsJX63prvrJ41kuHK/16RQBM7fcCAwEAAaOCAWAwggFcMB8GA1UdIwQYMBaAFMOc
|
||||
8/zTRgg0u85Gf6B8W/PiCMtZMFcGCCsGAQUFBwEBBEswSTAfBggrBgEFBQcwAYYT
|
||||
aHR0cDovL2d2LnN5bWNkLmNvbTAmBggrBgEFBQcwAoYaaHR0cDovL2d2LnN5bWNi
|
||||
LmNvbS9ndi5jcnQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB
|
||||
BggrBgEFBQcDAjAvBgNVHREEKDAmghN3d3cuY3J5cHRvZ3JhcGh5Lmlvgg9jcnlw
|
||||
dG9ncmFwaHkuaW8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL2d2LnN5bWNiLmNv
|
||||
bS9ndi5jcmwwDAYDVR0TAQH/BAIwADBFBgNVHSAEPjA8MDoGCmCGSAGG+EUBBzYw
|
||||
LDAqBggrBgEFBQcCARYeaHR0cHM6Ly93d3cucmFwaWRzc2wuY29tL2xlZ2FsMA0G
|
||||
CSqGSIb3DQEBCwUAA4IBAQAzIYO2jx7h17FBT74tJ2zbV9OKqGb7QF8y3wUtP4xc
|
||||
dH80vprI/Cfji8s86kr77aAvAqjDjaVjHn7UzebhSUivvRPmfzRgyWBacomnXTSt
|
||||
Xlt2dp2nDQuwGyK2vB7dMfKnQAkxwq1sYUXznB8i0IhhCAoXp01QGPKq51YoIlnF
|
||||
7DRMk6iEaL1SJbkIrLsCQyZFDf0xtfW9DqXugMMLoxeCsBhZJQzNyS2ryirrv9LH
|
||||
aK3+6IZjrcyy9bkpz/gzJucyhU+75c4My/mnRCrtItRbCQuiI5pd5poDowm+HH9i
|
||||
GVI9+0lAFwxOUnOnwsoI40iOoxjLMGB+CgFLKCGUcWxP
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
This file also contains text before...
|
||||
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
aHR0cHM6Ly9iaXQubHkvM3VKOXpZZw==
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
...and...
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFvTCCBKWgAwIBAgICPyAwDQYJKoZIhvcNAQELBQAwRzELMAkGA1UEBhMCVVMx
|
||||
FjAUBgNVBAoTDUdlb1RydXN0IEluYy4xIDAeBgNVBAMTF1JhcGlkU1NMIFNIQTI1
|
||||
NiBDQSAtIEczMB4XDTE0MTAxNTEyMDkzMloXDTE4MTExNjAxMTUwM1owgZcxEzAR
|
||||
BgNVBAsTCkdUNDg3NDI5NjUxMTAvBgNVBAsTKFNlZSB3d3cucmFwaWRzc2wuY29t
|
||||
L3Jlc291cmNlcy9jcHMgKGMpMTQxLzAtBgNVBAsTJkRvbWFpbiBDb250cm9sIFZh
|
||||
bGlkYXRlZCAtIFJhcGlkU1NMKFIpMRwwGgYDVQQDExN3d3cuY3J5cHRvZ3JhcGh5
|
||||
LmlvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAom/FebKJIot7Sp3s
|
||||
itG1sicpe3thCssjI+g1JDAS7I3GLVNmbms1DOdIIqwf01gZkzzXBN2+9sOnyRaR
|
||||
PPfCe1jTr3dk2y6rPE559vPa1nZQkhlzlhMhlPyjaT+S7g4Tio4qV2sCBZU01DZJ
|
||||
CaksfohN+5BNVWoJzTbOcrHOEJ+M8B484KlBCiSxqf9cyNQKru4W3bHaCVNVJ8eu
|
||||
6i6KyhzLa0L7yK3LXwwXVs583C0/vwFhccGWsFODqD/9xHUzsBIshE8HKjdjDi7Y
|
||||
3BFQzVUQFjBB50NSZfAA/jcdt1blxJouc7z9T8Oklh+V5DDBowgAsrT4b6Z2Fq6/
|
||||
r7D1GqivLK/ypUQmxq2WXWAUBb/Q6xHgxASxI4Br+CByIUQJsm8L2jzc7k+mF4hW
|
||||
ltAIUkbo8fGiVnat0505YJgxWEDKOLc4Gda6d/7GVd5AvKrz242bUqeaWo6e4MTx
|
||||
diku2Ma3rhdcr044Qvfh9hGyjqNjvhWY/I+VRWgihU7JrYvgwFdJqsQ5eiKT4OHi
|
||||
gsejvWwkZzDtiQ+aQTrzM1FsY2swJBJsLSX4ofohlVRlIJCn/ME+XErj553431Lu
|
||||
YQ5SzMd3nXzN78Vj6qzTfMUUY72UoT1/AcFiUMobgIqrrmwuNxfrkbVE2b6Bga74
|
||||
FsJX63prvrJ41kuHK/16RQBM7fcCAwEAAaOCAWAwggFcMB8GA1UdIwQYMBaAFMOc
|
||||
8/zTRgg0u85Gf6B8W/PiCMtZMFcGCCsGAQUFBwEBBEswSTAfBggrBgEFBQcwAYYT
|
||||
aHR0cDovL2d2LnN5bWNkLmNvbTAmBggrBgEFBQcwAoYaaHR0cDovL2d2LnN5bWNi
|
||||
LmNvbS9ndi5jcnQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB
|
||||
BggrBgEFBQcDAjAvBgNVHREEKDAmghN3d3cuY3J5cHRvZ3JhcGh5Lmlvgg9jcnlw
|
||||
dG9ncmFwaHkuaW8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL2d2LnN5bWNiLmNv
|
||||
bS9ndi5jcmwwDAYDVR0TAQH/BAIwADBFBgNVHSAEPjA8MDoGCmCGSAGG+EUBBzYw
|
||||
LDAqBggrBgEFBQcCARYeaHR0cHM6Ly93d3cucmFwaWRzc2wuY29tL2xlZ2FsMA0G
|
||||
CSqGSIb3DQEBCwUAA4IBAQAzIYO2jx7h17FBT74tJ2zbV9OKqGb7QF8y3wUtP4xc
|
||||
dH80vprI/Cfji8s86kr77aAvAqjDjaVjHn7UzebhSUivvRPmfzRgyWBacomnXTSt
|
||||
Xlt2dp2nDQuwGyK2vB7dMfKnQAkxwq1sYUXznB8i0IhhCAoXp01QGPKq51YoIlnF
|
||||
7DRMk6iEaL1SJbkIrLsCQyZFDf0xtfW9DqXugMMLoxeCsBhZJQzNyS2ryirrv9LH
|
||||
aK3+6IZjrcyy9bkpz/gzJucyhU+75c4My/mnRCrtItRbCQuiI5pd5poDowm+HH9i
|
||||
GVI9+0lAFwxOUnOnwsoI40iOoxjLMGB+CgFLKCGUcWxP
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
...between...
|
||||
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
aHR0cHM6Ly9iaXQubHkvM3VKOXpZZw==
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
...sections.
|
||||
Loading…
Reference in a new issue