Skip to content

Commit 9b59bb6

Browse files
alexCopilot
andauthored
Emit warnings on BER PKCS#7 and PKCS#12 (#12372)
* Emit warnings on BER PKCS#7 and PKCS#12 * Update src/rust/src/pkcs7.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 63a93bc commit 9b59bb6

File tree

13 files changed

+82
-30
lines changed

13 files changed

+82
-30
lines changed

src/rust/cryptography-x509/src/pkcs12.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ pub const X509_CERTIFICATE_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 1
1313
pub const FRIENDLY_NAME_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 9, 20);
1414
pub const LOCAL_KEY_ID_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 9, 21);
1515

16-
#[derive(asn1::Asn1Write)]
16+
#[derive(asn1::Asn1Write, asn1::Asn1Read)]
1717
pub struct Pfx<'a> {
1818
pub version: u8,
1919
pub auth_safe: pkcs7::ContentInfo<'a>,
2020
pub mac_data: Option<MacData<'a>>,
2121
}
2222

23-
#[derive(asn1::Asn1Write)]
23+
#[derive(asn1::Asn1Write, asn1::Asn1Read)]
2424
pub struct MacData<'a> {
2525
pub mac: pkcs7::DigestInfo<'a>,
2626
pub salt: &'a [u8],

src/rust/src/backend/ec.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use pyo3::types::{PyAnyMethods, PyDictMethods};
1010
use crate::backend::utils;
1111
use crate::buf::CffiBuf;
1212
use crate::error::{CryptographyError, CryptographyResult};
13-
use crate::x509::common::cstr_from_literal;
13+
use crate::utils::cstr_from_literal;
1414
use crate::{exceptions, types};
1515

1616
#[pyo3::pyclass(frozen, module = "cryptography.hazmat.bindings._rust.openssl.ec")]

src/rust/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ mod pkcs12;
2323
mod pkcs7;
2424
mod test_support;
2525
pub(crate) mod types;
26+
pub(crate) mod utils;
2627
mod x509;
2728

2829
#[cfg(CRYPTOGRAPHY_OPENSSL_300_OR_GREATER)]

src/rust/src/pkcs12.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ use crate::backend::{ciphers, hashes, hmac, kdf, keys};
66
use crate::buf::CffiBuf;
77
use crate::error::{CryptographyError, CryptographyResult};
88
use crate::padding::PKCS7PaddingContext;
9+
use crate::utils::cstr_from_literal;
910
use crate::x509::certificate::Certificate;
1011
use crate::{types, x509};
1112
use cryptography_x509::common::Utf8StoredBMPString;
1213
use pyo3::types::{PyAnyMethods, PyBytesMethods, PyListMethods};
1314
use pyo3::IntoPyObject;
15+
use pyo3::PyTypeInfo;
1416
use std::collections::hash_map::DefaultHasher;
1517
use std::hash::{Hash, Hasher};
1618

@@ -617,6 +619,7 @@ fn serialize_key_and_certificates<'p>(
617619
}
618620

619621
fn decode_p12(
622+
py: pyo3::Python<'_>,
620623
data: CffiBuf<'_>,
621624
password: Option<CffiBuf<'_>>,
622625
) -> CryptographyResult<openssl::pkcs12::ParsedPkcs12_2> {
@@ -637,6 +640,12 @@ fn decode_p12(
637640
.parse2(password)
638641
.map_err(|_| pyo3::exceptions::PyValueError::new_err("Invalid password or PKCS12 data"))?;
639642

643+
if asn1::parse_single::<cryptography_x509::pkcs12::Pfx<'_>>(data.as_bytes()).is_err() {
644+
let warning_cls = pyo3::exceptions::PyUserWarning::type_object(py);
645+
let message = cstr_from_literal!("PKCS#12 bundle could not be parsed as DER, falling back to parsing as BER. Please file an issue at https://github.com/pyca/cryptography/issues explaining how your PKCS#12 bundle was created. In the future, this may become an exception.");
646+
pyo3::PyErr::warn(py, &warning_cls, message, 1)?;
647+
}
648+
640649
Ok(parsed)
641650
}
642651

