https icon indicating copy to clipboard operation
https copied to clipboard

Multiple SSL Certificate Pinning

Open ericgosno opened this issue 6 years ago • 4 comments

Hello,

I am aware that from the Readme, it already said that "Once you've enabled SSL pinning you CAN NOT re-enable with a different host or certificate file." which means that for now the SSL Pinning can only work for 1 certificates.

Is there any workaround to make it works on more than 1 certificate in case we need to do SSL Pinning on more than one API endpoint?

ericgosno avatar Nov 04 '18 09:11 ericgosno

Actually I got the same need in my current project. Is this feature even included somewhere in the roadmap? And for the meantime, can we work something to make it work? Anything to point us in the right direction is appreciated.

ferryfw avatar Nov 05 '18 06:11 ferryfw

Apologies to both of you. We are a small company and unfortunately we don't have time to update this library right now. However, we do want to resolve the outstanding issues and will get to this as soon as we can. In the meantime, if you wanted to submit a PR we would appreciate it.

@roblav96 are there any workarounds you can think of in the short term?

jeffwhelpley avatar Nov 05 '18 12:11 jeffwhelpley

No Guarantees

Here's a patch that might work for you.

index a130232..0b368f1 100644
--- a/src/https.android.ts
+++ b/src/https.android.ts
@@ -27,18 +27,19 @@ interface Ipeer {
 	allowInvalidCertificates: boolean
 	validatesDomainName: boolean
 	host?: string
-	certificate?: string
+	certificates: string[]
 	x509Certificate?: java.security.cert.Certificate
 }
 let peer: Ipeer = {
 	enabled: false,
 	allowInvalidCertificates: false,
 	validatesDomainName: true,
+	certificates: [],
 }
 
 export function enableSSLPinning(options: Https.HttpsSSLPinningOptions) {
 	// console.log('options', options)
-	if (!peer.host && !peer.certificate) {
+	if (!peer.host) {
 		let certificate: string
 		let inputStream: java.io.FileInputStream
 		try {
@@ -58,7 +59,9 @@ export function enableSSLPinning(options: Https.HttpsSSLPinningOptions) {
 			return
 		}
 		peer.host = options.host
-		peer.certificate = certificate
+		if (peer.certificates.indexOf(certificate) === -1) {
+			peer.certificates.push(certificate)
+		}
 		if (options.allowInvalidCertificates == true) {
 			peer.allowInvalidCertificates = true
 		}
@@ -72,6 +75,8 @@ export function enableSSLPinning(options: Https.HttpsSSLPinningOptions) {
 }
 export function disableSSLPinning() {
 	peer.enabled = false
+	peer.certificates.length = 0;
+	getClient(true)
 	getClient(true)
 	console.log('nativescript-https > Disabled SSL pinning')
 }
@@ -100,7 +105,7 @@ function getClient(reload: boolean = false): okhttp3.OkHttpClient {
 			client.connectionSpecs(java.util.Collections.singletonList(spec))
 
 			let pinner = new okhttp3.CertificatePinner.Builder()
-			pinner.add(peer.host, [peer.certificate])
+			pinner.add(peer.host, peer.certificates)
 			client.certificatePinner(pinner.build())
 
 			if (peer.allowInvalidCertificates == false) {
diff --git a/src/https.ios.ts b/src/https.ios.ts
index aed1bf9..2bb0c92 100644
--- a/src/https.ios.ts
+++ b/src/https.ios.ts
@@ -17,6 +17,7 @@ let policies: Ipolicies = {
 }
 policies.def.allowInvalidCertificates = true
 policies.def.validatesDomainName = false
+let certificates: NSData[] = [];
 
 export function enableSSLPinning(options: Https.HttpsSSLPinningOptions) {
 	// console.log('options', options)
@@ -26,12 +27,12 @@ export function enableSSLPinning(options: Https.HttpsSSLPinningOptions) {
 		policies.secure.allowInvalidCertificates = allowInvalidCertificates
 		let validatesDomainName = (isDefined(options.validatesDomainName)) ? options.validatesDomainName : true
 		policies.secure.validatesDomainName = validatesDomainName
-		let data = NSData.dataWithContentsOfFile(options.certificate)
+		certificates.push(NSData.dataWithContentsOfFile(options.certificate))
 		// console.log('data.description', data.description)
 		// console.log('data.bytes', data.bytes)
 		// console.log('data.base64Encoding()', data.base64Encoding())
 		// console.log('data.length', data.length)
-		policies.secure.pinnedCertificates = NSSet.setWithObject(data)
+		policies.secure.pinnedCertificates = NSSet.setWithArray(certificates)
 	}
 	policies.secured = true
 	console.log('nativescript-https > Enabled SSL pinning')

facetious avatar Jan 08 '19 15:01 facetious

Was there ever an official fix for this? Has anyone gotten the above patch to work?

adambeck7 avatar Oct 07 '19 16:10 adambeck7