Skip to content

Commit ccd28fd

Browse files
committed
PKCS#7: add example to verify existing SignedData file
1 parent 57e641e commit ccd28fd

3 files changed

Lines changed: 362 additions & 0 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ pkcs7/signedData-CompressedFirmwarePkgData
185185
pkcs7/signedData-EncryptedCompressedFirmwarePkgData
186186
pkcs7/signedData-EncryptedFirmwareCB
187187
pkcs7/signedData-p7b
188+
pkcs7/signedData-cryptocb
189+
pkcs7/signedData-verifyFile
188190

189191
*.dSYM
190192
certmanager/certloadverifybuffer

pkcs7/README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,50 @@ Successfully encoded Signed Encrypted Compressed FirmwarePkgData (signedEncrypte
572572
Successfully extracted and verified bundle contents
573573
```
574574

575+
### Verify SignedData bundle from existing file
576+
577+
Example file: `signedData-verifyFile.c`
578+
579+
This example allows the caller to pass in an existing PKCS#7/CMS bundle
580+
in DER format, then attempts to verify the SignedData bundle using wolfCrypt.
581+
582+
Usage for this example is:
583+
584+
```
585+
signedData-verifyFile X.X.X (NOTE: All files relative to current directory)
586+
-? Help, print this usage
587+
-b <file> PKCS#7/CMS bundle to verify (DER format)
588+
-c <content> Detached content, if needed
589+
```
590+
591+
If wolfSSL has been configured and compiled with debug support, the bytes
592+
of the bundle will be printed out to the terminal window. For example to verify
593+
the bundle created by the `signedData` example:
594+
595+
```
596+
./signedData-verifyFile -b signedData_noattrs.der
597+
wolfCrypt PKCS#7/CMS SignedData verification example
598+
599+
Read 1982 bytes from signedData_noattrs.der
600+
Decoded content size is 11 bytes
601+
Successfully verified SignedData bundle!
602+
```
603+
604+
To verify SignedData bundles that represent a detached signature (which does
605+
not include content in the bundle), use the `-c` option to pass in a file to
606+
be used as the content. For example, to verify the bundle created by the
607+
example application `signedData-DetachedSignature`:
608+
609+
```
610+
./signedData-verifyFile -b signedData_detached_attrs.der -c content.txt
611+
wolfCrypt PKCS#7/CMS SignedData verification example
612+
613+
Read 1987 bytes from signedData_detached_attrs.der
614+
Read 11 bytes from content file: content.txt
615+
Decoded content size is 11 bytes
616+
Successfully verified SignedData bundle!
617+
```
618+
575619
### Converting P7B Certificate Bundle to PEM using PKCS7 SignedData API
576620

577621
Build wolfssl using: `./configure --enable-pkcs7 CFLAGS="-DWOLFSSL_DER_TO_PEM"`

pkcs7/signedData-verifyFile.c

Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
/* signedData-verifyFile.c
2+
*
3+
* Copyright (C) 2006-2023 wolfSSL Inc.
4+
*
5+
* This file is part of wolfSSL. (formerly known as CyaSSL)
6+
*
7+
* wolfSSL is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 2 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfSSL is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
20+
*/
21+
#include <wolfssl/options.h>
22+
#include <wolfssl/wolfcrypt/settings.h>
23+
#include <wolfssl/wolfcrypt/pkcs7.h>
24+
#include <wolfssl/wolfcrypt/error-crypt.h>
25+
#include <wolfssl/wolfcrypt/logging.h>
26+
27+
#include <wolfssl/ssl.h>
28+
#include <wolfssl/test.h>
29+
30+
/* Max PEM cert size, used to allocate memory below. Change as needed
31+
* for your expected PEM certificate sizes */
32+
#define MAX_PEM_CERT_SIZE 4096
33+
34+
/* The index of the command line option */
35+
int myoptind = 0;
36+
37+
/* The current command line option */
38+
char* myoptarg = NULL;
39+
40+
/**
41+
* Verify PKCS#7/CMS bundle contained in bundleBytes, of size bundleSz.
42+
*
43+
* Return 0 on success, negative on error
44+
*/
45+
static int VerifySignedData(byte* bundleBytes, word32 bundleSz,
46+
byte* detachedContent, word32 detachedContentSz)
47+
{
48+
int ret, i;
49+
PKCS7* pkcs7 = NULL;
50+
byte* singleCertDer; /* tmp ptr to one DER cert in decoded PKCS7 */
51+
word32 singleCertDerSz; /* tmp size of one DER cert in decoded PKCS7 */
52+
#ifdef WOLFSSL_DER_TO_PEM
53+
byte* singleCertPem;
54+
word32 singleCertPemSz;
55+
#endif
56+
(void)singleCertDer;
57+
58+
if (bundleBytes == NULL || bundleSz == 0) {
59+
return BAD_FUNC_ARG;
60+
}
61+
62+
pkcs7 = wc_PKCS7_New(NULL, INVALID_DEVID);
63+
if (pkcs7 == NULL) {
64+
printf("wc_PKCS7_New failed\n");
65+
return -1;
66+
}
67+
68+
if (detachedContent != NULL) {
69+
pkcs7->content = detachedContent;
70+
pkcs7->contentSz = detachedContentSz;
71+
}
72+
73+
/* Decode signedData, returns size */
74+
ret = wc_PKCS7_VerifySignedData(pkcs7, bundleBytes, bundleSz);
75+
if (ret < 0) {
76+
wc_PKCS7_Free(pkcs7);
77+
return ret;
78+
}
79+
80+
#ifdef DEBUG_WOLFSSL
81+
printf("Decoded content (%d bytes):\n", pkcs7->contentSz);
82+
WOLFSSL_BUFFER(pkcs7->content, pkcs7->contentSz);
83+
#else
84+
printf("Decoded content size is %d bytes\n", pkcs7->contentSz);
85+
#endif
86+
87+
/* wc_PKCS7_VerifySignedData() decodes input PKCS#7 and stores
88+
* decoded DER certificates into pkcs7->cert[]. Sizes of each cert entry
89+
* is stored in the separate pkcs7->certSz[] array. Max size of each
90+
* of the arrays is MAX_PKCS7_CERTS. Array memory is owned by wolfCrypt
91+
* PKCS7 and freed when calling wc_PKCS7_Free(). */
92+
93+
for (i = 0; i < MAX_PKCS7_CERTS; i++) {
94+
if (pkcs7->certSz[i] == 0) {
95+
/* reached end of valid certs in array */
96+
break;
97+
}
98+
99+
singleCertDer = pkcs7->cert[i];
100+
singleCertDerSz = pkcs7->certSz[i];
101+
printf("CERT [%d] size = %d bytes\n", i, singleCertDerSz);
102+
103+
#ifdef WOLFSSL_DER_TO_PEM
104+
/* allocate array for PEM */
105+
singleCertPem = (byte*)XMALLOC(MAX_PEM_CERT_SIZE, NULL,
106+
DYNAMIC_TYPE_TMP_BUFFER);
107+
if (singleCertPem == NULL) {
108+
printf("Error allocating memory for PEM\n");
109+
break;
110+
}
111+
singleCertPemSz = MAX_PEM_CERT_SIZE;
112+
XMEMSET(singleCertPem, 0, singleCertPemSz);
113+
114+
/* convert DER to PEM */
115+
singleCertPemSz = wc_DerToPem(singleCertDer, singleCertDerSz,
116+
singleCertPem, singleCertPemSz,
117+
CERT_TYPE);
118+
if (singleCertPem < 0) {
119+
printf("Error converting DER to PEM, ret = %d\n", ret);
120+
XFREE(singleCertPem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
121+
break;
122+
}
123+
printf("converted DER to PEM, pemSz = %d\n", singleCertPemSz);
124+
printf("CERT [%d] PEM:\n", i);
125+
126+
/* print PEM to terminal, only if able to NULL terminate */
127+
if (singleCertPemSz < MAX_PEM_CERT_SIZE - 1) {
128+
singleCertPem[singleCertPemSz] = 0;
129+
printf("%s\n", singleCertPem);
130+
}
131+
132+
/* PEM is now in singleCertPem, of size singleCertPemSz */
133+
XFREE(singleCertPem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
134+
#endif /* WOLFSSL_DER_TO_PEM */
135+
}
136+
137+
wc_PKCS7_Free(pkcs7);
138+
139+
return ret;
140+
}
141+
142+
#ifdef HAVE_PKCS7
143+
144+
/**
145+
* Read file into newly-allocated buffer fileBytes, set size of allocated
146+
* buffer into fileSz.
147+
*
148+
* Return 0 on success, negative on error
149+
*/
150+
static int ReadFile(char* fileName, byte** fileBytes, word32* fileSz)
151+
{
152+
int ret = 0;
153+
FILE* fp = NULL;
154+
word32 sz = 0;
155+
156+
if (fileName == NULL || fileBytes == NULL || fileSz == NULL) {
157+
return -1;
158+
}
159+
160+
fp = XFOPEN(fileName, "rb");
161+
if (fp == XBADFILE) {
162+
return -1;
163+
}
164+
165+
if (XFSEEK(fp, 0, XSEEK_END) != 0) {
166+
ret = -1;
167+
}
168+
169+
if (ret == 0) {
170+
sz = XFTELL(fp);
171+
if (sz <= 0) {
172+
ret = -1;
173+
}
174+
}
175+
176+
if (ret == 0) {
177+
if (XFSEEK(fp, 0, XSEEK_SET) != 0) {
178+
ret = -1;
179+
}
180+
}
181+
182+
if (ret == 0) {
183+
*fileBytes = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
184+
if (*fileBytes == NULL) {
185+
ret = MEMORY_E;
186+
}
187+
else {
188+
XMEMSET(*fileBytes, 0, sz);
189+
*fileSz = sz;
190+
}
191+
}
192+
193+
if (ret == 0) {
194+
if ((size_t)XFREAD(*fileBytes, 1, (size_t)sz, fp) != (size_t)sz) {
195+
ret = -1;
196+
}
197+
}
198+
199+
if (fp != XBADFILE) {
200+
XFCLOSE(fp);
201+
}
202+
203+
return ret;
204+
}
205+
206+
static void Usage(void)
207+
{
208+
printf("signedData-verifyFile " LIBWOLFSSL_VERSION_STRING
209+
" (NOTE: All files relative to current directory)\n");
210+
printf("-? Help, print this usage\n");
211+
printf("-b <file> PKCS#7/CMS bundle to verify (DER format)\n");
212+
printf("-c <content> Detached content, if needed\n");
213+
}
214+
215+
int main(int argc, char** argv)
216+
{
217+
int ret = 0;
218+
int ch = 0;
219+
220+
char* bundleFile = NULL;
221+
byte* bundleBytes = NULL;
222+
word32 bundleSz = 0;
223+
224+
char* detachedContentFile = NULL;
225+
byte* detachedContentBytes = NULL;
226+
word32 detachedContentSz = 0;
227+
228+
printf("wolfCrypt PKCS#7/CMS SignedData verification example\n\n");
229+
230+
while ((ch = mygetopt(argc, argv, "?b:c:")) != -1) {
231+
switch (ch) {
232+
case '?':
233+
Usage();
234+
exit(EXIT_SUCCESS);
235+
236+
/* File containing PKCS#7/CMS bundle */
237+
case 'b':
238+
bundleFile = myoptarg;
239+
break;
240+
241+
case 'c':
242+
detachedContentFile = myoptarg;
243+
break;
244+
245+
default:
246+
Usage();
247+
exit(MY_EX_USAGE);
248+
}
249+
}
250+
251+
#ifdef DEBUG_WOLFSSL
252+
wolfSSL_Debugging_ON();
253+
#endif
254+
255+
wolfSSL_Init();
256+
257+
/* Read PKCS#7 bundle file into array */
258+
ret = ReadFile(bundleFile, &bundleBytes, &bundleSz);
259+
if (ret == 0) {
260+
printf("Read %d bytes from %s\n", bundleSz, bundleFile);
261+
}
262+
else {
263+
printf("Failed to read bundle file: %s\n", bundleFile);
264+
}
265+
266+
/* Read detached content file into array, if given */
267+
if (ret == 0 && detachedContentFile != NULL) {
268+
ret = ReadFile(detachedContentFile, &detachedContentBytes,
269+
&detachedContentSz);
270+
if (ret == 0) {
271+
printf("Read %d bytes from content file: %s\n",
272+
detachedContentSz, detachedContentFile);
273+
}
274+
else {
275+
printf("Failed to read content file: %s\n", detachedContentFile);
276+
}
277+
}
278+
279+
/* Verify PKCS#7/CMS SignedData bundle */
280+
if (ret == 0) {
281+
ret = VerifySignedData(bundleBytes, bundleSz,
282+
detachedContentBytes, detachedContentSz);
283+
if (ret == 0) {
284+
printf("Successfully verified SignedData bundle!\n");
285+
}
286+
else {
287+
printf("Failed to verify SignedData bundle, ret = %d\n", ret);
288+
}
289+
}
290+
291+
/* Free detached content array, allocated by ReadFile() */
292+
if (detachedContentBytes != NULL) {
293+
XMEMSET(detachedContentBytes, 0, detachedContentSz);
294+
XFREE(detachedContentBytes, NULL, DYNAMIC_TYPE_TMP_BUFFER);
295+
}
296+
/* Free bundle array, allocated by ReadFile() */
297+
if (bundleBytes != NULL) {
298+
XMEMSET(bundleBytes, 0, bundleSz);
299+
XFREE(bundleBytes, NULL, DYNAMIC_TYPE_TMP_BUFFER);
300+
}
301+
302+
wolfSSL_Cleanup();
303+
304+
exit(EXIT_SUCCESS);
305+
}
306+
307+
#else
308+
309+
int main(int argc, char** argv)
310+
{
311+
printf("Must build wolfSSL using ./configure --enable-pkcs7\n");
312+
return 0;
313+
}
314+
315+
#endif /* HAVE_PKCS7 */
316+

0 commit comments

Comments
 (0)