2017-02-09 211 views
1

我试图实现相互TLS连接。这里是流量:使用客户端证书和secp512r1失败的TLS 1.2连接

  • 我生成CSR请求(使用椭圆曲线密钥,secp512r1)
  • 发送签名请求到服务器并接收的公钥证书作为响应
  • 我让P12证书使用步骤2中收到的公钥证书和我的ECC secp512r1私钥。我把它保存为文档“ca.p12”文件
  • ,当我得到NSURLAuthenticationMethodClientCertificate挑战我使用的凭据从此证书
  • 获取Error Domain=NSURLErrorDomain Code=-1200“发生SSL错误,无法进行到服务器的安全连接解决它“。

虽然检查服务器和客户端之间的流量似乎是客户端问题。

问题

  1. 确实iOS的9/10支持椭圆曲线按键,secp512r1在TLS握手?
  2. 我错过了什么?

任何想法,建议真的很感激。谢谢。

public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void) { 

//server trust works fine 
if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) { 
    if (self.shouldTrustProtectionSpace(space: challenge.protectionSpace)) { 
     completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!)) 
    } 
} 
//This one causes the issue 
else if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate) { 
    let identityAndTrust: IdentityAndTrust = self.extractIdentity() 

    let urlCredential: URLCredential = URLCredential(
     identity: identityAndTrust.identityRef, 
     certificates: identityAndTrust.certArray as? [AnyObject], 
     persistence: URLCredential.Persistence.forSession) 
     completionHandler(.useCredential, urlCredential) 
    } 
} 

struct IdentityAndTrust { 
    var identityRef: SecIdentity 
    var trust: SecTrust 
    var certArray: AnyObject 
} 

func extractIdentity() -> IdentityAndTrust { 
    var identityAndTrust: IdentityAndTrust! 
    var securityError: OSStatus = errSecSuccess 

    var path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String 
    path = path + "/ca.p12" 
    //let path: String = NSBundle.mainBundle().pathForResource("client", ofType: "p12")! 
    let PKCS12Data = NSData(contentsOfFile:path)! 
    let key: NSString = kSecImportExportPassphrase as NSString 
    let options: NSDictionary = [key : "123"] 
    //create variable for holding security information 
    //var privateKeyRef: SecKeyRef? = nil 

    var items: CFArray? 

    securityError = SecPKCS12Import(PKCS12Data, options, &items) 

    if securityError == errSecSuccess { 
     let certItems: CFArray = items as CFArray! 
     let certItemsArray: Array = certItems as Array 
     let dict: AnyObject? = certItemsArray.first 
     if let certEntry: Dictionary = dict as? Dictionary<String, AnyObject> { 

      // grab the identity 
      let identityPointer: AnyObject? = certEntry["identity"] 
      let secIdentityRef: SecIdentity = identityPointer as! SecIdentity! 
      print("\(identityPointer) :::: \(secIdentityRef)") 
      // grab the trust 
      let trustPointer: AnyObject? = certEntry["trust"] 
      let trustRef: SecTrust = trustPointer as! SecTrust 
      print("\(trustPointer) :::: \(trustRef)") 

      // grab the certificate chain 
      var certRef: SecCertificate? 
      SecIdentityCopyCertificate(secIdentityRef, &certRef) 
      let certArray: NSMutableArray = NSMutableArray() 

      let reader = DmailReader.sharedReader 
      let caCertString = reader.getCACert() 
      let cerData = X509Utility.der(fromData: caCertString) 

      let convertedData = cerData as! CFData 
      let caCert = SecCertificateCreateWithData(nil, convertedData) 
      certArray.add(certRef as SecCertificate!) 
      certArray.add(caCert!) 

      identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef, trust: trustRef, certArray: certArray) 
     } 
    } 
    return identityAndTrust 
} 
+0

根据PKIX(网络的PKI),在链应该(必须?)的所有证书使用'secp512r1'。另外,服务器必须支持'secp512r1'。要查看'secp512r1'是否是问题,请使用'secp256k1'测试。它是最常见的曲线,并提供了该领域最多的互操作性。 – jww

+0

@jww不幸的是,我不能使用secp256进行测试,因为服务器只支持secp512r –

+1

嗯,问题是Apple的SecureTransport可能是越野车。苹果以其软件质量差而闻名(参见[goto fail](https://nakedsecurity.sophos.com/2014/02/24/anatomy-of-a-goto-fail-apples-ssl-bug)解释/非正式补丁/),[SSL_OP_SAFARI_ECDHE_ECDSA_BUG](https://wiki.openssl.org/index.php/SSL_OP_SAFARI_ECDHE_ECDSA_BUG)等)。我认为你需要隔离secp512r1曲线的客户端证书来发现问题所在。使用secp256k1会测试客户端证书。你能用'openssl s_client'或其他工具来测试客户端证书吗? – jww

回答

0

看来,服务器响应我的证书链CSR的要求:一个客户端证书和一个中间。我只解析了第一个,显然跳过了中间语。

/*identity only contains client cert. Certificates is the array of intermediate certificates (in my case its 1, can be more)*/ 
NSURLCredential *credential = [[NSURLCredential alloc]initWithIdentity:identity 
                  certificates:certificates 
                  persistence:NSURLCredentialPersistencePermanent]; 

然后通过它在urlSession:didReceiveChallenge:completionHandler:

completionHandler(.useCredential, urlCredential)