2 * implement the applets for the CAC card.
4 * This code is licensed under the GNU LGPL, version 2.1 or later.
5 * See the COPYING.LIB file in the top-level directory.
8 #include "glib-compat.h"
15 #include "vcard_emul.h"
16 #include "card_7816.h"
18 /* private data for PKI applets */
19 typedef struct CACPKIAppletDataStruct
{
22 unsigned char *cert_buffer
;
24 unsigned char *sign_buffer
;
30 * CAC applet private data
32 struct VCardAppletPrivateStruct
{
34 CACPKIAppletData pki_data
;
40 * handle all the APDU's that are common to all CAC applets
43 cac_common_process_apdu(VCard
*card
, VCardAPDU
*apdu
, VCardResponse
**response
)
46 VCardStatus ret
= VCARD_FAIL
;
48 switch (apdu
->a_ins
) {
49 case VCARD7816_INS_SELECT_FILE
:
50 if (apdu
->a_p1
!= 0x02) {
51 /* let the 7816 code handle applet switches */
55 /* handle file id setting */
56 if (apdu
->a_Lc
!= 2) {
57 *response
= vcard_make_response(
58 VCARD7816_STATUS_ERROR_DATA_INVALID
);
62 /* CAC 1.0 only supports ef = 0 */
63 ef
= apdu
->a_body
[0] | (apdu
->a_body
[1] << 8);
65 *response
= vcard_make_response(
66 VCARD7816_STATUS_ERROR_FILE_NOT_FOUND
);
70 *response
= vcard_make_response(VCARD7816_STATUS_SUCCESS
);
73 case VCARD7816_INS_GET_RESPONSE
:
74 case VCARD7816_INS_VERIFY
:
75 /* let the 7816 code handle these */
78 case CAC_GET_PROPERTIES
:
80 /* skip these for now, this will probably be needed */
81 *response
= vcard_make_response(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT
);
85 *response
= vcard_make_response(
86 VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED
);
94 * reset the inter call state between applet selects
97 cac_applet_pki_reset(VCard
*card
, int channel
)
99 VCardAppletPrivate
*applet_private
;
100 CACPKIAppletData
*pki_applet
;
101 applet_private
= vcard_get_current_applet_private(card
, channel
);
102 assert(applet_private
);
103 pki_applet
= &(applet_private
->u
.pki_data
);
105 pki_applet
->cert_buffer
= NULL
;
106 g_free(pki_applet
->sign_buffer
);
107 pki_applet
->sign_buffer
= NULL
;
108 pki_applet
->cert_buffer_len
= 0;
109 pki_applet
->sign_buffer_len
= 0;
114 cac_applet_pki_process_apdu(VCard
*card
, VCardAPDU
*apdu
,
115 VCardResponse
**response
)
117 CACPKIAppletData
*pki_applet
;
118 VCardAppletPrivate
*applet_private
;
120 unsigned char *sign_buffer
;
121 bool retain_sign_buffer
= FALSE
;
122 vcard_7816_status_t status
;
123 VCardStatus ret
= VCARD_FAIL
;
125 applet_private
= vcard_get_current_applet_private(card
, apdu
->a_channel
);
126 assert(applet_private
);
127 pki_applet
= &(applet_private
->u
.pki_data
);
129 switch (apdu
->a_ins
) {
130 case CAC_UPDATE_BUFFER
:
131 *response
= vcard_make_response(
132 VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED
);
135 case CAC_GET_CERTIFICATE
:
136 if ((apdu
->a_p2
!= 0) || (apdu
->a_p1
!= 0)) {
137 *response
= vcard_make_response(
138 VCARD7816_STATUS_ERROR_P1_P2_INCORRECT
);
141 assert(pki_applet
->cert
!= NULL
);
143 if (pki_applet
->cert_buffer
== NULL
) {
144 pki_applet
->cert_buffer
= pki_applet
->cert
;
145 pki_applet
->cert_buffer_len
= pki_applet
->cert_len
;
147 size
= MIN(size
, pki_applet
->cert_buffer_len
);
148 next
= MIN(255, pki_applet
->cert_buffer_len
- size
);
149 *response
= vcard_response_new_bytes(
150 card
, pki_applet
->cert_buffer
, size
,
152 VCARD7816_SW1_WARNING_CHANGE
:
153 VCARD7816_SW1_SUCCESS
,
155 pki_applet
->cert_buffer
+= size
;
156 pki_applet
->cert_buffer_len
-= size
;
157 if ((*response
== NULL
) || (next
== 0)) {
158 pki_applet
->cert_buffer
= NULL
;
160 if (*response
== NULL
) {
161 *response
= vcard_make_response(
162 VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE
);
166 case CAC_SIGN_DECRYPT
:
167 if (apdu
->a_p2
!= 0) {
168 *response
= vcard_make_response(
169 VCARD7816_STATUS_ERROR_P1_P2_INCORRECT
);
174 sign_buffer
= g_realloc(pki_applet
->sign_buffer
,
175 pki_applet
->sign_buffer_len
+ size
);
176 memcpy(sign_buffer
+pki_applet
->sign_buffer_len
, apdu
->a_body
, size
);
177 size
+= pki_applet
->sign_buffer_len
;
178 switch (apdu
->a_p1
) {
180 /* p1 == 0x80 means we haven't yet sent the whole buffer, wait for
182 pki_applet
->sign_buffer
= sign_buffer
;
183 pki_applet
->sign_buffer_len
= size
;
184 *response
= vcard_make_response(VCARD7816_STATUS_SUCCESS
);
185 retain_sign_buffer
= TRUE
;
188 /* we now have the whole buffer, do the operation, result will be
189 * in the sign_buffer */
190 status
= vcard_emul_rsa_op(card
, pki_applet
->key
,
192 if (status
!= VCARD7816_STATUS_SUCCESS
) {
193 *response
= vcard_make_response(status
);
196 *response
= vcard_response_new(card
, sign_buffer
, size
, apdu
->a_Le
,
197 VCARD7816_STATUS_SUCCESS
);
198 if (*response
== NULL
) {
199 *response
= vcard_make_response(
200 VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE
);
204 *response
= vcard_make_response(
205 VCARD7816_STATUS_ERROR_P1_P2_INCORRECT
);
208 if (!retain_sign_buffer
) {
210 pki_applet
->sign_buffer
= NULL
;
211 pki_applet
->sign_buffer_len
= 0;
215 case CAC_READ_BUFFER
:
216 /* new CAC call, go ahead and use the old version for now */
217 /* TODO: implement */
218 *response
= vcard_make_response(
219 VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED
);
223 ret
= cac_common_process_apdu(card
, apdu
, response
);
231 cac_applet_id_process_apdu(VCard
*card
, VCardAPDU
*apdu
,
232 VCardResponse
**response
)
234 VCardStatus ret
= VCARD_FAIL
;
236 switch (apdu
->a_ins
) {
237 case CAC_UPDATE_BUFFER
:
238 *response
= vcard_make_response(
239 VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED
);
242 case CAC_READ_BUFFER
:
243 /* new CAC call, go ahead and use the old version for now */
244 /* TODO: implement */
245 *response
= vcard_make_response(
246 VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED
);
250 ret
= cac_common_process_apdu(card
, apdu
, response
);
258 * TODO: if we ever want to support general CAC middleware, we will need to
259 * implement the various containers.
262 cac_applet_container_process_apdu(VCard
*card
, VCardAPDU
*apdu
,
263 VCardResponse
**response
)
265 VCardStatus ret
= VCARD_FAIL
;
267 switch (apdu
->a_ins
) {
268 case CAC_READ_BUFFER
:
269 case CAC_UPDATE_BUFFER
:
270 *response
= vcard_make_response(
271 VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED
);
275 ret
= cac_common_process_apdu(card
, apdu
, response
);
282 * utilities for creating and destroying the private applet data
285 cac_delete_pki_applet_private(VCardAppletPrivate
*applet_private
)
287 CACPKIAppletData
*pki_applet_data
;
289 if (applet_private
== NULL
) {
292 pki_applet_data
= &(applet_private
->u
.pki_data
);
293 g_free(pki_applet_data
->cert
);
294 g_free(pki_applet_data
->sign_buffer
);
295 if (pki_applet_data
->key
!= NULL
) {
296 vcard_emul_delete_key(pki_applet_data
->key
);
298 g_free(applet_private
);
301 static VCardAppletPrivate
*
302 cac_new_pki_applet_private(const unsigned char *cert
,
303 int cert_len
, VCardKey
*key
)
305 CACPKIAppletData
*pki_applet_data
;
306 VCardAppletPrivate
*applet_private
;
308 applet_private
= g_new0(VCardAppletPrivate
, 1);
309 pki_applet_data
= &(applet_private
->u
.pki_data
);
310 pki_applet_data
->cert
= (unsigned char *)g_malloc(cert_len
+1);
312 * if we want to support compression, then we simply change the 0 to a 1
313 * and compress the cert data with libz
315 pki_applet_data
->cert
[0] = 0; /* not compressed */
316 memcpy(&pki_applet_data
->cert
[1], cert
, cert_len
);
317 pki_applet_data
->cert_len
= cert_len
+1;
319 pki_applet_data
->key
= key
;
320 return applet_private
;
325 * create a new cac applet which links to a given cert
328 cac_new_pki_applet(int i
, const unsigned char *cert
,
329 int cert_len
, VCardKey
*key
)
331 VCardAppletPrivate
*applet_private
;
333 unsigned char pki_aid
[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 };
334 int pki_aid_len
= sizeof(pki_aid
);
336 pki_aid
[pki_aid_len
-1] = i
;
338 applet_private
= cac_new_pki_applet_private(cert
, cert_len
, key
);
339 if (applet_private
== NULL
) {
342 applet
= vcard_new_applet(cac_applet_pki_process_apdu
, cac_applet_pki_reset
,
343 pki_aid
, pki_aid_len
);
344 if (applet
== NULL
) {
347 vcard_set_applet_private(applet
, applet_private
,
348 cac_delete_pki_applet_private
);
349 applet_private
= NULL
;
354 if (applet_private
!= NULL
) {
355 cac_delete_pki_applet_private(applet_private
);
361 static unsigned char cac_default_container_aid
[] = {
362 0xa0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00 };
363 static unsigned char cac_id_aid
[] = {
364 0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00 };
366 * Initialize the cac card. This is the only public function in this file. All
367 * the rest are connected through function pointers.
370 cac_card_init(VReader
*reader
, VCard
*card
,
372 unsigned char * const *cert
,
374 VCardKey
*key
[] /* adopt the keys*/,
380 /* CAC Cards are VM Cards */
381 vcard_set_type(card
, VCARD_VM
);
383 /* create one PKI applet for each cert */
384 for (i
= 0; i
< cert_count
; i
++) {
385 applet
= cac_new_pki_applet(i
, cert
[i
], cert_len
[i
], key
[i
]);
386 if (applet
== NULL
) {
389 vcard_add_applet(card
, applet
);
392 /* create a default blank container applet */
393 applet
= vcard_new_applet(cac_applet_container_process_apdu
,
394 NULL
, cac_default_container_aid
,
395 sizeof(cac_default_container_aid
));
396 if (applet
== NULL
) {
399 vcard_add_applet(card
, applet
);
401 /* create a default blank container applet */
402 applet
= vcard_new_applet(cac_applet_id_process_apdu
,
405 if (applet
== NULL
) {
408 vcard_add_applet(card
, applet
);