pkcs7: Support verification of hash with multiple signers

Make `mbedtls_pkcs7_signed_hash_verify` loop over all signatures in the
PKCS7 structure and return success if any of them verify successfully.

Signed-off-by: Nick Child <nick.child@ibm.com>
diff --git a/library/pkcs7.c b/library/pkcs7.c
index 0f4e1ec..65dc83a 100644
--- a/library/pkcs7.c
+++ b/library/pkcs7.c
@@ -637,18 +637,41 @@
                                       const mbedtls_x509_crt *cert,
                                       const unsigned char *hash, size_t hashlen)
 {
-    int ret;
+    int ret = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+    const mbedtls_md_info_t *md_info;
     mbedtls_md_type_t md_alg;
     mbedtls_pk_context pk_cxt;
-
-    ret = mbedtls_oid_get_md_alg( &pkcs7->signed_data.digest_alg_identifiers, &md_alg );
-    if( ret != 0 )
-        return( MBEDTLS_ERR_PKCS7_VERIFY_FAIL );
+    mbedtls_pkcs7_signer_info *signer;
 
     pk_cxt = cert->pk;
-    ret = mbedtls_pk_verify( &pk_cxt, md_alg, hash, hashlen,
-                             pkcs7->signed_data.signers.sig.p,
-                             pkcs7->signed_data.signers.sig.len );
+
+    if( pkcs7->signed_data.no_of_signers == 0 )
+        return( MBEDTLS_ERR_PKCS7_VERIFY_FAIL );
+
+    signer = &pkcs7->signed_data.signers;
+    while( signer )
+    {
+        ret = mbedtls_oid_get_md_alg( &signer->alg_identifier, &md_alg );
+        if( ret != 0 )
+            return( MBEDTLS_ERR_PKCS7_VERIFY_FAIL );
+
+        md_info = mbedtls_md_info_from_type( md_alg );
+
+        if( hashlen != mbedtls_md_get_size( md_info ) )
+        {
+            ret = MBEDTLS_ERR_PKCS7_VERIFY_FAIL;
+            signer = signer->next;
+            continue;
+        }
+
+        ret = mbedtls_pk_verify( &pk_cxt, md_alg, hash, hashlen,
+                                 pkcs7->signed_data.signers.sig.p,
+                                 pkcs7->signed_data.signers.sig.len );
+        if( ret == 0 )
+            break;
+
+        signer = signer->next;
+    }
 
     return ( ret );
 }
diff --git a/tests/suites/test_suite_pkcs7.data b/tests/suites/test_suite_pkcs7.data
index daced32..b813c6d 100644
--- a/tests/suites/test_suite_pkcs7.data
+++ b/tests/suites/test_suite_pkcs7.data
@@ -68,4 +68,8 @@
 
 PKCS7 Signed Data Verify with multiple signers #16
 depends_on:MBEDTLS_SHA256_C
-pkcs7_verify_multiple_signers:"data_files/pkcs7_data_multiple_signed.der":"data_files/pkcs7-rsa-sha256-1.crt":"data_files/pkcs7-rsa-sha256-2.crt":"data_files/pkcs7_data.bin"
\ No newline at end of file
+pkcs7_verify_multiple_signers:"data_files/pkcs7_data_multiple_signed.der":"data_files/pkcs7-rsa-sha256-1.crt":"data_files/pkcs7-rsa-sha256-2.crt":"data_files/pkcs7_data.bin"
+
+PKCS7 Signed Data Hash Verify with multiple signers #17
+depends_on:MBEDTLS_SHA256_C
+pkcs7_verify_hash_multiple_signers:"data_files/pkcs7_data_multiple_signed.der":"data_files/pkcs7-rsa-sha256-1.crt":"data_files/pkcs7-rsa-sha256-2.crt":"data_files/pkcs7_data.bin"
diff --git a/tests/suites/test_suite_pkcs7.function b/tests/suites/test_suite_pkcs7.function
index 261824d..9822fb8 100644
--- a/tests/suites/test_suite_pkcs7.function
+++ b/tests/suites/test_suite_pkcs7.function
@@ -294,6 +294,82 @@
 /* END_CASE */
 
 /* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C:MBEDTLS_PKCS1_V15:MBEDTLS_RSA_C */
+void pkcs7_verify_hash_multiple_signers( char *pkcs7_file, char *crt1, char *crt2, char *filetobesigned )
+{
+    unsigned char *pkcs7_buf = NULL;
+    size_t buflen;
+    unsigned char *data = NULL;
+    unsigned char hash[32];
+    struct stat st;
+    size_t datalen;
+    int res;
+    FILE *file;
+    const mbedtls_md_info_t *md_info;
+    mbedtls_md_type_t md_alg;
+
+    mbedtls_pkcs7 pkcs7;
+    mbedtls_x509_crt x509_1;
+    mbedtls_x509_crt x509_2;
+
+    USE_PSA_INIT();
+
+    mbedtls_pkcs7_init( &pkcs7 );
+    mbedtls_x509_crt_init( &x509_1 );
+    mbedtls_x509_crt_init( &x509_2 );
+
+    res = mbedtls_pk_load_file( pkcs7_file, &pkcs7_buf, &buflen );
+    TEST_ASSERT( res == 0 );
+
+    res = mbedtls_pkcs7_parse_der( &pkcs7, pkcs7_buf, buflen );
+    TEST_ASSERT( res == MBEDTLS_PKCS7_SIGNED_DATA );
+
+    TEST_ASSERT( pkcs7.signed_data.no_of_signers == 2 );
+
+    res = mbedtls_x509_crt_parse_file( &x509_1, crt1 );
+    TEST_ASSERT( res == 0 );
+
+    res = mbedtls_x509_crt_parse_file( &x509_2, crt2 );
+    TEST_ASSERT( res == 0 );
+
+    res = stat( filetobesigned, &st );
+    TEST_ASSERT( res == 0 );
+
+    file = fopen( filetobesigned, "r" );
+    TEST_ASSERT( file != NULL );
+
+    datalen = st.st_size;
+    data = ( unsigned char* ) calloc( datalen, sizeof(unsigned char) );
+    buflen = fread( ( void * )data , sizeof( unsigned char ), datalen, file );
+    TEST_ASSERT( buflen == datalen );
+
+    fclose( file );
+
+    res = mbedtls_oid_get_md_alg( &(pkcs7.signed_data.digest_alg_identifiers), &md_alg );
+    TEST_ASSERT( res == 0 );
+    TEST_ASSERT( md_alg == MBEDTLS_MD_SHA256 );
+
+    md_info = mbedtls_md_info_from_type( md_alg );
+
+    res = mbedtls_md( md_info, data, datalen, hash );
+    TEST_ASSERT( res == 0 );
+
+    res = mbedtls_pkcs7_signed_hash_verify( &pkcs7, &x509_1, hash, sizeof(hash));
+    TEST_ASSERT( res == 0 );
+
+    res = mbedtls_pkcs7_signed_data_verify( &pkcs7, &x509_2, data, datalen );
+    TEST_ASSERT( res == 0 );
+
+exit:
+    mbedtls_x509_crt_free( &x509_1 );
+    mbedtls_x509_crt_free( &x509_2 );
+    mbedtls_pkcs7_free( &pkcs7 );
+    mbedtls_free( data );
+    mbedtls_free( pkcs7_buf );
+    USE_PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C:MBEDTLS_PKCS1_V15:MBEDTLS_RSA_C */
 void pkcs7_verify_badcert( char *pkcs7_file, char *crt, char *filetobesigned )
 {
     unsigned char *pkcs7_buf = NULL;