@@ -654,7 +663,7 @@ fn load_key_and_certificates<'p>(
654663
)> {
655664
let _ = backend;
656665

657-
let p12 = decode_p12(data, password)?;
666+
let p12 = decode_p12(py, data, password)?;
658667

659668
let private_key = if let Some(pkey) = p12.pkey {
660669
let pkey_bytes = pkey.private_key_to_pkcs8()?;
@@ -702,7 +711,7 @@ fn load_pkcs12<'p>(
702711
) -> CryptographyResult<pyo3::Bound<'p, pyo3::PyAny>> {
703712
let _ = backend;
704713

705-
let p12 = decode_p12(data, password)?;
714+
let p12 = decode_p12(py, data, password)?;
706715

707716
let private_key = if let Some(pkey) = p12.pkey {
708717
let pkey_bytes = pkey.private_key_to_pkcs8()?;

src/rust/src/pkcs7.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use once_cell::sync::Lazy;
1414
#[cfg(not(CRYPTOGRAPHY_IS_BORINGSSL))]
1515
use openssl::pkcs7::Pkcs7;
1616
use pyo3::types::{PyAnyMethods, PyBytesMethods, PyListMethods};
17+
#[cfg(not(CRYPTOGRAPHY_IS_BORINGSSL))]
18+
use pyo3::PyTypeInfo;
1719

1820
use crate::asn1::encode_der_data;
1921
use crate::backend::ciphers;
@@ -22,6 +24,8 @@ use crate::error::{CryptographyError, CryptographyResult};
2224
use crate::padding::PKCS7UnpaddingContext;
2325
use crate::pkcs12::symmetric_encrypt;
2426
#[cfg(not(CRYPTOGRAPHY_IS_BORINGSSL))]
27+
use crate::utils::cstr_from_literal;
28+
#[cfg(not(CRYPTOGRAPHY_IS_BORINGSSL))]
2529
use crate::x509::certificate::load_der_x509_certificate;
2630
use crate::{exceptions, types, x509};
2731

@@ -744,12 +748,16 @@ fn load_pem_pkcs7_certificates<'p>(
744748
) -> CryptographyResult<pyo3::Bound<'p, pyo3::types::PyList>> {
745749
cfg_if::cfg_if! {
746750
if #[cfg(not(CRYPTOGRAPHY_IS_BORINGSSL))] {
747-
let pkcs7_decoded = openssl::pkcs7::Pkcs7::from_pem(data).map_err(|_| {
748-
CryptographyError::from(pyo3::exceptions::PyValueError::new_err(
749-
"Unable to parse PKCS7 data",
750-
))
751-
})?;
752-
load_pkcs7_certificates(py, pkcs7_decoded)
751+
let pem_block = pem::parse(data)?;
752+
if pem_block.tag() != "PKCS7" {
753+
return Err(CryptographyError::from(
754+
pyo3::exceptions::PyValueError::new_err(
755+
"The provided PEM data does not have the PKCS7 tag.",
756+
),
757+
));
758+
}
759+
760+
load_der_pkcs7_certificates(py, pem_block.contents())
753761
} else {
754762
let _ = py;
755763
let _ = data;
@@ -775,7 +783,14 @@ fn load_der_pkcs7_certificates<'p>(
775783
"Unable to parse PKCS7 data",
776784
))
777785
})?;
778-
load_pkcs7_certificates(py, pkcs7_decoded)
786+
let result = load_pkcs7_certificates(py, pkcs7_decoded)?;
787+
if asn1::parse_single::<pkcs7::ContentInfo<'_>>(data).is_err() {
788+
let warning_cls = pyo3::exceptions::PyUserWarning::type_object(py);
789+
let message = cstr_from_literal!("PKCS#7 certificates could not be parsed as DER, falling back to parsing as BER. Please file an issue at https://github.com/pyca/cryptography/issues explaining how your PKCS#7 certificates were created. In the future, this may become an exception.");
790+
pyo3::PyErr::warn(py, &warning_cls, message, 1)?;
791+
}
792+
793+
Ok(result)
779794
} else {
780795
let _ = py;
781796
let _ = data;

src/rust/src/utils.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// This file is dual licensed under the terms of the Apache License, Version
2+
// 2.0, and the BSD License. See the LICENSE file in the root of this repository
3+
// for complete details.
4+
5+
macro_rules! cstr_from_literal {
6+
($str:expr) => {
7+
std::ffi::CStr::from_bytes_with_nul(concat!($str, "\0").as_bytes()).unwrap()
8+
};
9+
}
10+
11+
pub(crate) use cstr_from_literal;

src/rust/src/x509/certificate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use crate::asn1::{
2525
};
2626
use crate::backend::{hashes, keys};
2727
use crate::error::{CryptographyError, CryptographyResult};
28-
use crate::x509::common::cstr_from_literal;
28+
use crate::utils::cstr_from_literal;
2929
use crate::x509::verify::PyCryptoOps;
3030
use crate::x509::{extensions, sct, sign};
3131
use crate::{exceptions, types, x509};

src/rust/src/x509/common.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -530,11 +530,3 @@ pub(crate) fn datetime_now(py: pyo3::Python<'_>) -> pyo3::PyResult<asn1::DateTim
530530
.call_method1(pyo3::intern!(py, "now"), (utc,))?,
531531
)
532532
}
533-
534-
macro_rules! cstr_from_literal {
535-
($str:expr) => {
536-
std::ffi::CStr::from_bytes_with_nul(concat!($str, "\0").as_bytes()).unwrap()
537-
};
538-
}
539-
540-
pub(crate) use cstr_from_literal;

src/rust/src/x509/crl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::asn1::{
2020
};
2121
use crate::backend::hashes::Hash;
2222
use crate::error::{CryptographyError, CryptographyResult};
23-
use crate::x509::common::cstr_from_literal;
23+
use crate::utils::cstr_from_literal;
2424
use crate::x509::{certificate, extensions, sign};
2525
use crate::{exceptions, types, x509};
2626

src/rust/src/x509/csr.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ use pyo3::types::{PyAnyMethods, PyListMethods};
1313
use crate::asn1::{encode_der_data, oid_to_py_oid, py_oid_to_oid};
1414
use crate::backend::keys;
1515
use crate::error::{CryptographyError, CryptographyResult};
16-
use crate::x509::{certificate, common::cstr_from_literal, sign};
16+
use crate::utils::cstr_from_literal;
17+
use crate::x509::{certificate, sign};
1718
use crate::{exceptions, types, x509};
1819

1920
self_cell::self_cell!(

0 commit comments

Comments
 (0)