@@ -2,6 +2,8 @@ import CocoaMQTT
22import os
33import Security
44
5+ typealias SecKeyPerformBlock = ( SecKey ) -> ( )
6+
57func loadX509Certificate( fromPem: String ) -> SecCertificate ? {
68 let pemContents = fromPem
79 . replacingOccurrences ( of: " -----BEGIN CERTIFICATE----- " , with: " " )
@@ -13,22 +15,6 @@ func loadX509Certificate(fromPem: String) -> SecCertificate? {
1315 return SecCertificateCreateWithData ( nil , data)
1416}
1517
16- func loadPrivateKey( fromPem: String ) -> SecKey ? {
17- let pemContents = fromPem
18- . replacingOccurrences ( of: " -----BEGIN RSA PRIVATE KEY----- " , with: " " )
19- . replacingOccurrences ( of: " -----END RSA PRIVATE KEY----- " , with: " " )
20- guard let data = NSData . init ( base64Encoded: pemContents, options: NSData . Base64DecodingOptions. ignoreUnknownCharacters) else
21- {
22- return nil
23- }
24- let options : [ String : Any ] = [
25- kSecAttrType as String : kSecAttrKeyTypeRSA,
26- kSecAttrKeyClass as String : kSecAttrKeyClassPrivate,
27- kSecAttrKeySizeInBits as String : 2048 // supposes that the private key has 2048 bits
28- ]
29- return SecKeyCreateWithData ( data, options as CFDictionary , nil )
30- }
31-
3218@objc ( MqttClient)
3319class MqttClient : RCTEventEmitter {
3420 static let DEFAULT_KEY_APPLICATION_TAG = " com.github.emoto-kc-ak.react-native-mqtt-client "
@@ -69,12 +55,36 @@ class MqttClient : RCTEventEmitter {
6955 self . hasListeners = false
7056 }
7157
58+ func loadPrivateKeyFromKeychain( keyTag: String , block: SecKeyPerformBlock ) {
59+ var query : [ String : AnyObject ] = [
60+ String ( kSecClass) : kSecClassKey,
61+ String ( kSecAttrApplicationTag) : keyTag as AnyObject ,
62+ String ( kSecReturnRef) : true as AnyObject
63+ ]
64+
65+ if #available( iOS 10 , * ) {
66+ query [ String ( kSecAttrKeyType) ] = kSecAttrKeyTypeECSECPrimeRandom
67+ } else {
68+ // Fallback on earlier versions
69+ query [ String ( kSecAttrKeyType) ] = kSecAttrKeyTypeEC
70+ }
71+
72+ var result : AnyObject ?
73+
74+ let status = SecItemCopyMatching ( query as CFDictionary , & result)
75+
76+ if status == errSecSuccess {
77+ print ( " \( keyTag) Key existed! " )
78+ block ( ( result as! SecKey ? ) !)
79+ }
80+ }
81+
7282 @objc ( setIdentity: resolve: reject: )
7383 func setIdentity( params: NSDictionary , resolve: RCTPromiseResolveBlock , reject: RCTPromiseRejectBlock ) -> Void
7484 {
7585 let caCertPem : String = RCTConvert . nsString ( params [ " caCertPem " ] )
7686 let certPem : String = RCTConvert . nsString ( params [ " certPem " ] )
77- let keyPem : String = RCTConvert . nsString ( params [ " keyPem " ] )
87+ let keyTag : String = RCTConvert . nsString ( params [ " keyTag " ] )
7888 let keyStoreOptions = RCTConvert . nsDictionary ( params [ " keyStoreOptions " ] )
7989 let caCertLabel : String = RCTConvert . nsString ( keyStoreOptions ? [ " caCertLabel " ] ) ?? Self . DEFAULT_CA_CERT_LABEL
8090 let certLabel : String = RCTConvert . nsString ( keyStoreOptions ? [ " certLabel " ] ) ?? Self . DEFAULT_CERT_LABEL
@@ -87,75 +97,71 @@ class MqttClient : RCTEventEmitter {
8797 reject ( " RANGE_ERROR " , " invalid certificate " , nil )
8898 return
8999 }
90- //guard let key = loadPrivateKey(fromPem: keyPem) else {
91- // reject("RANGE_ERROR", "invalid private key", nil)
92- // return
93- //}
94- do {
95- guard let key = try ECPrivateKey ( key: keyPem) . nativeKey else {
96- reject ( " RANGE_ERROR " , " invalid private key " , nil )
100+
101+ let block : SecKeyPerformBlock = { privateKey in
102+ do {
103+ // adds the private key to the keychain
104+ let addKeyAttrs : [ String : Any ] = [
105+ kSecClass as String : kSecClassKey,
106+ kSecValueRef as String : privateKey,
107+ kSecAttrLabel as String : " Private key that signed an MQTT client certificate " ,
108+ kSecAttrApplicationTag as String : keyApplicationTag
109+ ]
110+ let err = SecItemAdd ( addKeyAttrs as CFDictionary , nil )
111+ guard err == errSecSuccess || err == errSecDuplicateItem else {
112+ reject ( " INVALID_IDENTITY " , " failed to add the private key to the keychain: \( err) " , nil )
113+ return
114+ }
115+ }
116+ catch let error {
117+ reject ( " RANGE_ERROR " , error. localizedDescription, nil )
118+ }
119+ // adds the certificate to the keychain
120+ let addCertAttrs : [ String : Any ] = [
121+ kSecClass as String : kSecClassCertificate,
122+ kSecValueRef as String : cert,
123+ kSecAttrLabel as String : certLabel
124+ ]
125+ var err = SecItemAdd ( addCertAttrs as CFDictionary , nil )
126+ guard err == errSecSuccess || err == errSecDuplicateItem else {
127+ reject ( " INVALID_IDENTITY " , " failed to add the certificate to the keychain: \( err) " , nil )
97128 return
98129 }
99-
100- // adds the private key to the keychain
101- let addKeyAttrs : [ String : Any ] = [
102- kSecClass as String : kSecClassKey ,
103- kSecValueRef as String : key ,
104- kSecAttrLabel as String : " Private key that signed an MQTT client certificate " ,
105- kSecAttrApplicationTag as String : keyApplicationTag
130+ // adds the root certificate to the keychain
131+ // TODO: root certificate may be stored in other place,
132+ // because it is public information.
133+ let addCaCertAttrs : [ String : Any ] = [
134+ kSecClass as String : kSecClassCertificate ,
135+ kSecValueRef as String : caCert ,
136+ kSecAttrLabel as String : caCertLabel
106137 ]
107- let err = SecItemAdd ( addKeyAttrs as CFDictionary , nil )
138+ err = SecItemAdd ( addCaCertAttrs as CFDictionary , nil )
108139 guard err == errSecSuccess || err == errSecDuplicateItem else {
109- reject ( " INVALID_IDENTITY " , " failed to add the private key to the keychain: \( err) " , nil )
140+ reject ( " INVALID_IDENTITY " , " failed to add the root certificate to the keychain: \( err) " , nil )
110141 return
111142 }
143+ // obtains the identity
144+ let queryIdentityAttrs : [ String : Any ] = [
145+ kSecClass as String : kSecClassIdentity,
146+ kSecAttrApplicationTag as String : keyApplicationTag,
147+ kSecReturnRef as String : true
148+ ]
149+ var identity : CFTypeRef ?
150+ err = SecItemCopyMatching ( queryIdentityAttrs as CFDictionary , & identity)
151+ guard err == errSecSuccess else {
152+ reject ( " INVALID_IDENTITY " , " failed to query the keychain for the identity: \( err) " , nil )
153+ return
154+ }
155+ guard CFGetTypeID ( identity) == SecIdentityGetTypeID ( ) else {
156+ reject ( " INVALID_IDENTITY " , " failed to query the keychain for the identity: type ID mismatch " , nil )
157+ return
158+ }
159+ // remembers the identity and the CA certificate
160+ self . certArray = [ identity!, caCert] as CFArray
161+ resolve ( nil )
112162 }
113- catch let error {
114- reject ( " RANGE_ERROR " , error. localizedDescription, nil )
115- }
116- // adds the certificate to the keychain
117- let addCertAttrs : [ String : Any ] = [
118- kSecClass as String : kSecClassCertificate,
119- kSecValueRef as String : cert,
120- kSecAttrLabel as String : certLabel
121- ]
122- var err = SecItemAdd ( addCertAttrs as CFDictionary , nil )
123- guard err == errSecSuccess || err == errSecDuplicateItem else {
124- reject ( " INVALID_IDENTITY " , " failed to add the certificate to the keychain: \( err) " , nil )
125- return
126- }
127- // adds the root certificate to the keychain
128- // TODO: root certificate may be stored in other place,
129- // because it is public information.
130- let addCaCertAttrs : [ String : Any ] = [
131- kSecClass as String : kSecClassCertificate,
132- kSecValueRef as String : caCert,
133- kSecAttrLabel as String : caCertLabel
134- ]
135- err = SecItemAdd ( addCaCertAttrs as CFDictionary , nil )
136- guard err == errSecSuccess || err == errSecDuplicateItem else {
137- reject ( " INVALID_IDENTITY " , " failed to add the root certificate to the keychain: \( err) " , nil )
138- return
139- }
140- // obtains the identity
141- let queryIdentityAttrs : [ String : Any ] = [
142- kSecClass as String : kSecClassIdentity,
143- kSecAttrApplicationTag as String : keyApplicationTag,
144- kSecReturnRef as String : true
145- ]
146- var identity : CFTypeRef ?
147- err = SecItemCopyMatching ( queryIdentityAttrs as CFDictionary , & identity)
148- guard err == errSecSuccess else {
149- reject ( " INVALID_IDENTITY " , " failed to query the keychain for the identity: \( err) " , nil )
150- return
151- }
152- guard CFGetTypeID ( identity) == SecIdentityGetTypeID ( ) else {
153- reject ( " INVALID_IDENTITY " , " failed to query the keychain for the identity: type ID mismatch " , nil )
154- return
155- }
156- // remembers the identity and the CA certificate
157- self . certArray = [ identity!, caCert] as CFArray
158- resolve ( nil )
163+
164+ self . loadPrivateKeyFromKeychain ( keyTag: keyTag, block: block)
159165 }
160166
161167 @objc ( loadIdentity: resolve: reject: )
0 commit comments