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

то, что мне нужно, это эквивалент этого alamofire:

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

работает

$ 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. подали эти учетные данные для аутентификации (с: urlCredential) на отсутствующий sessionDidReceiveChallenge в делегате Alamofire 5

вот и все.

Жесткое кодирование пароля в конструкторе p12 было ужасно некрасивым. Эвв, что ключ, я думаю, это запекание base64 в p12 в код, а не в виде файла, подверженного прикреплению ipa patcher.