mirror of
https://github.com/httptoolkit/frida-interception-and-unpinning.git
synced 2026-10-02 05:52:28 +02:00
Validate the certificate chain (for our CA) when hooking iOS BoringSSL
This is really cool. Rather than just blindly disabling all TLS validation, we now verify the cert directly against the CA you provide. We only do extremely basic checks (some more testing required to validate this provides even basic guarantees) so this shouldn't be relied for rock-solid TLS validation (probably even after it's been tested tbh) and it won't handle many real-world cases of CA validation, but in terms of "do a local MitM while retaining the basics of TLS protection" it should do a reasonable job, hopefully.
This commit is contained in:
+59
-3
@@ -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 = [
|
||||
|
||||
Reference in New Issue
Block a user