parse signedData object with empty content
[strongswan.git] / src / libstrongswan / crypto / pkcs7.c
index e6e2679..252fc19 100644 (file)
@@ -8,6 +8,7 @@
 /*
  * Copyright (C) 2005 Jan Hutter, Martin Willi
  * Copyright (C) 2002-2008 Andreas Steffen
+ *
  * Hochschule fuer Technik Rapperswil, Switzerland
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -215,7 +216,7 @@ static char ASN1_pkcs7_encrypted_data_oid_str[] = {
                  0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06
 };
 
-const chunk_t ASN1_pkcs7_data_oid = 
+static const chunk_t ASN1_pkcs7_data_oid = 
                                                chunk_from_buf(ASN1_pkcs7_data_oid_str);
 static const chunk_t ASN1_pkcs7_signed_data_oid =
                                                chunk_from_buf(ASN1_pkcs7_signed_data_oid_str);
@@ -301,6 +302,11 @@ static bool parse_data(private_pkcs7_t *this)
        {
                return FALSE;
        }
+       if (data.len == 0)
+       {
+               this->data = chunk_empty;
+               return TRUE;
+       }
        if (parse_asn1_simple_object(&data, ASN1_OCTET_STRING, this->level, "data"))
        {
                this->data = chunk_clone(data);
@@ -313,7 +319,7 @@ static bool parse_data(private_pkcs7_t *this)
 }
 
 /**
- * Parse PKCS#7 signedData content
+ * Implements pkcs7_t.parse_signedData.
  */
 static bool parse_signedData(private_pkcs7_t *this, x509_t *cacert)
 {
@@ -348,7 +354,23 @@ static bool parse_signedData(private_pkcs7_t *this, x509_t *cacert)
                                digest_alg = parse_algorithmIdentifier(object, level, NULL);
                                break;
                        case PKCS7_SIGNED_CONTENT_INFO:
-                               this->data = chunk_clone(object);
+                               {
+                                       chunk_t pureData;
+                                       pkcs7_t *data = pkcs7_create_from_chunk(object, level+1);
+
+                                       if (data == NULL)
+                                       {
+                                               return FALSE;
+                                       }
+                                       if (!data->parse_data(data))
+                                       {
+                                               data->destroy(data);
+                                               return FALSE;
+                                       }
+                                       pureData = data->get_data(data);
+                                       this->data = (pureData.len)? chunk_clone(pureData) : chunk_empty;
+                                       data->destroy(data);
+                               }
                                break;
                        case PKCS7_SIGNED_CERT:
                                {
@@ -376,6 +398,7 @@ static bool parse_signedData(private_pkcs7_t *this, x509_t *cacert)
                        case PKCS7_AUTH_ATTRIBUTES:
                                *object.ptr = ASN1_SET;
                                this->attributes = pkcs9_create_from_chunk(object, level+1);
+                               *object.ptr = ASN1_CONTEXT_C_0;
                                break;
                        case PKCS7_DIGEST_ALGORITHM:
                                digest_alg = parse_algorithmIdentifier(object, level, NULL);
@@ -425,6 +448,39 @@ static bool parse_signedData(private_pkcs7_t *this, x509_t *cacert)
                {
                        DBG2("digest signature is valid");
                }
+               if (this->data.ptr != NULL)
+               {
+                       chunk_t messageDigest = this->attributes->get_messageDigest(this->attributes);
+
+                       if (messageDigest.ptr == NULL)
+                       {
+                               DBG1("messageDigest attribute not found");
+                               return FALSE;
+                       }
+                       else
+                       {
+                               hasher_t *hasher = hasher_create(algorithm);
+                               chunk_t hash;
+                               bool valid;
+
+                               hasher->allocate_hash(hasher, this->data, &hash);
+                               hasher->destroy(hasher);
+                               DBG3("hash: %B", &hash);
+
+                               valid = chunk_equals(messageDigest, hash);
+                               free(messageDigest.ptr);
+                               free(hash.ptr);
+                               if (valid)
+                               {
+                                       DBG2("messageDigest is valid");
+                               }
+                               else
+                               {
+                                       DBG1("invalid messageDigest");
+                                       return FALSE;
+                               }
+                       }
+               }
        }
        return TRUE;
 }
@@ -817,10 +873,28 @@ bool build_signedData(private_pkcs7_t *this, rsa_private_key_t *private_key,
 
        if (this->attributes != NULL)
        {
-               chunk_t attributes = this->attributes->get_encoding(this->attributes);
-
-               if (attributes.ptr)
+               if (this->data.ptr != NULL)
                {
+                       /* take the current time as signingTime */
+                       time_t now = time(NULL);
+                       chunk_t signingTime = timetoasn1(&now, ASN1_UTCTIME);
+
+                       chunk_t messageDigest, attributes;
+                       hasher_t *hasher = hasher_create(alg);
+               
+                       hasher->allocate_hash(hasher, this->data, &messageDigest);
+                       hasher->destroy(hasher);
+                       this->attributes->set_attribute(this->attributes,
+                                                               OID_PKCS9_CONTENT_TYPE, ASN1_pkcs7_data_oid);
+                       this->attributes->set_messageDigest(this->attributes,
+                                                               messageDigest);
+                       this->attributes->set_attribute(this->attributes,
+                                                               OID_PKCS9_SIGNING_TIME, signingTime);
+                       attributes = this->attributes->get_encoding(this->attributes);
+
+                       free(messageDigest.ptr);
+                       free(signingTime.ptr);
+
                        private_key->build_emsa_pkcs1_signature(private_key, alg,
                                                        attributes, &encryptedDigest);
                        authenticatedAttributes = chunk_clone(attributes);
@@ -907,7 +981,7 @@ static bool parse_contentInfo(chunk_t blob, u_int level0, private_pkcs7_t *cInfo
                                return FALSE;
                        }
                }
-               else if (objectID == PKCS7_INFO_CONTENT)
+               else if (objectID == PKCS7_INFO_CONTENT && object.len > 0)
                {
                        cInfo->content = chunk_clone(object);
                }