andrewcbancroft / SwiftyLocalReceiptValidator

An implementation of local receipt validation logic for iOS in Swift
MIT License
286 stars 32 forks source link

Use of unresolved type X509 #9

Open chamitha opened 6 years ago

chamitha commented 6 years ago

Hi there. I'm attempting to compile the ReceiptValidator in my project and running in to a few errors. Use of undeclared type X509 Use of unresolved identifier OpenSSL_add_all_digests Use of unresolved identifier c2i_ASN1_INTEGER - This has been raised and a workaround identified in a different thread so lets ignore it for now!

I'm using openssl 1.1.1 using a script similar to that in the OpenSSL pod. I have added the bridging header as per the demo project. My understanding is a module map is NOT required (as we are using bridging headers)?

Any assistance is most appreciated. Thanks!

kamiro commented 5 years ago

Just wanted to jump in on this thread and write how I fixed it.

I've been running around trying to figure out what happened to c2i_ASN1_INTEGER and it appears that in 2015 for OpenSSL 1.1.1 this method was moved into asn1_locl.h as a mechanism to hide it/make it private. https://github.com/openssl/openssl/commit/c315a547e62fc8f1bdc3e9d57138871117dca6f7

I did not really research why this was moved, so one could use OpenSSL 1.1.0 or... one could re-expose this method by copying the missing function definition lines into my OpenSSL/include/openssl/asn1.h file to allow swift to have access to it (which was still built when compiling OpenSSL 1.1.1).

int i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp); ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp, long length);

softmastx commented 5 years ago

Just wanted to jump in on this thread and write how I fixed it.

I've been running around trying to figure out what happened to c2i_ASN1_INTEGER and it appears that in 2015 for OpenSSL 1.1.1 this method was moved into asn1_locl.h as a mechanism to hide it/make it private. openssl/openssl@c315a54

I did not really research why this was moved, so one could use OpenSSL 1.1.0 or... one could re-expose this method by copying the missing function definition lines into my OpenSSL/include/openssl/asn1.h file to allow swift to have access to it (which was still built when compiling OpenSSL 1.1.1).

int i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp); ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp, long length);

By pasting int i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp); ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp, long length); into asn1.h that's it??

kamiro commented 5 years ago

Just wanted to jump in on this thread and write how I fixed it. I've been running around trying to figure out what happened to c2i_ASN1_INTEGER and it appears that in 2015 for OpenSSL 1.1.1 this method was moved into asn1_locl.h as a mechanism to hide it/make it private. openssl/openssl@c315a54 I did not really research why this was moved, so one could use OpenSSL 1.1.0 or... one could re-expose this method by copying the missing function definition lines into my OpenSSL/include/openssl/asn1.h file to allow swift to have access to it (which was still built when compiling OpenSSL 1.1.1). int i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp); ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp, long length);

By pasting int i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp); ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp, long length); into asn1.h that's it??

Pretty much. The method is still there, it just needs to be exposed... I still can't figure out why it was privatized. Copying that declaration into asn1.h and compiling solves the issue.

itsryry commented 5 years ago

any solutions for the x509 case?

moldis commented 5 years ago

Any feedback on it ?

thejeff77 commented 4 years ago

Fixed it up for 1.1.1d. I'll see if I can open a PR to update this project when I have time.

DecodeAS1Integer now becomes:

    func DecodeASN1Integer(startOfInt intPointer: inout UnsafePointer<UInt8>?, length: Int) -> Int? {
        let integer = d2i_ASN1_UINTEGER(nil, &intPointer, length)
        let result = ASN1_INTEGER_get(integer)
        ASN1_INTEGER_free(integer)

        return result
    }

Then OpenSSL_add_all_digests() becomes OPENSSL_init_crypto(UInt64(OPENSSL_INIT_ADD_ALL_DIGESTS), nil)

Then for the x509 issues in the ReceiptSignatureValidator, just combine the two internal methods - no need to separate them out and return an x509 type, just keep the result as a let constant and operate on it right away.

struct ReceiptSignatureValidator {
    func checkSignaturePresence(_ PKCS7Container: UnsafeMutablePointer<PKCS7>) throws {
        let pkcs7SignedTypeCode = OBJ_obj2nid(PKCS7Container.pointee.type)

        guard pkcs7SignedTypeCode == NID_pkcs7_signed else {
            throw ReceiptValidationError.receiptNotSigned
        }
    }

    func checkSignatureAuthenticity(_ PKCS7Container: UnsafeMutablePointer<PKCS7>) throws {
        try checkAppleRootCertificateAuthenticity(PKCS7Container: PKCS7Container)
    }

    fileprivate func checkAppleRootCertificateAuthenticity(PKCS7Container: UnsafeMutablePointer<PKCS7>) throws {
        guard
            let appleRootCertificateURL = Bundle.main.url(forResource: "AppleIncRootCertificate", withExtension: "cer"),
            let appleRootCertificateData = try? Data(contentsOf: appleRootCertificateURL)
            else {
                throw ReceiptValidationError.appleRootCertificateNotFound
        }

        let appleRootCertificateBIO = BIO_new(BIO_s_mem())
        BIO_write(appleRootCertificateBIO, (appleRootCertificateData as NSData).bytes, Int32(appleRootCertificateData.count))
        let appleRootCertificateX509 = d2i_X509_bio(appleRootCertificateBIO, nil)

        let x509CertificateStore = X509_STORE_new()
        X509_STORE_add_cert(x509CertificateStore, appleRootCertificateX509)

        OPENSSL_init_crypto(UInt64(OPENSSL_INIT_ADD_ALL_DIGESTS), nil)

        let result = PKCS7_verify(PKCS7Container, nil, x509CertificateStore, nil, nil, 0)

        if result != 1 {
            throw ReceiptValidationError.receiptSignatureInvalid
        }
    }
}
tcherna commented 4 years ago

Then OpenSSL_add_all_digests() becomes OPENSSL_init_crypto(UInt64(OPENSSL_INIT_ADD_ALL_DIGESTS), nil)

Isn't that no longer needed at all, since it is a default?

Also isn't there a memory free requirement on: let appleRootCertificateX509 = d2i_X509_bio(appleRootCertificateBIO, nil) Still trying to figure out which allocations need freeing.

yousifKashef commented 4 years ago

Hi Guys,

the reason these bugs come up in the ReceiptSignatureValidator class is because OpenSSL's X509 class, which contains the functionality used in ReceiptSignatureValidator is not imported in the bridging header. it can be imported by adding #import <openssl/x509.h> to the bridging header.h file. I hope this helps.

diachedelic commented 3 years ago

You can avoid using the c2i_ASN1_INTEGER function (and hence modifying asn1.h) by simply rewriting the DecodeASN1Integer function to use the d2i_* variant, which is exposed:

func DecodeASN1Integer(startOfInt intPointer: inout UnsafePointer<UInt8>?, length: Int) -> Int? {
    let integer = d2i_ASN1_UINTEGER(nil, &intPointer, length)
    let result = ASN1_INTEGER_get(integer)
    ASN1_INTEGER_free(integer)
    return result
}

Source: https://github.com/openssl/openssl/issues/7538#issuecomment-775977239