@@ -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;
61
+ size_t i, app_index, cert_num;
62
62
NSMutableArray <TKTokenKeychainItem *> *items;
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
@@ -103,112 +108,128 @@ - (nullable instancetype)initWithSmartCard:(TKSmartCard *)smartCard AID:(nullabl
103
108
EAC_set_x509_default_dir (Resources.fileSystemRepresentation );
104
109
}
105
110
111
+ items = [[NSMutableArray alloc ] init ];
112
+
106
113
app_generic = sc_pkcs15_get_application_by_type (card, " generic" );
107
114
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
115
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 ) {
116
+ /* Bind all applications starting with the "generic" one */
117
+ for (app_index = 0 ; app_index < SC_TOKEN_APPS_MAX_NUM; app_index++) {
118
+ r = sc_pkcs15_bind (card, aid, &p15card);
119
+ LOG_TEST_GOTO_ERR (ctx, r, " sc_pkcs15_bind" );
120
+
121
+ r = sc_pkcs15_get_objects (p15card, SC_PKCS15_TYPE_CERT_X509, objs, sizeof (objs)/(sizeof *objs));
122
+ LOG_TEST_GOTO_ERR (ctx, r, " sc_pkcs15_get_objects (SC_PKCS15_TYPE_CERT_X509)" );
123
+ cert_num = (size_t ) r;
124
+ for (i = 0 ; i < cert_num; i++) {
125
+ struct sc_pkcs15_cert_info *cert_info = objs[i]->data ;
126
+ struct sc_pkcs15_cert *cert = NULL ;
127
+ struct sc_pkcs15_object *prkey_obj = NULL ;
128
+ int private_obj = objs[i]->flags & SC_PKCS15_CO_FLAG_PRIVATE;
129
+
130
+ r = sc_pkcs15_read_certificate (p15card, cert_info, private_obj, &cert);
131
+ if (r) {
132
+ sc_log (ctx, " sc_pkcs15_read_certificate: %s " , sc_strerror (r));
133
+ continue ;
134
+ }
135
+ NSData * certificateData = [NSData dataWithBytes: (const void *)cert->data.value length: sizeof (unsigned char )*cert->data.len];
136
+ NSData * certificateID = idToData (app_index, TYPE_CERT, &cert_info->id );
137
+ NSString *certificateName = [NSString stringWithUTF8String: objs[i]->label];
138
+ id certificate = CFBridgingRelease (SecCertificateCreateWithData (kCFAllocatorDefault , (CFDataRef)certificateData));
139
+ if (certificateData == nil || certificateID == nil || certificateName == nil || certificate == NULL ) {
140
+ sc_pkcs15_free_certificate (cert);
141
+ continue ;
142
+ }
143
+ TKTokenKeychainCertificate *certificateItem = [[TKTokenKeychainCertificate alloc ] initWithCertificate: (__bridge SecCertificateRef)certificate objectID: certificateID];
144
+ if (certificateItem == nil ) {
145
+ sc_pkcs15_free_certificate (cert);
146
+ continue ;
147
+ }
148
+ [certificateItem setName: certificateName];
149
+ [items addObject: certificateItem];
136
150
sc_pkcs15_free_certificate (cert);
137
- continue ;
138
- }
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 );
151
+
152
+ // Create key item.
153
+ r = sc_pkcs15_find_prkey_by_id (p15card, &cert_info->id , &prkey_obj);
154
+ if (r) {
155
+ sc_log (ctx, " sc_pkcs15_find_prkey_by_id: %s " , sc_strerror (r));
156
+ continue ;
157
+ }
158
+ struct sc_pkcs15_prkey_info *prkey_info = (struct sc_pkcs15_prkey_info *) prkey_obj->data ;
159
+ NSData * keyID = idToData (app_index, TYPE_PRIV, &prkey_info->id );
160
+ NSString *keyName = [NSString stringWithUTF8String: objs[i]->label];
161
+ TKTokenKeychainKey *keyItem = [[TKTokenKeychainKey alloc ] initWithCertificate: (__bridge SecCertificateRef)certificate objectID: keyID];
162
+ if (keyID == nil || keyName == nil || keyItem == nil ) {
163
+ continue ;
164
+ }
165
+ [keyItem setName: keyName];
166
+
167
+ NSMutableDictionary <NSNumber *, TKTokenOperationConstraint> *constraints = [NSMutableDictionary dictionary ];
168
+ TKTokenOperationConstraint constraint;
169
+ if (prkey_obj->auth_id .len == 0 ) {
170
+ /* true, indicating that the operation is always allowed, without any authentication necessary. */
171
+ constraint = @YES ;
172
+ } else {
173
+ /* 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. */
174
+ constraint = idToData (app_index, TYPE_AUTH, &prkey_obj->auth_id );
175
+ }
176
+
177
+ if (USAGE_ANY_SIGN & prkey_info->usage ) {
178
+ keyItem.canSign = YES ;
179
+ constraints[@(TKTokenOperationSignData)] = constraint;
180
+ } else {
181
+ keyItem.canSign = NO ;
182
+ }
183
+ keyItem.suitableForLogin = keyItem.canSign ;
184
+
185
+ if (USAGE_ANY_DECIPHER & prkey_info->usage ) {
186
+ keyItem.canDecrypt = YES ;
187
+ constraints[@(TKTokenOperationDecryptData)] = constraint;
188
+ } else {
189
+ keyItem.canDecrypt = NO ;
190
+ }
191
+
192
+ if (USAGE_ANY_AGREEMENT & prkey_info->usage ) {
193
+ keyItem.canPerformKeyExchange = YES ;
194
+ constraints[@(TKTokenOperationPerformKeyExchange)] = constraint;
195
+ } else {
196
+ keyItem.canPerformKeyExchange = NO ;
197
+ }
198
+
199
+ keyItem.constraints = constraints;
200
+ [items addObject: keyItem];
166
201
}
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
202
176
- if (USAGE_ANY_DECIPHER & prkey_info->usage ) {
177
- keyItem.canDecrypt = YES ;
178
- constraints[@(TKTokenOperationDecryptData)] = constraint;
179
- } else {
180
- keyItem.canDecrypt = NO ;
181
- }
203
+ /* some tokens do not report a serial number */
204
+ if (p15card->tokeninfo != NULL && p15card->tokeninfo ->serial_number != NULL )
205
+ instanceID = [NSString stringWithUTF8String: p15card->tokeninfo->serial_number];
206
+ p15card->opts .use_pin_cache = 0 ;
182
207
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];
208
+ apps.p15card [app_index] = p15card;
209
+
210
+ /* 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 */
211
+ if (app_index >= card->app_count )
212
+ break ;
213
+ aid = &card->app [app_index]->aid ;
214
+ app_index++;
215
+ /* go to the beginning of the loop and try to bind the next application */
192
216
}
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
217
199
218
if (self = [super initWithSmartCard: smartCard AID: AID instanceID: instanceID tokenDriver: tokenDriver]) {
200
219
[self .keychainContents fillWithItems: items];
201
220
202
221
self.ctx = ctx;
203
222
self.card = card;
204
- self.p15card = p15card ;
223
+ self.apps = apps ;
205
224
} else {
206
225
goto err;
207
226
}
208
227
209
228
err:
210
- if (!self.p15card && p15card)
211
- sc_pkcs15_card_free (p15card);
229
+ for (app_index = 0 ; app_index < SC_TOKEN_APPS_MAX_NUM; app_index++) {
230
+ if (!self.apps .p15card [app_index] && apps.p15card [app_index])
231
+ sc_pkcs15_card_free (apps.p15card [app_index]);
232
+ }
212
233
if (!self.card && card)
213
234
sc_disconnect_card (card);
214
235
if (!self.ctx && ctx)
@@ -217,11 +238,13 @@ - (nullable instancetype)initWithSmartCard:(TKSmartCard *)smartCard AID:(nullabl
217
238
}
218
239
219
240
- (void )dealloc {
220
- sc_pkcs15_card_free (self.p15card );
241
+ for (size_t app_index = 0 ; app_index < SC_TOKEN_APPS_MAX_NUM; app_index++) {
242
+ sc_pkcs15_card_free (self.apps .p15card [app_index]);
243
+ self.apps .p15card [app_index] = NULL ;
244
+ }
221
245
sc_disconnect_card (self.card );
222
246
sc_release_context (self.ctx );
223
247
self.card = NULL ;
224
- self.p15card = NULL ;
225
248
self.ctx = NULL ;
226
249
}
227
250
0 commit comments