Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 53 additions & 13 deletions src/ssl_p7p12.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,14 +251,46 @@ WOLFSSL_STACK* wolfSSL_PKCS7_to_stack(PKCS7* pkcs7)
return NULL;
}

/* Return 1 if the DER certificate is equal to on of 'certs' passed in. */
static int wolfSSL_PKCS7_CertInStack(WOLFSSL_STACK* certs, const byte* der,
word32 derSz)
{
int i;
int num;

if (certs == NULL || der == NULL || derSz == 0) {
return 0;
}

num = wolfSSL_sk_X509_num(certs);
for (i = 0; i < num; i++) {
WOLFSSL_X509* x509;
const byte* certDer = NULL;
int certDerSz = 0;

x509 = wolfSSL_sk_X509_value(certs, i);
if (x509 != NULL) {
certDer = wolfSSL_X509_get_der(x509, &certDerSz);
}
if (certDer != NULL && certDerSz > 0 && (word32)certDerSz == derSz &&
XMEMCMP(certDer, der, derSz) == 0) {
return 1;
}
}

return 0;
}


/**
* 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
* certs - certificates the signer may be taken from. With PKCS7_NOINTERN the
* signer must be one of these.
* flags - flags to control function behavior.
*
* Return WOLFSSL_STACK of signers on success, NULL on error.
Expand All @@ -276,8 +308,13 @@ WOLFSSL_STACK* wolfSSL_PKCS7_get0_signers(PKCS7* pkcs7, WOLFSSL_STACK* certs,
return NULL;

if (flags & PKCS7_NOINTERN) {
WOLFSSL_MSG("PKCS7_NOINTERN flag not supported");
return NULL;
/* With this flag the signer must be in certs stack. A signer that is
* only embedded in the message is rejected. */
if (!wolfSSL_PKCS7_CertInStack(certs, p7->pkcs7.verifyCert,
p7->pkcs7.verifyCertSz)) {
WOLFSSL_MSG("PKCS7_NOINTERN: verified signer not in certs");
return NULL;
}
}

/* Prefer the certificate that actually verified the signature. Falling
Expand Down Expand Up @@ -315,8 +352,6 @@ WOLFSSL_STACK* wolfSSL_PKCS7_get0_signers(PKCS7* pkcs7, WOLFSSL_STACK* certs,
return NULL;
}

(void)certs;

return signers;
}

Expand Down Expand Up @@ -805,13 +840,6 @@ int wolfSSL_PKCS7_verify(PKCS7* pkcs7, WOLFSSL_STACK* certs,
p7->pkcs7.contentSz = (word32)memSz;
}

/* certs is the list of certificates to find the cert with issuer/serial. */
(void)certs;
/* store is the certificate store to use to verify signer certificate
* associated with the signers.
*/
(void)store;

ret = wc_PKCS7_VerifySignedData(&p7->pkcs7, p7->data, p7->len);
if (ret != 0)
return WOLFSSL_FAILURE;
Expand All @@ -829,6 +857,15 @@ int wolfSSL_PKCS7_verify(PKCS7* pkcs7, WOLFSSL_STACK* certs,
return WOLFSSL_FAILURE;
}

/* A signer lookup happens regardless of PKCS7_NOVERIFY. With PKCS7_NOINTERN
* the signer must be in the certs stack. */
if ((flags & PKCS7_NOINTERN) &&
!wolfSSL_PKCS7_CertInStack(certs, p7->pkcs7.verifyCert,
p7->pkcs7.verifyCertSz)) {
WOLFSSL_MSG("PKCS7_NOINTERN: verified signer not in certs");
return WOLFSSL_FAILURE;
}

