Provision device using certificate and private key in swift using REST API.

Shahanshah Alam 0 Reputation points
2024-08-08T12:57:21.46+00:00

I have x509 certificate in pem format.

CertificatePem: -----BEGIN CERTIFICATE----- MIIC3jCCAcYCAQAw...9gBFNQUdahSccXF2bnZkv2Kh -----END CERTIFICATE-----

PrivatekeyPem: -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQE...ooxp1Nyl17zfP -----END RSA PRIVATE KEY-----

And I convert it to base64 using this JS code


export const convertPemToBase64 = (pemKey, type) => {
  try {
    const pemHeader =
      type === 'certificate'
        ? '-----BEGIN CERTIFICATE-----'
        : '-----BEGIN RSA PRIVATE KEY-----';
    const pemFooter =
      type === 'certificate'
        ? '-----END CERTIFICATE-----'
        : '-----END RSA PRIVATE KEY-----';

    let base64Key = pemKey.replace(pemHeader, '').replace(pemFooter, '');

    // Remove any newline characters
    base64Key = base64Key.replace(/\r?\n|\r/g, '');

    return base64Key;
  } catch (err) {
    console.log('error in convertPemToBase64', err);
  }
};

And my

CertificateBase64 look like: MIIC3jCCAcYCAQAw...9gBFNQUdahSccXF2bnZkv2Kh

PrivateBase64: MIIEowIBAAKCAQE...ooxp1Nyl17zfP

I want to create identity to use in https request.

I am getting error:

Unable to create identity

My loadIdentity function look like this:

import Foundation
import Security

class URLSessionPinningDelegate: NSObject, URLSessionDelegate {
    var identity: SecIdentity

    init(identity: SecIdentity) {
        self.identity = identity
    }

    func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        let credential = URLCredential(identity: self.identity, certificates: nil, persistence: .forSession)
        completionHandler(.useCredential, credential)
    }
}

    
func loadIdentity(certificate: String, privateKey: String) -> SecIdentity? {


    guard let certData = Data(base64Encoded: certificate) else {
        print("Unable to decode certificate PEM")
        return nil
    }
    print("certData: \(certData)")

// Create certificate object
    guard let cert = SecCertificateCreateWithData(nil, certData as CFData) else {
        print("Unable to create certificate")
        return nil
    }
      // Add certificate to the keychain
    let certAddQuery: [NSString: Any] = [
        kSecClass: kSecClassCertificate,
        kSecValueRef: cert,
        kSecAttrLabel: "mycertificate"
    ]
   
    var status = SecItemAdd(certAddQuery as CFDictionary, nil)
    if status != errSecSuccess && status != errSecDuplicateItem {
        print("Failed to add certificate to keychain: \(status)")
        return nil
    }


    guard let keyData = Data(base64Encoded: privateKey) else {
        print("Unable to decode private key PEM")
        return nil
    }
    print("keyData: \(keyData)")

   // Define attributes for the private key
    let keyDict: [NSString: Any] = [
        kSecAttrKeyType: kSecAttrKeyTypeRSA,
        kSecAttrKeyClass: kSecAttrKeyClassPrivate,
        kSecAttrKeySizeInBits: 2048,
        kSecReturnPersistentRef: true
    ]

//    Create private key object
    var error: Unmanaged<CFError>?
    guard let privateKeyData = SecKeyCreateWithData(keyData as CFData, keyDict as CFDictionary, &error) else {
        // print("Unable to create private key: \(error?.takeRetainedValue() ?? "Unknown error" as CFError)")
        print("Unable to create private key")
        return nil
    }

        // Add private key to the keychain
    let keyAddQuery: [NSString: Any] = [
        kSecClass: kSecClassKey,
        kSecValueRef: privateKeyData,
        kSecAttrLabel: "myprivatekey",
        kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked
    ]
    status = SecItemAdd(keyAddQuery as CFDictionary, nil)
    if status != errSecSuccess && status != errSecDuplicateItem {
        print("Failed to add private key to keychain: \(status)")
        return nil
    }
    
        // Query to retrieve the identity from the keychain
    let identityQuery: [NSString: Any] = [
        kSecClass: kSecClassIdentity,
        kSecReturnRef: true,
        kSecAttrLabel: "mycertificate",
        // kSecMatchItemList: [cert, privateKeyData]
    ]
    
    var identity: CFTypeRef?
    status = SecItemCopyMatching(identityQuery as CFDictionary, &identity)
    
     guard status == errSecSuccess else {
         print("Unable to create identity")
         return nil
     }

    return (identity as! SecIdentity)
    
}


@objc(AzureProvisionWithCertificate)
class AzureProvisionWithCertificate: NSObject {

  @objc(provisionAndUploadFile:withRegistrationId:withKey:withCertificate:withProvisionHost:withFileNameWithFolder:withModelId:withResolver:withRejecter:)
  func provisionAndUploadFile(scopeId:String, registrationId:String, key:String, certificate:String,  provisionHost:String,  fileNameWithFolder:String,  modelId:String, resolve:@escaping RCTPromiseResolveBlock, reject:@escaping RCTPromiseRejectBlock) -> Void {
      print("starting swift code here")
      print("key: \(key)")
      print("certificate: \(certificate)")
      

    guard let identity = loadIdentity(certificate: certificate, privateKey: key) else {
        print("Unable to load identity")
        return
    }
    
    // let session = URLSession(configuration: .default, delegate: URLSessionPinningDelegate(identity: identity), delegateQueue: nil)
    
    // guard let url = URL(string: "https://global.azure-devices-provisioning.net/[scopeId]/registrations/[registrationId]/register?api-version=2021-06-01") else {
    //     print("Invalid URL")
    //     return
    // }
    //   var request = URLRequest(url: url)
    // request.httpMethod = "PUT"
    // request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    // request.setValue("utf-8", forHTTPHeaderField: "Content-Encoding")
    
    // let body = ["registrationId": "registrationId"]
    // request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: [])

    // let task = session.dataTask(with: request) { data, response, error in
    //     if let error = error {
    //         print("Request failed: \(error)")
    //     } else if let data = data, let responseString = String(data: data, encoding: .utf8) {
    //         print("Response: \(responseString)")
    //     }
    // }
    
    // task.resume()

  }
}

Azure IoT Hub
Azure IoT Hub
An Azure service that enables bidirectional communication between internet of things (IoT) devices and applications.
1,176 questions
0 comments No comments
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.