Skip to content

Instantly share code, notes, and snippets.

@pilotmoon
Created February 10, 2011 08:43
Show Gist options
  • Save pilotmoon/820151 to your computer and use it in GitHub Desktop.
Save pilotmoon/820151 to your computer and use it in GitHub Desktop.
Checking the receipt is signed
// This is based on https://github.com/roddi/ValidateStoreReceipt
// However, we use a hard coded SHA-1 hash to check the root cert, rather than the going to the keychain.
// Sorry for bad indenting. It looks OK in my Xcode!
// link with Foundation.framework and IOKit.framework libCrypto (via -lcrypto in Other Linker Flags)
// #import <Foundation/Foundation.h>
// #include <openssl/pkcs7.h>
// #include <openssl/objects.h>
// #include <openssl/sha.h>
// #include <openssl/x509.h>
// #include <openssl/err.h>
/* SHA-1 Fingerprint taken from Keychain Access 25 Nov 2010. Cert Expires 9 Feb 2035 */
static const unsigned char rootsig[] = {
0x61, 0x1E, 0x5B, 0x66,
0x2C, 0x59, 0x3A, 0x08,
0xFF, 0x58, 0xD1, 0x4A,
0xE2, 0x24, 0x52, 0xD1,
0x98, 0xDF, 0x6C, 0x60
};
ERR_load_PKCS7_strings();
ERR_load_X509_strings();
OpenSSL_add_all_digests();
// open receipt file
FILE *fp = fopen(receiptPath, "rb");
if (fp == NULL)
return nil;
// pull data into PKCS7 object and close file
PKCS7 *p7 = d2i_PKCS7_fp(fp, NULL);
fclose(fp);
// do basic checks on receipt
if (!PKCS7_type_is_signed(p7)) {
PKCS7_free(p7);
return nil;
}
if (!PKCS7_type_is_data(p7->d.sign->contents)) {
PKCS7_free(p7);
return nil;
}
/***************
Cert Validation
***************/
BOOL certIsValid=FALSE;
X509_STORE *store = X509_STORE_new();
if (store)
{
BIO *payload = BIO_new(BIO_s_mem());
if (payload)
{
// get the certificate chain from the receipt
STACK_OF(X509) *stack = p7->d.sign->cert;
if (stack)
{
// get the root certificate from the certificate chain
X509 *root = (X509*)sk_value(stack, sk_num(stack)-1);
if (root)
{
NSLog(@"Root Signer: name = %s", root->name);
NSLog(@"Ser Num = %d", root->cert_info->serialNumber->data[0]);
NSLog(@"Version = %d", root->cert_info->version->data[0]);
// create a SHA1 fingerprint of the root certificate
// you can test md and verify the root certificate is from Apple and is correct
unsigned char md[EVP_MAX_MD_SIZE];
unsigned int mdlen=0;
X509_digest(root, EVP_sha1(), md, &mdlen);
// is digest right length
if (SHA_DIGEST_LENGTH==mdlen)
{
NSLog(@"Receipt Root Signature is %@", [NSData dataWithBytes:md length:SHA_DIGEST_LENGTH]);
// do bytes match
if (0==memcmp(md, rootsig, SHA_DIGEST_LENGTH))
{
// root cert is the apple root ca
// verify the certificate chain
X509_STORE_add_cert(store, root);
if (PKCS7_verify(p7, NULL, store, NULL, payload, 0) != 1)
{
#ifdef DEBUG_BUILD
unsigned long err = ERR_get_error();
NSLog(@"%lu: %s\n", err, ERR_error_string(err,NULL));
#endif
}
else
{
certIsValid=YES;
}
}
}
}
}
BIO_free(payload);
}
X509_STORE_free(store);
}
EVP_cleanup();
if (!certIsValid)
{
NSLog(@"Certificate is not valid");
PKCS7_free(p7);
return nil;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment