I'm in the process of using in-app purchase in my App... now I want to validate the receipt, and for validating receipt signature I use the below code in the AppDelegate (in order to know if the user already purchased it when launching the App)
actually the code comes from the WWDC 2013 - session 308 ;-)
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
NSData *certificateData = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"AppleIncRootCertificate" withExtension:@"cer"]];
// The PKCS #7 container (the receipt) and The Apple root certificate.
BIO *b_receipt = BIO_new_mem_buf((void *) [receiptData bytes], (int)[receiptData length]);
BIO *b_x509 = BIO_new_mem_buf((void *)[certificateData bytes], (int)[certificateData length]);
// Convert receipt data to PKCS #7 Representation
PKCS7 *p7 = d2i_PKCS7_bio(b_receipt, NULL);
// Create the root certificate
X509_STORE *store = X509_STORE_new();
X509 *appleRootCA = d2i_X509_bio(b_x509, NULL);
X509_STORE_add_cert(store, appleRootCA);
// Verify the signature. If the verification is correct, b_receiptPayload will contain the PKCS #7 payload and result will be 1.
BIO *b_receiptPayload = BIO_new(BIO_s_mem());
int result = PKCS7_verify(p7, NULL, store, NULL, b_receiptPayload, 0);
if (result == 1)
{
NSLog(@"Receipt Signature is valid");
} else {
unsigned long error = ERR_get_error();
const char* error_str = ERR_error_string(error, NULL);
NSLog(@"OpenSSL Error --> %s",error_str);
}but I always get the following OpenSSL Error: error:2006F079:lib(32):func(111):reason(121)
I already google it but without any result...any suggestion?
Another way to validate receipt signature?
thank you in advance for your cooperation...
Keep in mind that all you are doing is validating the signature, not the contents of the receipt. An app can have a valid receipt whether or not an IAP was purchased.
Here are the differences between what you do and what I do. I suspect somewhere in here is the error. I suspect it is the OpenSSL_add_all_digests(): but it could be something else:
//you
BIO *b_receipt = BIO_new_mem_buf((void *) [receiptData bytes], (int)[receiptData length]);
//me
BIO *b_receipt=BIO_new(BIO_s_mem());
BIO_write(b_receipt, [receiptData bytes], (int)[receiptData length]);
//(I think these are equivalent)
//you
BIO *b_x509 = BIO_new_mem_buf((void *)[certificateData bytes], (int)[certificateData length]);
//me
BIO *b_x509 = BIO_new(BIO_s_mem());
BIO_write(b_x509, (const void *) [certificateData bytes], (int) [certificateData length]);
// I think tehse are equivalent
//you
BIO *b_receiptPayload = BIO_new(BIO_s_mem());
int result = PKCS7_verify(p7, NULL, store, NULL, b_receiptPayload, 0);
//me
OpenSSL_add_all_digests(); // try adding this before this line
int result=PKCS7_verify(p7,NULL,store,NULL,NULL,0);
// I think you are missing a key line!