if ((flags & PKCS7_NOVERIFY) != PKCS7_NOVERIFY) {
/* Verify signer certificates */
if (store == NULL || store->cm == NULL) {
Expand All @@ -851,7 +888,10 @@ int wolfSSL_PKCS7_verify(PKCS7* pkcs7, WOLFSSL_STACK* certs,

for (i = 0; i < wolfSSL_sk_X509_num(signers); i++) {
signer = wolfSSL_sk_X509_value(signers, i);
if (wolfSSL_X509_STORE_CTX_init(ctx, store, signer, NULL)

/* Trust anchors come from the store and untrusted intermediates
* from the certs stack. */
if (wolfSSL_X509_STORE_CTX_init(ctx, store, signer, certs)
!= WOLFSSL_SUCCESS) {
WOLFSSL_MSG("Failed to initialize X509 STORE CTX");
wolfSSL_sk_X509_pop_free(signers, NULL);
Expand Down
125 changes: 125 additions & 0 deletions tests/api/test_ossl_p7p12.c
Original file line number Diff line number Diff line change
Expand Up @@ -1466,6 +1466,131 @@ int test_wolfSSL_SMIME_write_PKCS7(void)
return EXPECT_RESULT();
}

/* PKCS7_NOINTERN means the signer must be found in the certs argument, not
* among the certificates embedded in the message.
*/
int test_wolfSSL_PKCS7_verify_nointern(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_ALL) && defined(HAVE_PKCS7) && !defined(NO_RSA) && \
!defined(NO_BIO) && !defined(NO_FILESYSTEM) && defined(HAVE_SMIME)
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";
int signFlags = PKCS7_DETACHED | PKCS7_STREAM;
WOLFSSL_BIO* certBio = NULL;
WOLFSSL_BIO* keyBio = NULL;
WOLFSSL_BIO* caBio = NULL;
WOLFSSL_BIO* inBio = NULL;
WOLFSSL_BIO* smimeBio = NULL;
WOLFSSL_BIO* readBio = NULL;
WOLFSSL_BIO* content = NULL;
X509* signCert = NULL;
EVP_PKEY* signKey = NULL;
X509* caCert = NULL;
X509_STORE* store = NULL;
STACK_OF(X509)* signerSk = NULL;
STACK_OF(X509)* caSk = NULL;
STACK_OF(X509)* signers = NULL;
PKCS7* p7 = NULL;
PKCS7* p7Ver = NULL;
const byte* smime = NULL;
int smimeSz = 0;
int i;
struct {
int certsSel; /* 0 = NULL, 1 = { ca-cert }, 2 = { server-cert } */
int useStore;
int flags;
int expectOk;
} cases[] = {
/* Signer only embedded in the message: rejected. */
{ 1, 0, PKCS7_NOVERIFY | PKCS7_NOINTERN, 0 },
{ 0, 0, PKCS7_NOVERIFY | PKCS7_NOINTERN, 0 },
{ 1, 1, PKCS7_NOINTERN, 0 },
/* Signer present in certs: accepted. */
{ 2, 0, PKCS7_NOVERIFY | PKCS7_NOINTERN, 1 },
{ 2, 1, PKCS7_NOINTERN, 1 },
/* Without PKCS7_NOINTERN the embedded signer may be used. */
{ 1, 0, PKCS7_NOVERIFY, 1 },
};

ExpectNotNull(certBio = BIO_new_file(cert, "r"));
ExpectNotNull(keyBio = BIO_new_file(key, "r"));
ExpectNotNull(caBio = BIO_new_file(ca, "r"));
ExpectNotNull(signCert = PEM_read_bio_X509(certBio, NULL, 0, NULL));
ExpectNotNull(signKey = PEM_read_bio_PrivateKey(keyBio, NULL, 0, NULL));
ExpectNotNull(caCert = PEM_read_bio_X509(caBio, NULL, 0, NULL));
ExpectNotNull(store = X509_STORE_new());
ExpectIntEQ(X509_STORE_add_cert(store, caCert), 1);

/* Stacks only borrow the certs; freed with sk_X509_free(). */
ExpectNotNull(signerSk = sk_X509_new_null());
ExpectIntGT(sk_X509_push(signerSk, signCert), 0);
ExpectNotNull(caSk = sk_X509_new_null());
ExpectIntGT(sk_X509_push(caSk, caCert), 0);

/* Detached S/MIME message signed by server-cert, which is embedded. */
ExpectNotNull(inBio = BIO_new(BIO_s_mem()));
ExpectIntGT(BIO_write(inBio, data, sizeof(data)), 0);
ExpectNotNull(p7 = PKCS7_sign(signCert, signKey, NULL, inBio, signFlags));
ExpectNotNull(smimeBio = BIO_new(BIO_s_mem()));
ExpectIntEQ(SMIME_write_PKCS7(smimeBio, p7, inBio, signFlags), 1);
ExpectIntGT((smimeSz = BIO_get_mem_data(smimeBio, &smime)), 0);

/* Run through the various combinations of flags and test against the
* expected results. */
for (i = 0; i < (int)(sizeof(cases) / sizeof(cases[0])); i++) {
STACK_OF(X509)* certs = (cases[i].certsSel == 1) ? caSk :
(cases[i].certsSel == 2) ? signerSk : NULL;

ExpectNotNull(readBio = BIO_new_mem_buf(smime, smimeSz));
ExpectNotNull(p7Ver = SMIME_read_PKCS7(readBio, &content));
ExpectIntEQ(PKCS7_verify(p7Ver, certs,
cases[i].useStore ? store : NULL,
content, NULL, cases[i].flags),
cases[i].expectOk ? WOLFSSL_SUCCESS :
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));

BIO_free(content);
content = NULL;
BIO_free(readBio);
readBio = NULL;
PKCS7_free(p7Ver);
p7Ver = NULL;
}

/* PKCS7_get0_signers() honors PKCS7_NOINTERN after a verify. */
ExpectNotNull(readBio = BIO_new_mem_buf(smime, smimeSz));
ExpectNotNull(p7Ver = SMIME_read_PKCS7(readBio, &content));
ExpectIntEQ(PKCS7_verify(p7Ver, NULL, NULL, content, NULL,
PKCS7_NOVERIFY), WOLFSSL_SUCCESS);
ExpectNull(PKCS7_get0_signers(p7Ver, caSk, PKCS7_NOINTERN));
ExpectNull(PKCS7_get0_signers(p7Ver, NULL, PKCS7_NOINTERN));
ExpectNotNull(signers = PKCS7_get0_signers(p7Ver, signerSk,
PKCS7_NOINTERN));
ExpectIntEQ(sk_X509_num(signers), 1);
sk_X509_pop_free(signers, X509_free);

BIO_free(content);
BIO_free(readBio);
PKCS7_free(p7Ver);
PKCS7_free(p7);
BIO_free(smimeBio);
BIO_free(inBio);
sk_X509_free(caSk);
sk_X509_free(signerSk);
X509_STORE_free(store);
X509_free(caCert);
X509_free(signCert);
EVP_PKEY_free(signKey);
BIO_free(keyBio);
BIO_free(certBio);
BIO_free(caBio);
#endif
return EXPECT_RESULT();
}

/* Testing functions dealing with PKCS12 parsing out X509 certs */
int test_wolfSSL_PKCS12(void)
{
Expand Down
4 changes: 3 additions & 1 deletion tests/api/test_ossl_p7p12.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ int test_wolfSSL_PEM_write_bio_PKCS7(void);
int test_wolfSSL_PEM_write_bio_encryptedKey(void);
int test_wolfSSL_SMIME_read_PKCS7(void);
int test_wolfSSL_SMIME_write_PKCS7(void);
int test_wolfSSL_PKCS7_verify_nointern(void);
int test_wolfSSL_PKCS12(void);

#define TEST_OSSL_PKCS7_DECLS \
Expand All @@ -51,7 +52,8 @@ int test_wolfSSL_PKCS12(void);

#define TEST_OSSL_SMIME_DECLS \
TEST_DECL_GROUP("ossl_smime", test_wolfSSL_SMIME_read_PKCS7), \
TEST_DECL_GROUP("ossl_smime", test_wolfSSL_SMIME_write_PKCS7)
TEST_DECL_GROUP("ossl_smime", test_wolfSSL_SMIME_write_PKCS7), \
TEST_DECL_GROUP("ossl_smime", test_wolfSSL_PKCS7_verify_nointern)

#define TEST_OSSL_PKCS12_DECLS \
TEST_DECL_GROUP("ossl_p12", test_wolfSSL_PKCS12)
Expand Down
Loading