swift - 为什么无法读取设备上验证的收据数据

标签 swift openssl in-app-purchase

我正在使用以下代码读取收据数据。我可以使用 OpenSSL 静态库 1.1.1k 成功验证收据签名

 private func readReceipt(_ receiptPKCS7: UnsafeMutablePointer<PKCS7>?) {
        // Get a pointer to the start and end of the ASN.1 payload
        let receiptSign = receiptPKCS7?.pointee.d.sign
        let octets = receiptSign?.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
      
        ASN1_get_object(&ptr, &length, &type, &xclass, ptr!.distance(to: end))
        guard type == V_ASN1_SET else {
            status = .unexpectedASN1Type
            return
        }

        // 1
        while ptr! < end {
            // 2
            ASN1_get_object(&ptr, &length, &type, &xclass, ptr!.distance(to: end))
            guard type == V_ASN1_SEQUENCE else {
                status = .unexpectedASN1Type
                return
            }
            
        
            // 3 type
            guard let attributeType = readASN1Integer(ptr: &ptr, maxLength: length) else {
              status = .unexpectedASN1Type
              return
            }
            print("shark-IAP, ", attributeType)
            
            // 4 version
            guard let _ = readASN1Integer(ptr: &ptr, maxLength: ptr!.distance(to: end)) else {
                print("shark-IAP, 3")
              status = .unexpectedASN1Type
              return
            }
            
            // 5 value
            ASN1_get_object(&ptr, &length, &type, &xclass, ptr!.distance(to: end))
            guard type == V_ASN1_OCTET_STRING else {
                print("shark-IAP, 4")
              status = .unexpectedASN1Type
              return
            }
            
            switch attributeType {
                case 2: // The bundle identifier
                    var stringStartPtr = ptr
                    bundleIdString = readASN1String(ptr: &stringStartPtr, maxLength: length)
                    bundleIdData = readASN1Data(ptr: ptr!, length: length)
              
                case 3: // Bundle version
                    var stringStartPtr = ptr
                    bundleVersionString = readASN1String(ptr: &stringStartPtr, maxLength: length)
              
                case 4: // Opaque value
                    let dataStartPtr = ptr!
                    opaqueData = readASN1Data(ptr: dataStartPtr, length: length)
              
                case 5: // Computed GUID (SHA-1 Hash)
                    let dataStartPtr = ptr!
                    hashData = readASN1Data(ptr: dataStartPtr, length: length)
              
                case 12: // Receipt Creation Date
                    var dateStartPtr = ptr
                    receiptCreationDate = readASN1Date(ptr: &dateStartPtr, maxLength: length)
              
                case 17: // IAP Receipt
                    var iapStartPtr = ptr
                    let parsedReceipt = IAPReceipt(with: &iapStartPtr, payloadLength: length)
                    if let newReceipt = parsedReceipt {
                        inAppReceipts.append(newReceipt)
                    }
              
                case 19: // Original App Version
                    var stringStartPtr = ptr
                    originalAppVersion = readASN1String(ptr: &stringStartPtr, maxLength: length)
              
                case 21: // Expiration Date
                    var dateStartPtr = ptr
                    expirationDate = readASN1Date(ptr: &dateStartPtr, maxLength: length)
              
                default: // Ignore other attributes in receipt
                    print("Not processing attribute type: \(attributeType)")
            }
            
            // Advance pointer to the next item
            ptr = ptr!.advanced(by: length)
        } // end while
    }



func readASN1Integer(ptr: inout UnsafePointer<UInt8>?, maxLength: Int) -> Int? {
    var type: Int32 = 0
    var xclass: Int32 = 0
    var length: Int = 0
  
    ASN1_get_object(&ptr, &length, &type, &xclass, maxLength)
    
    guard type == V_ASN1_INTEGER else {
        print("shark-IAP no!", type)
        return nil
    }
   
//     let integerObject = c2i_ASN1_INTEGER(nil, &ptr, length)
    let integerObject = d2i_ASN1_UINTEGER(nil, &ptr, length)
    let intValue = ASN1_INTEGER_get(integerObject)
    ASN1_INTEGER_free(integerObject)
  
    
    return intValue
}

我得到了这些打印输出。我怀疑函数 readASN1Integer 是错误的。也许 c2i_ASN1_INTEGER 会很好,但这在 OpenSSL 1.1* 中已弃用,而是使用 d2i_ASN1_UINTEGER。而 d2i_ASN1_UINTEGER 需要传递(标识符+长度/八位字节+内容),而不仅仅是内容。在 ASN1_get_object 中,指针改变了位置。所以 d2i_ASN1_UINTEGER 读错了。第一个 readASN1Integer 导致偏差,第二个 readASN1Integer 抛出错误。

shark-IAP,  0
shark-IAP no! 8
shark-IAP, 3
shark-IAP, bundleVersionString nil
shark-IAP, expirationData nil
shark-IAP,  0
shark-IAP no! 8
shark-IAP, 3
shark-IAP, bundleVersionString nil
shark-IAP, expirationData nil

但我不知道如何调整代码以适应 d2i_ASN1_UINTEGER。感谢您的帮助!

最佳答案

stackoverflow是一个镇压鬼子的地方。

我找到了解决方案。我将 readASN1Integer 修改为这个

func readASN1Integer(ptr: inout UnsafePointer<UInt8>?, maxLength: Int) -> Int? {
    var type: Int32 = 0
    var xclass: Int32 = 0
    var length: Int = 0
    let save_ptr = ptr
    ASN1_get_object(&ptr, &length, &type, &xclass, maxLength)

    guard type == V_ASN1_INTEGER else {
        return nil
    }
   
//     let integerObject = c2i_ASN1_INTEGER(nil, &ptr, length)
    ptr = save_ptr
    let integerObject = d2i_ASN1_UINTEGER(nil, &ptr, maxLength)
    let intValue = ASN1_INTEGER_get(integerObject)
    ASN1_INTEGER_free(integerObject)
  
    
    return intValue
}
  1. 由于指针位置改变了,需要重新设置,所以save_ptr就来了(引用自c2i_ASN1_INTEGER function in Openssl 1.1.0)
  2. d2i_ASN1_UINTEGER(nil, &ptr, length) 更改为 d2i_ASN1_UINTEGER(nil, &ptr, maxLength)。对于每个地方,包括在 readReceipt 中,长度应该是 maxLength 或 ptr!.distance(to: end)。

关于swift - 为什么无法读取设备上验证的收据数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66932598/

相关文章:

android - 如何检查我的应用内支付产品是否已被用户在应用内购买?

iphone - iOS 上的软件即服务需要订阅吗?

android-studio - 当我发布到内部测试轨道时,我可以使用 Android Studio 模拟器来测试 Google 应用内购买吗?

ios - 如何使用 UILocalNotification 打开包含核心数据的特定 View

iphone - 即使应用程序终止也更新用户位置

C OpenSSLRSA双重加密失败

C 输出不同于 openssl 输出

php - Composer 无法在 Windows 上工作,给出 [Composer\Exception\NoSslException] 错误

ios - HomeKit accessoryDidUpdateReachability 不工作

ios - 如何使用 RxSwift 检测双击