| auto *md = indir_data->messageDigest; | |
| auto nid = OBJ_obj2nid(md->digestAlgorithm->algorithm); | |
| auto digest = std::vector<std::uint8_t>(md->digest->data, md->digest->data + md->digest->length); |
| struct win_certificate { | |
| uint32_t length; /* dwLength */ | |
| uint16_t revision; /* wRevision */ | |
| uint16_t certificate_type; /* wCertificateType */ | |
| uint8_t certificate[/* length */]; /* bCertificate */ | |
| } __attribute__((aligned (8))); |
| SpcSerializedObject ::= SEQUENCE { | |
| classId SpcUuid, | |
| serializedData Impl_SpcSerializedData | |
| } | |
| Impl_SpcSerializedData ::= SET OF Impl_SpcPageHash | |
| Impl_SpcPageHash ::= SEQUENCE { | |
| type OBJECT IDENTIFIER, | |
| pageHashes OCTETSTRING | |
| } |
| struct impl_page_hash { | |
| /* page_offset corresponds to a real file offset within each section, | |
| * and should be aligned by page size. | |
| */ | |
| uint32_t page_offset; | |
| uint8_t page_hash[IMPL_PAGE_HASH_SIZE]; | |
| } __attribute__((packed)); | |
| typedef impl_page_hash *impl_page_hashes; |
| SpcIndirectDataContent ::= SEQUENCE { | |
| data SpcAttributeTypeAndOptionalValue, | |
| messageDigest DigestInfo | |
| } | |
| SpcAttributeTypeAndOptionalValue ::= SEQUENCE { | |
| type OBJECT IDENTIFIER, | |
| value [0] EXPLICIT ANY OPTIONAL | |
| } | |
| DigestInfo ::= SEQUENCE { | |
| digestAlgorithm AlgorithmIdentifier, | |
| digest OCTETSTRING | |
| } | |
| AlgorithmIdentifier ::= SEQUENCE { | |
| algorithm OBJECT IDENTIFIER, | |
| parameters [0] EXPLICIT ANY OPTIONAL | |
| } |
| typedef struct { | |
| ASN1_OBJECT *type; | |
| ASN1_TYPE *value; | |
| } Authenticode_SpcAttributeTypeAndOptionalValue; | |
| typedef struct { | |
| X509_ALGOR *digestAlgorithm; | |
| ASN1_OCTET_STRING *digest; | |
| } Authenticode_DigestInfo; | |
| typedef struct { | |
| Authenticode_SpcAttributeTypeAndOptionalValue *data; | |
| Authenticode_DigestInfo *messageDigest; | |
| } Authenticode_SpcIndirectDataContent; | |
| ASN1_SEQUENCE(Authenticode_SpcAttributeTypeAndOptionalValue) = { | |
| ASN1_SIMPLE(Authenticode_SpcAttributeTypeAndOptionalValue, type, ASN1_OBJECT), | |
| ASN1_OPT(Authenticode_SpcAttributeTypeAndOptionalValue, value, ASN1_ANY) | |
| } ASN1_SEQUENCE_END(Authenticode_SpcAttributeTypeAndOptionalValue) | |
| IMPLEMENT_ASN1_FUNCTIONS(Authenticode_SpcAttributeTypeAndOptionalValue) | |
| ASN1_SEQUENCE(Authenticode_DigestInfo) = { | |
| ASN1_SIMPLE(Authenticode_DigestInfo, digestAlgorithm, X509_ALGOR), | |
| ASN1_SIMPLE(Authenticode_DigestInfo, digest, ASN1_OCTET_STRING) | |
| } ASN1_SEQUENCE_END(Authenticode_DigestInfo) | |
| IMPLEMENT_ASN1_FUNCTIONS(Authenticode_DigestInfo) | |
| ASN1_SEQUENCE(Authenticode_SpcIndirectDataContent) = { | |
| ASN1_SIMPLE(Authenticode_SpcIndirectDataContent, data, Authenticode_SpcAttributeTypeAndOptionalValue), | |
| ASN1_SIMPLE(Authenticode_SpcIndirectDataContent, messageDigest, Authenticode_DigestInfo) | |
| } ASN1_SEQUENCE_END(Authenticode_SpcIndirectDataContent) | |
| IMPLEMENT_ASN1_FUNCTIONS(Authenticode_SpcIndirectDataContent) |
| TimeStampRequest ::= SEQUENCE { | |
| countersignatureType OBJECT IDENTIFIER, | |
| attributes Attributes OPTIONAL, | |
| content ContentInfo | |
| } |
| #include <uthenticode.h> | |
| #include <iostream> | |
| int main(int argc, char **argv) { | |
| auto *pe = peparse::ParsePEFromFile(argv[1]); | |
| std::cout << argv[1] << " has a " | |
| << (uthenticode::verify(pe) ? "valid" : "invalid") | |
| << " signature!"; | |
| } |
| /* Assuming that buf is an OpenSSL BIO* containing the DER-encoded PKCS#7 object */ | |
| auto *p7 = d2i_PKCS7_bio(buf, nullptr); | |
| auto *contents = p7->d.sign->contents; | |
| /* The d2i_ family increments the pointer passed to it, so we make a copy. */ | |
| auto *indir_data_inc_ptr = contents->d.other->value.sequence->data; | |
| auto *indir_data = d2i_Authenticode_SpcIndirectDataContent( | |
| nullptr, &indir_data_inc_ptr, contents->d.other->value.sequence->length); |
| STACK_OF(X509) *certs = p7->d.sign->cert; | |
| /* Re-serialize the SpcIndirectDataContent to DER... */ | |
| std::uint8_t indir_data_buf = nullptr; | |
| i2d_Authenticode_SpcIndirectDataContent(indir_data, &indir_data_buf); | |
| /* ...so that we can unwrap its sequence here. */ | |
| const auto *signed_data_seq = indir_data_buf; | |
| long length = 0; | |
| int tag = 0, tag_class = 0; | |
| ASN1_get_object(&signed_data_seq, &length, &tag, &tag_class, buf_size); | |
| assert(tag == V_ASN1_SEQUENCE); | |
| auto *signed_data = BIO_new_mem_buf(signed_data_seq, length); | |
| /* Our stack of certs isn't guaranteed to include the root cert, | |
| * so pass PKCS7_NOVERIFY. | |
| */ | |
| PKCS7_verify(p7, certs, nullptr, signed_data, nullptr, PKCS7_NOVERIFY); | |
| assert(status == 1); |