Created
February 10, 2011 08:43
-
-
Save pilotmoon/820151 to your computer and use it in GitHub Desktop.
Checking the receipt is signed
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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