Merge pull request #4845 from cconlon/pkcs7compat
This commit is contained in:
commit
9763030675
703
src/ssl.c
703
src/ssl.c
@ -20920,7 +20920,7 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
|
||||
|
||||
|
||||
#if (defined(KEEP_PEER_CERT) && defined(SESSION_CERTS)) || \
|
||||
(defined(OPENSSL_ALL) && defined(HAVE_PKCS7))
|
||||
(defined(OPENSSL_EXTRA) && defined(SESSION_CERTS))
|
||||
/* Decode the X509 DER encoded certificate into a WOLFSSL_X509 object.
|
||||
*
|
||||
* x509 WOLFSSL_X509 object to decode into.
|
||||
@ -20962,7 +20962,7 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* (KEEP_PEER_CERT && SESSION_CERTS) || (OPENSSL_ALL && HAVE_PKCS7) */
|
||||
#endif /* (KEEP_PEER_CERT & SESSION_CERTS) || (OPENSSL_EXTRA & SESSION_CERTS) */
|
||||
|
||||
|
||||
#ifdef KEEP_PEER_CERT
|
||||
@ -60641,9 +60641,10 @@ PKCS7* wolfSSL_PKCS7_new(void)
|
||||
WOLFSSL_PKCS7* pkcs7;
|
||||
int ret = 0;
|
||||
|
||||
pkcs7 = (WOLFSSL_PKCS7*)XMALLOC(sizeof(*pkcs7), NULL, DYNAMIC_TYPE_PKCS7);
|
||||
pkcs7 = (WOLFSSL_PKCS7*)XMALLOC(sizeof(WOLFSSL_PKCS7), NULL,
|
||||
DYNAMIC_TYPE_PKCS7);
|
||||
if (pkcs7 != NULL) {
|
||||
XMEMSET(pkcs7, 0, sizeof(*pkcs7));
|
||||
XMEMSET(pkcs7, 0, sizeof(WOLFSSL_PKCS7));
|
||||
ret = wc_PKCS7_Init(&pkcs7->pkcs7, NULL, INVALID_DEVID);
|
||||
}
|
||||
|
||||
@ -60698,6 +60699,16 @@ void wolfSSL_PKCS7_SIGNED_free(PKCS7_SIGNED* p7)
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert DER/ASN.1 encoded signedData structure to internal PKCS7
|
||||
* structure. Note, does not support detached content.
|
||||
*
|
||||
* p7 - pointer to set to address of newly created PKCS7 structure on return
|
||||
* in - pointer to pointer of DER/ASN.1 data
|
||||
* len - length of input data, bytes
|
||||
*
|
||||
* Returns newly allocated and populated PKCS7 structure or NULL on error.
|
||||
*/
|
||||
PKCS7* wolfSSL_d2i_PKCS7(PKCS7** p7, const unsigned char** in, int len)
|
||||
{
|
||||
return wolfSSL_d2i_PKCS7_ex(p7, in, len, NULL, 0);
|
||||
@ -60718,22 +60729,16 @@ PKCS7* wolfSSL_d2i_PKCS7_ex(PKCS7** p7, const unsigned char** in, int len,
|
||||
byte* content, word32 contentSz)
|
||||
{
|
||||
WOLFSSL_PKCS7* pkcs7 = NULL;
|
||||
word32 idx = 0;
|
||||
|
||||
WOLFSSL_ENTER("wolfSSL_d2i_PKCS7_ex");
|
||||
|
||||
if (in == NULL || *in == NULL)
|
||||
if (in == NULL || *in == NULL || len < 0)
|
||||
return NULL;
|
||||
|
||||
if ((pkcs7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (GetSequence(*in, &idx, &pkcs7->len, len) < 0) {
|
||||
wolfSSL_PKCS7_free((PKCS7*)pkcs7);
|
||||
return NULL;
|
||||
}
|
||||
pkcs7->len += idx;
|
||||
|
||||
pkcs7->len = len;
|
||||
pkcs7->data = (byte*)XMALLOC(pkcs7->len, NULL, DYNAMIC_TYPE_PKCS7);
|
||||
if (pkcs7->data == NULL) {
|
||||
wolfSSL_PKCS7_free((PKCS7*)pkcs7);
|
||||
@ -60811,37 +60816,48 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return stack of signers contained in PKCS7 cert.
|
||||
* Notes:
|
||||
* - Currently only PKCS#7 messages with a single signer cert is supported.
|
||||
* - Returned WOLFSSL_STACK must be freed by caller.
|
||||
*
|
||||
* pkcs7 - PKCS7 struct to retrieve signer certs from.
|
||||
* certs - currently unused
|
||||
* flags - flags to control function behavior.
|
||||
*
|
||||
* Return WOLFSSL_STACK of signers on success, NULL on error.
|
||||
*/
|
||||
WOLFSSL_STACK* wolfSSL_PKCS7_get0_signers(PKCS7* pkcs7, WOLFSSL_STACK* certs,
|
||||
int flags)
|
||||
{
|
||||
WOLFSSL_X509* x509 = NULL;
|
||||
WOLFSSL_STACK* signers = NULL;
|
||||
WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7;
|
||||
|
||||
if (p7 == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Only PKCS#7 messages with a single cert that is the verifying certificate
|
||||
* is supported.
|
||||
*/
|
||||
if ((flags | PKCS7_NOINTERN) == PKCS7_NOINTERN)
|
||||
return NULL;
|
||||
|
||||
signers = (WOLFSSL_STACK*)XMALLOC(sizeof(WOLFSSL_STACK), NULL,
|
||||
DYNAMIC_TYPE_X509);
|
||||
if (signers == NULL)
|
||||
return NULL;
|
||||
|
||||
signers->num = 1;
|
||||
signers->data.x509 = (WOLFSSL_X509*)XMALLOC(sizeof(WOLFSSL_X509), NULL,
|
||||
DYNAMIC_TYPE_X509);
|
||||
if (signers->data.x509 == NULL) {
|
||||
XFREE(signers, NULL, DYNAMIC_TYPE_X509);
|
||||
if (flags & PKCS7_NOINTERN) {
|
||||
WOLFSSL_MSG("PKCS7_NOINTERN flag not supported");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (DecodeToX509(signers->data.x509, p7->pkcs7.singleCert,
|
||||
p7->pkcs7.singleCertSz) != 0) {
|
||||
XFREE(signers->data.x509, NULL, DYNAMIC_TYPE_X509);
|
||||
XFREE(signers, NULL, DYNAMIC_TYPE_X509);
|
||||
signers = wolfSSL_sk_X509_new();
|
||||
if (signers == NULL)
|
||||
return NULL;
|
||||
|
||||
if (wolfSSL_d2i_X509(&x509, (const byte**)&p7->pkcs7.singleCert,
|
||||
p7->pkcs7.singleCertSz) == NULL) {
|
||||
wolfSSL_sk_X509_pop_free(signers, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (wolfSSL_sk_X509_push(signers, x509) != WOLFSSL_SUCCESS) {
|
||||
wolfSSL_sk_X509_pop_free(signers, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -60977,13 +60993,354 @@ cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a PKCS7 signedData structure.
|
||||
*
|
||||
* Inner content type is set to DATA to match OpenSSL behavior.
|
||||
*
|
||||
* signer - certificate to sign bundle with
|
||||
* pkey - private key matching signer
|
||||
* certs - optional additional set of certificates to include
|
||||
* in - input data to be signed
|
||||
* flags - optional set of flags to control sign behavior
|
||||
*
|
||||
* PKCS7_BINARY - Do not translate input data to MIME canonical
|
||||
* format (\r\n line endings), thus preventing corruption of
|
||||
* binary content.
|
||||
* PKCS7_TEXT - Prepend MIME headers for text/plain to content.
|
||||
* PKCS7_DETACHED - Set signature detached, omit content from output bundle.
|
||||
* PKCS7_STREAM - initialize PKCS7 struct for signing, do not read data.
|
||||
*
|
||||
* Flags not currently supported:
|
||||
* PKCS7_NOCERTS - Do not include the signer cert in the output bundle.
|
||||
* PKCS7_PARTIAL - Allow for PKCS7_sign() to be only partially set up,
|
||||
* then signers etc to be added separately before
|
||||
* calling PKCS7_final().
|
||||
*
|
||||
* Returns valid PKCS7 structure pointer, or NULL if an error occurred.
|
||||
*/
|
||||
PKCS7* wolfSSL_PKCS7_sign(WOLFSSL_X509* signer, WOLFSSL_EVP_PKEY* pkey,
|
||||
WOLFSSL_STACK* certs, WOLFSSL_BIO* in, int flags)
|
||||
{
|
||||
int err = 0;
|
||||
WOLFSSL_PKCS7* p7 = NULL;
|
||||
WOLFSSL_STACK* cert = certs;
|
||||
|
||||
WOLFSSL_ENTER("wolfSSL_PKCS7_sign");
|
||||
|
||||
if (flags & PKCS7_NOCERTS) {
|
||||
WOLFSSL_MSG("PKCS7_NOCERTS flag not yet supported");
|
||||
err = 1;
|
||||
}
|
||||
|
||||
if (flags & PKCS7_PARTIAL) {
|
||||
WOLFSSL_MSG("PKCS7_PARTIAL flag not yet supported");
|
||||
err = 1;
|
||||
}
|
||||
|
||||
if ((err == 0) && (signer == NULL || signer->derCert == NULL ||
|
||||
signer->derCert->length == 0)) {
|
||||
WOLFSSL_MSG("Bad function arg, signer is NULL or incomplete");
|
||||
err = 1;
|
||||
}
|
||||
|
||||
if ((err == 0) && (pkey == NULL || pkey->pkey.ptr == NULL ||
|
||||
pkey->pkey_sz <= 0)) {
|
||||
WOLFSSL_MSG("Bad function arg, pkey is NULL or incomplete");
|
||||
err = 1;
|
||||
}
|
||||
|
||||
if ((err == 0) && (in == NULL) && !(flags & PKCS7_STREAM)) {
|
||||
WOLFSSL_MSG("input data required unless PKCS7_STREAM used");
|
||||
err = 1;
|
||||
}
|
||||
|
||||
if ((err == 0) && ((p7 = (WOLFSSL_PKCS7*)wolfSSL_PKCS7_new()) == NULL)) {
|
||||
WOLFSSL_MSG("Error allocating new WOLFSSL_PKCS7");
|
||||
err = 1;
|
||||
}
|
||||
|
||||
/* load signer certificate */
|
||||
if (err == 0) {
|
||||
if (wc_PKCS7_InitWithCert(&p7->pkcs7, signer->derCert->buffer,
|
||||
signer->derCert->length) != 0) {
|
||||
WOLFSSL_MSG("Failed to load signer certificate");
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* set signer private key, data types, defaults */
|
||||
if (err == 0) {
|
||||
p7->pkcs7.privateKey = (byte*)pkey->pkey.ptr;
|
||||
p7->pkcs7.privateKeySz = pkey->pkey_sz;
|
||||
p7->pkcs7.contentOID = DATA; /* inner content default is DATA */
|
||||
p7->pkcs7.hashOID = SHA256h; /* default to SHA-256 hash type */
|
||||
p7->type = SIGNED_DATA; /* PKCS7_final switches on type */
|
||||
}
|
||||
|
||||
/* add additional chain certs if provided */
|
||||
while (cert && (err == 0)) {
|
||||
if (cert->data.x509 != NULL && cert->data.x509->derCert != NULL) {
|
||||
if (wc_PKCS7_AddCertificate(&p7->pkcs7,
|
||||
cert->data.x509->derCert->buffer,
|
||||
cert->data.x509->derCert->length) != 0) {
|
||||
WOLFSSL_MSG("Error in wc_PKCS7_AddCertificate");
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
cert = cert->next;
|
||||
}
|
||||
|
||||
if ((err == 0) && (flags & PKCS7_DETACHED)) {
|
||||
if (wc_PKCS7_SetDetached(&p7->pkcs7, 1) != 0) {
|
||||
WOLFSSL_MSG("Failed to set signature detached");
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((err == 0) && (flags & PKCS7_STREAM)) {
|
||||
/* if streaming, return before finalizing */
|
||||
return (PKCS7*)p7;
|
||||
}
|
||||
|
||||
if ((err == 0) && (wolfSSL_PKCS7_final((PKCS7*)p7, in, flags) != 1)) {
|
||||
WOLFSSL_MSG("Error calling wolfSSL_PKCS7_final");
|
||||
err = 1;
|
||||
}
|
||||
|
||||
if ((err != 0) && (p7 != NULL)) {
|
||||
wolfSSL_PKCS7_free((PKCS7*)p7);
|
||||
p7 = NULL;
|
||||
}
|
||||
|
||||
return (PKCS7*)p7;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SMIME
|
||||
|
||||
#ifndef MAX_MIME_LINE_LEN
|
||||
#define MAX_MIME_LINE_LEN 1024
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Copy input BIO to output BIO, but convert all line endings to CRLF (\r\n),
|
||||
* used by PKCS7_final().
|
||||
*
|
||||
* in - input WOLFSSL_BIO to be converted
|
||||
* out - output WOLFSSL_BIO to hold copy of in, with line endings adjusted
|
||||
*
|
||||
* Return 0 on success, negative on error
|
||||
*/
|
||||
static int wolfSSL_BIO_to_MIME_crlf(WOLFSSL_BIO* in, WOLFSSL_BIO* out)
|
||||
{
|
||||
int ret = 0;
|
||||
int lineLen = 0;
|
||||
word32 canonLineLen = 0;
|
||||
char* canonLine = NULL;
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
char* line = NULL;
|
||||
#else
|
||||
char line[MAX_MIME_LINE_LEN];
|
||||
#endif
|
||||
|
||||
if (in == NULL || out == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
line = (char*)XMALLOC(MAX_MIME_LINE_LEN, in->heap,
|
||||
DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (line == NULL) {
|
||||
return MEMORY_E;
|
||||
}
|
||||
#endif
|
||||
XMEMSET(line, 0, MAX_MIME_LINE_LEN);
|
||||
|
||||
while ((lineLen = wolfSSL_BIO_gets(in, line, (int)sizeof(line))) > 0) {
|
||||
|
||||
if (line[lineLen - 1] == '\r' || line[lineLen - 1] == '\n') {
|
||||
canonLineLen = (word32)lineLen;
|
||||
if ((canonLine = wc_MIME_single_canonicalize(
|
||||
line, &canonLineLen)) == NULL) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* remove trailing null */
|
||||
if (canonLine[canonLineLen] == '\0') {
|
||||
canonLineLen--;
|
||||
}
|
||||
|
||||
if (wolfSSL_BIO_write(out, canonLine, (int)canonLineLen) < 0) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7);
|
||||
canonLine = NULL;
|
||||
}
|
||||
else {
|
||||
/* no line ending in current line, write direct to out */
|
||||
if (wolfSSL_BIO_write(out, line, lineLen) < 0) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (canonLine != NULL) {
|
||||
XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7);
|
||||
}
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
XFREE(line, in->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* HAVE_SMIME */
|
||||
|
||||
/* Used by both PKCS7_final() and PKCS7_verify() */
|
||||
static const char contTypeText[] = "Content-Type: text/plain\r\n\r\n";
|
||||
|
||||
/**
|
||||
* Finalize PKCS7 structure, currently supports signedData only.
|
||||
*
|
||||
* Does not generate final bundle (ie: signedData), but finalizes
|
||||
* the PKCS7 structure in preparation for a output function to be called next.
|
||||
*
|
||||
* pkcs7 - initialized PKCS7 structure, populated with signer, etc
|
||||
* in - input data
|
||||
* flags - flags to control PKCS7 behavior. Other flags except those noted
|
||||
* below are ignored:
|
||||
*
|
||||
* PKCS7_BINARY - Do not translate input data to MIME canonical
|
||||
* format (\r\n line endings), thus preventing corruption of
|
||||
* binary content.
|
||||
* PKCS7_TEXT - Prepend MIME headers for text/plain to content.
|
||||
*
|
||||
* Returns 1 on success, 0 on error
|
||||
*/
|
||||
int wolfSSL_PKCS7_final(PKCS7* pkcs7, WOLFSSL_BIO* in, int flags)
|
||||
{
|
||||
int ret = 1;
|
||||
int memSz = 0;
|
||||
unsigned char* mem = NULL;
|
||||
WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7;
|
||||
WOLFSSL_BIO* data = NULL;
|
||||
|
||||
WOLFSSL_ENTER("wolfSSL_PKCS7_final");
|
||||
|
||||
if (p7 == NULL || in == NULL) {
|
||||
WOLFSSL_MSG("Bad input args to PKCS7_final");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (ret == 1) {
|
||||
if ((data = wolfSSL_BIO_new(wolfSSL_BIO_s_mem())) == NULL) {
|
||||
WOLFSSL_MSG("Error in wolfSSL_BIO_new");
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* prepend Content-Type header if PKCS7_TEXT */
|
||||
if ((ret == 1) && (flags & PKCS7_TEXT)) {
|
||||
if (wolfSSL_BIO_write(data, contTypeText,
|
||||
(int)XSTR_SIZEOF(contTypeText)) < 0) {
|
||||
WOLFSSL_MSG("Error prepending Content-Type header");
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* convert line endings to CRLF if !PKCS7_BINARY */
|
||||
if (ret == 1) {
|
||||
if (flags & PKCS7_BINARY) {
|
||||
|
||||
/* no CRLF conversion, direct copy content */
|
||||
if ((memSz = wolfSSL_BIO_get_len(in)) <= 0) {
|
||||
ret = 0;
|
||||
}
|
||||
if (ret == 1) {
|
||||
mem = (unsigned char*)XMALLOC(memSz, in->heap,
|
||||
DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (mem == NULL) {
|
||||
WOLFSSL_MSG("Failed to allocate memory for input data");
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 1) {
|
||||
if (wolfSSL_BIO_read(in, mem, memSz) != memSz) {
|
||||
WOLFSSL_MSG("Error reading from input BIO");
|
||||
ret = 0;
|
||||
}
|
||||
else if (wolfSSL_BIO_write(data, mem, memSz) < 0) {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (mem != NULL) {
|
||||
XFREE(mem, in->heap, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef HAVE_SMIME
|
||||
/* convert content line endings to CRLF */
|
||||
if (wolfSSL_BIO_to_MIME_crlf(in, data) != 0) {
|
||||
WOLFSSL_MSG("Error converting line endings to CRLF");
|
||||
ret = 0;
|
||||
}
|
||||
else {
|
||||
p7->pkcs7.contentCRLF = 1;
|
||||
}
|
||||
#else
|
||||
WOLFSSL_MSG("Without PKCS7_BINARY requires wolfSSL to be built "
|
||||
"with HAVE_SMIME");
|
||||
ret = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if ((ret == 1) && ((memSz = wolfSSL_BIO_get_mem_data(data, &mem)) < 0)) {
|
||||
WOLFSSL_MSG("Error in wolfSSL_BIO_get_mem_data");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (ret == 1) {
|
||||
if (p7->data != NULL) {
|
||||
XFREE(p7->data, NULL, DYNAMIC_TYPE_PKCS7);
|
||||
}
|
||||
p7->data = (byte*)XMALLOC(memSz, NULL, DYNAMIC_TYPE_PKCS7);
|
||||
if (p7->data == NULL) {
|
||||
ret = 0;
|
||||
}
|
||||
else {
|
||||
XMEMCPY(p7->data, mem, memSz);
|
||||
p7->len = memSz;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 1) {
|
||||
p7->pkcs7.content = p7->data;
|
||||
p7->pkcs7.contentSz = p7->len;
|
||||
}
|
||||
|
||||
if (data != NULL) {
|
||||
wolfSSL_BIO_free(data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wolfSSL_PKCS7_verify(PKCS7* pkcs7, WOLFSSL_STACK* certs,
|
||||
WOLFSSL_X509_STORE* store, WOLFSSL_BIO* in, WOLFSSL_BIO* out, int flags)
|
||||
{
|
||||
int ret = 0;
|
||||
int i, ret = 0;
|
||||
unsigned char* mem = NULL;
|
||||
int memSz = 0;
|
||||
WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7;
|
||||
int contTypeLen;
|
||||
WOLFSSL_X509* signer = NULL;
|
||||
WOLFSSL_STACK* signers = NULL;
|
||||
|
||||
WOLFSSL_ENTER("wolfSSL_PKCS7_verify");
|
||||
|
||||
@ -61010,12 +61367,49 @@ int wolfSSL_PKCS7_verify(PKCS7* pkcs7, WOLFSSL_STACK* certs,
|
||||
return WOLFSSL_FAILURE;
|
||||
|
||||
if ((flags & PKCS7_NOVERIFY) != PKCS7_NOVERIFY) {
|
||||
/* All signer certificates are verified. */
|
||||
return WOLFSSL_FAILURE;
|
||||
/* Verify signer certificates */
|
||||
if (store == NULL || store->cm == NULL) {
|
||||
WOLFSSL_MSG("No store or store certs, but PKCS7_NOVERIFY not set");
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
|
||||
signers = wolfSSL_PKCS7_get0_signers(pkcs7, certs, flags);
|
||||
if (signers == NULL) {
|
||||
WOLFSSL_MSG("No signers found to verify");
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
for (i = 0; i < wolfSSL_sk_X509_num(signers); i++) {
|
||||
signer = wolfSSL_sk_X509_value(signers, i);
|
||||
|
||||
if (wolfSSL_CertManagerVerifyBuffer(store->cm,
|
||||
signer->derCert->buffer,
|
||||
signer->derCert->length,
|
||||
WOLFSSL_FILETYPE_ASN1) != WOLFSSL_SUCCESS) {
|
||||
WOLFSSL_MSG("Failed to verify signer certificate");
|
||||
wolfSSL_sk_X509_pop_free(signers, NULL);
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
}
|
||||
wolfSSL_sk_X509_pop_free(signers, NULL);
|
||||
}
|
||||
|
||||
if (out != NULL)
|
||||
wolfSSL_BIO_write(out, p7->pkcs7.content, p7->pkcs7.contentSz);
|
||||
if (flags & PKCS7_TEXT) {
|
||||
/* strip MIME header for text/plain, otherwise error */
|
||||
contTypeLen = XSTR_SIZEOF(contTypeText);
|
||||
if ((p7->pkcs7.contentSz < (word32)contTypeLen) ||
|
||||
(XMEMCMP(p7->pkcs7.content, contTypeText, contTypeLen) != 0)) {
|
||||
WOLFSSL_MSG("Error PKCS7 Content-Type not found with PKCS7_TEXT");
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
p7->pkcs7.content += contTypeLen;
|
||||
p7->pkcs7.contentSz -= contTypeLen;
|
||||
}
|
||||
|
||||
if (out != NULL) {
|
||||
wolfSSL_BIO_write(out, p7->pkcs7.content, p7->pkcs7.contentSz);
|
||||
}
|
||||
|
||||
WOLFSSL_LEAVE("wolfSSL_PKCS7_verify", WOLFSSL_SUCCESS);
|
||||
|
||||
return WOLFSSL_SUCCESS;
|
||||
}
|
||||
@ -61246,6 +61640,7 @@ WOLFSSL_API PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in,
|
||||
char* canonSection = NULL;
|
||||
PKCS7* pkcs7 = NULL;
|
||||
word32 outLen = 0;
|
||||
word32 canonLineLen = 0;
|
||||
byte* out = NULL;
|
||||
byte* outHead = NULL;
|
||||
|
||||
@ -61265,6 +61660,7 @@ WOLFSSL_API PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in,
|
||||
static const char kAppPkcs7Mime[] = "application/pkcs7-mime";
|
||||
static const char kAppXPkcs7Mime[] = "application/x-pkcs7-mime";
|
||||
|
||||
WOLFSSL_ENTER("wolfSSL_SMIME_read_PKCS7");
|
||||
|
||||
if (in == NULL || bcont == NULL) {
|
||||
goto error;
|
||||
@ -61361,14 +61757,16 @@ WOLFSSL_API PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in,
|
||||
lineLen = wolfSSL_BIO_gets(in, section, remainLen);
|
||||
while (XSTRNCMP(§ion[sectionLen], boundary, boundLen) &&
|
||||
remainLen > 0) {
|
||||
canonLine = wc_MIME_canonicalize(§ion[sectionLen]);
|
||||
canonLineLen = lineLen;
|
||||
canonLine = wc_MIME_single_canonicalize(§ion[sectionLen],
|
||||
&canonLineLen);
|
||||
if (canonLine == NULL) {
|
||||
goto error;
|
||||
}
|
||||
/* If line endings were added, the initial length may be
|
||||
* exceeded. */
|
||||
if ((canonPos + XSTRLEN(canonLine) + 1) >= canonSize) {
|
||||
canonSize = canonPos + XSTRLEN(canonLine) + 1;
|
||||
if ((canonPos + canonLineLen) >= canonSize) {
|
||||
canonSize = canonPos + canonLineLen;
|
||||
canonSection = (char*)XREALLOC(canonSection, canonSize,
|
||||
NULL, DYNAMIC_TYPE_PKCS7);
|
||||
if (canonSection == NULL) {
|
||||
@ -61376,8 +61774,8 @@ WOLFSSL_API PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in,
|
||||
}
|
||||
}
|
||||
XMEMCPY(&canonSection[canonPos], canonLine,
|
||||
(int)XSTRLEN(canonLine));
|
||||
canonPos += XSTRLEN(canonLine);
|
||||
(int)canonLineLen - 1);
|
||||
canonPos += canonLineLen - 1;
|
||||
XFREE(canonLine, NULL, DYNAMIC_TYPE_PKCS7);
|
||||
canonLine = NULL;
|
||||
|
||||
@ -61412,8 +61810,8 @@ WOLFSSL_API PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in,
|
||||
|
||||
*bcont = wolfSSL_BIO_new(wolfSSL_BIO_s_mem());
|
||||
ret = wolfSSL_BIO_write(*bcont, canonSection,
|
||||
(int)XSTRLEN(canonSection));
|
||||
if (ret != (int)XSTRLEN(canonSection)) {
|
||||
canonPos + 1);
|
||||
if (ret != (canonPos+1)) {
|
||||
goto error;
|
||||
}
|
||||
if ((bcontMemSz = wolfSSL_BIO_get_mem_data(*bcont, &bcontMem))
|
||||
@ -61423,7 +61821,6 @@ WOLFSSL_API PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in,
|
||||
XFREE(canonSection, NULL, DYNAMIC_TYPE_PKCS7);
|
||||
canonSection = NULL;
|
||||
|
||||
|
||||
wc_MIME_free_hdrs(allHdrs);
|
||||
allHdrs = NULL;
|
||||
section[0] = '\0';
|
||||
@ -61555,6 +61952,228 @@ error:
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Convert hash algo OID (from Hash_Sum in asn.h) to SMIME string equivalent.
|
||||
* Returns hash algorithm string or "unknown" if not found */
|
||||
static const char* wolfSSL_SMIME_HashOIDToString(int hashOID)
|
||||
{
|
||||
switch (hashOID) {
|
||||
case MD5h:
|
||||
return "md5";
|
||||
case SHAh:
|
||||
return "sha1";
|
||||
case SHA224h:
|
||||
return "sha-224";
|
||||
case SHA256h:
|
||||
return "sha-256";
|
||||
case SHA384h:
|
||||
return "sha-384";
|
||||
case SHA512h:
|
||||
return "sha-512";
|
||||
case SHA3_224h:
|
||||
return "sha3-224";
|
||||
case SHA3_384h:
|
||||
return "sha3-384";
|
||||
case SHA3_512h:
|
||||
return "sha3-512";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
/* Convert PKCS#7 type (from PKCS7_TYPES in pkcs7.h) to SMIME string.
|
||||
* RFC2633 only defines signed-data, enveloped-data, certs-only.
|
||||
* Returns string on success, NULL on unknown type. */
|
||||
static const char* wolfSSL_SMIME_PKCS7TypeToString(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case SIGNED_DATA:
|
||||
return "signed-data";
|
||||
case ENVELOPED_DATA:
|
||||
return "enveloped-data";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert PKCS7 structure to SMIME format, adding necessary headers.
|
||||
*
|
||||
* Handles generation of PKCS7 bundle (ie: signedData). PKCS7 structure
|
||||
* should be set up beforehand with PKCS7_sign/final/etc. Output is always
|
||||
* Base64 encoded.
|
||||
*
|
||||
* out - output BIO for SMIME formatted data to be placed
|
||||
* pkcs7 - input PKCS7 structure, initialized and set up
|
||||
* in - input content to be encoded into PKCS7
|
||||
* flags - flags to control behavior of PKCS7 generation
|
||||
*
|
||||
* Returns 1 on success, 0 or negative on failure
|
||||
*/
|
||||
int wolfSSL_SMIME_write_PKCS7(WOLFSSL_BIO* out, PKCS7* pkcs7, WOLFSSL_BIO* in,
|
||||
int flags)
|
||||
{
|
||||
int i;
|
||||
int ret = 1;
|
||||
WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7;
|
||||
byte* p7out = NULL;
|
||||
int len = 0;
|
||||
|
||||
char boundary[33]; /* 32 chars + \0 */
|
||||
byte* sigBase64 = NULL;
|
||||
word32 sigBase64Len = 0;
|
||||
const char* p7TypeString = NULL;
|
||||
|
||||
static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
if (out == NULL || p7 == NULL) {
|
||||
WOLFSSL_MSG("Bad function arguments");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (in != NULL && (p7->pkcs7.content == NULL || p7->pkcs7.contentSz == 0 ||
|
||||
p7->pkcs7.contentCRLF == 0)) {
|
||||
/* store and adjust content line endings for CRLF if needed */
|
||||
if (wolfSSL_PKCS7_final((PKCS7*)p7, in, flags) != 1) {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
/* Generate signedData bundle, DER in output (dynamic) */
|
||||
if ((len = wolfSSL_i2d_PKCS7((PKCS7*)p7, &p7out)) == WOLFSSL_FAILURE) {
|
||||
WOLFSSL_MSG("Error in wolfSSL_i2d_PKCS7");
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Base64 encode signedData bundle */
|
||||
if (ret > 0) {
|
||||
if (Base64_Encode(p7out, len, NULL, &sigBase64Len) != LENGTH_ONLY_E) {
|
||||
ret = 0;
|
||||
}
|
||||
else {
|
||||
sigBase64 = (byte*)XMALLOC(sigBase64Len, NULL,
|
||||
DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (sigBase64 == NULL) {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
XMEMSET(sigBase64, 0, sigBase64Len);
|
||||
if (Base64_Encode(p7out, len, sigBase64, &sigBase64Len) < 0) {
|
||||
WOLFSSL_MSG("Error in Base64_Encode of signature");
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* build up SMIME message */
|
||||
if (ret > 0) {
|
||||
if (flags & PKCS7_DETACHED) {
|
||||
|
||||
/* generate random boundary */
|
||||
if (initGlobalRNG == 0 && wolfSSL_RAND_Init() != WOLFSSL_SUCCESS) {
|
||||
WOLFSSL_MSG("No RNG to use");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* no need to generate random byte for null terminator (size-1) */
|
||||
if ((ret > 0) && (wc_RNG_GenerateBlock(&globalRNG, (byte*)boundary,
|
||||
sizeof(boundary) - 1 ) != 0)) {
|
||||
WOLFSSL_MSG("Error in wc_RNG_GenerateBlock");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
for (i = 0; i < (int)sizeof(boundary) - 1; i++) {
|
||||
boundary[i] =
|
||||
alphanum[boundary[i] % XSTR_SIZEOF(alphanum)];
|
||||
}
|
||||
boundary[sizeof(boundary)-1] = 0;
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
/* S/MIME header beginning */
|
||||
ret = wolfSSL_BIO_printf(out,
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: multipart/signed; "
|
||||
"protocol=\"application/x-pkcs7-signature\"; "
|
||||
"micalg=\"%s\"; "
|
||||
"boundary=\"----%s\"\n\n"
|
||||
"This is an S/MIME signed message\n\n"
|
||||
"------%s\n",
|
||||
wolfSSL_SMIME_HashOIDToString(p7->pkcs7.hashOID),
|
||||
boundary, boundary);
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
/* S/MIME content */
|
||||
ret = wolfSSL_BIO_write(out,
|
||||
p7->pkcs7.content, p7->pkcs7.contentSz);
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
/* S/SMIME header end boundary */
|
||||
ret = wolfSSL_BIO_printf(out,
|
||||
"\n------%s\n", boundary);
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
/* Signature and header */
|
||||
ret = wolfSSL_BIO_printf(out,
|
||||
"Content-Type: application/x-pkcs7-signature; "
|
||||
"name=\"smime.p7s\"\n"
|
||||
"Content-Transfer-Encoding: base64\n"
|
||||
"Content-Disposition: attachment; "
|
||||
"filename=\"smime.p7s\"\n\n"
|
||||
"%.*s\n" /* Base64 encoded signature */
|
||||
"------%s--\n\n",
|
||||
sigBase64Len, sigBase64,
|
||||
boundary);
|
||||
}
|
||||
}
|
||||
else {
|
||||
p7TypeString = wolfSSL_SMIME_PKCS7TypeToString(p7->type);
|
||||
if (p7TypeString == NULL) {
|
||||
WOLFSSL_MSG("Unsupported PKCS7 SMIME type");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
/* not detached */
|
||||
ret = wolfSSL_BIO_printf(out,
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Disposition: attachment; "
|
||||
"filename=\"smime.p7m\"\n"
|
||||
"Content-Type: application/x-pkcs7-mime; "
|
||||
"smime-type=%s; name=\"smime.p7m\"\n"
|
||||
"Content-Transfer-Encoding: base64\n\n"
|
||||
"%.*s\n" /* signature */,
|
||||
p7TypeString, sigBase64Len, sigBase64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p7out != NULL) {
|
||||
XFREE(p7out, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
}
|
||||
if (sigBase64 != NULL) {
|
||||
XFREE(sigBase64, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
return WOLFSSL_SUCCESS;
|
||||
}
|
||||
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
|
||||
#endif /* HAVE_SMIME */
|
||||
#endif /* !NO_BIO */
|
||||
#endif /* OPENSSL_ALL */
|
||||
|
351
tests/api.c
351
tests/api.c
@ -47104,6 +47104,181 @@ static void test_wolfssl_PKCS7(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_wolfSSL_PKCS7_sign(void)
|
||||
{
|
||||
#if defined(OPENSSL_ALL) && defined(HAVE_PKCS7) && !defined(NO_BIO) && \
|
||||
!defined(NO_FILESYSTEM) && !defined(NO_RSA)
|
||||
|
||||
PKCS7* p7 = NULL;
|
||||
PKCS7* p7Ver = NULL;
|
||||
byte* out = NULL;
|
||||
byte* tmpPtr = NULL;
|
||||
int outLen = 0;
|
||||
int flags = 0;
|
||||
byte data[] = "Test data to encode.";
|
||||
|
||||
const char* cert = "./certs/server-cert.pem";
|
||||
const char* key = "./certs/server-key.pem";
|
||||
const char* ca = "./certs/ca-cert.pem";
|
||||
|
||||
WOLFSSL_BIO* certBio = NULL;
|
||||
WOLFSSL_BIO* keyBio = NULL;
|
||||
WOLFSSL_BIO* caBio = NULL;
|
||||
WOLFSSL_BIO* inBio = NULL;
|
||||
X509* signCert = NULL;
|
||||
EVP_PKEY* signKey = NULL;
|
||||
X509* caCert = NULL;
|
||||
X509_STORE* store = NULL;
|
||||
|
||||
printf(testingFmt, "wolfSSL_PKCS7_sign()");
|
||||
|
||||
/* read signer cert/key into BIO */
|
||||
AssertNotNull(certBio = BIO_new_file(cert, "r"));
|
||||
AssertNotNull(keyBio = BIO_new_file(key, "r"));
|
||||
AssertNotNull(signCert = PEM_read_bio_X509(certBio, NULL, 0, NULL));
|
||||
AssertNotNull(signKey = PEM_read_bio_PrivateKey(keyBio, NULL, 0, NULL));
|
||||
|
||||
/* read CA cert into store (for verify) */
|
||||
AssertNotNull(caBio = BIO_new_file(ca, "r"));
|
||||
AssertNotNull(caCert = PEM_read_bio_X509(caBio, NULL, 0, NULL));
|
||||
AssertNotNull(store = X509_STORE_new());
|
||||
AssertIntEQ(X509_STORE_add_cert(store, caCert), 1);
|
||||
|
||||
/* data to be signed into BIO */
|
||||
AssertNotNull(inBio = BIO_new(BIO_s_mem()));
|
||||
AssertIntGT(BIO_write(inBio, data, sizeof(data)), 0);
|
||||
|
||||
/* PKCS7_sign, bad args: signer NULL */
|
||||
AssertNull(p7 = PKCS7_sign(NULL, signKey, NULL, inBio, 0));
|
||||
/* PKCS7_sign, bad args: signer key NULL */
|
||||
AssertNull(p7 = PKCS7_sign(signCert, NULL, NULL, inBio, 0));
|
||||
/* PKCS7_sign, bad args: in data NULL without PKCS7_STREAM */
|
||||
AssertNull(p7 = PKCS7_sign(signCert, signKey, NULL, NULL, 0));
|
||||
/* PKCS7_sign, bad args: PKCS7_NOCERTS flag not supported */
|
||||
AssertNull(p7 = PKCS7_sign(signCert, signKey, NULL, inBio, PKCS7_NOCERTS));
|
||||
/* PKCS7_sign, bad args: PKCS7_PARTIAL flag not supported */
|
||||
AssertNull(p7 = PKCS7_sign(signCert, signKey, NULL, inBio, PKCS7_PARTIAL));
|
||||
|
||||
/* TEST SUCCESS: Not detached, not streaming, not MIME */
|
||||
{
|
||||
flags = PKCS7_BINARY;
|
||||
AssertNotNull(p7 = PKCS7_sign(signCert, signKey, NULL, inBio, flags));
|
||||
AssertIntGT((outLen = i2d_PKCS7(p7, &out)), 0);
|
||||
|
||||
/* verify with d2i_PKCS7 */
|
||||
tmpPtr = out;
|
||||
AssertNotNull(p7Ver = d2i_PKCS7(NULL, (const byte**)&tmpPtr, outLen));
|
||||
AssertIntEQ(PKCS7_verify(p7Ver, NULL, store, NULL, NULL, flags), 1);
|
||||
PKCS7_free(p7Ver);
|
||||
|
||||
/* verify with wc_PKCS7_VerifySignedData */
|
||||
AssertNotNull(p7Ver = wc_PKCS7_New(HEAP_HINT, devId));
|
||||
AssertIntEQ(wc_PKCS7_Init(p7Ver, HEAP_HINT, INVALID_DEVID), 0);
|
||||
AssertIntEQ(wc_PKCS7_VerifySignedData(p7Ver, out, outLen), 0);
|
||||
wc_PKCS7_Free(p7Ver);
|
||||
|
||||
AssertNotNull(out);
|
||||
XFREE(out, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
out = NULL;
|
||||
PKCS7_free(p7);
|
||||
}
|
||||
|
||||
/* TEST SUCCESS: Not detached, streaming, not MIME. Also bad arg
|
||||
* tests for PKCS7_final() while we have a PKCS7 pointer to use */
|
||||
{
|
||||
/* re-populate input BIO, may have been consumed */
|
||||
BIO_free(inBio);
|
||||
AssertNotNull(inBio = BIO_new(BIO_s_mem()));
|
||||
AssertIntGT(BIO_write(inBio, data, sizeof(data)), 0);
|
||||
|
||||
flags = PKCS7_BINARY | PKCS7_STREAM;
|
||||
AssertNotNull(p7 = PKCS7_sign(signCert, signKey, NULL, inBio, flags));
|
||||
AssertIntEQ(PKCS7_final(p7, inBio, flags), 1);
|
||||
AssertIntGT((outLen = i2d_PKCS7(p7, &out)), 0);
|
||||
|
||||
/* PKCS7_final, bad args: PKCS7 null */
|
||||
AssertIntEQ(PKCS7_final(NULL, inBio, 0), 0);
|
||||
/* PKCS7_final, bad args: PKCS7 null */
|
||||
AssertIntEQ(PKCS7_final(p7, NULL, 0), 0);
|
||||
|
||||
tmpPtr = out;
|
||||
AssertNotNull(p7Ver = d2i_PKCS7(NULL, (const byte**)&tmpPtr, outLen));
|
||||
AssertIntEQ(PKCS7_verify(p7Ver, NULL, store, NULL, NULL, flags), 1);
|
||||
PKCS7_free(p7Ver);
|
||||
|
||||
AssertNotNull(out);
|
||||
XFREE(out, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
out = NULL;
|
||||
PKCS7_free(p7);
|
||||
}
|
||||
|
||||
/* TEST SUCCESS: Detached, not streaming, not MIME */
|
||||
{
|
||||
/* re-populate input BIO, may have been consumed */
|
||||
BIO_free(inBio);
|
||||
AssertNotNull(inBio = BIO_new(BIO_s_mem()));
|
||||
AssertIntGT(BIO_write(inBio, data, sizeof(data)), 0);
|
||||
|
||||
flags = PKCS7_BINARY | PKCS7_DETACHED;
|
||||
AssertNotNull(p7 = PKCS7_sign(signCert, signKey, NULL, inBio, flags));
|
||||
AssertIntGT((outLen = i2d_PKCS7(p7, &out)), 0);
|
||||
|
||||
/* verify with wolfCrypt, d2i_PKCS7 does not support detached content */
|
||||
AssertNotNull(p7Ver = wc_PKCS7_New(HEAP_HINT, devId));
|
||||
p7Ver->content = data;
|
||||
p7Ver->contentSz = sizeof(data);
|
||||
AssertIntEQ(wc_PKCS7_VerifySignedData(p7Ver, out, outLen), 0);
|
||||
wc_PKCS7_Free(p7Ver);
|
||||
|
||||
/* verify expected failure (NULL return) from d2i_PKCS7, it does not
|
||||
* yet support detached content */
|
||||
tmpPtr = out;
|
||||
AssertNull(p7Ver = d2i_PKCS7(NULL, (const byte**)&tmpPtr, outLen));
|
||||
PKCS7_free(p7Ver);
|
||||
|
||||
AssertNotNull(out);
|
||||
XFREE(out, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
out = NULL;
|
||||
PKCS7_free(p7);
|
||||
}
|
||||
|
||||
/* TEST SUCCESS: Detached, streaming, not MIME */
|
||||
{
|
||||
/* re-populate input BIO, may have been consumed */
|
||||
BIO_free(inBio);
|
||||
AssertNotNull(inBio = BIO_new(BIO_s_mem()));
|
||||
AssertIntGT(BIO_write(inBio, data, sizeof(data)), 0);
|
||||
|
||||
flags = PKCS7_BINARY | PKCS7_DETACHED | PKCS7_STREAM;
|
||||
AssertNotNull(p7 = PKCS7_sign(signCert, signKey, NULL, inBio, flags));
|
||||
AssertIntEQ(PKCS7_final(p7, inBio, flags), 1);
|
||||
AssertIntGT((outLen = i2d_PKCS7(p7, &out)), 0);
|
||||
|
||||
/* verify with wolfCrypt, d2i_PKCS7 does not support detached content */
|
||||
AssertNotNull(p7Ver = wc_PKCS7_New(HEAP_HINT, devId));
|
||||
p7Ver->content = data;
|
||||
p7Ver->contentSz = sizeof(data);
|
||||
AssertIntEQ(wc_PKCS7_VerifySignedData(p7Ver, out, outLen), 0);
|
||||
wc_PKCS7_Free(p7Ver);
|
||||
|
||||
AssertNotNull(out);
|
||||
XFREE(out, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
PKCS7_free(p7);
|
||||
}
|
||||
|
||||
X509_STORE_free(store);
|
||||
X509_free(caCert);
|
||||
X509_free(signCert);
|
||||
EVP_PKEY_free(signKey);
|
||||
BIO_free(inBio);
|
||||
BIO_free(keyBio);
|
||||
BIO_free(certBio);
|
||||
BIO_free(caBio);
|
||||
|
||||
printf(resultFmt, passed);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_wolfSSL_PKCS7_SIGNED_new(void)
|
||||
{
|
||||
#if defined(OPENSSL_ALL) && defined(HAVE_PKCS7)
|
||||
@ -47243,43 +47418,73 @@ static void test_wolfSSL_SMIME_read_PKCS7(void)
|
||||
PKCS7* pkcs7 = NULL;
|
||||
BIO* bio = NULL;
|
||||
BIO* bcont = NULL;
|
||||
BIO* out = NULL;
|
||||
const byte* outBuf = NULL;
|
||||
int outBufLen = 0;
|
||||
static const char contTypeText[] = "Content-Type: text/plain\r\n\r\n";
|
||||
XFILE smimeTestFile = XFOPEN("./certs/test/smime-test.p7s", "r");
|
||||
|
||||
printf(testingFmt, "wolfSSL_SMIME_read_PKCS7()");
|
||||
|
||||
/* smime-test.p7s */
|
||||
bio = wolfSSL_BIO_new(wolfSSL_BIO_s_file());
|
||||
AssertNotNull(bio);
|
||||
AssertIntEQ(wolfSSL_BIO_set_fp(bio, smimeTestFile, BIO_CLOSE), SSL_SUCCESS);
|
||||
pkcs7 = wolfSSL_SMIME_read_PKCS7(bio, &bcont);
|
||||
AssertNotNull(pkcs7);
|
||||
AssertIntEQ(wolfSSL_PKCS7_verify(pkcs7, NULL, NULL, bcont, NULL, PKCS7_NOVERIFY), SSL_SUCCESS);
|
||||
AssertIntEQ(wolfSSL_PKCS7_verify(pkcs7, NULL, NULL, bcont, NULL,
|
||||
PKCS7_NOVERIFY), SSL_SUCCESS);
|
||||
XFCLOSE(smimeTestFile);
|
||||
if (bcont) BIO_free(bcont);
|
||||
wolfSSL_PKCS7_free(pkcs7);
|
||||
|
||||
/* smime-test-multipart.p7s */
|
||||
smimeTestFile = XFOPEN("./certs/test/smime-test-multipart.p7s", "r");
|
||||
AssertIntEQ(wolfSSL_BIO_set_fp(bio, smimeTestFile, BIO_CLOSE), SSL_SUCCESS);
|
||||
pkcs7 = wolfSSL_SMIME_read_PKCS7(bio, &bcont);
|
||||
AssertNotNull(pkcs7);
|
||||
AssertIntEQ(wolfSSL_PKCS7_verify(pkcs7, NULL, NULL, bcont, NULL, PKCS7_NOVERIFY), SSL_SUCCESS);
|
||||
AssertIntEQ(wolfSSL_PKCS7_verify(pkcs7, NULL, NULL, bcont, NULL,
|
||||
PKCS7_NOVERIFY), SSL_SUCCESS);
|
||||
XFCLOSE(smimeTestFile);
|
||||
if (bcont) BIO_free(bcont);
|
||||
wolfSSL_PKCS7_free(pkcs7);
|
||||
|
||||
/* smime-test-multipart-badsig.p7s */
|
||||
smimeTestFile = XFOPEN("./certs/test/smime-test-multipart-badsig.p7s", "r");
|
||||
AssertIntEQ(wolfSSL_BIO_set_fp(bio, smimeTestFile, BIO_CLOSE), SSL_SUCCESS);
|
||||
pkcs7 = wolfSSL_SMIME_read_PKCS7(bio, &bcont);
|
||||
AssertNull(pkcs7);
|
||||
AssertIntEQ(wolfSSL_PKCS7_verify(pkcs7, NULL, NULL, bcont, NULL, PKCS7_NOVERIFY), SSL_FAILURE);
|
||||
AssertIntEQ(wolfSSL_PKCS7_verify(pkcs7, NULL, NULL, bcont, NULL,
|
||||
PKCS7_NOVERIFY), SSL_FAILURE);
|
||||
XFCLOSE(smimeTestFile);
|
||||
if (bcont) BIO_free(bcont);
|
||||
wolfSSL_PKCS7_free(pkcs7);
|
||||
|
||||
/* smime-test-canon.p7s */
|
||||
smimeTestFile = XFOPEN("./certs/test/smime-test-canon.p7s", "r");
|
||||
AssertIntEQ(wolfSSL_BIO_set_fp(bio, smimeTestFile, BIO_CLOSE), SSL_SUCCESS);
|
||||
pkcs7 = wolfSSL_SMIME_read_PKCS7(bio, &bcont);
|
||||
AssertNotNull(pkcs7);
|
||||
AssertIntEQ(wolfSSL_PKCS7_verify(pkcs7, NULL, NULL, bcont, NULL, PKCS7_NOVERIFY), SSL_SUCCESS);
|
||||
AssertIntEQ(wolfSSL_PKCS7_verify(pkcs7, NULL, NULL, bcont, NULL,
|
||||
PKCS7_NOVERIFY), SSL_SUCCESS);
|
||||
if (bcont) BIO_free(bcont);
|
||||
wolfSSL_PKCS7_free(pkcs7);
|
||||
|
||||
/* Test PKCS7_TEXT, PKCS7_verify() should remove Content-Type: text/plain */
|
||||
smimeTestFile = XFOPEN("./certs/test/smime-test-canon.p7s", "r");
|
||||
AssertIntEQ(wolfSSL_BIO_set_fp(bio, smimeTestFile, BIO_CLOSE), SSL_SUCCESS);
|
||||
pkcs7 = wolfSSL_SMIME_read_PKCS7(bio, &bcont);
|
||||
AssertNotNull(pkcs7);
|
||||
out = wolfSSL_BIO_new(BIO_s_mem());
|
||||
AssertNotNull(out);
|
||||
AssertIntEQ(wolfSSL_PKCS7_verify(pkcs7, NULL, NULL, bcont, out,
|
||||
PKCS7_NOVERIFY | PKCS7_TEXT), SSL_SUCCESS);
|
||||
AssertIntGT((outBufLen = BIO_get_mem_data(out, &outBuf)), 0);
|
||||
/* Content-Type should not show up at beginning of output buffer */
|
||||
AssertIntGT(outBufLen, XSTRLEN(contTypeText));
|
||||
AssertIntGT(XMEMCMP(outBuf, contTypeText, XSTRLEN(contTypeText)), 0);
|
||||
|
||||
BIO_free(out);
|
||||
BIO_free(bio);
|
||||
if (bcont) BIO_free(bcont);
|
||||
wolfSSL_PKCS7_free(pkcs7);
|
||||
@ -47287,6 +47492,142 @@ static void test_wolfSSL_SMIME_read_PKCS7(void)
|
||||
printf(resultFmt, passed);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_wolfSSL_SMIME_write_PKCS7(void)
|
||||
{
|
||||
#if defined(OPENSSL_ALL) && defined(HAVE_PKCS7) && !defined(NO_RSA)
|
||||
|
||||
PKCS7* p7 = NULL;
|
||||
PKCS7* p7Ver = NULL;
|
||||
int flags = 0;
|
||||
byte data[] = "Test data to encode.";
|
||||
|
||||
const char* cert = "./certs/server-cert.pem";
|
||||
const char* key = "./certs/server-key.pem";
|
||||
const char* ca = "./certs/ca-cert.pem";
|
||||
|
||||
WOLFSSL_BIO* certBio = NULL;
|
||||
WOLFSSL_BIO* keyBio = NULL;
|
||||
WOLFSSL_BIO* caBio = NULL;
|
||||
WOLFSSL_BIO* inBio = NULL;
|
||||
WOLFSSL_BIO* outBio = NULL;
|
||||
WOLFSSL_BIO* content = NULL;
|
||||
X509* signCert = NULL;
|
||||
EVP_PKEY* signKey = NULL;
|
||||
X509* caCert = NULL;
|
||||
X509_STORE* store = NULL;
|
||||
|
||||
printf(testingFmt, "wolfSSL_SMIME_write_PKCS7()");
|
||||
|
||||
/* read signer cert/key into BIO */
|
||||
AssertNotNull(certBio = BIO_new_file(cert, "r"));
|
||||
AssertNotNull(keyBio = BIO_new_file(key, "r"));
|
||||
AssertNotNull(signCert = PEM_read_bio_X509(certBio, NULL, 0, NULL));
|
||||
AssertNotNull(signKey = PEM_read_bio_PrivateKey(keyBio, NULL, 0, NULL));
|
||||
|
||||
/* read CA cert into store (for verify) */
|
||||
AssertNotNull(caBio = BIO_new_file(ca, "r"));
|
||||
AssertNotNull(caCert = PEM_read_bio_X509(caBio, NULL, 0, NULL));
|
||||
AssertNotNull(store = X509_STORE_new());
|
||||
AssertIntEQ(X509_STORE_add_cert(store, caCert), 1);
|
||||
|
||||
|
||||
/* generate and verify SMIME: not detached */
|
||||
{
|
||||
AssertNotNull(inBio = BIO_new(BIO_s_mem()));
|
||||
AssertIntGT(BIO_write(inBio, data, sizeof(data)), 0);
|
||||
|
||||
flags = PKCS7_STREAM;
|
||||
AssertNotNull(p7 = PKCS7_sign(signCert, signKey, NULL, inBio, flags));
|
||||
AssertNotNull(outBio = BIO_new(BIO_s_mem()));
|
||||
AssertIntEQ(SMIME_write_PKCS7(outBio, p7, inBio, flags), 1);
|
||||
|
||||
/* bad arg: out NULL */
|
||||
AssertIntEQ(SMIME_write_PKCS7(NULL, p7, inBio, flags), 0);
|
||||
/* bad arg: pkcs7 NULL */
|
||||
AssertIntEQ(SMIME_write_PKCS7(outBio, NULL, inBio, flags), 0);
|
||||
|
||||
AssertNotNull(p7Ver = SMIME_read_PKCS7(outBio, &content));
|
||||
AssertIntEQ(PKCS7_verify(p7Ver, NULL, store, NULL, NULL, flags), 1);
|
||||
|
||||
BIO_free(content);
|
||||
BIO_free(inBio);
|
||||
BIO_free(outBio);
|
||||
PKCS7_free(p7Ver);
|
||||
PKCS7_free(p7);
|
||||
}
|
||||
|
||||
/* generate and verify SMIME: not detached, add Content-Type */
|
||||
{
|
||||
AssertNotNull(inBio = BIO_new(BIO_s_mem()));
|
||||
AssertIntGT(BIO_write(inBio, data, sizeof(data)), 0);
|
||||
|
||||
flags = PKCS7_STREAM | PKCS7_TEXT;
|
||||
AssertNotNull(p7 = PKCS7_sign(signCert, signKey, NULL, inBio, flags));
|
||||
AssertNotNull(outBio = BIO_new(BIO_s_mem()));
|
||||
AssertIntEQ(SMIME_write_PKCS7(outBio, p7, inBio, flags), 1);
|
||||
|
||||
AssertNotNull(p7Ver = SMIME_read_PKCS7(outBio, &content));
|
||||
AssertIntEQ(PKCS7_verify(p7Ver, NULL, store, NULL, NULL, flags), 1);
|
||||
|
||||
BIO_free(content);
|
||||
BIO_free(inBio);
|
||||
BIO_free(outBio);
|
||||
PKCS7_free(p7Ver);
|
||||
PKCS7_free(p7);
|
||||
}
|
||||
|
||||
/* generate and verify SMIME: detached */
|
||||
{
|
||||
AssertNotNull(inBio = BIO_new(BIO_s_mem()));
|
||||
AssertIntGT(BIO_write(inBio, data, sizeof(data)), 0);
|
||||
|
||||
flags = PKCS7_DETACHED | PKCS7_STREAM;
|
||||
AssertNotNull(p7 = PKCS7_sign(signCert, signKey, NULL, inBio, flags));
|
||||
AssertNotNull(outBio = BIO_new(BIO_s_mem()));
|
||||
AssertIntEQ(SMIME_write_PKCS7(outBio, p7, inBio, flags), 1);
|
||||
|
||||
AssertNotNull(p7Ver = SMIME_read_PKCS7(outBio, &content));
|
||||
AssertIntEQ(PKCS7_verify(p7Ver, NULL, store, content, NULL, flags), 1);
|
||||
|
||||
BIO_free(content);
|
||||
BIO_free(inBio);
|
||||
BIO_free(outBio);
|
||||
PKCS7_free(p7Ver);
|
||||
PKCS7_free(p7);
|
||||
}
|
||||
|
||||
/* generate and verify SMIME: PKCS7_TEXT to add Content-Type header */
|
||||
{
|
||||
AssertNotNull(inBio = BIO_new(BIO_s_mem()));
|
||||
AssertIntGT(BIO_write(inBio, data, sizeof(data)), 0);
|
||||
|
||||
flags = PKCS7_STREAM | PKCS7_DETACHED | PKCS7_TEXT;
|
||||
AssertNotNull(p7 = PKCS7_sign(signCert, signKey, NULL, inBio, flags));
|
||||
AssertNotNull(outBio = BIO_new(BIO_s_mem()));
|
||||
AssertIntEQ(SMIME_write_PKCS7(outBio, p7, inBio, flags), 1);
|
||||
|
||||
AssertNotNull(p7Ver = SMIME_read_PKCS7(outBio, &content));
|
||||
AssertIntEQ(PKCS7_verify(p7Ver, NULL, store, content, NULL, flags), 1);
|
||||
|
||||
BIO_free(content);
|
||||
BIO_free(inBio);
|
||||
BIO_free(outBio);
|
||||
PKCS7_free(p7Ver);
|
||||
PKCS7_free(p7);
|
||||
}
|
||||
|
||||
X509_STORE_free(store);
|
||||
X509_free(caCert);
|
||||
X509_free(signCert);
|
||||
EVP_PKEY_free(signKey);
|
||||
BIO_free(keyBio);
|
||||
BIO_free(certBio);
|
||||
BIO_free(caBio);
|
||||
|
||||
printf(resultFmt, passed);
|
||||
#endif
|
||||
}
|
||||
#endif /* HAVE_SMIME*/
|
||||
#endif /* !NO_BIO */
|
||||
|
||||
@ -53195,11 +53536,13 @@ void ApiTest(void)
|
||||
test_X509_REQ();
|
||||
/* OpenSSL PKCS7 API test */
|
||||
test_wolfssl_PKCS7();
|
||||
test_wolfSSL_PKCS7_sign();
|
||||
test_wolfSSL_PKCS7_SIGNED_new();
|
||||
#ifndef NO_BIO
|
||||
test_wolfSSL_PEM_write_bio_PKCS7();
|
||||
#ifdef HAVE_SMIME
|
||||
test_wolfSSL_SMIME_read_PKCS7();
|
||||
test_wolfSSL_SMIME_write_PKCS7();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -32493,22 +32493,25 @@ MimeParam* wc_MIME_find_param_attr(const char* attribute,
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* wc_MIME_canonicalize - Canonicalize a line by converting all line endings
|
||||
* to CRLF.
|
||||
* wc_MIME_single_canonicalize - Canonicalize a line by converting the trailing
|
||||
* line ending to CRLF.
|
||||
*
|
||||
* line - input line to canonicalize
|
||||
* len - length of line in chars on input, length of output array on return
|
||||
*
|
||||
* RETURNS:
|
||||
* returns a pointer to a canonicalized line on success, NULL on error.
|
||||
*/
|
||||
char* wc_MIME_canonicalize(const char* line)
|
||||
char* wc_MIME_single_canonicalize(const char* line, word32* len)
|
||||
{
|
||||
size_t end = 0;
|
||||
char* canonLine = NULL;
|
||||
|
||||
if (line == NULL || XSTRLEN(line) == 0) {
|
||||
if (line == NULL || len == NULL || *len == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
end = XSTRLEN(line);
|
||||
end = *len;
|
||||
while (end >= 1 && ((line[end-1] == '\r') || (line[end-1] == '\n'))) {
|
||||
end--;
|
||||
}
|
||||
@ -32519,10 +32522,11 @@ char* wc_MIME_canonicalize(const char* line)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
XSTRNCPY(canonLine, line, end);
|
||||
XMEMCPY(canonLine, line, end);
|
||||
canonLine[end] = '\r';
|
||||
canonLine[end+1] = '\n';
|
||||
canonLine[end+2] = '\0';
|
||||
*len = (word32)(end + 3);
|
||||
|
||||
return canonLine;
|
||||
}
|
||||
|
@ -34,14 +34,21 @@
|
||||
|
||||
#if defined(OPENSSL_ALL) && defined(HAVE_PKCS7)
|
||||
|
||||
#define PKCS7_TEXT 0x1
|
||||
#define PKCS7_NOCERTS 0x2
|
||||
#define PKCS7_DETACHED 0x40
|
||||
#define PKCS7_BINARY 0x80
|
||||
#define PKCS7_NOINTERN 0x0010
|
||||
#define PKCS7_NOVERIFY 0x0020
|
||||
#define PKCS7_STREAM 0x1000
|
||||
#define PKCS7_PARTIAL 0x4000
|
||||
|
||||
typedef struct WOLFSSL_PKCS7
|
||||
{
|
||||
PKCS7 pkcs7;
|
||||
unsigned char* data;
|
||||
int len;
|
||||
int type; /* from PKCS7_TYPES, for PKCS7_final() */
|
||||
WOLFSSL_STACK* certs;
|
||||
} WOLFSSL_PKCS7;
|
||||
|
||||
@ -57,8 +64,11 @@ WOLFSSL_LOCAL PKCS7* wolfSSL_d2i_PKCS7_ex(PKCS7** p7, const unsigned char** in,
|
||||
WOLFSSL_API PKCS7* wolfSSL_d2i_PKCS7_bio(WOLFSSL_BIO* bio, PKCS7** p7);
|
||||
WOLFSSL_API int wolfSSL_i2d_PKCS7_bio(WOLFSSL_BIO *bio, PKCS7 *p7);
|
||||
WOLFSSL_API int wolfSSL_i2d_PKCS7(PKCS7 *p7, unsigned char **out);
|
||||
WOLFSSL_API PKCS7* wolfSSL_PKCS7_sign(WOLFSSL_X509* signer,
|
||||
WOLFSSL_EVP_PKEY* pkey, WOLFSSL_STACK* certs, WOLFSSL_BIO* in, int flags);
|
||||
WOLFSSL_API int wolfSSL_PKCS7_verify(PKCS7* p7, WOLFSSL_STACK* certs,
|
||||
WOLFSSL_X509_STORE* store, WOLFSSL_BIO* in, WOLFSSL_BIO* out, int flags);
|
||||
WOLFSSL_API int wolfSSL_PKCS7_final(PKCS7* pkcs7, WOLFSSL_BIO* in, int flags);
|
||||
WOLFSSL_API int wolfSSL_PKCS7_encode_certs(PKCS7* p7, WOLFSSL_STACK* certs,
|
||||
WOLFSSL_BIO* out);
|
||||
WOLFSSL_API WOLFSSL_STACK* wolfSSL_PKCS7_to_stack(PKCS7* pkcs7);
|
||||
@ -67,6 +77,8 @@ WOLFSSL_API WOLFSSL_STACK* wolfSSL_PKCS7_get0_signers(PKCS7* p7,
|
||||
WOLFSSL_API int wolfSSL_PEM_write_bio_PKCS7(WOLFSSL_BIO* bio, PKCS7* p7);
|
||||
#if defined(HAVE_SMIME)
|
||||
WOLFSSL_API PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in, WOLFSSL_BIO** bcont);
|
||||
WOLFSSL_API int wolfSSL_SMIME_write_PKCS7(WOLFSSL_BIO* out, PKCS7* pkcs7,
|
||||
WOLFSSL_BIO* in, int flags);
|
||||
#endif /* HAVE_SMIME */
|
||||
|
||||
|
||||
@ -78,11 +90,14 @@ WOLFSSL_API PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in, WOLFSSL_BIO** bcont
|
||||
#define d2i_PKCS7_bio wolfSSL_d2i_PKCS7_bio
|
||||
#define i2d_PKCS7_bio wolfSSL_i2d_PKCS7_bio
|
||||
#define i2d_PKCS7 wolfSSL_i2d_PKCS7
|
||||
#define PKCS7_sign wolfSSL_PKCS7_sign
|
||||
#define PKCS7_verify wolfSSL_PKCS7_verify
|
||||
#define PKCS7_final wolfSSL_PKCS7_final
|
||||
#define PKCS7_get0_signers wolfSSL_PKCS7_get0_signers
|
||||
#define PEM_write_bio_PKCS7 wolfSSL_PEM_write_bio_PKCS7
|
||||
#if defined(HAVE_SMIME)
|
||||
#define SMIME_read_PKCS7 wolfSSL_SMIME_read_PKCS7
|
||||
#define SMIME_write_PKCS7 wolfSSL_SMIME_write_PKCS7
|
||||
#endif /* HAVE_SMIME */
|
||||
|
||||
#endif /* OPENSSL_ALL && HAVE_PKCS7 */
|
||||
|
@ -2029,11 +2029,9 @@ WOLFSSL_LOCAL void FreeDer(DerBuffer** der);
|
||||
#ifdef HAVE_SMIME
|
||||
WOLFSSL_LOCAL int wc_MIME_parse_headers(char* in, int inLen, MimeHdr** hdrs);
|
||||
WOLFSSL_LOCAL int wc_MIME_header_strip(char* in, char** out, size_t start, size_t end);
|
||||
WOLFSSL_LOCAL int wc_MIME_create_header(char* name, char* body, MimeHdr** hdr);
|
||||
WOLFSSL_LOCAL int wc_MIME_create_parameter(char* attribute, char* value, MimeParam** param);
|
||||
WOLFSSL_LOCAL MimeHdr* wc_MIME_find_header_name(const char* name, MimeHdr* hdr);
|
||||
WOLFSSL_LOCAL MimeParam* wc_MIME_find_param_attr(const char* attribute, MimeParam* param);
|
||||
WOLFSSL_LOCAL char* wc_MIME_canonicalize(const char* line);
|
||||
WOLFSSL_LOCAL char* wc_MIME_single_canonicalize(const char* line, word32* len);
|
||||
WOLFSSL_LOCAL int wc_MIME_free_hdrs(MimeHdr* head);
|
||||
#endif /* HAVE_SMIME */
|
||||
|
||||
|
@ -331,6 +331,7 @@ struct PKCS7 {
|
||||
/* used by DecodeEnvelopedData with multiple encrypted contents */
|
||||
byte* cachedEncryptedContent;
|
||||
word32 cachedEncryptedContentSz;
|
||||
word16 contentCRLF:1; /* have content line endings been converted to CRLF */
|
||||
/* !! NEW DATA MEMBERS MUST BE ADDED AT END !! */
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user