Changed memory management and call logic in PKCS#7 parser/generator.

This commit is contained in:
Tobias Brunner 2012-05-12 18:15:50 +02:00
parent 2bf125f0ed
commit 6e6d78a561
2 changed files with 86 additions and 85 deletions

View File

@ -55,11 +55,6 @@ struct private_pkcs7_t {
*/ */
chunk_t content; chunk_t content;
/**
* Has the content already been parsed?
*/
bool parsed;
/** /**
* ASN.1 parsing start level * ASN.1 parsing start level
*/ */
@ -99,6 +94,69 @@ METHOD(pkcs7_t, is_envelopedData, bool,
return this->type == OID_PKCS7_ENVELOPED_DATA; return this->type == OID_PKCS7_ENVELOPED_DATA;
} }
/**
* ASN.1 definition of the PKCS#7 ContentInfo type
*/
static const asn1Object_t contentInfoObjects[] = {
{ 0, "contentInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
{ 1, "contentType", ASN1_OID, ASN1_BODY }, /* 1 */
{ 1, "content", ASN1_CONTEXT_C_0, ASN1_OPT |
ASN1_BODY }, /* 2 */
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define PKCS7_INFO_TYPE 1
#define PKCS7_INFO_CONTENT 2
/**
* Parse PKCS#7 contentInfo object
*/
static bool parse_contentInfo(private_pkcs7_t *this)
{
asn1_parser_t *parser;
chunk_t object;
int objectID;
bool success = FALSE;
if (!this->data.ptr)
{
return FALSE;
}
parser = asn1_parser_create(contentInfoObjects, this->data);
parser->set_top_level(parser, this->level);
while (parser->iterate(parser, &objectID, &object))
{
if (objectID == PKCS7_INFO_TYPE)
{
this->type = asn1_known_oid(object);
if (this->type < OID_PKCS7_DATA ||
this->type > OID_PKCS7_ENCRYPTED_DATA)
{
DBG1(DBG_LIB, "unknown pkcs7 content type");
goto end;
}
}
else if (objectID == PKCS7_INFO_CONTENT && object.len > 0)
{
chunk_free(&this->content);
this->content = chunk_clone(object);
}
}
success = parser->success(parser);
if (success)
{
this->level += 2;
chunk_free(&this->data);
}
end:
parser->destroy(parser);
return success;
}
/** /**
* Check whether to abort the requested parsing * Check whether to abort the requested parsing
*/ */
@ -110,30 +168,27 @@ static bool abort_parsing(private_pkcs7_t *this, int type)
oid_names[type].name); oid_names[type].name);
return TRUE; return TRUE;
} }
if (this->parsed)
{
DBG1(DBG_LIB, "pkcs7 content has already been parsed");
return TRUE;
}
this->parsed = TRUE;
return FALSE; return FALSE;
} }
METHOD(pkcs7_t, parse_data, bool, METHOD(pkcs7_t, parse_data, bool,
private_pkcs7_t *this) private_pkcs7_t *this)
{ {
chunk_t data = this->content; chunk_t data;
if (abort_parsing(this, OID_PKCS7_DATA)) if (!parse_contentInfo(this) ||
abort_parsing(this, OID_PKCS7_DATA))
{ {
return FALSE; return FALSE;
} }
data = this->content;
if (data.len == 0) if (data.len == 0)
{ {
this->data = chunk_empty; this->data = chunk_empty;
return TRUE; return TRUE;
} }
if (asn1_parse_simple_object(&data, ASN1_OCTET_STRING, this->level, "data")) if (asn1_parse_simple_object(&data, ASN1_OCTET_STRING,
this->level, "data"))
{ {
this->data = chunk_clone(data); this->data = chunk_clone(data);
return TRUE; return TRUE;
@ -202,7 +257,8 @@ METHOD(pkcs7_t, parse_signedData, bool,
chunk_t encrypted_digest = chunk_empty; chunk_t encrypted_digest = chunk_empty;
if (abort_parsing(this, OID_PKCS7_SIGNED_DATA)) if (!parse_contentInfo(this) ||
abort_parsing(this, OID_PKCS7_SIGNED_DATA))
{ {
return FALSE; return FALSE;
} }
@ -225,20 +281,14 @@ METHOD(pkcs7_t, parse_signedData, bool,
break; break;
case PKCS7_SIGNED_CONTENT_INFO: case PKCS7_SIGNED_CONTENT_INFO:
{ {
chunk_t pureData;
pkcs7_t *data = pkcs7_create_from_chunk(object, level+1); pkcs7_t *data = pkcs7_create_from_chunk(object, level+1);
if (data == NULL) if (!data || !data->parse_data(data))
{ {
DESTROY_IF(data);
goto end; goto end;
} }
if (!data->parse_data(data)) this->data = chunk_clone(data->get_data(data));
{
data->destroy(data);
goto end;
}
pureData = data->get_data(data);
this->data = (pureData.len) ? chunk_clone(pureData) : chunk_empty;
data->destroy(data); data->destroy(data);
break; break;
} }
@ -443,7 +493,8 @@ METHOD(pkcs7_t, parse_envelopedData, bool,
crypter_t *crypter = NULL; crypter_t *crypter = NULL;
if (abort_parsing(this, OID_PKCS7_ENVELOPED_DATA)) if (!parse_contentInfo(this) ||
abort_parsing(this, OID_PKCS7_ENVELOPED_DATA))
{ {
return FALSE; return FALSE;
} }
@ -813,7 +864,9 @@ METHOD(pkcs7_t, build_envelopedData, bool,
ASN1_INTEGER_0, ASN1_INTEGER_0,
asn1_wrap(ASN1_SET, "m", recipientInfo), asn1_wrap(ASN1_SET, "m", recipientInfo),
encryptedContentInfo); encryptedContentInfo);
chunk_free(&this->data);
this->type = OID_PKCS7_ENVELOPED_DATA; this->type = OID_PKCS7_ENVELOPED_DATA;
this->data = get_contentInfo(this);
} }
return TRUE; return TRUE;
} }
@ -900,7 +953,6 @@ METHOD(pkcs7_t, build_signedData, bool,
this->data = get_contentInfo(this); this->data = get_contentInfo(this);
chunk_free(&this->content); chunk_free(&this->content);
this->type = OID_PKCS7_SIGNED_DATA;
cert->get_encoding(cert, CERT_ASN1_DER, &encoding); cert->get_encoding(cert, CERT_ASN1_DER, &encoding);
this->content = asn1_wrap(ASN1_SEQUENCE, "cmcmm", this->content = asn1_wrap(ASN1_SEQUENCE, "cmcmm",
@ -909,6 +961,9 @@ METHOD(pkcs7_t, build_signedData, bool,
this->data, this->data,
asn1_wrap(ASN1_CONTEXT_C_0, "m", encoding), asn1_wrap(ASN1_CONTEXT_C_0, "m", encoding),
asn1_wrap(ASN1_SET, "m", signerInfo)); asn1_wrap(ASN1_SET, "m", signerInfo));
chunk_free(&this->data);
this->type = OID_PKCS7_SIGNED_DATA;
this->data = get_contentInfo(this);
return TRUE; return TRUE;
} }
@ -923,57 +978,6 @@ METHOD(pkcs7_t, destroy, void,
free(this); free(this);
} }
/**
* ASN.1 definition of the PKCS#7 ContentInfo type
*/
static const asn1Object_t contentInfoObjects[] = {
{ 0, "contentInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
{ 1, "contentType", ASN1_OID, ASN1_BODY }, /* 1 */
{ 1, "content", ASN1_CONTEXT_C_0, ASN1_OPT |
ASN1_BODY }, /* 2 */
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define PKCS7_INFO_TYPE 1
#define PKCS7_INFO_CONTENT 2
/**
* Parse PKCS#7 contentInfo object
*/
static bool parse_contentInfo(chunk_t blob, u_int level0, private_pkcs7_t *cInfo)
{
asn1_parser_t *parser;
chunk_t object;
int objectID;
bool success = FALSE;
parser = asn1_parser_create(contentInfoObjects, blob);
parser->set_top_level(parser, level0);
while (parser->iterate(parser, &objectID, &object))
{
if (objectID == PKCS7_INFO_TYPE)
{
cInfo->type = asn1_known_oid(object);
if (cInfo->type < OID_PKCS7_DATA
|| cInfo->type > OID_PKCS7_ENCRYPTED_DATA)
{
DBG1(DBG_LIB, "unknown pkcs7 content type");
goto end;
}
}
else if (objectID == PKCS7_INFO_CONTENT && object.len > 0)
{
cInfo->content = chunk_clone(object);
}
}
success = parser->success(parser);
end:
parser->destroy(parser);
return success;
}
/** /**
* Generic private constructor * Generic private constructor
*/ */
@ -1013,12 +1017,9 @@ pkcs7_t *pkcs7_create_from_chunk(chunk_t chunk, u_int level)
{ {
private_pkcs7_t *this = pkcs7_create_empty(); private_pkcs7_t *this = pkcs7_create_empty();
this->level = level + 2; this->level = level;
if (!parse_contentInfo(chunk, level, this)) this->data = chunk_clone(chunk);
{
destroy(this);
return NULL;
}
return &this->public; return &this->public;
} }
@ -1030,7 +1031,6 @@ pkcs7_t *pkcs7_create_from_data(chunk_t data)
private_pkcs7_t *this = pkcs7_create_empty(); private_pkcs7_t *this = pkcs7_create_empty();
this->data = chunk_clone(data); this->data = chunk_clone(data);
this->parsed = TRUE;
return &this->public; return &this->public;
} }

View File

@ -64,7 +64,8 @@ struct pkcs7_t {
bool (*parse_data) (pkcs7_t *this); bool (*parse_data) (pkcs7_t *this);
/** /**
* Parse a PKCS#7 signedData content. * Parse a PKCS#7 signedData content. The contained PKCS#7 data is parsed
* and verified.
* *
* @param cacert cacert used to verify the signature * @param cacert cacert used to verify the signature
* @return TRUE if parsing was successful * @return TRUE if parsing was successful