Skip to content

Commit

Permalink
Skip passing cert into verify
Browse files Browse the repository at this point in the history
  • Loading branch information
William Tisäter committed Oct 25, 2023
1 parent 7c51434 commit 490ebb0
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 97 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rsmime"
version = "0.4.0"
version = "0.4.1"
edition = "2021"

[lib]
Expand Down
71 changes: 21 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,23 @@ Rust powered Python package for signing data in S/MIME format

## Usage

### Install
```
pip install rsmime
```

### Sign
```py
import rsmime

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())
```

```
Expand All @@ -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
```
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
10 changes: 5 additions & 5 deletions rsmime.pyi
Original file line number Diff line number Diff line change
@@ -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:
...
55 changes: 16 additions & 39 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<u8>> {
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(),
Expand Down Expand Up @@ -73,28 +72,18 @@ fn validate_expiry(certs: &StackRef<X509>) -> Result<(), Error> {
Ok(())
}

fn _verify(cert_file: &str, data_to_verify: &[u8], throw_on_expiry: bool) -> PyResult<Vec<u8>> {
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<u8> = Vec::new();
fn _verify(data_to_verify: &[u8], throw_on_expiry: bool) -> PyResult<Vec<u8>> {
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<u8> = Vec::new();
pkcs7
.verify(
certs.as_ref(),
Expand All @@ -117,29 +106,17 @@ fn sign(py: Python, cert_file: &str, key_file: &str, data_to_sign: Vec<u8>) -> P
}

#[pyfunction]
#[pyo3(signature = (cert_file, data_to_verify, *, throw_on_expiry = false))]
fn verify(
py: Python,
cert_file: &str,
data_to_verify: Vec<u8>,
throw_on_expiry: bool,
) -> PyResult<PyObject> {
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<u8>, throw_on_expiry: bool) -> PyResult<PyObject> {
match _verify(&data_to_verify, throw_on_expiry) {
Ok(data) => Ok(PyBytes::new(py, &data).into()),
Err(err) => Err(err),
}
}

#[pymodule]
fn rsmime(py: Python, m: &PyModule) -> PyResult<()> {
m.add(
"ReadCertificateError",
py.get_type::<ReadCertificateError>(),
)?;
m.add(
"LoadCertificateError",
py.get_type::<LoadCertificateError>(),
)?;
m.add("CertificateError", py.get_type::<CertificateError>())?;
m.add("SignError", py.get_type::<SignError>())?;
m.add("VerifyError", py.get_type::<VerifyError>())?;
m.add_function(wrap_pyfunction!(sign, m)?)?;
Expand Down

0 comments on commit 490ebb0

Please sign in to comment.