diff --git a/ios/ios-tls-override.js b/ios/ios-tls-override.js index ed7b4ef..3294e9c 100644 --- a/ios/ios-tls-override.js +++ b/ios/ios-tls-override.js @@ -13,10 +13,66 @@ try { } } -const SSL_VERIFY_NONE = 0x0; +// Get the peer certificates from an SSL pointer. Returns a pointer to a STACK_OF(CRYPTO_BUFFER) +// which requires use of the next few methods below to actually access. +// https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_get0_peer_certificates +const SSL_get0_peer_certificates = new NativeFunction( + Module.findExportByName('libboringssl.dylib', 'SSL_get0_peer_certificates'), + 'pointer', ['pointer'] +); -const VerificationCallback = new NativeCallback(function (ssl, out_alert){ - return SSL_VERIFY_NONE; +// Stack methods: +// https://commondatastorage.googleapis.com/chromium-boringssl-docs/stack.h.html +const sk_num = new NativeFunction( + Module.findExportByName('libboringssl.dylib', 'sk_num'), + 'size_t', ['pointer'] +); + +const sk_value = new NativeFunction( + Module.findExportByName('libboringssl.dylib', 'sk_value'), + 'pointer', ['pointer', 'int'] +); + +// Crypto buffer methods: +// https://commondatastorage.googleapis.com/chromium-boringssl-docs/pool.h.html +const crypto_buffer_len = new NativeFunction( + Module.findExportByName('libboringssl.dylib', 'CRYPTO_BUFFER_len'), + 'size_t', ['pointer'] +); + +const crypto_buffer_data = new NativeFunction( + Module.findExportByName('libboringssl.dylib', 'CRYPTO_BUFFER_data'), + 'pointer', ['pointer'] +); + +const SSL_VERIFY_NONE = 0x0; +const SSL_VERIFY_PEER = 0x1; + +const VerificationCallback = new NativeCallback(function (ssl, out_alert) { + // Extremely dumb certificate validation: we accept any chain where the *exact* CA cert + // we were given is present. No flexibility for non-trivial cert chains, and zero + // validation of expiry/hostname/etc. + + const peerCerts = SSL_get0_peer_certificates(ssl); + + // Loop through every cert in the chain: + for (let i = 0; i < sk_num(peerCerts); i++) { + // For each cert, check if it *exactly* matches our configured CA cert: + const cert = sk_value(peerCerts, i); + const certDataLength = crypto_buffer_len(cert).toNumber(); + + if (certDataLength !== CERT_DER.byteLength) continue; + + const certPointer = crypto_buffer_data(cert); + const certData = new Uint8Array(certPointer.readByteArray(certDataLength)); + + if (certData.every((byte, j) => CERT_DER[j] === byte)) { + return SSL_VERIFY_NONE; + } + } + + // No matched peer - fallback to default OpenSSL cert verification + return SSL_VERIFY_PEER; },'int',['pointer','pointer']); const customVerifyAddrs = [