ios, alamofire5: ต้องการ curl --key foo.key --cert foo, pem --location --request GET 'https: //bar.baz/foo "

Sep 11 2020

ฉันมีคีย์ส่วนตัวนอกเหนือจากคีย์สาธารณะเพื่อปักหมุดใบรับรอง

จะตรวจสอบความถูกต้องกับเซิร์ฟเวอร์อย่างไร?

$ file *
foo.der:         data
foo.private.der: data

มาพร้อมกับ openssl จาก

foo.key: PEM RSA private key
foo.pem: PEM certificate

สิ่งที่ฉันต้องการคืออะลาโมไฟร์เทียบเท่าสิ่งนี้:

curl --key foo.key --cert foo.pem --location --request GET 'https: // somhostofmine / v1 / welcome /'

$ curl --key ./client_key.pem --cert ./client.pem --location --request GET 'https: // someurl' "สวัสดีครับ!"

ได้ผล

$ curl --cert ./client.pem --location --request GET 'https: // someurl / v1 / welcome /' curl: (58) ไม่สามารถตั้งค่าไฟล์คีย์ส่วนตัว: "./client.pem 'พิมพ์ PEM

ไม่

ดังนั้นคำแนะนำในการใช้ใบรับรองเองโดยไม่มีคีย์ส่วนตัวจึงไม่ได้ผล

เรากำลังจัดการกับใบรับรองที่ตรึงไว้ที่นี่หรือได้รับคีย์ส่วนตัวนี่เป็นอย่างอื่นไปที่นี่ ???

คำตอบ

2 gcharita Sep 14 2020 at 08:32

คุณสามารถสร้างServerTrustManagerพารามิเตอร์การส่งผ่านเป็นผู้ประเมินของคุณต่อชื่อโฮสต์ สำหรับการตรึงคีย์สาธารณะให้ใช้PublicKeysTrustEvaluatorดังนี้:

let evaluators: [String : ServerTrustEvaluating] = [
    "your.host.com": PublicKeysTrustEvaluator(performDefaultValidation: false, validateHost: false)
]
let serverTrustManager = ServerTrustManager(evaluators: evaluators)

สำหรับการตรึงใบรับรองให้ใช้PinnedCertificatesTrustEvaluatorดังนี้:

let evaluators: [String : ServerTrustEvaluating] = [
    "your.host.com": PinnedCertificatesTrustEvaluator(
        acceptSelfSignedCertificates: true,
        performDefaultValidation: false,
        validateHost: false
    )
]
let serverTrustManager = ServerTrustManager(evaluators: evaluators)

ทั้งสองวิธีนี้จำเป็นต้องมีใบรับรองของคุณรวมอยู่ในบันเดิลเป็น.cerหรือ.derไฟล์

หลังจากสร้างServerTrustManagerรหัสผ่านไปยังSessionอินสแตนซ์และใช้สิ่งนี้สำหรับคำขอของคุณ:

let session = Session(serverTrustManager: serverTrustManager)

หากคุณต้องการมีตรรกะที่ซับซ้อนมากขึ้นในการตรวจสอบเซิร์ฟเวอร์ของคุณหรือคุณต้องใช้สัญลักษณ์แทนในโดเมนของคุณคุณต้องมีคลาสย่อยServerTrustManagerและแทนที่serverTrustEvaluator(forHost:)ฟังก์ชัน:

class MyServerTrustManager: ServerTrustManager {
    init() {
        super.init(evaluators: [:])
    }
    
    override func serverTrustEvaluator(forHost host: String) throws -> ServerTrustEvaluating? {
        guard host.hasSuffix(".host.com") else {
            return try super.serverTrustEvaluator(forHost: host)
        }
        return PublicKeysTrustEvaluator(performDefaultValidation: false, validateHost: false)
    }
}
2 AntonTropashko Sep 14 2020 at 12:04
  1. บรรจุคีย์ส่วนตัวและสาธารณะลงในคอนเทนเนอร์ p12 ด้วย openssl
  2. นี่คือคีย์Alamofire ที่ไม่มีการประเมินและการส่งใบรับรองไคลเอ็นต์

สร้างอินสแตนซ์ PKCS512 () และสร้าง URLCredential โดยใช้ (โค้ดในลิงค์ด้านบน) ใน alamofire สิ่งที่คุณต้องการจากลิงค์ด้านบนคือคลาส PKCS12 และส่วนขยาย URLCredential

public class PKCS12 {
    let label:String?
    let keyID:NSData?
    let trust:SecTrust?
    let certChain:[SecTrust]?
    let identity:SecIdentity?

    public init(PKCS12Data:NSData,password:String)
    {
        let importPasswordOption:NSDictionary = [kSecImportExportPassphrase as NSString:password]
        var items : CFArray?
        let secError:OSStatus = SecPKCS12Import(PKCS12Data, importPasswordOption, &items)

        guard secError == errSecSuccess else {
            if secError == errSecAuthFailed {
                NSLog("ERROR: SecPKCS12Import returned errSecAuthFailed. Incorrect password?")
            }
            fatalError("SecPKCS12Import returned an error trying to import PKCS12 data")
        }

        guard let theItemsCFArray = items else { fatalError()  }
        let theItemsNSArray:NSArray = theItemsCFArray as NSArray
        guard let dictArray = theItemsNSArray as? [[String:AnyObject]] else { fatalError() }

        func f<T>(key:CFString) -> T? {
            for d in dictArray {
                if let v = d[key as String] as? T {
                    return v
                }
            }
            return nil
        }

        self.label = f(key: kSecImportItemLabel)
        self.keyID = f(key: kSecImportItemKeyID)
        self.trust = f(key: kSecImportItemTrust)
        self.certChain = f(key: kSecImportItemCertChain)
        self.identity =  f(key: kSecImportItemIdentity)
    }
}

extension URLCredential {
    public convenience init?(PKCS12 thePKCS12:PKCS12) {
        if let identity = thePKCS12.identity {
            self.init(
                identity: identity,
                certificates: thePKCS12.certChain,
                persistence: URLCredential.Persistence.forSession)
        }
        else { return nil }
    }
}
  1. ป้อนข้อมูลรับรองนั้นเพื่อพิสูจน์ตัวตน (with: urlCredential) ต่อMissing sessionDidReceiveChallenge ใน Alamofire 5 delegate

และนั่นก็คือ

รหัสผ่านฮาร์ดโค้ดในตัวสร้าง p12 นั้นน่าเกลียดมาก ฉันคิดว่าสิ่งที่สำคัญคือการเบเกอรี่ base64 ใน p12 เป็นรหัสแทนที่จะเป็นไฟล์ที่มีแนวโน้มที่จะแนบ ipa patcher