forked from pool/openssl
192 lines
6.1 KiB
Diff
192 lines
6.1 KiB
Diff
|
commit d3d52c73544bba800c2a8f5ef3376358158cf2ca
|
||
|
Author: Emilia Kasper <emilia@openssl.org>
|
||
|
Date: Fri Feb 27 16:52:23 2015 +0100
|
||
|
|
||
|
PKCS#7: avoid NULL pointer dereferences with missing content
|
||
|
|
||
|
In PKCS#7, the ASN.1 content component is optional.
|
||
|
This typically applies to inner content (detached signatures),
|
||
|
however we must also handle unexpected missing outer content
|
||
|
correctly.
|
||
|
|
||
|
This patch only addresses functions reachable from parsing,
|
||
|
decryption and verification, and functions otherwise associated
|
||
|
with reading potentially untrusted data.
|
||
|
|
||
|
Correcting all low-level API calls requires further work.
|
||
|
|
||
|
CVE-2015-0289
|
||
|
|
||
|
Thanks to Michal Zalewski (Google) for reporting this issue.
|
||
|
|
||
|
Reviewed-by: Steve Henson <steve@openssl.org>
|
||
|
|
||
|
Index: openssl-1.0.1i/crypto/pkcs7/pk7_doit.c
|
||
|
===================================================================
|
||
|
--- openssl-1.0.1i.orig/crypto/pkcs7/pk7_doit.c 2015-03-17 13:23:33.961649688 +0100
|
||
|
+++ openssl-1.0.1i/crypto/pkcs7/pk7_doit.c 2015-03-17 13:34:34.445347342 +0100
|
||
|
@@ -272,6 +272,25 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio)
|
||
|
PKCS7_RECIP_INFO *ri=NULL;
|
||
|
ASN1_OCTET_STRING *os=NULL;
|
||
|
|
||
|
+ if (p7 == NULL) {
|
||
|
+ PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_INVALID_NULL_POINTER);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ /*
|
||
|
+ * The content field in the PKCS7 ContentInfo is optional, but that really
|
||
|
+ * only applies to inner content (precisely, detached signatures).
|
||
|
+ *
|
||
|
+ * When reading content, missing outer content is therefore treated as an
|
||
|
+ * error.
|
||
|
+ *
|
||
|
+ * When creating content, PKCS7_content_new() must be called before
|
||
|
+ * calling this method, so a NULL p7->d is always an error.
|
||
|
+ */
|
||
|
+ if (p7->d.ptr == NULL) {
|
||
|
+ PKCS7err(PKCS7_F_PKCS7_DATAINIT, PKCS7_R_NO_CONTENT);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
i=OBJ_obj2nid(p7->type);
|
||
|
p7->state=PKCS7_S_HEADER;
|
||
|
|
||
|
@@ -433,6 +452,16 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKE
|
||
|
unsigned char *ek = NULL, *tkey = NULL;
|
||
|
int eklen = 0, tkeylen = 0;
|
||
|
|
||
|
+ if (p7 == NULL) {
|
||
|
+ PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_INVALID_NULL_POINTER);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (p7->d.ptr == NULL) {
|
||
|
+ PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
i=OBJ_obj2nid(p7->type);
|
||
|
p7->state=PKCS7_S_HEADER;
|
||
|
|
||
|
@@ -752,6 +781,16 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
|
||
|
STACK_OF(PKCS7_SIGNER_INFO) *si_sk=NULL;
|
||
|
ASN1_OCTET_STRING *os=NULL;
|
||
|
|
||
|
+ if (p7 == NULL) {
|
||
|
+ PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_INVALID_NULL_POINTER);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (p7->d.ptr == NULL) {
|
||
|
+ PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_NO_CONTENT);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
EVP_MD_CTX_init(&ctx_tmp);
|
||
|
i=OBJ_obj2nid(p7->type);
|
||
|
p7->state=PKCS7_S_HEADER;
|
||
|
@@ -796,6 +835,7 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
|
||
|
/* If detached data then the content is excluded */
|
||
|
if(PKCS7_type_is_data(p7->d.sign->contents) && p7->detached) {
|
||
|
M_ASN1_OCTET_STRING_free(os);
|
||
|
+ os = NULL;
|
||
|
p7->d.sign->contents->d.data = NULL;
|
||
|
}
|
||
|
break;
|
||
|
@@ -806,6 +846,7 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
|
||
|
if(PKCS7_type_is_data(p7->d.digest->contents) && p7->detached)
|
||
|
{
|
||
|
M_ASN1_OCTET_STRING_free(os);
|
||
|
+ os = NULL;
|
||
|
p7->d.digest->contents->d.data = NULL;
|
||
|
}
|
||
|
break;
|
||
|
@@ -878,24 +919,31 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio)
|
||
|
M_ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len);
|
||
|
}
|
||
|
|
||
|
- if (!PKCS7_is_detached(p7) && !(os->flags & ASN1_STRING_FLAG_NDEF))
|
||
|
- {
|
||
|
- char *cont;
|
||
|
- long contlen;
|
||
|
- btmp=BIO_find_type(bio,BIO_TYPE_MEM);
|
||
|
- if (btmp == NULL)
|
||
|
- {
|
||
|
- PKCS7err(PKCS7_F_PKCS7_DATAFINAL,PKCS7_R_UNABLE_TO_FIND_MEM_BIO);
|
||
|
- goto err;
|
||
|
- }
|
||
|
- contlen = BIO_get_mem_data(btmp, &cont);
|
||
|
- /* Mark the BIO read only then we can use its copy of the data
|
||
|
- * instead of making an extra copy.
|
||
|
- */
|
||
|
- BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY);
|
||
|
- BIO_set_mem_eof_return(btmp, 0);
|
||
|
- ASN1_STRING_set0(os, (unsigned char *)cont, contlen);
|
||
|
- }
|
||
|
+ if (!PKCS7_is_detached(p7)) {
|
||
|
+ /*
|
||
|
+ * NOTE(emilia): I think we only reach os == NULL here because detached
|
||
|
+ * digested data support is broken.
|
||
|
+ */
|
||
|
+ if (os == NULL)
|
||
|
+ goto err;
|
||
|
+ if (!(os->flags & ASN1_STRING_FLAG_NDEF)) {
|
||
|
+ char *cont;
|
||
|
+ long contlen;
|
||
|
+ btmp = BIO_find_type(bio, BIO_TYPE_MEM);
|
||
|
+ if (btmp == NULL) {
|
||
|
+ PKCS7err(PKCS7_F_PKCS7_DATAFINAL, PKCS7_R_UNABLE_TO_FIND_MEM_BIO);
|
||
|
+ goto err;
|
||
|
+ }
|
||
|
+ contlen = BIO_get_mem_data(btmp, &cont);
|
||
|
+ /*
|
||
|
+ * Mark the BIO read only then we can use its copy of the data
|
||
|
+ * instead of making an extra copy.
|
||
|
+ */
|
||
|
+ BIO_set_flags(btmp, BIO_FLAGS_MEM_RDONLY);
|
||
|
+ BIO_set_mem_eof_return(btmp, 0);
|
||
|
+ ASN1_STRING_set0(os, (unsigned char *)cont, contlen);
|
||
|
+ }
|
||
|
+ }
|
||
|
ret=1;
|
||
|
err:
|
||
|
EVP_MD_CTX_cleanup(&ctx_tmp);
|
||
|
@@ -971,6 +1019,16 @@ int PKCS7_dataVerify(X509_STORE *cert_st
|
||
|
STACK_OF(X509) *cert;
|
||
|
X509 *x509;
|
||
|
|
||
|
+ if (p7 == NULL) {
|
||
|
+ PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_INVALID_NULL_POINTER);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (p7->d.ptr == NULL) {
|
||
|
+ PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_NO_CONTENT);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
if (PKCS7_type_is_signed(p7))
|
||
|
{
|
||
|
cert=p7->d.sign->cert;
|
||
|
Index: openssl-1.0.1i/crypto/pkcs7/pk7_lib.c
|
||
|
===================================================================
|
||
|
--- openssl-1.0.1i.orig/crypto/pkcs7/pk7_lib.c 2015-03-17 13:23:37.451700626 +0100
|
||
|
+++ openssl-1.0.1i/crypto/pkcs7/pk7_lib.c 2015-03-17 13:36:01.708627632 +0100
|
||
|
@@ -71,6 +71,7 @@ long PKCS7_ctrl(PKCS7 *p7, int cmd, long
|
||
|
|
||
|
switch (cmd)
|
||
|
{
|
||
|
+ /* NOTE(emilia): does not support detached digested data. */
|
||
|
case PKCS7_OP_SET_DETACHED_SIGNATURE:
|
||
|
if (nid == NID_pkcs7_signed)
|
||
|
{
|
||
|
@@ -459,6 +460,8 @@ int PKCS7_set_digest(PKCS7 *p7, const EV
|
||
|
|
||
|
STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7)
|
||
|
{
|
||
|
+ if (p7 == NULL || p7->d.ptr == NULL)
|
||
|
+ return NULL;
|
||
|
if (PKCS7_type_is_signed(p7))
|
||
|
{
|
||
|
return(p7->d.sign->signer_info);
|