@@ -673,13 +673,12 @@ fn compute_pkcs7_signature_algorithm<'p>(
673673}
674674
675675#[ pyo3:: pyfunction]
676- #[ pyo3( signature = ( signature, content = None , certificate = None , options = None ) ) ]
676+ #[ pyo3( signature = ( signature, content = None , certificate = None ) ) ]
677677fn verify_smime < ' p > (
678678 py : pyo3:: Python < ' p > ,
679679 signature : & [ u8 ] ,
680680 content : Option < & [ u8 ] > ,
681681 certificate : Option < pyo3:: Bound < ' p , x509:: certificate:: Certificate > > ,
682- options : Option < & pyo3:: Bound < ' p , pyo3:: types:: PyList > > ,
683682) -> CryptographyResult < ( ) > {
684683 // Parse the email
685684 let py_content_and_signature = types:: SMIME_SIGNED_DECODE . get ( py) ?. call1 ( ( signature, ) ) ?;
@@ -703,17 +702,16 @@ fn verify_smime<'p>(
703702 }
704703 } ;
705704
706- verify_der ( py, signature, content, certificate, options )
705+ verify_der ( py, signature, content, certificate)
707706}
708707
709708#[ pyo3:: pyfunction]
710- #[ pyo3( signature = ( signature, content = None , certificate = None , options = None ) ) ]
709+ #[ pyo3( signature = ( signature, content = None , certificate = None ) ) ]
711710fn verify_pem < ' p > (
712711 py : pyo3:: Python < ' p > ,
713712 signature : & [ u8 ] ,
714713 content : Option < & [ u8 ] > ,
715714 certificate : Option < pyo3:: Bound < ' p , x509:: certificate:: Certificate > > ,
716- options : Option < & pyo3:: Bound < ' p , pyo3:: types:: PyList > > ,
717715) -> CryptographyResult < ( ) > {
718716 let pem_str = std:: str:: from_utf8 ( signature)
719717 . map_err ( |_| pyo3:: exceptions:: PyValueError :: new_err ( "Invalid PEM data" ) ) ?;
@@ -729,25 +727,17 @@ fn verify_pem<'p>(
729727 ) ) ;
730728 }
731729
732- verify_der ( py, & pem. into_contents ( ) , content, certificate, options )
730+ verify_der ( py, & pem. into_contents ( ) , content, certificate)
733731}
734732
735733#[ pyo3:: pyfunction]
736- #[ pyo3( signature = ( signature, content = None , certificate = None , options = None ) ) ]
734+ #[ pyo3( signature = ( signature, content = None , certificate = None ) ) ]
737735fn verify_der < ' p > (
738736 py : pyo3:: Python < ' p > ,
739737 signature : & [ u8 ] ,
740738 content : Option < & [ u8 ] > ,
741739 certificate : Option < pyo3:: Bound < ' p , x509:: certificate:: Certificate > > ,
742- options : Option < & pyo3:: Bound < ' p , pyo3:: types:: PyList > > ,
743740) -> CryptographyResult < ( ) > {
744- // Check the verify options
745- let options = match options {
746- Some ( options) => Cow :: Borrowed ( options) ,
747- None => Cow :: Owned ( pyo3:: types:: PyList :: empty ( py) ) ,
748- } ;
749- check_verify_options ( py, & options) ?;
750-
751741 // Verify the data
752742 let content_info = asn1:: parse_single :: < pkcs7:: ContentInfo < ' _ > > ( signature) ?;
753743 match content_info. content {
@@ -793,88 +783,84 @@ fn verify_der<'p>(
793783
794784 // Get recipients, and find the one matching with the signer infos (if any)
795785 // TODO: what to do for multiple certificates?
796- if !options. contains ( types:: PKCS7_NO_SIGS . get ( py) ?) ? {
797- let mut signer_infos = signed_data. signer_infos . unwrap_read ( ) . clone ( ) ;
798- let signer_certificate = certificate. get ( ) . raw . borrow_dependent ( ) ;
799- let signer_serial_number = signer_certificate. tbs_cert . serial ;
800- let signer_issuer = signer_certificate. tbs_cert . issuer . clone ( ) ;
801- let found_signer_info = signer_infos. find ( |info| {
802- info. issuer_and_serial_number . serial_number == signer_serial_number
803- && info. issuer_and_serial_number . issuer == signer_issuer
804- } ) ;
786+ let mut signer_infos = signed_data. signer_infos . unwrap_read ( ) . clone ( ) ;
787+ let signer_certificate = certificate. get ( ) . raw . borrow_dependent ( ) ;
788+ let signer_serial_number = signer_certificate. tbs_cert . serial ;
789+ let signer_issuer = signer_certificate. tbs_cert . issuer . clone ( ) ;
790+ let found_signer_info = signer_infos. find ( |info| {
791+ info. issuer_and_serial_number . serial_number == signer_serial_number
792+ && info. issuer_and_serial_number . issuer == signer_issuer
793+ } ) ;
805794
806- // Raise error when no signer is found
807- let signer_info = match found_signer_info {
808- Some ( info) => info,
809- None => {
810- return Err ( CryptographyError :: from (
811- pyo3:: exceptions:: PyValueError :: new_err (
812- "No signer found that matches the given certificate." ,
813- ) ,
814- ) ) ;
815- }
816- } ;
817-
818- // Prepare the content: try to use the authenticated attributes, then the content stored
819- // in the signed data, then the provided content. If None of these are available, raise
820- // an error. TODO: what should the order be?
821- let data = match signer_info. authenticated_attributes {
822- Some ( attrs) => Cow :: Owned ( asn1:: write_single ( & attrs) ?) ,
823- None => match content {
824- Some ( data) => Cow :: Borrowed ( data) ,
825- None => match signed_data. content_info . content {
826- pkcs7:: Content :: Data ( Some ( data) ) => Cow :: Borrowed ( data. into_inner ( ) ) ,
827- _ => {
828- return Err ( CryptographyError :: from (
829- pyo3:: exceptions:: PyValueError :: new_err (
830- "No content stored in the signature or provided." ,
831- ) ,
832- ) ) ;
833- }
834- } ,
835- } ,
836- } ;
837-
838- // For RSA signatures (with no PSS padding), the OID is always the same no matter the
839- // digest algorithm. We need to modify the algorithm identifier to add the hash
840- // algorithm information. We are checking for RSA-256, which the S/MIME v3.2 RFC
841- // specifies as MUST support (https://datatracker.ietf.org/doc/html/rfc5751#section-2.2)
842- let signature_algorithm = match signer_info. digest_encryption_algorithm . oid ( ) {
843- & oid:: RSA_OID => match signer_info. digest_algorithm . oid ( ) {
844- & oid:: SHA256_OID => common:: AlgorithmIdentifier {
845- oid : asn1:: DefinedByMarker :: marker ( ) ,
846- params : common:: AlgorithmParameters :: RsaWithSha256 ( Some ( ( ) ) ) ,
847- } ,
795+ // Raise error when no signer is found
796+ let signer_info = match found_signer_info {
797+ Some ( info) => info,
798+ None => {
799+ return Err ( CryptographyError :: from (
800+ pyo3:: exceptions:: PyValueError :: new_err (
801+ "No signer found that matches the given certificate." ,
802+ ) ,
803+ ) ) ;
804+ }
805+ } ;
806+
807+ // Prepare the content: try to use the authenticated attributes, then the content stored
808+ // in the signed data, then the provided content. If None of these are available, raise
809+ // an error. TODO: what should the order be?
810+ let data = match signer_info. authenticated_attributes {
811+ Some ( attrs) => Cow :: Owned ( asn1:: write_single ( & attrs) ?) ,
812+ None => match content {
813+ Some ( data) => Cow :: Borrowed ( data) ,
814+ None => match signed_data. content_info . content {
815+ pkcs7:: Content :: Data ( Some ( data) ) => Cow :: Borrowed ( data. into_inner ( ) ) ,
848816 _ => {
849817 return Err ( CryptographyError :: from (
850- exceptions:: UnsupportedAlgorithm :: new_err ( (
851- "Only SHA-256 is currently supported for content verification with RSA." ,
852- exceptions:: Reasons :: UNSUPPORTED_SERIALIZATION ,
853- ) ) ,
854- ) )
818+ pyo3:: exceptions:: PyValueError :: new_err (
819+ "No content stored in the signature or provided." ,
820+ ) ,
821+ ) ) ;
855822 }
856823 } ,
857- _ => signer_info. digest_encryption_algorithm ,
858- } ;
859-
860- // Verify the signature
861- x509:: sign:: verify_signature_with_signature_algorithm (
862- py,
863- certificate. call_method0 ( pyo3:: intern!( py, "public_key" ) ) ?,
864- & signature_algorithm,
865- signer_info. encrypted_digest ,
866- & data,
867- ) ?;
868- }
824+ } ,
825+ } ;
826+
827+ // For RSA signatures (with no PSS padding), the OID is always the same no matter the
828+ // digest algorithm. We need to modify the algorithm identifier to add the hash
829+ // algorithm information. We are checking for RSA-256, which the S/MIME v3.2 RFC
830+ // specifies as MUST support (https://datatracker.ietf.org/doc/html/rfc5751#section-2.2)
831+ let signature_algorithm = match signer_info. digest_encryption_algorithm . oid ( ) {
832+ & oid:: RSA_OID => match signer_info. digest_algorithm . oid ( ) {
833+ & oid:: SHA256_OID => common:: AlgorithmIdentifier {
834+ oid : asn1:: DefinedByMarker :: marker ( ) ,
835+ params : common:: AlgorithmParameters :: RsaWithSha256 ( Some ( ( ) ) ) ,
836+ } ,
837+ _ => {
838+ return Err ( CryptographyError :: from (
839+ exceptions:: UnsupportedAlgorithm :: new_err ( (
840+ "Only SHA-256 is currently supported for content verification with RSA." ,
841+ exceptions:: Reasons :: UNSUPPORTED_SERIALIZATION ,
842+ ) ) ,
843+ ) )
844+ }
845+ } ,
846+ _ => signer_info. digest_encryption_algorithm ,
847+ } ;
848+
849+ // Verify the signature
850+ x509:: sign:: verify_signature_with_signature_algorithm (
851+ py,
852+ certificate. call_method0 ( pyo3:: intern!( py, "public_key" ) ) ?,
853+ & signature_algorithm,
854+ signer_info. encrypted_digest ,
855+ & data,
856+ ) ?;
869857
870858 // Verify the certificate
871- if !options. contains ( types:: PKCS7_NO_VERIFY . get ( py) ?) ? {
872- let certificates = pyo3:: types:: PyList :: empty ( py) ;
873- certificates. append ( certificate) ?;
874- types:: VERIFY_PKCS7_CERTIFICATES
875- . get ( py) ?
876- . call1 ( ( certificates, ) ) ?;
877- }
859+ let certificates = pyo3:: types:: PyList :: empty ( py) ;
860+ certificates. append ( certificate) ?;
861+ types:: VERIFY_PKCS7_CERTIFICATES
862+ . get ( py) ?
863+ . call1 ( ( certificates, ) ) ?;
878864 }
879865 _ => {
880866 return Err ( CryptographyError :: from (
@@ -888,38 +874,6 @@ fn verify_der<'p>(
888874 Ok ( ( ) )
889875}
890876
891- fn check_verify_options < ' p > (
892- py : pyo3:: Python < ' p > ,
893- options : & pyo3:: Bound < ' p , pyo3:: types:: PyList > ,
894- ) -> Result < ( ) , CryptographyError > {
895- // Check if all options are from the PKCS7Options enum
896- let pkcs7_options = types:: PKCS7_OPTIONS . get ( py) ?;
897- for opt in options. iter ( ) {
898- if !opt. is_instance ( & pkcs7_options) ? {
899- return Err ( CryptographyError :: from (
900- pyo3:: exceptions:: PyValueError :: new_err (
901- "options must be from the PKCS7Options enum" ,
902- ) ,
903- ) ) ;
904- }
905- }
906-
907- // Check if any option is not PKCS7Options::NoVerify
908- let no_verify_option = types:: PKCS7_NO_VERIFY . get ( py) ?;
909- let no_sigs_option = types:: PKCS7_NO_SIGS . get ( py) ?;
910- for opt in options. iter ( ) {
911- if opt. ne ( no_verify_option. clone ( ) ) ? & opt. ne ( no_sigs_option. clone ( ) ) ? {
912- return Err ( CryptographyError :: from (
913- pyo3:: exceptions:: PyValueError :: new_err (
914- "Only the following options are supported for verification: NoVerify, NoSigs" ,
915- ) ,
916- ) ) ;
917- }
918- }
919-
920- Ok ( ( ) )
921- }
922-
923877fn smime_canonicalize ( data : & [ u8 ] , text_mode : bool ) -> ( Cow < ' _ , [ u8 ] > , Cow < ' _ , [ u8 ] > ) {
924878 let mut new_data_with_header = vec ! [ ] ;
925879 let mut new_data_without_header = vec ! [ ] ;
0 commit comments