PKCS#7: add example to verify existing SignedData file

pull/400/head
Chris Conlon 2023-09-12 15:27:05 -06:00
parent 57e641e6a9
commit ccd28fda67
3 changed files with 362 additions and 0 deletions

2
.gitignore vendored
View File

@ -185,6 +185,8 @@ pkcs7/signedData-CompressedFirmwarePkgData
pkcs7/signedData-EncryptedCompressedFirmwarePkgData
pkcs7/signedData-EncryptedFirmwareCB
pkcs7/signedData-p7b
pkcs7/signedData-cryptocb
pkcs7/signedData-verifyFile
*.dSYM
certmanager/certloadverifybuffer

View File

@ -572,6 +572,50 @@ Successfully encoded Signed Encrypted Compressed FirmwarePkgData (signedEncrypte
Successfully extracted and verified bundle contents
```
### Verify SignedData bundle from existing file
Example file: `signedData-verifyFile.c`
This example allows the caller to pass in an existing PKCS#7/CMS bundle
in DER format, then attempts to verify the SignedData bundle using wolfCrypt.
Usage for this example is:
```
signedData-verifyFile X.X.X (NOTE: All files relative to current directory)
-? Help, print this usage
-b <file> PKCS#7/CMS bundle to verify (DER format)
-c <content> Detached content, if needed
```
If wolfSSL has been configured and compiled with debug support, the bytes
of the bundle will be printed out to the terminal window. For example to verify
the bundle created by the `signedData` example:
```
./signedData-verifyFile -b signedData_noattrs.der
wolfCrypt PKCS#7/CMS SignedData verification example
Read 1982 bytes from signedData_noattrs.der
Decoded content size is 11 bytes
Successfully verified SignedData bundle!
```
To verify SignedData bundles that represent a detached signature (which does
not include content in the bundle), use the `-c` option to pass in a file to
be used as the content. For example, to verify the bundle created by the
example application `signedData-DetachedSignature`:
```
./signedData-verifyFile -b signedData_detached_attrs.der -c content.txt
wolfCrypt PKCS#7/CMS SignedData verification example
Read 1987 bytes from signedData_detached_attrs.der
Read 11 bytes from content file: content.txt
Decoded content size is 11 bytes
Successfully verified SignedData bundle!
```
### Converting P7B Certificate Bundle to PEM using PKCS7 SignedData API
Build wolfssl using: `./configure --enable-pkcs7 CFLAGS="-DWOLFSSL_DER_TO_PEM"`

View File

@ -0,0 +1,316 @@
/* signedData-verifyFile.c
*
* Copyright (C) 2006-2023 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/pkcs7.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/logging.h>
#include <wolfssl/ssl.h>
#include <wolfssl/test.h>
/* Max PEM cert size, used to allocate memory below. Change as needed
* for your expected PEM certificate sizes */
#define MAX_PEM_CERT_SIZE 4096
/* The index of the command line option */
int myoptind = 0;
/* The current command line option */
char* myoptarg = NULL;
/**
* Verify PKCS#7/CMS bundle contained in bundleBytes, of size bundleSz.
*
* Return 0 on success, negative on error
*/
static int VerifySignedData(byte* bundleBytes, word32 bundleSz,
byte* detachedContent, word32 detachedContentSz)
{
int ret, i;
PKCS7* pkcs7 = NULL;
byte* singleCertDer; /* tmp ptr to one DER cert in decoded PKCS7 */
word32 singleCertDerSz; /* tmp size of one DER cert in decoded PKCS7 */
#ifdef WOLFSSL_DER_TO_PEM
byte* singleCertPem;
word32 singleCertPemSz;
#endif
(void)singleCertDer;
if (bundleBytes == NULL || bundleSz == 0) {
return BAD_FUNC_ARG;
}
pkcs7 = wc_PKCS7_New(NULL, INVALID_DEVID);
if (pkcs7 == NULL) {
printf("wc_PKCS7_New failed\n");
return -1;
}
if (detachedContent != NULL) {
pkcs7->content = detachedContent;
pkcs7->contentSz = detachedContentSz;
}
/* Decode signedData, returns size */
ret = wc_PKCS7_VerifySignedData(pkcs7, bundleBytes, bundleSz);
if (ret < 0) {
wc_PKCS7_Free(pkcs7);
return ret;
}
#ifdef DEBUG_WOLFSSL
printf("Decoded content (%d bytes):\n", pkcs7->contentSz);
WOLFSSL_BUFFER(pkcs7->content, pkcs7->contentSz);
#else
printf("Decoded content size is %d bytes\n", pkcs7->contentSz);
#endif
/* wc_PKCS7_VerifySignedData() decodes input PKCS#7 and stores
* decoded DER certificates into pkcs7->cert[]. Sizes of each cert entry
* is stored in the separate pkcs7->certSz[] array. Max size of each
* of the arrays is MAX_PKCS7_CERTS. Array memory is owned by wolfCrypt
* PKCS7 and freed when calling wc_PKCS7_Free(). */
for (i = 0; i < MAX_PKCS7_CERTS; i++) {
if (pkcs7->certSz[i] == 0) {
/* reached end of valid certs in array */
break;
}
singleCertDer = pkcs7->cert[i];
singleCertDerSz = pkcs7->certSz[i];
printf("CERT [%d] size = %d bytes\n", i, singleCertDerSz);
#ifdef WOLFSSL_DER_TO_PEM
/* allocate array for PEM */
singleCertPem = (byte*)XMALLOC(MAX_PEM_CERT_SIZE, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (singleCertPem == NULL) {
printf("Error allocating memory for PEM\n");
break;
}
singleCertPemSz = MAX_PEM_CERT_SIZE;
XMEMSET(singleCertPem, 0, singleCertPemSz);
/* convert DER to PEM */
singleCertPemSz = wc_DerToPem(singleCertDer, singleCertDerSz,
singleCertPem, singleCertPemSz,
CERT_TYPE);
if (singleCertPem < 0) {
printf("Error converting DER to PEM, ret = %d\n", ret);
XFREE(singleCertPem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
break;
}
printf("converted DER to PEM, pemSz = %d\n", singleCertPemSz);
printf("CERT [%d] PEM:\n", i);
/* print PEM to terminal, only if able to NULL terminate */
if (singleCertPemSz < MAX_PEM_CERT_SIZE - 1) {
singleCertPem[singleCertPemSz] = 0;
printf("%s\n", singleCertPem);
}
/* PEM is now in singleCertPem, of size singleCertPemSz */
XFREE(singleCertPem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif /* WOLFSSL_DER_TO_PEM */
}
wc_PKCS7_Free(pkcs7);
return ret;
}
#ifdef HAVE_PKCS7
/**
* Read file into newly-allocated buffer fileBytes, set size of allocated
* buffer into fileSz.
*
* Return 0 on success, negative on error
*/
static int ReadFile(char* fileName, byte** fileBytes, word32* fileSz)
{
int ret = 0;
FILE* fp = NULL;
word32 sz = 0;
if (fileName == NULL || fileBytes == NULL || fileSz == NULL) {
return -1;
}
fp = XFOPEN(fileName, "rb");
if (fp == XBADFILE) {
return -1;
}
if (XFSEEK(fp, 0, XSEEK_END) != 0) {
ret = -1;
}
if (ret == 0) {
sz = XFTELL(fp);
if (sz <= 0) {
ret = -1;
}
}
if (ret == 0) {
if (XFSEEK(fp, 0, XSEEK_SET) != 0) {
ret = -1;
}
}
if (ret == 0) {
*fileBytes = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (*fileBytes == NULL) {
ret = MEMORY_E;
}
else {
XMEMSET(*fileBytes, 0, sz);
*fileSz = sz;
}
}
if (ret == 0) {
if ((size_t)XFREAD(*fileBytes, 1, (size_t)sz, fp) != (size_t)sz) {
ret = -1;
}
}
if (fp != XBADFILE) {
XFCLOSE(fp);
}
return ret;
}
static void Usage(void)
{
printf("signedData-verifyFile " LIBWOLFSSL_VERSION_STRING
" (NOTE: All files relative to current directory)\n");
printf("-? Help, print this usage\n");
printf("-b <file> PKCS#7/CMS bundle to verify (DER format)\n");
printf("-c <content> Detached content, if needed\n");
}
int main(int argc, char** argv)
{
int ret = 0;
int ch = 0;
char* bundleFile = NULL;
byte* bundleBytes = NULL;
word32 bundleSz = 0;
char* detachedContentFile = NULL;
byte* detachedContentBytes = NULL;
word32 detachedContentSz = 0;
printf("wolfCrypt PKCS#7/CMS SignedData verification example\n\n");
while ((ch = mygetopt(argc, argv, "?b:c:")) != -1) {
switch (ch) {
case '?':
Usage();
exit(EXIT_SUCCESS);
/* File containing PKCS#7/CMS bundle */
case 'b':
bundleFile = myoptarg;
break;
case 'c':
detachedContentFile = myoptarg;
break;
default:
Usage();
exit(MY_EX_USAGE);
}
}
#ifdef DEBUG_WOLFSSL
wolfSSL_Debugging_ON();
#endif
wolfSSL_Init();
/* Read PKCS#7 bundle file into array */
ret = ReadFile(bundleFile, &bundleBytes, &bundleSz);
if (ret == 0) {
printf("Read %d bytes from %s\n", bundleSz, bundleFile);
}
else {
printf("Failed to read bundle file: %s\n", bundleFile);
}
/* Read detached content file into array, if given */
if (ret == 0 && detachedContentFile != NULL) {
ret = ReadFile(detachedContentFile, &detachedContentBytes,
&detachedContentSz);
if (ret == 0) {
printf("Read %d bytes from content file: %s\n",
detachedContentSz, detachedContentFile);
}
else {
printf("Failed to read content file: %s\n", detachedContentFile);
}
}
/* Verify PKCS#7/CMS SignedData bundle */
if (ret == 0) {
ret = VerifySignedData(bundleBytes, bundleSz,
detachedContentBytes, detachedContentSz);
if (ret == 0) {
printf("Successfully verified SignedData bundle!\n");
}
else {
printf("Failed to verify SignedData bundle, ret = %d\n", ret);
}
}
/* Free detached content array, allocated by ReadFile() */
if (detachedContentBytes != NULL) {
XMEMSET(detachedContentBytes, 0, detachedContentSz);
XFREE(detachedContentBytes, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
/* Free bundle array, allocated by ReadFile() */
if (bundleBytes != NULL) {
XMEMSET(bundleBytes, 0, bundleSz);
XFREE(bundleBytes, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
wolfSSL_Cleanup();
exit(EXIT_SUCCESS);
}
#else
int main(int argc, char** argv)
{
printf("Must build wolfSSL using ./configure --enable-pkcs7\n");
return 0;
}
#endif /* HAVE_PKCS7 */