I used the "keytool -keyalg RSA -keysize 2048 -storetype PKCS12" command to generate a p12 format certificate, then I installed it on my Mac and exported a cer certificate.
But an error occurred when I request the server.
iOS: 11.4, Swift: 5, Alamofire: 5.2
error: Extended key usage does not match certificate usage
serverTrustEvaluationFailed(reason: Alamofire.AFError.ServerTrustFailureReason.trustEvaluationFailed(error: Optional(Error Domain=NSOSStatusErrorDomain Code=-67609 "“***” certificate is not permitted for this usage" UserInfo={NSLocalizedDescription=“***” certificate is not permitted for this usage, NSUnderlyingError=0x6000006233c0 {Error Domain=NSOSStatusErrorDomain Code=-67609 "Certificate 0 “***” has errors: Extended key usage does not match certificate usage;" UserInfo={NSLocalizedDescription=Certificate 0 “***” has errors: Extended key usage does not match certificate usage;}}})))
error:Certificate Pinning Error
Server configuration:
server:
port: ***
servlet:
context-path: /fik
ssl:
key-store: classpath:ssl/fik-server-730.p12
key-store-password: ****
key-store-type: PKCS12
key-alias: fik-cer
Swift code:
final class AlamofireClient {
let evaluators = ["47.*.*.*": PinnedCertificatesTrustEvaluator(certificates: [Certificates.stackExchange], acceptSelfSignedCertificates: true)]
let session: Session
private init() {
session = Session(serverTrustManager: ServerTrustManager(evaluators: evaluators))
}
private static let shared = AlamofireClient()
static func doPost(api: String, parameters: [String: String]) -> String {
var dict = parameters
let timestamp = Int64(Date().timeIntervalSince1970 * 1000)
dict["timestamp"] = "\(timestamp)"
let sign = self.getSign(dict: dict)
let url = CHConstants.ApiGateway + api
let headers: HTTPHeaders = [
HTTPHeader(name: "Content-Type", value: "application/json"),
HTTPHeader(name: "signature", value: sign),
HTTPHeader(name: "time", value: "\(timestamp)")
]
shared.session.request(url, method: .post, parameters: parameters, encoder: JSONParameterEncoder.default, headers: headers).responseJSON { response in
switch response.result {
case .success:
print("value:\(response.value)")
print("data:\(response.data)")
case let .failure(error):
let isServerTrustEvaluationError = error.asAFError?.isServerTrustEvaluationError ?? false
let message: String
if isServerTrustEvaluationError {
message = "Certificate Pinning Error"
} else {
message = error.localizedDescription
}
print(error)
print("error:\(message)")
}
}
return "ok"
}
private static func getSign(dict: [String: String]) -> String {
...
return sign
}
}
struct Certificates {
static let stackExchange = Certificates.certificate(filename: "fik-server-730", type: "cer")
private static func certificate(filename: String, type: String) -> SecCertificate {
let filePath = Bundle.main.path(forResource: filename, ofType: type)!
let data = try! Data(contentsOf: URL(fileURLWithPath: filePath))
let certificate = SecCertificateCreateWithData(nil, data as CFData)!
return certificate
}
}
Looking at the documentation you need to set the extension for ExtendedkeyUsage
to serverAuth
when generating the certificate:
keytool -keyalg RSA -keysize 2048 -storetype PKCS12 -ext EKU=serverAuth