NEHotspotEAPSettings setTrustedServerCertificates returning "invalid certificate data type"

I am currently working on an app that programmatically connects to wifi hotspot.

I have a root and intermediate certificate and I'm trying to add them using setTrustedServerCertificates but xcode is returning "NEHotspotEAPSettings invalid certificate data type"

NOTE: caCert and intCert are both SecCertificateRef objects

Here's my code

    let clientCert = RSAUtils.getClientCertificate(targetPemFile: "client-cert")
    let caCert = RSAUtils.getClientCertificate(targetPemFile: "ca.crt")
    let intCert = RSAUtils.getClientCertificate(targetPemFile: "int.crt")
    KeychainUtils.addToKeychain(certificate: clientCert!, withLabel: "Client-Cert")
    KeychainUtils.addToKeychain(certificate: caCert!, withLabel: "CA-Cert")
    KeychainUtils.addToKeychain(certificate: intCert!, withLabel: "Int-Cert")
    if let filepath = Bundle.main.path(forResource: "client-key", ofType: "pem") {
      do {
        var contents = try! String(contentsOfFile: filepath)
        // remove the header string
        let offset = String("-----BEGIN PRIVATE KEY-----").count
        let index = contents.index(contents.startIndex, offsetBy: offset+1)
        contents = String(contents.suffix(from: index))
        // remove the tail string
        let tailWord = "-----END PRIVATE KEY-----"
        if let lowerBound = contents.range(of: tailWord)?.lowerBound {
          contents = String(contents.prefix(upTo: lowerBound))
        }
        contents = contents.replacingOccurrences(of: "\n", with: "")
        let data = NSData(base64Encoded: contents, options:NSData.Base64DecodingOptions.ignoreUnknownCharacters)!
        let strippedData = try! RSAUtils.stripPrivateKeyHeader(data as Data)
        var privateKey: SecKey?
        let attributes = [kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits: 1024] as CFDictionary
        var error: Unmanaged<CFError>? = nil
        privateKey = SecKeyCreateWithData(strippedData! as CFData, attributes, &error)
        let ssidSting = "K3Yhotspot-1"
        let hotspotEAPSettings = NEHotspotEAPSettings()
        hotspotEAPSettings.isTLSClientCertificateRequired = true
        let caCert = KeychainUtils.retrieveCertificate(certificateLabel: "CA-Cert")
        let intCert = KeychainUtils.retrieveCertificate(certificateLabel: "Int-Cert")
        hotspotEAPSettings.ttlsInnerAuthenticationType = .eapttlsInnerAuthenticationEAP
        hotspotEAPSettings.supportedEAPTypes = [NEHotspotEAPSettings.EAPType.EAPTLS.rawValue as NSNumber]
        hotspotEAPSettings.setTrustedServerCertificates([caCert, intCert])
        //hotspotEAPSettings.setIdentity(SecIdentity) // Still need to add identity here
        let hotspotConfig = NEHotspotConfiguration(ssid: ssidSting, eapSettings: hotspotEAPSettings)
        NEHotspotConfigurationManager.shared.apply(hotspotConfig) {[unowned self] (error) in
          if let error = error {
           print("error = ",error)
          }
          else {
           print("Success!")
          }
        }
      }
    }

invalid certificate data type

The most common reason this can happen is that the certificate is not in a binary format, DER format, and a PEM is being used instead. Now it looks like ca.crt and int.crt are in binary format, but I cannot tell what format client-cert is in? One thing you can do to lint this out is after these Keychain assets are added to the Keychain, pull them back out and add their binary data to create SecCertificate objects and SecKey objects, that would narrow down and formatting issues before the NEHotspotEAPSettings API uses them.

Now, having said the above, there was a bug with the setTrustedServerCertificates API in the iOS 15.0 - iOS 15.2 timeframe, so if you are on these versions you will want to update to iOS 15.3 to test your code out there also.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
NEHotspotEAPSettings setTrustedServerCertificates returning "invalid certificate data type"
 
 
Q