From 490ebb031dca419c01981f7caead23b4f2d36f22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?William=20Tis=C3=A4ter?= Date: Thu, 26 Oct 2023 00:40:49 +0200 Subject: [PATCH] Skip passing cert into verify --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 71 +++++++++++++++----------------------------------- pyproject.toml | 2 +- rsmime.pyi | 10 +++---- src/lib.rs | 55 ++++++++++++-------------------------- 6 files changed, 45 insertions(+), 97 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d87ed4..70676aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -281,7 +281,7 @@ dependencies = [ [[package]] name = "rsmime" -version = "0.4.0" +version = "0.4.1" dependencies = [ "openssl", "pyo3", diff --git a/Cargo.toml b/Cargo.toml index ecf0691..059e788 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rsmime" -version = "0.4.0" +version = "0.4.1" edition = "2021" [lib] diff --git a/README.md b/README.md index ab3f1bb..101e99e 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,12 @@ Rust powered Python package for signing data in S/MIME format ## Usage +### Install ``` pip install rsmime ``` +### Sign ```py import rsmime @@ -15,10 +17,10 @@ raw_data = b'data to sign' try: signed_data = rsmime.sign('some.crt', 'some.key', raw_data) -except rsmime.SignError as e: +except (rsmime.SignError, rsmime.CertificateError) as e: print("Failed to sign:", e) -print(signed_data) +print(signed_data.decode()) ``` ``` @@ -28,54 +30,23 @@ Content-Type: application/x-pkcs7-mime; smime-type=signed-data; name="smime.p7m" Content-Transfer-Encoding: base64 MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0B -BwGggCSABAxkYXRhIHRvIHNpZ24AAAAAAACgggaZMIIGlTCCBX2gAwIBAgIQBIEz -UwwPu+XzT84yElfBUDANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzEVMBMG -A1UEChMMRGlnaUNlcnQgSW5jMSkwJwYDVQQDEyBEaWdpQ2VydCBUTFMgUlNBIFNI -QTI1NiAyMDIwIENBMTAeFw0yMjA0MDUwMDAwMDBaFw0yMzA0MDYyMzU5NTlaMEwx -CzAJBgNVBAYTAlNFMRIwEAYDVQQHEwlTdG9ja2hvbG0xEjAQBgNVBAoTCVJhZGRs -ZSBBQjEVMBMGA1UEAxMMaW50cmVjZXB0LnNlMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEAv2lTExs+cT2I2n/bKLm7aVv346rmlZSY4WriAU2XnCQPXGr0 -PCKQBTDStiJhqgoQ2tvG1Uit3AfypfVgyfiuI+xb78+C6iBZKjC6xsppHenFTmsW -4mrwOfz2FnasQR/44S9wyk3Zf+rlKt4X9SQHLz+VTCTzhNa2R30v9mShXKxktNyl -8B5/UskuVojzk1lDSOInpTN/wrcPmZrQLBHbzqYyZylDG3e7fSAVdcFiSYT6Ctbf -RXLeamWt8/8P0EgGyPGcrdHXaXBbdbK5J2fIw0DC7+ULDQ5+jhXkZoL587FGXSlk -VqwXtS8YD9Wigf2jwcXalecDjmSEvoq4p3LfWQIDAQABo4IDbjCCA2owHwYDVR0j -BBgwFoAUt2ui6qiqhIx56rTaD5iyxZV2ufQwHQYDVR0OBBYEFGQ2AknqbgsOEyQc -KOf9zKHG6PJcMBcGA1UdEQQQMA6CDGludHJlY2VwdC5zZTAOBgNVHQ8BAf8EBAMC -BaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMIGPBgNVHR8EgYcwgYQw -QKA+oDyGOmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRMU1JTQVNI -QTI1NjIwMjBDQTEtNC5jcmwwQKA+oDyGOmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNv -bS9EaWdpQ2VydFRMU1JTQVNIQTI1NjIwMjBDQTEtNC5jcmwwPgYDVR0gBDcwNTAz -BgZngQwBAgIwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20v -Q1BTMH8GCCsGAQUFBwEBBHMwcTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln -aWNlcnQuY29tMEkGCCsGAQUFBzAChj1odHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5j -b20vRGlnaUNlcnRUTFNSU0FTSEEyNTYyMDIwQ0ExLTEuY3J0MAkGA1UdEwQCMAAw -ggGABgorBgEEAdZ5AgQCBIIBcASCAWwBagB2AOg+0No+9QY1MudXKLyJa8kD08vR -EWvs62nhd31tBr1uAAABf/lXYlcAAAQDAEcwRQIgerFadnbRm9azVBblJQdBtj4I -yUuBzNqSXB9BWevbItsCIQDkifi/JwsMneNFcnaD6imugY7MXRr5Wq+DG3H4PMUa -hQB3ADXPGRu/sWxXvw+tTG1Cy7u2JyAmUeo/4SrvqAPDO9ZMAAABf/lXYk4AAAQD -AEgwRgIhAJ0+Nhtn2KW5dz+rJazDqxPuXaBYXXGpt/WDWpC8KVivAiEAkVhB7/qK -SoVLL8IhXy+5dXxtyUXc1qQsyVPiJDxesRsAdwCzc3cH4YRQ+GOG1gWp3BEJSnkt -sWcMC4fc8AMOeTalmgAAAX/5V2KvAAAEAwBIMEYCIQCkhDiNatThkI3bjwd3Z+wG -vvb2Gn82/Byn32ovxXN5OQIhALQK1/QmDCDzSv85v2gExprobh5PjcRDEoYOagcf -NIwYMA0GCSqGSIb3DQEBCwUAA4IBAQC4F7oCzLopzWMmMdK9G0O8wSoddpGTmfty -q+oPTfi1KFMThQIzOHHGSgnnU9hwhd4yrE7s5KDEcGrAIfmxcKWbmN7bEDjCFRPk -s9PssDX2u4thoZHcBBWHXfPECy0rd0qKTY36wgNWMFoK+ygj1f+M6hv4YRvZl//G -NBXx7oQq6rY8EyOwgrD7Eh5rCG09qNVoMnL+1dmP1gYl7otzTfpKCqlIrLyjW9h2 -Y7pmHOEuw+JJTVqVbdnGo/FRqR7EHcJVTbtclFeMo3pG6HuiE2A8QT6jM0SVsZQY -2aWCq3AdAVfDEgn1thtnEi5uW5sPkACC8owZp1eub9AbrCS1fS/MMYICdTCCAnEC -AQEwYzBPMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMSkwJwYD -VQQDEyBEaWdpQ2VydCBUTFMgUlNBIFNIQTI1NiAyMDIwIENBMQIQBIEzUwwPu+Xz -T84yElfBUDANBglghkgBZQMEAgEFAKCB5DAYBgkqhkiG9w0BCQMxCwYJKoZIhvcN -AQcBMBwGCSqGSIb3DQEJBTEPFw0yMzEwMjQwOTI5NTRaMC8GCSqGSIb3DQEJBDEi -BCAVcZKydtojzISrB4/IdVwFHF8EML9IAuVXGCIea3bHdzB5BgkqhkiG9w0BCQ8x -bDBqMAsGCWCGSAFlAwQBKjALBglghkgBZQMEARYwCwYJYIZIAWUDBAECMAoGCCqG -SIb3DQMHMA4GCCqGSIb3DQMCAgIAgDANBggqhkiG9w0DAgIBQDAHBgUrDgMCBzAN -BggqhkiG9w0DAgIBKDANBgkqhkiG9w0BAQEFAASCAQBZO8T/pSfckmQtdm9gVz+K -sgjumiVRMbJzuAGh9uS669cXAs6Qx4vJfJbfP7K+g1mZ3j4SYhHT20w0wbIUgGgQ -AvyD2GOiCsaF0hM/JbVqfZUtGn9BK6aaFVYFG+cTgvSGF4F+IrCptymInP6Tt/3e -NOGJxKsL7MiJvNhRTEP7NouD0FPOycHDDo22vB/Q8OD9/qkhAG+6gyvKjt7/zyj2 -OwPILgJ+UuQ4mKUGqhZD2qGC2XYG137zUwfnRJFjJpIjNtTXiD/kRe+b01xciCoA +... SwxRisLtodx8YQ7VoOLFi9FNoia3SsJtCnu2hILeobjPTnPCAL+8N2bc22MX44mc AAAAAAAA ``` + +### Verify +```py +import rsmime + +try: + raw_data = rsmime.verify(signed_data) +except rsmime.VerifyError as e: + print("Failed to verify:", e) + +print(raw_data.decode()) +``` + +``` +data to sign +``` \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 6df2623..3841742 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "rsmime" -version = "0.4.0" +version = "0.4.1" classifiers = [ "License :: OSI Approved :: MIT License", "Development Status :: 3 - Alpha", diff --git a/rsmime.pyi b/rsmime.pyi index 5ba03c4..40147e8 100644 --- a/rsmime.pyi +++ b/rsmime.pyi @@ -1,14 +1,14 @@ -class ReadCertificateError(Exception): - ... - -class LoadCertificateError(Exception): +class CertificateError(Exception): ... class SignError(Exception): ... +class VerifyError(Exception): + ... + def sign(cert_file: str, key_file: str, data_to_sign: bytes) -> bytes: ... -def verify(cert_file: str, data_to_verify: bytes, throw_on_expiry: bool = False) -> bytes: +def verify(data_to_verify: bytes, throw_on_expiry: bool = False) -> bytes: ... diff --git a/src/lib.rs b/src/lib.rs index 84ecf9a..e839e5d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,29 +14,28 @@ use pyo3::exceptions::PyException; use pyo3::prelude::*; use pyo3::types::PyBytes; -create_exception!(rsmime, ReadCertificateError, PyException); -create_exception!(rsmime, LoadCertificateError, PyException); +create_exception!(rsmime, CertificateError, PyException); create_exception!(rsmime, SignError, PyException); create_exception!(rsmime, VerifyError, PyException); fn _sign(cert_file: &str, key_file: &str, data_to_sign: &[u8]) -> PyResult> { - let certs = Stack::new().expect("Failed to create stack"); + let certs = Stack::new().unwrap(); if data_to_sign.is_empty() { return Err(SignError::new_err("Cannot sign empty data")); } let cert_data = - std::fs::read(cert_file).map_err(|err| ReadCertificateError::new_err(err.to_string()))?; + std::fs::read(cert_file).map_err(|err| CertificateError::new_err(err.to_string()))?; let key_data = - std::fs::read(key_file).map_err(|err| ReadCertificateError::new_err(err.to_string()))?; + std::fs::read(key_file).map_err(|err| CertificateError::new_err(err.to_string()))?; let cert = - X509::from_pem(&cert_data).map_err(|err| LoadCertificateError::new_err(err.to_string()))?; + X509::from_pem(&cert_data).map_err(|err| CertificateError::new_err(err.to_string()))?; let rsa = Rsa::private_key_from_pem(&key_data) - .map_err(|err| LoadCertificateError::new_err(err.to_string()))?; + .map_err(|err| CertificateError::new_err(err.to_string()))?; let pkey = - pkey::PKey::from_rsa(rsa).map_err(|err| LoadCertificateError::new_err(err.to_string()))?; + pkey::PKey::from_rsa(rsa).map_err(|err| CertificateError::new_err(err.to_string()))?; let pkcs7 = Pkcs7::sign( cert.as_ref(), @@ -73,28 +72,18 @@ fn validate_expiry(certs: &StackRef) -> Result<(), Error> { Ok(()) } -fn _verify(cert_file: &str, data_to_verify: &[u8], throw_on_expiry: bool) -> PyResult> { - let cert_data = - std::fs::read(cert_file).map_err(|err| ReadCertificateError::new_err(err.to_string()))?; - let cert = - X509::from_pem(&cert_data).map_err(|err| LoadCertificateError::new_err(err.to_string()))?; - - let mut certs = Stack::new().expect("Failed to create stack"); - certs - .push(cert) - .map_err(|err| LoadCertificateError::new_err(err.to_string()))?; - - let mut out: Vec = Vec::new(); +fn _verify(data_to_verify: &[u8], throw_on_expiry: bool) -> PyResult> { + let certs = Stack::new().unwrap(); let store = X509StoreBuilder::new().unwrap().build(); - let x = Pkcs7::from_smime(data_to_verify); - let x = x.map_err(|err| VerifyError::new_err(err.to_string()))?; - let (pkcs7, _) = x; + let (pkcs7, _) = + Pkcs7::from_smime(data_to_verify).map_err(|err| VerifyError::new_err(err.to_string()))?; if throw_on_expiry { validate_expiry(certs.as_ref()).map_err(|err| VerifyError::new_err(err.to_string()))?; } + let mut out: Vec = Vec::new(); pkcs7 .verify( certs.as_ref(), @@ -117,14 +106,9 @@ fn sign(py: Python, cert_file: &str, key_file: &str, data_to_sign: Vec) -> P } #[pyfunction] -#[pyo3(signature = (cert_file, data_to_verify, *, throw_on_expiry = false))] -fn verify( - py: Python, - cert_file: &str, - data_to_verify: Vec, - throw_on_expiry: bool, -) -> PyResult { - match _verify(cert_file, &data_to_verify, throw_on_expiry) { +#[pyo3(signature = (data_to_verify, *, throw_on_expiry = false))] +fn verify(py: Python, data_to_verify: Vec, throw_on_expiry: bool) -> PyResult { + match _verify(&data_to_verify, throw_on_expiry) { Ok(data) => Ok(PyBytes::new(py, &data).into()), Err(err) => Err(err), } @@ -132,14 +116,7 @@ fn verify( #[pymodule] fn rsmime(py: Python, m: &PyModule) -> PyResult<()> { - m.add( - "ReadCertificateError", - py.get_type::(), - )?; - m.add( - "LoadCertificateError", - py.get_type::(), - )?; + m.add("CertificateError", py.get_type::())?; m.add("SignError", py.get_type::())?; m.add("VerifyError", py.get_type::())?; m.add_function(wrap_pyfunction!(sign, m)?)?;