swift https证书单向验证
class Manager: NSObject {
func setAlamofireHttps() {
SessionManager.default.delegate.sessionDidReceiveChallenge = { (session: URLSession, challenge: URLAuthenticationChallenge) in
let method = challenge.protectionSpace.authenticationMethod
if method == NSURLAuthenticationMethodServerTrust {
//验证服务器,直接信任或者验证证书二选一,推荐验证证书,更安全
return HTTPSManager.trustServerWithCer(challenge: challenge)
// return HTTPSManager.trustServer(challenge: challenge)
}else if method == NSURLAuthenticationMethodClientCertificate {
//认证客户端证书
return HTTPSManager.sendClientCer()
}else{
//其他情况,不通过验证
return (.cancelAuthenticationChallenge, nil)
}
}
}
//不做任何验证,直接信任服务器
static private func trustServer(challenge: URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?) {
let disposition = URLSession.AuthChallengeDisposition.useCredential
letcredential =URLCredential.init(trust: challenge.protectionSpace.serverTrust!)
return(disposition, credential)
}
//验证服务器证书
static private func trustServerWithCer(challenge: URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?) {
var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling
varcredential:URLCredential?
//获取服务器发送过来的证书
letserverTrust:SecTrust= challenge.protectionSpace.serverTrust!
letcertificate =SecTrustGetCertificateAtIndex(serverTrust,0)!
letremoteCertificateData =CFBridgingRetain(SecCertificateCopyData(certificate))!
//加载本地CA证书
varcerPath =""
cerPath =Bundle.main.path(forResource:"本地证书名", ofType:"der")!
letcerUrl =URL(fileURLWithPath:cerPath)
letlocalCertificateData =try!Data(contentsOf: cerUrl)
print(remoteCertificateData)
print(localCertificateData)
if(remoteCertificateData.isEqual(localCertificateData)==true) {
//服务器证书验证通过
disposition =URLSession.AuthChallengeDisposition.useCredential
credential =URLCredential(trust: serverTrust)
}else{
//服务器证书验证失败
disposition =URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge
}
return(disposition, credential)
}
//发送客户端证书交由服务器验证
static private func sendClientCer() -> (URLSession.AuthChallengeDisposition, URLCredential?) {
let disposition = URLSession.AuthChallengeDisposition.useCredential
varcredential:URLCredential?
//获取项目中P12证书文件的路径
letpath:String=Bundle.main.path(forResource:"你本地的p12证书文件名", ofType:"p12")!
letPKCS12Data =NSData(contentsOfFile:path)!
let key : NSString = kSecImportExportPassphrase as NSString
letoptions :NSDictionary= [key :"p12证书的密码"]//客户端证书密码
varitems:CFArray?
leterror =SecPKCS12Import(PKCS12Data, options, &items)
iferror==errSecSuccess{
letitemArr = items!asArray
letitem = itemArr.first!
letidentityPointer = item["identity"];
letsecIdentityRef = identityPointeras!SecIdentity
letchainPointer = item["chain"]
letchainRef = chainPointeras? [Any]
credential =URLCredential.init(identity: secIdentityRef, certificates: chainRef, persistence:URLCredential.Persistence.forSession)
}
return(disposition, credential)
}
}
上面是 最终的代码 跟网上的都差不多 没什么好说的
但是问题是
读服务端给的cer证书的时候,
SecCertificateCreateWithData
总是返回为nil,
ServerTrustPolicy.certificates()
这个alamofire自带的识别本地证书的方法都没识别出证书的内容
public static funccertificates(in bundle:Bundle=Bundle.main) -> [SecCertificate] {
var certificates: [SecCertificate] = []
let paths =Set([".cer",".CER",".crt",".CRT",".der",".DER"].map{ fileExtensionin
bundle.paths(forResourcesOfType: fileExtension, inDirectory:nil)
}.joined())
for path in paths {
if
let certificateData = try?Data(contentsOf:URL(fileURLWithPath: path)) as CFData,
let certificate =SecCertificateCreateWithData(nil, certificateData)
{
certificates.append(certificate)
}
}
return certificates
}
path里是能识别出来的 但是到证书那就没了 这就很诡异了
查了半天原因是因为这个证书是服务器自己生成的,不是正规的CA机构颁发的,(虽然服务端的小伙伴一直说是正规机构发的)但是 苹果安全性要求是很高的,只认正规机构颁发的cer 自己服务器生成的得是der cer这个怎么弄都读不出来,
最后跟服务端的小伙伴沟通无效 自己把证书从cer转换了证书变成der的就没事了。。。
所以正规不正规的 你懂得
原因是:The newly created certificate object. Call the CFRelease function to release this object when you are finished with it. Returns NULL if the data passed in the data parameter is not a valid DER-encoded X.509 certificate.
据说可以使用:
openssl x509 -in xxx.cer -outform der -out xxx.der来转
我用的是:
cer 转换der的网址
https://www.ssldun.com/tools/ssl-converter.php
所以 不要盲目的 不能偏听偏信 解决问题还得靠自己