ios, alamofire5: brauche ein Äquivalent von curl --key foo.key --cert foo, pem --location --request GET 'https: //bar.baz/foo "

Sep 11 2020

Ich habe einen privaten Schlüssel zusätzlich zu einem öffentlichen Schlüssel zum Anheften des Zertifikats.

Wie würde ich mich beim Server authentifizieren?

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

abgeleitet mit openssl von

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

Was ich brauche, ist ein Alamofire-Äquivalent dazu:

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' "Hallo wold!"

funktioniert

$ curl --cert ./client.pem --location --request GET 'https: // someurl / v1 / welcome /' curl: (58) private Schlüsseldatei kann nicht festgelegt werden: './client.pem' Typ PEM

nicht

Vorschläge zur Verwendung des Zertifikats selbst ohne privaten Schlüssel funktionieren daher nicht.

Haben wir es hier mit dem Anheften von Zertifikaten zu tun oder ist das Vorhandensein des privaten Schlüssels etwas anderes?

Antworten

2 gcharita Sep 14 2020 at 08:32

Sie können eine ServerTrustManagerÜbergabe als Parameter für Ihre Evaluatoren pro Hostname erstellen . Verwenden Sie zum Anheften von öffentlichen Schlüsseln Folgendes PublicKeysTrustEvaluator:

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

Verwenden Sie zum Anheften von Zertifikaten Folgendes PinnedCertificatesTrustEvaluator:

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

Bei beiden Methoden muss Ihr Zertifikat in Ihrem Bundle als .ceroder in Ihrer .derDatei enthalten sein.

Nachdem Sie Ihren ServerTrustManagerPass an eine SessionInstanz erstellt haben, verwenden Sie diesen für Ihre Anforderungen:

let session = Session(serverTrustManager: serverTrustManager)

Wenn Sie eine komplexere Logik für die Überprüfung Ihres Servers haben möchten oder Platzhalter in Ihrer Domäne verwenden müssen, müssen Sie folgende Funktionen unterordnen ServerTrustManagerund überschreiben 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. gepackter privater und öffentlicher Schlüssel in p12 Container mit openssl
  2. Dies war der Schlüssel von Alamofire ohne Bewertung und mit dem Senden des Client-Zertifikats

Die PKCS512 () - Instanz wurde erstellt und URLCredential mit diesem (Code im obigen Link) in alamofire erstellt. Alles, was Sie über den obigen Link benötigen, ist die PKCS12-Klasse und die URLCredential-Erweiterung

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. diesen Berechtigungsnachweis zur Authentifizierung (mit: urlCredential) pro fehlender SitzungDidReceiveChallenge in Alamofire 5-Delegat eingegeben

und das war es.

Das Hardcodieren des Passworts in den p12-Konstruktor war super hässlich. Eww Was der Schlüssel ist, denke ich, ist, dass base64 in p12 in Code backt, anstatt ihn als Datei zu haben, die für das Anhängen von IPA-Patchern anfällig ist.