8 Replies
      Latest reply: Feb 20, 2017 4:06 AM by encastellano RSS
      RossDM Level 1 Level 1 (0 points)

        Hi guys,

         

        I'm trying to implement mutual TLS connection. Here is the flow:

         

        1. I generate the csr request (using elliptic curve key, secp512r1)
        2. Send the signing rquest to the server and receive the public key certificate as a response
        3. I make p12 certificate using public key certificate received in step2 with my ECC secp512r1 private key. I save it as "ca.p12" file in Documents
        4. when I get NSURLAuthenticationMethodClientCertificate challenge I resolve it using the credentials from this certificate.
        5. Get Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made."

         

        While checking the traffic between server and client it appears that it's a client side issue.

         

        Questions:

        1. Does iOS 9/10 support elliptic curve keys, secp512r1 in TLS handshake?

        2. Is there anything that is wrong or I missed some critical item in my flow?

         

        Any thoughts, suggestions are really appreciated. Thanks.

         

         

         

        public func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void) {
                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)
                }
                
                // server trust verification works fine
                if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
                    if (self.shouldTrustProtectionSpace(space: challenge.protectionSpace)) {               
                        completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
                    }
                }
            }
        
        
        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 PKCS12Data = NSData(contentsOfFile:path)!
                let key: NSString = kSecImportExportPassphrase as NSString
                let options: NSDictionary = [key : "123"]
        
                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> {
                 
                        /
                        let identityPointer: AnyObject? = certEntry["identity"]
                        let secIdentityRef: SecIdentity = identityPointer as! SecIdentity!
                        print("\(identityPointer)  :::: \(secIdentityRef)")
                        /
                        let trustPointer: AnyObject? = certEntry["trust"]
                        let trustRef: SecTrust = trustPointer as! SecTrust
                        print("\(trustPointer)  :::: \(trustRef)")
                 
                        //get certificates from identity
                        var certRef: SecCertificate?
                        SecIdentityCopyCertificate(secIdentityRef, &certRef)
                        let certArray: NSMutableArray = NSMutableArray()
                        certArray.add(certRef as SecCertificate!)
                    
                        //add also ca root certificate
                        let caRootCert = CertRepository.caRootCertificate()
                        certArray.add(caRootCert)
                 
                        identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef, trust: trustRef, certArray:  certArray)
                    }
                }
                return identityAndTrust
            }
        
        
        
        
        • Re: mutual TLS with secp512r1 private key certificate
          eskimo Apple Staff Apple Staff (6,280 points)

          What I recommend you do in this situation is split the problem in half.  Right now your process consists of two important steps:

          • Generate the PKCS#12

          • Use the PKCS#12 for client certificate authentication

          You can split this up easily:

          • You can generate a PKCS#12 on iOS, and then see if OpenSSL is able to use it for client certificate authentication

          • You can generate a PKCS#12 with OpenSSL, and then see if iOS is able to use it for client certificate authentication

          IMPORTANT The ancient OpenSSL built in to macOS does not have good ECC support.  You’ll either need to update that yourself or run the test on some other platform (I generally do this by running Ubuntu in a VM).

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

            • Re: mutual TLS with secp512r1 private key certificate
              RossDM Level 1 Level 1 (0 points)

              I did the following:

              • generated PKC#12 on iOS, saved it to my documents folder, copied to desktop mac and extracted public certificate and private key into pem.
              • Updated openSSL to 1.0.2k
              • Used s_client to check client authentication
              openssl s_client -connect myhost.ae:27447 -cert publicCert.pem -key privateKey.pem -CAfile serverCA.crt -state -debug
              
              

               

              Output:

              ...................
              SSL-Session:
                  Protocol  : TLSv1.2
                  Cipher    : ECDHE-ECDSA-AES256-GCM-SHA384
                  Session-ID: 589DB1117865D9E3B17FB648FA0826CB5EEECE6FF18C02957C7963F0876E84AC
                  Session-ID-ctx:
                  Master-Key: EC2D8B658A6A9B5F5BD7AE4812E31E0067D094E061B01F90503951DDA4CCE1F51A8F7067D6A69BCAA76A28015ED52C2F
                  Key-Arg   : None
                  PSK identity: None
                  PSK identity hint: None
                  SRP username: None
                  Start Time: 1486729489
                  Timeout   : 300 (sec)
                  Verify return code: 0 (ok)
              ---
              
              

               

              Still can't seem to make it work on iOS.

                • Re: mutual TLS with secp512r1 private key certificate
                  eskimo Apple Staff Apple Staff (6,280 points)

                  Now that you’ve got that identity on your Mac, try using it with TLSTool to see if it works there.

                  Share and Enjoy

                  Quinn “The Eskimo!”
                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                  let myEmail = "eskimo" + "1" + "@apple.com"

                    • Re: mutual TLS with secp512r1 private key certificate
                      encastellano Level 1 Level 1 (0 points)

                      Hi,

                       

                      (first, sorry for my english)

                       

                      im in the same situation, and practically the same code. I have a client certificate send by a client in pk12 format. The client certificate have 3 certificates inside server, intermediate, and root, and a private RSA key. The certificate also has a passphrase

                       

                      I imported this certificate on my application defining a custom type on my app, changing the extension of the certificate file and getting it as an nsdata.

                       

                      I cheked with openssl (first I updated openssl to 1.0.2k like RossDM, for tlsv1_2 support) and the output seems ok

                       

                      
                      ---
                      SSL handshake has read 7222 bytes and written 2591 bytes
                      ---
                      New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
                      Server public key is 2048 bit
                      Secure Renegotiation IS supported
                      Compression: NONE
                      Expansion: NONE
                      No ALPN negotiated
                      SSL-Session:
                          Protocol  : TLSv1.2
                          Cipher    : ECDHE-RSA-AES256-GCM-SHA384
                          Session-ID: 3FA9104FDB80678A89F92CF8D2A50C8D14D30B6E186C17F83E279D1A0B2974B2
                          Session-ID-ctx:
                          Master-Key: 7657EB9AD1ADA969EEA8888627ED50F919431D909DBBA0E782BE390D5527F597359B726C6BB1C8E62422CCB6EE765482
                          Key-Arg   : None
                          PSK identity: None
                          PSK identity hint: None
                          SRP username: None
                      
                      

                       

                       

                      I tested with TLSTOOL and the result seems ok (i think)

                       

                      
                      ./TLSTool s_client  -connect host:443 -min tls1_2 -cert certname
                      * client identity: identityname (Qualified Certificate: xxx-xx-xxx-xxx)
                      *  input stream did open
                      * output stream did open
                      * output stream has space
                      * protocol: TLS 1.2
                      * cipher: ECDHE_RSA_WITH_AES_256_GCM_SHA384
                      * trust result: unspecified
                      * certificate info:
                      *   0 + rsaEncryption 2048 sha256-with-rsa-signature 'server cert'
                      *   1 + rsaEncryption 4096 sha256-with-rsa-signature 'intermediate'
                      *   2 + rsaEncryption 4096 sha1-with-rsa-signature 'root'
                      *  input stream has bytes
                      *  input stream end
                      * close
                      * bytes sent 0, bytes received 0
                      
                      

                       

                       

                      In other answers to similar problems in this forum, as in this https://forums.developer.apple.com/message/201856. You say that there is a bug and that it can not be done and you refer to a bug that I do not know how to consult. I have also read that the public key must be deleted since it can have conflicts with the private key.

                       

                      It's really a problem detected or I'm actually doing something wrong??. Since the certificate seems to be fine, the server seems to be fine, even the development on other platforms has not had a problem, I do not know what direction I should take now.

                       

                       

                      Thanks for the support

                        • Re: mutual TLS with secp512r1 private key certificate
                          eskimo Apple Staff Apple Staff (6,280 points)

                          In other answers to similar problems in this forum, as in this …. You say that there is a bug and that it can not be done

                          Right, but that bug relates to WKWebView specifically.  RossDM is talking about NSURLSession, which is capable of handling client certificate authentication challenges just fine.

                          So, which API are you using to test this?

                          Share and Enjoy

                          Quinn “The Eskimo!”
                          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                          let myEmail = "eskimo" + "1" + "@apple.com"

                            • Re: mutual TLS with secp512r1 private key certificate
                              encastellano Level 1 Level 1 (0 points)

                              Your are right, im using WKWebView.

                               

                              Should i use UIWebView instead WKWebView? Does uiwebview behave correctly with client certificates?

                               

                              Thanks for the support, at this point I needed help not to waste more time on something that did not work

                                • Re: mutual TLS with secp512r1 private key certificate
                                  eskimo Apple Staff Apple Staff (6,280 points)

                                  Does uiwebview behave correctly with client certificates?

                                  No.  UIWebView does not explicitly support any authentication challenges.

                                  Should i use UIWebView instead WKWebView?

                                  Well, that’s a complex question (-:  You can hack around this problem by sliding an NSURLProtocol underneath UIWebView, as shown by the CustomHTTPProtocol sample code.  This works with UIWebView because UIWebView does its networking in your process.  OTOH, it doesn’t work with WKWebView because WKWebView does most of its work, including its networking, out of process.

                                  There’s a bunch of drawbacks to doing this:

                                  • You’re using UIWebView not WKWebView, and the latter is the future of web views on our platforms.

                                  • It requires a bunch of gnarly low-level code.

                                  If you have any control over the server then I recommend you switch it to use some other authentication scheme.  For example, this problem often comes up in enterprise environments, where you can use Single Sign-On to avoid the whole issue.  However, if you can’t do that then your only current option is to switch to UIWebView and use the custom NSURLProtocol hackaround.

                                  Share and Enjoy

                                  Quinn “The Eskimo!”
                                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                                  let myEmail = "eskimo" + "1" + "@apple.com"

                                    • Re: mutual TLS with secp512r1 private key certificate
                                      encastellano Level 1 Level 1 (0 points)

                                      Hi,

                                       

                                      I've changed the component by the old uiwebview, handling the challenge with the URLConection, and I've been able to connect to the client certificate.

                                       

                                      I have "lost" a week of work with a component that has a bug, and nowhere in the documentation does it indicate. I think it would be nice to create a technical note, like other similar ones that already exist, or modify the documentation regarding authentication with a client certificate.

                                       

                                      Thank you very much for the help and for orienting me, very good job