From 07cb361a4ee49ed43103ae8eb8262fe968588e26 Mon Sep 17 00:00:00 2001 From: Kyle Fazzari Date: Wed, 9 Sep 2020 13:13:35 -0700 Subject: [PATCH] Use S/MIME API from cryptography instead of SSL bindings The SROS2 utilities use the Cryptography library, which doesn't officially support S/MIME. As a result, we had to hit the SSL bindings directly to get that functionality. These bindings were removed in v3.1 of Cryptography, which means the SROS2 utilities were stuck on v3.0 at the latest. However, Cryptography has added an official S/MIME API which is far easier to use than the raw SSL API. Update the SROS2 utilities to use it. Resolve #239 Update ros2/ci#507 Signed-off-by: Kyle Fazzari --- sros2/sros2/api/_utilities.py | 49 ++++++----------------------------- 1 file changed, 8 insertions(+), 41 deletions(-) diff --git a/sros2/sros2/api/_utilities.py b/sros2/sros2/api/_utilities.py index 0a0a5a82..eb382ad6 100644 --- a/sros2/sros2/api/_utilities.py +++ b/sros2/sros2/api/_utilities.py @@ -19,9 +19,9 @@ from cryptography import x509 from cryptography.hazmat.backends import default_backend as cryptography_backend -from cryptography.hazmat.bindings.openssl.binding import Binding as SSLBinding from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives import smime from cryptography.hazmat.primitives.asymmetric import ec _DOMAIN_ID_ENV = 'ROS_DOMAIN_ID' @@ -63,7 +63,13 @@ def create_smime_signed_file(cert_path, key_path, unsigned_file_path, signed_fil # Sign the contents, and write the result to the appropriate place with open(signed_file_path, 'wb') as f: - f.write(_sign_bytes(cert, private_key, content)) + builder = smime.SMIMESignatureBuilder( + content).add_signer( + cert, private_key, hashes.SHA256() + ) + f.write(builder.sign( + smime.SMIMEEncoding.PEM, + (smime.SMIMEOptions.Text, smime.SMIMEOptions.DetachedSignature))) def build_key_and_cert(subject_name, *, ca=False, ca_key=None, issuer_name=''): @@ -130,42 +136,3 @@ def load_cert(cert_path): with open(cert_path, 'rb') as cert_file: return x509.load_pem_x509_certificate( cert_file.read(), cryptography_backend()) - - -def _sign_bytes(cert, key, byte_string): - # Using two flags here to get the output required: - # - PKCS7_DETACHED: Use cleartext signing - # - PKCS7_TEXT: Set the MIME headers for text/plain - flags = SSLBinding.lib.PKCS7_DETACHED - flags |= SSLBinding.lib.PKCS7_TEXT - - # Convert the byte string into a buffer for SSL - bio_in = SSLBinding.lib.BIO_new_mem_buf(byte_string, len(byte_string)) - try: - pkcs7 = SSLBinding.lib.PKCS7_sign( - cert._x509, key._evp_pkey, SSLBinding.ffi.NULL, bio_in, flags) - finally: - # Free the memory allocated for the buffer - SSLBinding.lib.BIO_free(bio_in) - - # PKCS7_sign consumes the buffer; allocate a new one again to get it into the final document - bio_in = SSLBinding.lib.BIO_new_mem_buf(byte_string, len(byte_string)) - try: - # Allocate a buffer for the output document - bio_out = SSLBinding.lib.BIO_new(SSLBinding.lib.BIO_s_mem()) - try: - # Write the final document out to the buffer - SSLBinding.lib.SMIME_write_PKCS7(bio_out, pkcs7, bio_in, flags) - - # Copy the output document back to python-managed memory - result_buffer = SSLBinding.ffi.new('char**') - buffer_length = SSLBinding.lib.BIO_get_mem_data(bio_out, result_buffer) - output = SSLBinding.ffi.buffer(result_buffer[0], buffer_length)[:] - finally: - # Free the memory required for the output buffer - SSLBinding.lib.BIO_free(bio_out) - finally: - # Free the memory allocated for the input buffer - SSLBinding.lib.BIO_free(bio_in) - - return output