diff --git a/certs/include.am b/certs/include.am index cf7a4aa11..8e1b17efe 100644 --- a/certs/include.am +++ b/certs/include.am @@ -37,6 +37,7 @@ EXTRA_DIST += \ certs/server-revoked-cert.pem \ certs/server-revoked-key.pem \ certs/wolfssl-website-ca.pem \ + certs/test-degenerate.p7b \ certs/test-servercert.p12 \ certs/ecc-rsa-server.p12 \ certs/dsaparams.pem \ diff --git a/certs/renewcerts.sh b/certs/renewcerts.sh index 611d8e82b..f34e07edd 100755 --- a/certs/renewcerts.sh +++ b/certs/renewcerts.sh @@ -30,6 +30,9 @@ # crl/crl.revoked # crl/eccCliCRL.pem # crl/eccSrvCRL.pem +# +# pkcs7: +# test-degenerate.p7b # if HAVE_NTRU # ntru-cert.pem # ntru-key.raw @@ -570,6 +573,19 @@ run_renewcerts(){ echo "ran ./gencrls.sh" echo "" + ############################################################ + ########## generate PKCS7 bundles ########################## + ############################################################ + echo "Changing directory to wolfssl certs..." + echo "" + cd ../ || exit 1 + echo "Creating test-degenerate.p7b..." + echo "" + openssl crl2pkcs7 -nocrl -certfile ./client-cert.pem -out test-degenerate.p7b -outform DER + check_result $? "" + echo "End of section" + echo "---------------------------------------------------------------------" + #cleanup the file system now that we're done echo "Performing final steps, cleaning up the file system..." echo "" diff --git a/certs/test-degenerate.p7b b/certs/test-degenerate.p7b new file mode 100644 index 000000000..f52482f9b Binary files /dev/null and b/certs/test-degenerate.p7b differ diff --git a/tests/api.c b/tests/api.c index f555f3517..cefdbb1d4 100644 --- a/tests/api.c +++ b/tests/api.c @@ -15897,6 +15897,42 @@ static void test_wc_PKCS7_EncodeEncryptedData (void) #endif } /* END test_wc_PKCS7_EncodeEncryptedData() */ +/* + * Testing wc_PKCS7_Degenerate() + */ +static void test_wc_PKCS7_Degenerate(void) +{ +#if defined(HAVE_PKCS7) && !defined(NO_FILESYSTEM) + PKCS7 pkcs7; + char fName[] = "./certs/test-degenerate.p7b"; + XFILE f; + byte der[4096]; + word32 derSz; + + printf(testingFmt, "wc_PKCS7_Degenerate()"); + + AssertNotNull(f = XFOPEN(fName, "rb")); + AssertIntGT((derSz = fread(der, 1, sizeof(der), f)), 0); + XFCLOSE(f); + + /* test degenerate success */ + AssertIntEQ(wc_PKCS7_Init(&pkcs7, HEAP_HINT, INVALID_DEVID), 0); + AssertIntEQ(wc_PKCS7_InitWithCert(&pkcs7, NULL, 0), 0); + AssertIntEQ(wc_PKCS7_VerifySignedData(&pkcs7, der, derSz), 0); + wc_PKCS7_Free(&pkcs7); + + /* test with turning off degenerate cases */ + AssertIntEQ(wc_PKCS7_Init(&pkcs7, HEAP_HINT, INVALID_DEVID), 0); + AssertIntEQ(wc_PKCS7_InitWithCert(&pkcs7, NULL, 0), 0); + wc_PKCS7_AllowDegenerate(&pkcs7, 0); /* override allowing degenerate case */ + AssertIntEQ(wc_PKCS7_VerifySignedData(&pkcs7, der, derSz), PKCS7_NO_SIGNER_E); + wc_PKCS7_Free(&pkcs7); + + printf(resultFmt, passed); +#endif +} /* END test_wc_PKCS7_Degenerate() */ + + /* Testing wc_SignatureGetSize() for signature type ECC */ static int test_wc_SignatureGetSize_ecc(void) { @@ -22474,6 +22510,7 @@ void ApiTest(void) test_wc_PKCS7_VerifySignedData(); test_wc_PKCS7_EncodeDecodeEnvelopedData(); test_wc_PKCS7_EncodeEncryptedData(); + test_wc_PKCS7_Degenerate(); test_wolfSSL_CTX_LoadCRL(); diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 5dd34252f..52b995517 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -1897,7 +1897,33 @@ static int wc_PKCS7_ParseAttribs(PKCS7* pkcs7, byte* in, int inSz) return found; } -/* Finds the certificates in the message and saves it. */ + +/* option to turn off support for degenerate cases + * flag 0 turns off support + * flag 1 turns on support + * + * by default support for SignedData degenerate cases is on + */ +void wc_PKCS7_AllowDegenerate(PKCS7* pkcs7, word16 flag) +{ + if (pkcs7) { + if (flag) { /* flag of 1 turns on support for degenerate */ + pkcs7->noDegenerate = 0; + } + else { /* flag of 0 turns off support */ + pkcs7->noDegenerate = 1; + } + } +} + +/* Finds the certificates in the message and saves it. By default allows + * degenerate cases which can have no signer. + * + * By default expects type SIGNED_DATA (SignedData) which can have any number of + * elements in signerInfos collection, inluding zero. (RFC2315 section 9.1) + * When adding support for the case of SignedAndEnvelopedData content types a + * signer is required. In this case the PKCS7 flag noDegenerate could be set. + */ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, word32 hashSz, byte* pkiMsg, word32 pkiMsgSz, byte* pkiMsg2, word32 pkiMsg2Sz) @@ -1993,6 +2019,9 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, /* Skip the set. */ idx += length; degenerate = (length == 0)? 1 : 0; + if (pkcs7->noDegenerate == 1 && degenerate == 1) { + return PKCS7_NO_SIGNER_E; + } /* Get the inner ContentInfo sequence */ if (GetSequence(pkiMsg, &idx, &length, totalSz) < 0) @@ -2135,8 +2164,10 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, /* update idx if successful */ if (ret == 0) idx = localIdx; - else - pkiMsg2 = pkiMsg; + else { + pkiMsg2 = pkiMsg; + pkiMsg2Sz = pkiMsgSz; + } /* If getting the content info failed with non degenerate then return the * error case. Otherwise with a degenerate it is ok if the content @@ -2223,88 +2254,96 @@ static int PKCS7_VerifySignedData(PKCS7* pkcs7, const byte* hashBuf, if (GetSet(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) return ASN_PARSE_E; - if (length == 0) + /* require a signer if degenerate case not allowed */ + if (length == 0 && pkcs7->noDegenerate == 1) return PKCS7_NO_SIGNER_E; - /* Get the sequence of the first signerInfo */ - if (GetSequence(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) - return ASN_PARSE_E; - - /* Get the version */ - if (GetMyVersion(pkiMsg2, &idx, &version, pkiMsg2Sz) < 0) - return ASN_PARSE_E; - - if (version != 1) { - WOLFSSL_MSG("PKCS#7 signerInfo needs to be of version 1"); - return ASN_VERSION_E; + if (degenerate == 0 && length == 0) { + WOLFSSL_MSG("PKCS7 signers expected"); + return PKCS7_NO_SIGNER_E; } - /* Get the sequence of IssuerAndSerialNumber */ - if (GetSequence(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) - return ASN_PARSE_E; - - /* Skip it */ - idx += length; - - /* Get the sequence of digestAlgorithm */ - if (GetAlgoId(pkiMsg2, &idx, &hashOID, oidHashType, pkiMsg2Sz) < 0) { - return ASN_PARSE_E; - } - pkcs7->hashOID = (int)hashOID; - - /* Get the IMPLICIT[0] SET OF signedAttributes */ - if (pkiMsg2[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { - idx++; - - if (GetLength(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) + if (length > 0 && degenerate == 0) { + /* Get the sequence of the first signerInfo */ + if (GetSequence(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) return ASN_PARSE_E; - /* save pointer and length */ - signedAttrib = &pkiMsg2[idx]; - signedAttribSz = length; + /* Get the version */ + if (GetMyVersion(pkiMsg2, &idx, &version, pkiMsg2Sz) < 0) + return ASN_PARSE_E; - if (wc_PKCS7_ParseAttribs(pkcs7, signedAttrib, signedAttribSz) <0) { - WOLFSSL_MSG("Error parsing signed attributes"); + if (version != 1) { + WOLFSSL_MSG("PKCS#7 signerInfo needs to be of version 1"); + return ASN_VERSION_E; + } + + /* Get the sequence of IssuerAndSerialNumber */ + if (GetSequence(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) + return ASN_PARSE_E; + + /* Skip it */ + idx += length; + + /* Get the sequence of digestAlgorithm */ + if (GetAlgoId(pkiMsg2, &idx, &hashOID, oidHashType, pkiMsg2Sz) < 0) { + return ASN_PARSE_E; + } + pkcs7->hashOID = (int)hashOID; + + /* Get the IMPLICIT[0] SET OF signedAttributes */ + if (pkiMsg2[idx] == (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) { + idx++; + + if (GetLength(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) + return ASN_PARSE_E; + + /* save pointer and length */ + signedAttrib = &pkiMsg2[idx]; + signedAttribSz = length; + + if (wc_PKCS7_ParseAttribs(pkcs7, signedAttrib, signedAttribSz) <0) { + WOLFSSL_MSG("Error parsing signed attributes"); + return ASN_PARSE_E; + } + + idx += length; + } + + /* Get digestEncryptionAlgorithm */ + if (GetAlgoId(pkiMsg2, &idx, &sigOID, oidSigType, pkiMsg2Sz) < 0) { return ASN_PARSE_E; } - idx += length; - } + /* store public key type based on digestEncryptionAlgorithm */ + ret = wc_PKCS7_SetPublicKeyOID(pkcs7, sigOID); + if (ret <= 0) { + WOLFSSL_MSG("Failed to set public key OID from signature"); + return ret; + } - /* Get digestEncryptionAlgorithm */ - if (GetAlgoId(pkiMsg2, &idx, &sigOID, oidSigType, pkiMsg2Sz) < 0) { - return ASN_PARSE_E; - } + /* Get the signature */ + if (pkiMsg2[idx] == ASN_OCTET_STRING) { + idx++; - /* store public key type based on digestEncryptionAlgorithm */ - ret = wc_PKCS7_SetPublicKeyOID(pkcs7, sigOID); - if (ret <= 0) { - WOLFSSL_MSG("Failed to set public key OID from signature"); - return ret; - } + if (GetLength(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) + return ASN_PARSE_E; - /* Get the signature */ - if (pkiMsg2[idx] == ASN_OCTET_STRING) { - idx++; + /* save pointer and length */ + sig = &pkiMsg2[idx]; + sigSz = length; - if (GetLength(pkiMsg2, &idx, &length, pkiMsg2Sz) < 0) - return ASN_PARSE_E; + idx += length; + } - /* save pointer and length */ - sig = &pkiMsg2[idx]; - sigSz = length; + pkcs7->content = content; + pkcs7->contentSz = contentSz; - idx += length; - } - - pkcs7->content = content; - pkcs7->contentSz = contentSz; - - ret = wc_PKCS7_SignedDataVerifySignature(pkcs7, sig, sigSz, + ret = wc_PKCS7_SignedDataVerifySignature(pkcs7, sig, sigSz, signedAttrib, signedAttribSz, hashBuf, hashSz); - if (ret < 0) - return ret; + if (ret < 0) + return ret; + } return 0; } diff --git a/wolfssl/wolfcrypt/pkcs7.h b/wolfssl/wolfcrypt/pkcs7.h index 5c1c14587..41a39e757 100644 --- a/wolfssl/wolfcrypt/pkcs7.h +++ b/wolfssl/wolfcrypt/pkcs7.h @@ -145,6 +145,7 @@ typedef struct PKCS7 { /* flags - up to 16-bits */ word16 isDynamic:1; + word16 noDegenerate:1; /* allow degenerate case in verify function */ /* !! NEW DATA MEMBERS MUST BE ADDED AT END !! */ } PKCS7; @@ -164,6 +165,7 @@ WOLFSSL_API int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, WOLFSSL_API int wc_PKCS7_EncodeSignedData_ex(PKCS7* pkcs7, const byte* hashBuf, word32 hashSz, byte* outputHead, word32* outputHeadSz, byte* outputFoot, word32* outputFootSz); +WOLFSSL_API void wc_PKCS7_AllowDegenerate(PKCS7* pkcs7, word16 flag); WOLFSSL_API int wc_PKCS7_VerifySignedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz); WOLFSSL_API int wc_PKCS7_VerifySignedData_ex(PKCS7* pkcs7, const byte* hashBuf,