Permalink
Browse files

working certificate check

  • Loading branch information...
1 parent d2513f5 commit 9fef3207552194ef6ad9e203776c473344a34b48 @roddi committed Nov 3, 2010
Showing with 110 additions and 0 deletions.
  1. +4 −0 ValidateStoreReceipt.xcodeproj/project.pbxproj
  2. +106 −0 validatereceipt.m
@@ -13,6 +13,7 @@
8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
DD5EBFFF1273472D00361AC6 /* validatereceipt.m in Sources */ = {isa = PBXBuildFile; fileRef = DD5EBFFE1273472D00361AC6 /* validatereceipt.m */; };
DD5EC0011273474F00361AC6 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD5EC0001273474F00361AC6 /* IOKit.framework */; };
+ DDDE9E931281FFD3003F581D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DDDE9E921281FFD3003F581D /* Security.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -36,6 +37,7 @@
DD5EBFFD1273472D00361AC6 /* validatereceipt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = validatereceipt.h; sourceTree = "<group>"; };
DD5EBFFE1273472D00361AC6 /* validatereceipt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = validatereceipt.m; sourceTree = "<group>"; };
DD5EC0001273474F00361AC6 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
+ DDDE9E921281FFD3003F581D /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -52,6 +54,7 @@
files = (
8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */,
DD5EC0011273474F00361AC6 /* IOKit.framework in Frameworks */,
+ DDDE9E931281FFD3003F581D /* Security.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -66,6 +69,7 @@
08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
1AB674ADFE9D54B511CA2CBB /* Products */,
DD5EC0001273474F00361AC6 /* IOKit.framework */,
+ DDDE9E921281FFD3003F581D /* Security.framework */,
);
name = ValidateStoreReceipt;
sourceTree = "<group>";
View
@@ -12,9 +12,13 @@
#import <IOKit/IOKitLib.h>
#import <Foundation/Foundation.h>
+#import <Security/Security.h>
+
#include <openssl/pkcs7.h>
#include <openssl/objects.h>
#include <openssl/sha.h>
+#include <openssl/x509.h>
+#include <openssl/err.h>
//#define USE_SAMPLE_RECEIPT
@@ -36,8 +40,74 @@
NSString *kReceiptOpaqueValue = @"OpaqueValue";
NSString *kReceiptHash = @"Hash";
+
+NSData * appleRootCert()
+{
+ OSStatus status;
+
+ SecKeychainRef keychain = nil;
+ status = SecKeychainOpen("/System/Library/Keychains/SystemRootCertificates.keychain", &keychain);
+ if(status) {
+ if(keychain) CFRelease(keychain);
+ return nil;
+ }
+
+ CFArrayRef searchList = CFArrayCreate(kCFAllocatorDefault, (const void**)&keychain, 1, &kCFTypeArrayCallBacks);
+
+ if (keychain)
+ CFRelease(keychain);
+
+ SecKeychainSearchRef searchRef = nil;
+ status = SecKeychainSearchCreateFromAttributes(searchList, kSecCertificateItemClass, NULL, &searchRef);
+ if(status) {
+ if(searchRef) CFRelease(searchRef);
+ if(searchList) CFRelease(searchList);
+ return nil;
+ }
+
+ SecKeychainItemRef itemRef = nil;
+ NSData * resultData = nil;
+
+ while(SecKeychainSearchCopyNext(searchRef, &itemRef) == noErr && resultData == nil) {
+ // Grab the name of the certificate
+ SecKeychainAttributeList list;
+ SecKeychainAttribute attributes[1];
+
+ attributes[0].tag = kSecLabelItemAttr;
+
+ list.count = 1;
+ list.attr = attributes;
+
+ SecKeychainItemCopyContent(itemRef, nil, &list, nil, nil);
+ NSData *nameData = [NSData dataWithBytesNoCopy:attributes[0].data length:attributes[0].length freeWhenDone:NO];
+ NSString *name = [[NSString alloc] initWithData:nameData encoding:NSUTF8StringEncoding];
+
+ if([name isEqualToString:@"Apple Root CA"]) {
+ CSSM_DATA certData;
+ status = SecCertificateGetData((SecCertificateRef)itemRef, &certData);
+ if(status) {
+ if(itemRef) CFRelease(itemRef);
+ }
+
+ resultData = [NSData dataWithBytes:certData.Data length:certData.Length];
+
+ SecKeychainItemFreeContent(&list, NULL);
+ if(itemRef) CFRelease(itemRef);
+ }
+
+ [name release];
+ }
+ CFRelease(searchList);
+ CFRelease(searchRef);
+
+ return resultData;
+}
+
+
NSDictionary * dictionaryWithAppStoreReceipt(NSString * path)
{
+ NSData * rootCertData = appleRootCert();
+
enum ATTRIBUTES
{
ATTR_START = 1,
@@ -48,6 +118,12 @@
ATTR_END
};
+ ERR_load_PKCS7_strings();
+ ERR_load_X509_strings();
+ OpenSSL_add_all_digests();
+
+ //X509_TEA_set_state(0);
+
// Expected input is a PKCS7 container with signed data containing
// an ASN.1 SET of SEQUENCE structures. Each SEQUENCE contains
// two INTEGERS and an OCTET STRING.
@@ -70,6 +146,36 @@
return nil;
}
+ BIO *payload = BIO_new(BIO_s_mem());
+ X509_STORE *store = X509_STORE_new();
+
+ const unsigned char *data = rootCertData.bytes;
+ X509 *appleCA = d2i_X509(NULL, &data, rootCertData.length);
+
+ X509_STORE_add_cert(store, appleCA);
+
+ int verifyReturnValue = PKCS7_verify(p7,NULL,store,NULL,payload,0);
+
+ // this code will come handy when the first real receipts arrive
+#if 0
+ unsigned long err = ERR_get_error();
+ if(err)
+ printf("%lu: %s\n",err,ERR_error_string(err,NULL));
+ else {
+ STACK_OF(X509) *stack = PKCS7_get0_signers(p7, NULL, 0);
+ for(NSUInteger i = 0; i < sk_num(stack); i++) {
+ const X509 *signer = (X509*)sk_value(stack, i);
+ NSLog(@"name = %s", signer->name);
+ }
+ }
+#endif
+
+ X509_STORE_free(store);
+ EVP_cleanup();
+
+ if (verifyReturnValue != 1)
+ return nil;
+
ASN1_OCTET_STRING *octets = p7->d.sign->contents->d.data;
unsigned char *p = octets->data;
unsigned char *end = p + octets->length;

0 comments on commit 9fef320

Please sign in to comment.