@@ -2,6 +2,8 @@ import CocoaMQTT
2
2
import os
3
3
import Security
4
4
5
+ typealias SecKeyPerformBlock = ( SecKey ) -> ( )
6
+
5
7
func loadX509Certificate( fromPem: String ) -> SecCertificate ? {
6
8
let pemContents = fromPem
7
9
. replacingOccurrences ( of: " -----BEGIN CERTIFICATE----- " , with: " " )
@@ -13,22 +15,6 @@ func loadX509Certificate(fromPem: String) -> SecCertificate? {
13
15
return SecCertificateCreateWithData ( nil , data)
14
16
}
15
17
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
-
32
18
@objc ( MqttClient)
33
19
class MqttClient : RCTEventEmitter {
34
20
static let DEFAULT_KEY_APPLICATION_TAG = " com.github.emoto-kc-ak.react-native-mqtt-client "
@@ -69,12 +55,38 @@ class MqttClient : RCTEventEmitter {
69
55
self . hasListeners = false
70
56
}
71
57
58
+ func loadPrivateKeyFromKeychain( keyTag: String , reject: RCTPromiseRejectBlock , 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
+ } else {
80
+ reject ( " LOAD_KEY_ERROR " , " Key does not exist " , nil )
81
+ }
82
+ }
83
+
72
84
@objc ( setIdentity: resolve: reject: )
73
85
func setIdentity( params: NSDictionary , resolve: RCTPromiseResolveBlock , reject: RCTPromiseRejectBlock ) -> Void
74
86
{
75
87
let caCertPem : String = RCTConvert . nsString ( params [ " caCertPem " ] )
76
88
let certPem : String = RCTConvert . nsString ( params [ " certPem " ] )
77
- let keyPem : String = RCTConvert . nsString ( params [ " keyPem " ] )
89
+ let keyTag : String = RCTConvert . nsString ( params [ " keyTag " ] )
78
90
let keyStoreOptions = RCTConvert . nsDictionary ( params [ " keyStoreOptions " ] )
79
91
let caCertLabel : String = RCTConvert . nsString ( keyStoreOptions ? [ " caCertLabel " ] ) ?? Self . DEFAULT_CA_CERT_LABEL
80
92
let certLabel : String = RCTConvert . nsString ( keyStoreOptions ? [ " certLabel " ] ) ?? Self . DEFAULT_CERT_LABEL
@@ -87,75 +99,71 @@ class MqttClient : RCTEventEmitter {
87
99
reject ( " RANGE_ERROR " , " invalid certificate " , nil )
88
100
return
89
101
}
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 )
102
+
103
+ let block : SecKeyPerformBlock = { privateKey in
104
+ do {
105
+ // adds the private key to the keychain
106
+ let addKeyAttrs : [ String : Any ] = [
107
+ kSecClass as String : kSecClassKey,
108
+ kSecValueRef as String : privateKey,
109
+ kSecAttrLabel as String : " Private key that signed an MQTT client certificate " ,
110
+ kSecAttrApplicationTag as String : keyApplicationTag
111
+ ]
112
+ let err = SecItemAdd ( addKeyAttrs as CFDictionary , nil )
113
+ guard err == errSecSuccess || err == errSecDuplicateItem else {
114
+ reject ( " INVALID_IDENTITY " , " failed to add the private key to the keychain: \( err) " , nil )
115
+ return
116
+ }
117
+ }
118
+ catch let error {
119
+ reject ( " RANGE_ERROR " , error. localizedDescription, nil )
120
+ }
121
+ // adds the certificate to the keychain
122
+ let addCertAttrs : [ String : Any ] = [
123
+ kSecClass as String : kSecClassCertificate,
124
+ kSecValueRef as String : cert,
125
+ kSecAttrLabel as String : certLabel
126
+ ]
127
+ var err = SecItemAdd ( addCertAttrs as CFDictionary , nil )
128
+ guard err == errSecSuccess || err == errSecDuplicateItem else {
129
+ reject ( " INVALID_IDENTITY " , " failed to add the certificate to the keychain: \( err) " , nil )
97
130
return
98
131
}
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
132
+ // adds the root certificate to the keychain
133
+ // TODO: root certificate may be stored in other place,
134
+ // because it is public information.
135
+ let addCaCertAttrs : [ String : Any ] = [
136
+ kSecClass as String : kSecClassCertificate ,
137
+ kSecValueRef as String : caCert ,
138
+ kSecAttrLabel as String : caCertLabel
106
139
]
107
- let err = SecItemAdd ( addKeyAttrs as CFDictionary , nil )
140
+ err = SecItemAdd ( addCaCertAttrs as CFDictionary , nil )
108
141
guard err == errSecSuccess || err == errSecDuplicateItem else {
109
- reject ( " INVALID_IDENTITY " , " failed to add the private key to the keychain: \( err) " , nil )
142
+ reject ( " INVALID_IDENTITY " , " failed to add the root certificate to the keychain: \( err) " , nil )
110
143
return
111
144
}
145
+ // obtains the identity
146
+ let queryIdentityAttrs : [ String : Any ] = [
147
+ kSecClass as String : kSecClassIdentity,
148
+ kSecAttrApplicationTag as String : keyApplicationTag,
149
+ kSecReturnRef as String : true
150
+ ]
151
+ var identity : CFTypeRef ?
152
+ err = SecItemCopyMatching ( queryIdentityAttrs as CFDictionary , & identity)
153
+ guard err == errSecSuccess else {
154
+ reject ( " INVALID_IDENTITY " , " failed to query the keychain for the identity: \( err) " , nil )
155
+ return
156
+ }
157
+ guard CFGetTypeID ( identity) == SecIdentityGetTypeID ( ) else {
158
+ reject ( " INVALID_IDENTITY " , " failed to query the keychain for the identity: type ID mismatch " , nil )
159
+ return
160
+ }
161
+ // remembers the identity and the CA certificate
162
+ self . certArray = [ identity!, caCert] as CFArray
163
+ resolve ( nil )
112
164
}
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 )
165
+
166
+ self . loadPrivateKeyFromKeychain ( keyTag: keyTag, reject: reject, block: block)
159
167
}
160
168
161
169
@objc ( loadIdentity: resolve: reject: )
0 commit comments