4 Replies
      Latest reply on Feb 13, 2019 1:54 AM by eskimo
      LordOfTheFries Level 1 Level 1 (0 points)

        I'm trying to set up a client connection to communicate with an MQTT broker using client side certificates. I've been able to proof-of-concept this all on the Linux side using command line. The MQTT broker is set to require client cert, and a command like:

         

            mosquitto_pub -h servername -p 8899 -t 1234/2/Q/8 -m myMessage --cafile myChain.crt --cert client.crt --key client.pem

        does the job nicely. Now I'm trying to set up an NWConnection:

         

            self.connection = NWConnection(
                host: NWEndpoint.Host("servername"),
                port: NWEndpoint.Port(integerLiteral: 8899),
                using: .tls)

         

        But I think that simple .tls class var needs to be a much more involved NWParameters object, but I'm at a complete loss (documentation is pretty sparse) as to what I create there to attach the client certs to the parameters. Nor do I know how I even move from .crt/.pem file to something the app manages programatically.

         

        What is an example of how one would configure the NWParameters to support the client certs?

        • Re: How to setup iOS 12 NWConnection that uses client cert
          eskimo Apple Staff Apple Staff (10,695 points)

          Sorry I didn’t respond sooner; somehow I missed your post when it first showed up )-:

          What is an example of how one would configure the NWParameters to support the client certs?

          Yeah, that’s a bit tricky.  The basic structure for this as as follows:

          let options = NWProtocolTLS.Options()
          let securityOptions = options.securityProtocolOptions
          … configure `securityOptions` here …
          let params = NWParameters(tls: options)
          let conn = NWConnection(host: "example.com", port: 443, using: params)

          The above gives you access to the sec_protocol_options_t, allowing you to customise various TLS operations.  For example:

          • To customise server trust evaluation, set a verify block:

            sec_protocol_options_set_verify_block(securityOptions, { (_, trust, completionHandler) in
                let isTrusted = … your code here …
                completionHandler(isTrusted)
            }, .main)

            .

          • To always supply a client identity, set it as the local identity:

            let clientIdentity: SecIdentity = … your code here …
            sec_protocol_options_set_local_identity(
               securityOptions,
               sec_identity_create(clientIdentity)!
            )

            .

          • To respond to client certificate challenges from the server — this allows you to pick an identity based on info returned to you by the server — set a challenge block:

            sec_protocol_options_set_challenge_block(securityOptions, { (_, completionHandler) in
                let clientIdentity: SecIdentity = … your code here …
                completionHandler(sec_identity_create(clientIdentity)!)
            }, .main)

            .

          Share and Enjoy

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

            • Re: How to setup iOS 12 NWConnection that uses client cert
              LordOfTheFries Level 1 Level 1 (0 points)

              Thanks Quinn, I've been working through this. But I'm getting stuck at the

               

              let clientIdentity: SecIdentity = … your code here …

               

              part. I'm getting my cert/key pair from a prior BLE negotiaton (and they are self signed). So I can create my key using:

               

              // private key
              var error: Unmanaged?
              if let rsaKey = SecKeyCreateWithData(KeyData as CFData, keyOptions as CFDictionary, &error) {
                  "key \(rsaKey)".print()
              }
              else {
                  "NO KEY \(error!.takeRetainedValue() as Error)".print()
              }
              
              

              AndI can create the cert using a similiar construct:

               

              // client cert
              let certificate = SecCertificateCreateWithData(nil, CertData as CFData)
              if let certificate = certificate {
                  "certificate \(certificate)".print()
              }
              else {
                  "NO CERTIFICATE".print()
              }

               

              But the function that I though I would use to create an Identity

              SecIdentityCreateWithCertificate(nil, certificate!, &identity)

              is only availabe in macOS. I'm running on iOS. I noticed the function SecAddItem, but it doesn't talk about keys at all.

               

              Given I have the DER bytes for both the certificate and the key, what is the right way to turn these into entites I can use the Sec framework on iOS?

               

              (does this need to be a new question, rather than a continuation of your excellent example above)

                • Re: How to setup iOS 12 NWConnection that uses client cert
                  LordOfTheFries Level 1 Level 1 (0 points)

                  I found a single comment below a StackOverflow answer that ended up being the solution:  SecPKCS12Import().

                   

                  XCA lets me bundle up my cert/chain/privkey files as .p12 just as well. Using those bytes, I can import it and extract the SecIdentity.

                   

                  let importOptions = [ kSecImportExportPassphrase as String: "" ]
                  var rawItems: CFArray?
                  let status = SecPKCS12Import(P12Data as CFData, importOptions as CFDictionary, &rawItems)
                  let items = rawItems! as! Array<Dictionary<String, Any>>
                  let firstItem = items[0]
                  let clientIdentity = firstItem[kSecImportItemIdentity as String]! as! SecIdentity
                  print("clientIdentity \(clientIdentity)")
                    • Re: How to setup iOS 12 NWConnection that uses client cert
                      eskimo Apple Staff Apple Staff (10,695 points)

                      XCA lets me bundle up my cert/chain/privkey files as .p12 just as well.

                      Excellent news.  If you start with a .p12, this process is simple.  However, if you start with a private key and certificate pair, things get complex.  On iOS, the absence of SecIdentityCreateWithCertificate means that you have to bounce through the keychain.

                      Share and Enjoy

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