-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for encrypting S/MIME messages #10889
base: main
Are you sure you want to change the base?
Conversation
// | ||
// AES-IV ::= OCTET STRING (SIZE(16)) | ||
#[defined_by(oid::AES_128_CBC_OID)] | ||
AesCbc(&'a [u8]), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity: does rust-asn1
know to turn this &[u8]
into the inner value of the OCTET STRING
, or does this end up containing the raw TLV for the OCTET STRING
? I suspect it's the former, but we should confirm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
&[u8]
in rust-asn1 are OCTET STRINGs, not raw TLVs.
pub const AES_256_CBC_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 1, 42); | ||
pub const AES_192_CBC_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 1, 22); | ||
pub const AES_128_CBC_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 1, 2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for cross-checking: confirmed these against their parent arc: https://oidref.com/2.16.840.1.101.3.4.1
fp = io.BytesIO() | ||
g = email.generator.BytesGenerator( | ||
fp, | ||
maxheaderlen=0, | ||
mangle_from_=False, | ||
policy=m.policy.clone(linesep="\n"), | ||
) | ||
g.flatten(m) | ||
return fp.getvalue() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: you might be able to get away with just m.as_bytes(...)
rather than jumping through a BytesIO
+ BytesGenerator
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed!
ed60635
to
9b83b39
Compare
@@ -225,6 +307,26 @@ def _smime_encode( | |||
return fp.getvalue() | |||
|
|||
|
|||
def _smime_enveloped_encode(data: bytes) -> bytes: | |||
# This function works pretty hard to replicate what OpenSSL does | |||
# precisely. For good and for ill. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: might be good to include a URL or code reference for OpenSSL's construction of the encoding here, just in case this ever needs to be re-evaluated 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually a comment from the other encoder function that I used as a base for this one (_smime_signed_encode
).
I think it doesn't make much sense here since we just add the headers, so I removed it
6a2e2ef
to
21c50ec
Compare
I'm opening this PR with an initial implementation of S/MIME encryption, in order to better discuss the API design, the algorithms we want to support, and how we want to approach testing.
The target is a subset of S/MIME v3.2 (RFC5751):
PKCS1v15
padding.I've been checking the output produced against the output of the
openssl-cms
command, sinceopenssl-smime
is now legacy. For example:I added some tests for the unencrypted parts of the message, but complete testing would require that we parse and decrypt the messages. We could follow a similar approach as with testing S/MIME signing, where we call OpenSSL directly to parse and check our output during the tests:
cryptography/tests/hazmat/primitives/test_pkcs7.py
Line 103 in ed60635
cc @alex @reaperhulk @woodruffw
(the issue tracking this feature is #5488)