@@ -58,15 +58,20 @@ - (nullable instancetype)initWithSmartCard:(TKSmartCard *)smartCard AID:(nullabl
58
58
struct sc_aid *aid = NULL ;
59
59
struct sc_pkcs15_object *objs[32 ];
60
60
int r;
61
- size_t i, cert_num;
62
- NSMutableArray <TKTokenKeychainItem *> *items;
61
+ size_t i, app_index, cert_num;
62
+ NSMutableArray <TKTokenKeychainItem *> *items = [[ NSMutableArray alloc ] init ] ;
63
63
NSString *instanceID = nil ;
64
+ struct token_apps apps;
64
65
65
66
/* TODO: Move card and p15card to smartCard.context. smartCard.context would automatically be set to nil if the card gets reset or the state gets modified by a different session, see documentation for TKSmartCard */
66
67
67
68
self.card = NULL ;
68
- self.p15card = NULL ;
69
69
self.ctx = NULL ;
70
+ /* self.apps.p15card allows binding multiple on-card-application. index 0 always contains the "generic" app. */
71
+ for (app_index = 0 ; app_index < SC_TOKEN_APPS_MAX_NUM; app_index++) {
72
+ self.apps .p15card [app_index] = NULL ;
73
+ apps.p15card [app_index] = NULL ;
74
+ }
70
75
71
76
os_log (OS_LOG_DEFAULT, " %s " , OPENSC_SCM_REVISION);
72
77
@@ -105,110 +110,123 @@ - (nullable instancetype)initWithSmartCard:(TKSmartCard *)smartCard AID:(nullabl
105
110
106
111
app_generic = sc_pkcs15_get_application_by_type (card, " generic" );
107
112
aid = app_generic ? &app_generic->aid : NULL ;
108
- r = sc_pkcs15_bind (card, aid, &p15card);
109
- LOG_TEST_GOTO_ERR (ctx, r, " sc_pkcs15_bind" );
110
113
111
- r = sc_pkcs15_get_objects (p15card, SC_PKCS15_TYPE_CERT_X509, objs, sizeof (objs)/(sizeof *objs));
112
- LOG_TEST_GOTO_ERR (ctx, r, " sc_pkcs15_get_objects (SC_PKCS15_TYPE_CERT_X509)" );
113
- cert_num = (size_t ) r;
114
- items = [NSMutableArray arrayWithCapacity: cert_num];
115
- for (i = 0 ; i < cert_num; i++) {
116
- struct sc_pkcs15_cert_info *cert_info = objs[i]->data ;
117
- struct sc_pkcs15_cert *cert = NULL ;
118
- struct sc_pkcs15_object *prkey_obj = NULL ;
119
- int private_obj = objs[i]->flags & SC_PKCS15_CO_FLAG_PRIVATE;
120
-
121
- r = sc_pkcs15_read_certificate (p15card, cert_info, private_obj, &cert);
122
- if (r) {
123
- sc_log (ctx, " sc_pkcs15_read_certificate: %s " , sc_strerror (r));
124
- continue ;
125
- }
126
- NSData * certificateData = [NSData dataWithBytes: (const void *)cert->data.value length: sizeof (unsigned char )*cert->data.len];
127
- NSData * certificateID = idToData (TYPE_CERT, &cert_info->id );
128
- NSString *certificateName = [NSString stringWithUTF8String: objs[i]->label];
129
- id certificate = CFBridgingRelease (SecCertificateCreateWithData (kCFAllocatorDefault , (CFDataRef)certificateData));
130
- if (certificateData == nil || certificateID == nil || certificateName == nil || certificate == NULL ) {
131
- sc_pkcs15_free_certificate (cert);
132
- continue ;
133
- }
134
- TKTokenKeychainCertificate *certificateItem = [[TKTokenKeychainCertificate alloc ] initWithCertificate: (__bridge SecCertificateRef)certificate objectID: certificateID];
135
- if (certificateItem == nil ) {
114
+ /* Bind all applications starting with the "generic" one */
115
+ for (app_index = 0 ; app_index < SC_TOKEN_APPS_MAX_NUM; app_index++) {
116
+ r = sc_pkcs15_bind (card, aid, &p15card);
117
+ apps.p15card [app_index] = p15card;
118
+ LOG_TEST_GOTO_ERR (ctx, r, " sc_pkcs15_bind" );
119
+
120
+ r = sc_pkcs15_get_objects (p15card, SC_PKCS15_TYPE_CERT_X509, objs, sizeof (objs)/(sizeof *objs));
121
+ LOG_TEST_GOTO_ERR (ctx, r, " sc_pkcs15_get_objects (SC_PKCS15_TYPE_CERT_X509)" );
122
+ cert_num = (size_t ) r;
123
+ for (i = 0 ; i < cert_num; i++) {
124
+ struct sc_pkcs15_cert_info *cert_info = objs[i]->data ;
125
+ struct sc_pkcs15_cert *cert = NULL ;
126
+ struct sc_pkcs15_object *prkey_obj = NULL ;
127
+ int private_obj = objs[i]->flags & SC_PKCS15_CO_FLAG_PRIVATE;
128
+
129
+ r = sc_pkcs15_read_certificate (p15card, cert_info, private_obj, &cert);
130
+ if (r) {
131
+ sc_log (ctx, " sc_pkcs15_read_certificate: %s " , sc_strerror (r));
132
+ continue ;
133
+ }
134
+ NSData * certificateData = [NSData dataWithBytes: (const void *)cert->data.value length: sizeof (unsigned char )*cert->data.len];
135
+ NSData * certificateID = idToData (app_index, TYPE_CERT, &cert_info->id );
136
+ NSString *certificateName = [NSString stringWithUTF8String: objs[i]->label];
137
+ id certificate = CFBridgingRelease (SecCertificateCreateWithData (kCFAllocatorDefault , (CFDataRef)certificateData));
138
+ if (certificateData == nil || certificateID == nil || certificateName == nil || certificate == NULL ) {
139
+ sc_pkcs15_free_certificate (cert);
140
+ continue ;
141
+ }
142
+ TKTokenKeychainCertificate *certificateItem = [[TKTokenKeychainCertificate alloc ] initWithCertificate: (__bridge SecCertificateRef)certificate objectID: certificateID];
143
+ if (certificateItem == nil ) {
144
+ sc_pkcs15_free_certificate (cert);
145
+ continue ;
146
+ }
147
+ [certificateItem setName: certificateName];
148
+ [items addObject: certificateItem];
136
149
sc_pkcs15_free_certificate (cert);
137
- continue ;
150
+
151
+ // Create key item.
152
+ r = sc_pkcs15_find_prkey_by_id (p15card, &cert_info->id , &prkey_obj);
153
+ if (r) {
154
+ sc_log (ctx, " sc_pkcs15_find_prkey_by_id: %s " , sc_strerror (r));
155
+ continue ;
156
+ }
157
+ struct sc_pkcs15_prkey_info *prkey_info = (struct sc_pkcs15_prkey_info *) prkey_obj->data ;
158
+ NSData * keyID = idToData (app_index, TYPE_PRIV, &prkey_info->id );
159
+ NSString *keyName = [NSString stringWithUTF8String: objs[i]->label];
160
+ TKTokenKeychainKey *keyItem = [[TKTokenKeychainKey alloc ] initWithCertificate: (__bridge SecCertificateRef)certificate objectID: keyID];
161
+ if (keyID == nil || keyName == nil || keyItem == nil ) {
162
+ continue ;
163
+ }
164
+ [keyItem setName: keyName];
165
+
166
+ NSMutableDictionary <NSNumber *, TKTokenOperationConstraint> *constraints = [NSMutableDictionary dictionary ];
167
+ TKTokenOperationConstraint constraint;
168
+ if (prkey_obj->auth_id .len == 0 ) {
169
+ /* true, indicating that the operation is always allowed, without any authentication necessary. */
170
+ constraint = @YES ;
171
+ } else {
172
+ /* Any other property list compatible value defined by the implementation of the token extension. Any such constraint is required to stay constant for the entire lifetime of the token. */
173
+ constraint = idToData (app_index, TYPE_AUTH, &prkey_obj->auth_id );
174
+ }
175
+
176
+ if (USAGE_ANY_SIGN & prkey_info->usage ) {
177
+ keyItem.canSign = YES ;
178
+ constraints[@(TKTokenOperationSignData)] = constraint;
179
+ } else {
180
+ keyItem.canSign = NO ;
181
+ }
182
+ keyItem.suitableForLogin = keyItem.canSign ;
183
+
184
+ if (USAGE_ANY_DECIPHER & prkey_info->usage ) {
185
+ keyItem.canDecrypt = YES ;
186
+ constraints[@(TKTokenOperationDecryptData)] = constraint;
187
+ } else {
188
+ keyItem.canDecrypt = NO ;
189
+ }
190
+
191
+ if (USAGE_ANY_AGREEMENT & prkey_info->usage ) {
192
+ keyItem.canPerformKeyExchange = YES ;
193
+ constraints[@(TKTokenOperationPerformKeyExchange)] = constraint;
194
+ } else {
195
+ keyItem.canPerformKeyExchange = NO ;
196
+ }
197
+
198
+ keyItem.constraints = constraints;
199
+ [items addObject: keyItem];
138
200
}
139
- [certificateItem setName: certificateName];
140
- [items addObject: certificateItem];
141
- sc_pkcs15_free_certificate (cert);
142
-
143
- // Create key item.
144
- r = sc_pkcs15_find_prkey_by_id (p15card, &cert_info->id , &prkey_obj);
145
- if (r) {
146
- sc_log (ctx, " sc_pkcs15_find_prkey_by_id: %s " , sc_strerror (r));
147
- continue ;
148
- }
149
- struct sc_pkcs15_prkey_info *prkey_info = (struct sc_pkcs15_prkey_info *) prkey_obj->data ;
150
- NSData * keyID = idToData (TYPE_PRIV, &prkey_info->id );
151
- NSString *keyName = [NSString stringWithUTF8String: objs[i]->label];
152
- TKTokenKeychainKey *keyItem = [[TKTokenKeychainKey alloc ] initWithCertificate: (__bridge SecCertificateRef)certificate objectID: keyID];
153
- if (keyID == nil || keyName == nil || keyItem == nil ) {
154
- continue ;
155
- }
156
- [keyItem setName: keyName];
157
-
158
- NSMutableDictionary <NSNumber *, TKTokenOperationConstraint> *constraints = [NSMutableDictionary dictionary ];
159
- TKTokenOperationConstraint constraint;
160
- if (prkey_obj->auth_id .len == 0 ) {
161
- /* true, indicating that the operation is always allowed, without any authentication necessary. */
162
- constraint = @YES ;
163
- } else {
164
- /* Any other property list compatible value defined by the implementation of the token extension. Any such constraint is required to stay constant for the entire lifetime of the token. */
165
- constraint = idToData (TYPE_AUTH, &prkey_obj->auth_id );
166
- }
167
-
168
- if (USAGE_ANY_SIGN & prkey_info->usage ) {
169
- keyItem.canSign = YES ;
170
- constraints[@(TKTokenOperationSignData)] = constraint;
171
- } else {
172
- keyItem.canSign = NO ;
173
- }
174
- keyItem.suitableForLogin = keyItem.canSign ;
175
201
176
- if (USAGE_ANY_DECIPHER & prkey_info->usage ) {
177
- keyItem.canDecrypt = YES ;
178
- constraints[@(TKTokenOperationDecryptData)] = constraint;
179
- } else {
180
- keyItem.canDecrypt = NO ;
181
- }
202
+ /* some tokens do not report a serial number */
203
+ if (p15card->tokeninfo != NULL && p15card->tokeninfo ->serial_number != NULL )
204
+ instanceID = [NSString stringWithUTF8String: p15card->tokeninfo->serial_number];
205
+ p15card->opts .use_pin_cache = 0 ;
182
206
183
- if (USAGE_ANY_AGREEMENT & prkey_info->usage ) {
184
- keyItem.canPerformKeyExchange = YES ;
185
- constraints[@(TKTokenOperationPerformKeyExchange)] = constraint;
186
- } else {
187
- keyItem.canPerformKeyExchange = NO ;
188
- }
189
-
190
- keyItem.constraints = constraints;
191
- [items addObject: keyItem];
207
+ /* find the next application. Note that the "generic" application is at index 0, which means that the apps from card->app are taking the **subsequent** slots */
208
+ if (app_index >= card->app_count )
209
+ break ;
210
+ aid = &card->app [app_index]->aid ;
211
+ app_index++;
212
+ /* go to the beginning of the loop and try to bind the next application */
213
+ p15card = NULL ;
192
214
}
193
-
194
- /* some tokens do not report a serial number */
195
- if (p15card->tokeninfo != NULL && p15card->tokeninfo ->serial_number != NULL )
196
- instanceID = [NSString stringWithUTF8String: p15card->tokeninfo->serial_number];
197
- p15card->opts .use_pin_cache = 0 ;
198
215
199
216
if (self = [super initWithSmartCard: smartCard AID: AID instanceID: instanceID tokenDriver: tokenDriver]) {
200
217
[self .keychainContents fillWithItems: items];
201
-
202
218
self.ctx = ctx;
203
219
self.card = card;
204
- self.p15card = p15card ;
220
+ self.apps = apps ;
205
221
} else {
206
222
goto err;
207
223
}
208
224
209
225
err:
210
- if (!self.p15card && p15card)
211
- sc_pkcs15_card_free (p15card);
226
+ for (app_index = 0 ; app_index < SC_TOKEN_APPS_MAX_NUM; app_index++) {
227
+ if (!self.apps .p15card [app_index] && apps.p15card [app_index])
228
+ sc_pkcs15_card_free (apps.p15card [app_index]);
229
+ }
212
230
if (!self.card && card)
213
231
sc_disconnect_card (card);
214
232
if (!self.ctx && ctx)
@@ -217,11 +235,13 @@ - (nullable instancetype)initWithSmartCard:(TKSmartCard *)smartCard AID:(nullabl
217
235
}
218
236
219
237
- (void )dealloc {
220
- sc_pkcs15_card_free (self.p15card );
238
+ for (size_t app_index = 0 ; app_index < SC_TOKEN_APPS_MAX_NUM; app_index++) {
239
+ sc_pkcs15_card_free (self.apps .p15card [app_index]);
240
+ self.apps .p15card [app_index] = NULL ;
241
+ }
221
242
sc_disconnect_card (self.card );
222
243
sc_release_context (self.ctx );
223
244
self.card = NULL ;
224
- self.p15card = NULL ;
225
245
self.ctx = NULL ;
226
246
}
227
247
0 commit comments