Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: KranthiBandla/http_certificate_pinning
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: fss-org/http_certificate_pinning
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Able to merge. These branches can be automatically merged.
  • 2 commits
  • 2 files changed
  • 2 contributors

Commits on Sep 3, 2024

  1. fix: generate incorrect hash value of public key in iOS

    Yasuaki Tamura committed Sep 3, 2024
    Copy the full SHA
    e8c516c View commit details
  2. Update README.md

    ty0521-fss authored Sep 3, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    d8dca83 View commit details
Showing with 110 additions and 59 deletions.
  1. +8 −7 README.md
  2. +102 −52 ios/Classes/SwiftHttpCertificatePinningPlugin.swift
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Http Certificate Pinning
# HTTP Public Key Pinning

Https Certificate pinning for Flutter
HTTP Public Key pinning for Flutter

This project ins based on [ssl_pinning_plugin](https://github.com/macif-dev/ssl_pinning_plugin)
This project is based on [ssl_pinning_plugin](https://github.com/macif-dev/ssl_pinning_plugin) and [http_certificate_pinning](https://github.com/KranthiBandla/http_certificate_pinning)

Any help is appreciated! Comment, suggestions, issues, PR's!

@@ -13,7 +13,8 @@ In your flutter or dart project add the dependency:
```yml
dependencies:
...
http_certificate_pinning: 2.1.3
public_key_pinning:
git: https://github.com/fss-org/http_certificate_pinning.git
```
## Get Certificate FingerPrint
@@ -34,7 +35,7 @@ The Result is like:
### Using Dio

```dart
import 'package:http_certificate_pinning/http_certificate_pinning.dart';
import 'package:public_key_pinning/public_key_pinning.dart';
// Add CertificatePinningInterceptor in dio Client
Dio getClient(String baseUrl, List<String> allowedSHAFingerprints){
@@ -51,7 +52,7 @@ import 'package:http_certificate_pinning/http_certificate_pinning.dart';
### Using Http

```dart
import 'package:http_certificate_pinning/secure_http_client.dart';
import 'package:public_key_pinning/public_key_pinning.dart';
// Uses SecureHttpClient to make requests
SecureHttpClient getClient(List<String> allowedSHAFingerprints){
@@ -68,7 +69,7 @@ import 'package:http_certificate_pinning/secure_http_client.dart';
### Other Client

```dart
import 'package:http_certificate_pinning/http_certificate_pinning.dart';
import 'package:public_key_pinning/public_key_pinning.dart';
Future myCustomImplementation(String url, Map<String,String> headers, List<String> allowedSHAFingerprints) async {
try{
154 changes: 102 additions & 52 deletions ios/Classes/SwiftHttpCertificatePinningPlugin.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Flutter
import UIKit
import CryptoSwift
import Alamofire
import CommonCrypto

public class SwiftHttpCertificatePinningPlugin: NSObject, FlutterPlugin {

@@ -92,72 +91,123 @@ public class SwiftHttpCertificatePinningPlugin: NSObject, FlutterPlugin {
}

manager.delegate.sessionDidReceiveChallenge = { session, challenge in
guard let serverTrust = challenge.protectionSpace.serverTrust, let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0) else {
guard let serverTrust = challenge.protectionSpace.serverTrust else {
flutterResult(
FlutterError(
code: "ERROR CERT",
message: "Invalid Certificate",
details: nil
)
)

return (.cancelAuthenticationChallenge, nil)
}

// Set SSL policies for domain name check
let policies: [SecPolicy] = [SecPolicyCreateSSL(true, (challenge.protectionSpace.host as CFString))]
SecTrustSetPolicies(serverTrust, policies as CFTypeRef)

// Evaluate server certificate
var result: SecTrustResultType = .invalid
SecTrustEvaluate(serverTrust, &result)
let isServerTrusted: Bool = (result == .unspecified || result == .proceed)

guard let publicKey = SecCertificateCopyKey(certificate),
let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, nil) as Data? else {
flutterResult(
FlutterError(
code: "ERROR CERT",
message: "Invalid Public Key",
details: nil
let policies = NSMutableArray()
policies.add(SecPolicyCreateSSL(true, (challenge.protectionSpace.host as CFString)))
SecTrustSetPolicies(serverTrust, policies)

let isServerTrusted = SecTrustEvaluateWithError(serverTrust, nil)
if(isServerTrusted) {
guard let certificates = SecTrustCopyCertificateChain(serverTrust) as? [SecCertificate] else {
flutterResult(
FlutterError(
code: "ERROR CERT",
message: "Invalid Certificate",
details: nil
)
)
)
return (.cancelAuthenticationChallenge, nil)
}

var publicKeySha = publicKeyData.sha256().toHexString()

if(type == "SHA1"){
publicKeySha = publicKeyData.sha1().toHexString()
}

return (.cancelAuthenticationChallenge, nil)
}

// For certificate Key
//let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0)
// let remoteCertData = SecCertificateCopyData(serverCertificate) as Data
// var certificateKey = remoteCertData.sha256().toHexString()

/*
let publicKeyList = Set( certificates.map { SecCertificateCopyKey($0) } )
publicKeyList.forEach { secKey in
if let secKey = secKey, let publicKeyData = SecKeyCopyExternalRepresentation(secKey, nil) as? Data {
let keyString = self.sha256(data: publicKeyData)
print(keyString)
}
}
*/

var isSecure = false

if let secKey = SecCertificateCopyKey(certificates[0]) , let publicKeyData = SecKeyCopyExternalRepresentation(secKey, nil) as? Data {
let keyString = self.sha256(data: publicKeyData)
print(keyString)

if var fp = self.fingerprints {
fp = fp.compactMap { (val) -> String? in
val.replacingOccurrences(of: " ", with: "")
}
isSecure = fp.contains(where: { (value) -> Bool in
value.caseInsensitiveCompare(keyString) == .orderedSame
})
}
}
else {
flutterResult(
FlutterError(
code: "ERROR CERT",
message: "Invalid Public Key",
details: nil
)
)
return (.cancelAuthenticationChallenge, nil)
}

if isServerTrusted && isSecure {
flutterResult("CONNECTION_SECURE")
resultDispatched = true
} else {
flutterResult(
FlutterError(
code: "CONNECTION_NOT_SECURE",
message: nil,
details: nil
)
)
resultDispatched = true
}

var isSecure = false
if var fp = self.fingerprints {
fp = fp.compactMap { (val) -> String? in
val.replacingOccurrences(of: " ", with: "")
}

return (.cancelAuthenticationChallenge, nil)
}
}

private func sha256(data : Data) -> String {
let rsa2048Asn1Header:[UInt8] = [
0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00
]

var keyWithHeader = Data(rsa2048Asn1Header)
keyWithHeader.append(data)
var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
keyWithHeader.withUnsafeBytes {
// _ = CC_SHA256($0, CC_LONG(keyWithHeader.count), &hash) // deprecated withUnsafeBytes
guard let pointer = $0.baseAddress?.assumingMemoryBound(to: UInt8.self) else { return }
_ = CC_SHA256(pointer, CC_LONG(keyWithHeader.count), &hash)
}
// return Data(hash).base64EncodedString()
return Data(hash).toHexString()

isSecure = fp.contains(where: { (value) -> Bool in
value.caseInsensitiveCompare(publicKeySha) == .orderedSame
})
}
}

if isServerTrusted && isSecure {
flutterResult("CONNECTION_SECURE")
resultDispatched = true
} else {
flutterResult(
FlutterError(
code: "CONNECTION_NOT_SECURE",
message: nil,
details: nil
)
)
resultDispatched = true
}
}

return (.cancelAuthenticationChallenge, nil)
}
extension Data {
func toHexString() -> String {
return String(self.flatMap { byte in
String(format:"%02x", byte)
})
}
}