I have no Idea how to to check if the app verifies receipts on the device and support the SHA-256 algorithm. My App is purchased once and without in-app purchase.
the are the verifying process:
// Load the receipt into a Data object
let _receipt_url = Bundle.main.appStoreReceiptURL,
let _receipt_data = try? Data(contentsOf: _receipt_url)
let _receipt_bio = BIO_new(BIO_s_mem())
let _receipt_bytes: [UInt8] = .init(_receipt_data)
BIO_write(_receipt_bio, _receipt_bytes, Int32(_receipt_data.count))
let _receipt_pkcs7 = d2i_PKCS7_bio(_receipt_bio, nil)
BIO_free(_receipt_bio)
guard _receipt_pkcs7 != nil else {
SKReceiptRefreshRequest().start()
return
}
// Check that the container has a signature
guard OBJ_obj2nid(_receipt_pkcs7!.pointee.type) == NID_pkcs7_signed else {
SKReceiptRefreshRequest().start()
return
}
// Check that the container contains data
let _receipt_contents = _receipt_pkcs7!.pointee.d.sign.pointee.contents
guard OBJ_obj2nid(_receipt_contents?.pointee.type) == NID_pkcs7_data else {
SKReceiptRefreshRequest().start()
return
}
// Load the AppleInc_root_certificate into a Data object
guard
let _root_cert_url = Bundle.main.url(forResource: "AppleIncRootCertificate", withExtension: "cer"),
let _root_cert_data = try? Data(contentsOf: _root_cert_url)
else {
return
}
let _root_cert_bio = BIO_new(BIO_s_mem())
let _root_cert_bytes: [UInt8] = .init(_root_cert_data)
BIO_write(_root_cert_bio, _root_cert_bytes, Int32(_root_cert_data.count))
let _root_cert_x509 = d2i_X509_bio(_root_cert_bio, nil)
BIO_free(_root_cert_bio)
// Verify the signature
let _store = X509_STORE_new()
X509_STORE_add_cert(_store, _root_cert_x509)
OpenSSL_add_all_digests()
let _verification_result = PKCS7_verify(_receipt_pkcs7, nil, _store, nil, nil, 0)
guard _verification_result == 1 else {
return
}
// Get a pointer to the start and end of the ASN.1 payload
let _receipt_sign = _receipt_pkcs7?.pointee.d.sign
let _octets = _receipt_sign?.pointee.contents.pointee.d.data
var _ptr = UnsafePointer(_octets?.pointee.data)
let _end = _ptr!.advanced(by: Int(_octets!.pointee.length))
var _type: Int32 = 0
var _xclass: Int32 = 0
var _length: Int = 0
// Key attributes of in-app purchase.
var _iap_id = ""
var _iap_quantity = -1
var _iap_set: [(String, Int)] = []
// Parse ASN.1 payload
ASN1_get_object(&_ptr, &_length, &_type, &_xclass, _ptr!.distance(to: _end))
guard _type == V_ASN1_SET else {
return
}
while _ptr! < _end {
ASN1_get_object(&_ptr, &_length, &_type, &_xclass, _ptr!.distance(to: _end))
guard _type == V_ASN1_SEQUENCE else {
continue
}
ASN1_get_object(&_ptr, &_length, &_type, &_xclass, _ptr!.distance(to: _end))
guard _type == V_ASN1_INTEGER else {
continue
}
let _attribute_type = ASN1_INTEGER_get(c2i_ASN1_INTEGER(nil, &_ptr, _length))
ASN1_get_object(&_ptr, &_length, &_type, &_xclass, _ptr!.distance(to: _end))
guard _type == V_ASN1_INTEGER else {
continue
}
_ptr = _ptr?.advanced(by: _length)
ASN1_get_object(&_ptr, &_length, &_type, &_xclass, _ptr!.distance(to: _end))
guard _type == V_ASN1_OCTET_STRING else {
continue
}
switch _attribute_type {
case 17:
// Parse In-App purchase receipt.
ASN1_get_object(&_ptr, &_length, &_type, &_xclass, _ptr!.distance(to: _end))
guard _type == V_ASN1_SET else {
return
}
case 1701:
ASN1_get_object(&_ptr, &_length, &_type, &_xclass, _ptr!.distance(to: _end))
guard _type == V_ASN1_INTEGER else {
continue
}
_iap_quantity = ASN1_INTEGER_get(c2i_ASN1_INTEGER(nil, &_ptr, _length))
if _iap_quantity != -1 && _iap_id != "" {
_iap_set.append((_iap_id, _iap_quantity))
_iap_quantity = -1
_iap_id = ""
}
case 1702:
ASN1_get_object(&_ptr, &_length, &_type, &_xclass, _ptr!.distance(to: _end))
guard _type == V_ASN1_UTF8STRING else {
continue
}
let _mutable_ptr = UnsafeMutableRawPointer(mutating: _ptr!)
_iap_id = String(bytesNoCopy: _mutable_ptr, length: _length, encoding: .utf8, freeWhenDone: false) ?? ""
if _iap_quantity != -1 && _iap_id != "" {
_iap_set.append((_iap_id, _iap_quantity))
_iap_quantity = -1
_iap_id = ""
}
default:
_ptr = _ptr?.advanced(by: _length)
}
}
Should I need to change it?