Skip to content

Instantly share code, notes, and snippets.

@MortimerGoro
Created June 4, 2014 10:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MortimerGoro/73103944326698e57f34 to your computer and use it in GitHub Desktop.
Save MortimerGoro/73103944326698e57f34 to your computer and use it in GitHub Desktop.
Receipt validation using OpenSSL and asn1c.
/* The PKCS #7 container (the receipt) and the output of the verification. */
BIO *b_p7;
PKCS7 *p7;
/* The Apple root certificate, as raw data and in its OpenSSL representation. */
BIO *b_x509;
X509 *Apple;
/* The root certificate for chain-of-trust verification. */
X509_STORE *store = X509_STORE_new();
/* ... Initialize both BIO variables using BIO_new_mem_buf() with a buffer and its size ... */
/* Initialize b_out as an output BIO to hold the receipt payload extracted during signature verification. */
BIO *b_out = BIO_new(BIO_s_mem());
/* Capture the content of the receipt file and populate the p7 variable with the PKCS #7 container. */
p7 = d2i_PKCS7_bio(b_p7, NULL);
/* ... Load the Apple root certificate into b_X509 ... */
/* Initialize b_x509 as an input BIO with a value of the Apple root certificate and load it into X509 data structure. Then add the Apple root certificate to the structure. */
Apple = d2i_X509_bio(b_x509, NULL);
X509_STORE_add_cert(store, Apple);
/* Verify the signature. If the verification is correct, b_out will contain the PKCS #7 payload and rc will be 1. */
int rc = PKCS7_verify(p7, NULL, store, NULL, b_out, 0);
/* For additional security, you may verify the fingerprint of the root certificate and verify the OIDs of the intermediate certificate and signing certificate. The OID in the certificate policies extension of the intermediate certificate is (1 2 840 113635 100 5 6 1), and the marker OID of the signing certificate is (1 2 840 113635 100 6 11 1). */
#include "Payload.h" /* This header file is generated by asn1c. */
/* The receipt payload and its size. */
void *pld = NULL;
size_t pld_sz;
/* Variables used to parse the payload. Both data types are declared in Payload.h. */
Payload_t *payload = NULL;
asn_dec_rval_t rval;
/* ... Load the payload from the receipt file into pld and set pld_sz to the payload size ... */
/* Parse the buffer using the decoder function generated by asn1c. The payload variable will contain the receipt attributes. */
rval = asn_DEF_Payload.ber_decoder(NULL, &asn_DEF_Payload, (void **)&payload, pld, pld_sz, 0);
/* Variables used to store the receipt attributes. */
OCTET_STRING_t *bundle_id = NULL;
OCTET_STRING_t *bundle_version = NULL;
OCTET_STRING_t *opaque = NULL;
OCTET_STRING_t *hash = NULL;
/* Iterate over the receipt attributes, saving the values needed to compute the GUID hash. */
size_t i;
for (i = 0; i < payload->list.count; i++) {
ReceiptAttribute_t *entry;
entry = payload->list.array[i];
switch (entry->type) {
case 2:
bundle_id = &entry->value;
break;
case 3:
bundle_version = &entry->value;
break;
case 4:
opaque = &entry->value;
break;
case 5:
hash = &entry->value;
break;
}
}
/* The GUID returned by copy_mac_address() is a CFDataRef. Use CFDataGetBytePtr() and CFDataGetLength() to get a pointer to the bytes that make up the GUID and to get its length. */
UInt8 *guid = NULL;
size_t guid_sz;
/* Declare and initialize an EVP context for OpenSSL. */
EVP_MD_CTX evp_ctx;
EVP_MD_CTX_init(&evp_ctx);
/* A buffer for result of the hash computation. */
UInt8 digest[20];
/* Set up the EVP context to compute a SHA-1 digest. */
EVP_DigestInit_ex(&evp_ctx, EVP_sha1(), NULL);
/* Concatenate the pieces to be hashed. They must be concatenated in this order. */
EVP_DigestUpdate(&evp_ctx, guid, guid_sz);
EVP_DigestUpdate(&evp_ctx, opaque->buf, opaque->size);
EVP_DigestUpdate(&evp_ctx, bundle_id->buf, bundle_id->size);
/* Compute the hash, saving the result into the digest variable. */
EVP_DigestFinal_ex(&evp_ctx, digest, NULL);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment