|
|
1.1 ! root 1: /* ! 2: * implement the applets for the CAC card. ! 3: * ! 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. ! 6: */ ! 7: ! 8: #include "qemu-common.h" ! 9: ! 10: #include "cac.h" ! 11: #include "vcard.h" ! 12: #include "vcard_emul.h" ! 13: #include "card_7816.h" ! 14: ! 15: #define CAC_GET_PROPERTIES 0x56 ! 16: #define CAC_GET_ACR 0x4c ! 17: #define CAC_READ_BUFFER 0x52 ! 18: #define CAC_UPDATE_BUFFER 0x58 ! 19: #define CAC_SIGN_DECRYPT 0x42 ! 20: #define CAC_GET_CERTIFICATE 0x36 ! 21: ! 22: /* private data for PKI applets */ ! 23: typedef struct CACPKIAppletDataStruct { ! 24: unsigned char *cert; ! 25: int cert_len; ! 26: unsigned char *cert_buffer; ! 27: int cert_buffer_len; ! 28: unsigned char *sign_buffer; ! 29: int sign_buffer_len; ! 30: VCardKey *key; ! 31: } CACPKIAppletData; ! 32: ! 33: /* ! 34: * CAC applet private data ! 35: */ ! 36: struct VCardAppletPrivateStruct { ! 37: union { ! 38: CACPKIAppletData pki_data; ! 39: void *reserved; ! 40: } u; ! 41: }; ! 42: ! 43: /* ! 44: * handle all the APDU's that are common to all CAC applets ! 45: */ ! 46: static VCardStatus ! 47: cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) ! 48: { ! 49: int ef; ! 50: ! 51: switch (apdu->a_ins) { ! 52: case VCARD7816_INS_SELECT_FILE: ! 53: if (apdu->a_p1 != 0x02) { ! 54: /* let the 7816 code handle applet switches */ ! 55: return VCARD_NEXT; ! 56: } ! 57: /* handle file id setting */ ! 58: if (apdu->a_Lc != 2) { ! 59: *response = vcard_make_response( ! 60: VCARD7816_STATUS_ERROR_DATA_INVALID); ! 61: return VCARD_DONE; ! 62: } ! 63: /* CAC 1.0 only supports ef = 0 */ ! 64: ef = apdu->a_body[0] | (apdu->a_body[1] << 8); ! 65: if (ef != 0) { ! 66: *response = vcard_make_response( ! 67: VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); ! 68: return VCARD_DONE; ! 69: } ! 70: *response = vcard_make_response(VCARD7816_STATUS_SUCCESS); ! 71: return VCARD_DONE; ! 72: case VCARD7816_INS_GET_RESPONSE: ! 73: case VCARD7816_INS_VERIFY: ! 74: /* let the 7816 code handle these */ ! 75: return VCARD_NEXT; ! 76: case CAC_GET_PROPERTIES: ! 77: case CAC_GET_ACR: ! 78: /* skip these for now, this will probably be needed */ ! 79: *response = vcard_make_response(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); ! 80: return VCARD_DONE; ! 81: } ! 82: *response = vcard_make_response( ! 83: VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); ! 84: return VCARD_DONE; ! 85: } ! 86: ! 87: /* ! 88: * reset the inter call state between applet selects ! 89: */ ! 90: static VCardStatus ! 91: cac_applet_pki_reset(VCard *card, int channel) ! 92: { ! 93: VCardAppletPrivate *applet_private = NULL; ! 94: CACPKIAppletData *pki_applet = NULL; ! 95: applet_private = vcard_get_current_applet_private(card, channel); ! 96: assert(applet_private); ! 97: pki_applet = &(applet_private->u.pki_data); ! 98: ! 99: pki_applet->cert_buffer = NULL; ! 100: if (pki_applet->sign_buffer) { ! 101: qemu_free(pki_applet->sign_buffer); ! 102: pki_applet->sign_buffer = NULL; ! 103: } ! 104: pki_applet->cert_buffer_len = 0; ! 105: pki_applet->sign_buffer_len = 0; ! 106: return VCARD_DONE; ! 107: } ! 108: ! 109: static VCardStatus ! 110: cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu, ! 111: VCardResponse **response) ! 112: { ! 113: CACPKIAppletData *pki_applet = NULL; ! 114: VCardAppletPrivate *applet_private = NULL; ! 115: int size, next; ! 116: unsigned char *sign_buffer; ! 117: vcard_7816_status_t status; ! 118: ! 119: applet_private = vcard_get_current_applet_private(card, apdu->a_channel); ! 120: assert(applet_private); ! 121: pki_applet = &(applet_private->u.pki_data); ! 122: ! 123: switch (apdu->a_ins) { ! 124: case CAC_UPDATE_BUFFER: ! 125: *response = vcard_make_response( ! 126: VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); ! 127: return VCARD_DONE; ! 128: case CAC_GET_CERTIFICATE: ! 129: if ((apdu->a_p2 != 0) || (apdu->a_p1 != 0)) { ! 130: *response = vcard_make_response( ! 131: VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); ! 132: break; ! 133: } ! 134: assert(pki_applet->cert != NULL); ! 135: size = apdu->a_Le; ! 136: if (pki_applet->cert_buffer == NULL) { ! 137: pki_applet->cert_buffer = pki_applet->cert; ! 138: pki_applet->cert_buffer_len = pki_applet->cert_len; ! 139: } ! 140: size = MIN(size, pki_applet->cert_buffer_len); ! 141: next = MIN(255, pki_applet->cert_buffer_len - size); ! 142: *response = vcard_response_new_bytes( ! 143: card, pki_applet->cert_buffer, size, ! 144: apdu->a_Le, next ? ! 145: VCARD7816_SW1_WARNING_CHANGE : ! 146: VCARD7816_SW1_SUCCESS, ! 147: next); ! 148: pki_applet->cert_buffer += size; ! 149: pki_applet->cert_buffer_len -= size; ! 150: if ((*response == NULL) || (next == 0)) { ! 151: pki_applet->cert_buffer = NULL; ! 152: } ! 153: if (*response == NULL) { ! 154: *response = vcard_make_response( ! 155: VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); ! 156: } ! 157: return VCARD_DONE; ! 158: case CAC_SIGN_DECRYPT: ! 159: if (apdu->a_p2 != 0) { ! 160: *response = vcard_make_response( ! 161: VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); ! 162: break; ! 163: } ! 164: size = apdu->a_Lc; ! 165: ! 166: sign_buffer = realloc(pki_applet->sign_buffer, ! 167: pki_applet->sign_buffer_len+size); ! 168: if (sign_buffer == NULL) { ! 169: qemu_free(pki_applet->sign_buffer); ! 170: pki_applet->sign_buffer = NULL; ! 171: pki_applet->sign_buffer_len = 0; ! 172: *response = vcard_make_response( ! 173: VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); ! 174: return VCARD_DONE; ! 175: } ! 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) { ! 179: case 0x80: ! 180: /* p1 == 0x80 means we haven't yet sent the whole buffer, wait for ! 181: * the rest */ ! 182: pki_applet->sign_buffer = sign_buffer; ! 183: pki_applet->sign_buffer_len = size; ! 184: *response = vcard_make_response(VCARD7816_STATUS_SUCCESS); ! 185: return VCARD_DONE; ! 186: case 0x00: ! 187: /* we now have the whole buffer, do the operation, result will be ! 188: * in the sign_buffer */ ! 189: status = vcard_emul_rsa_op(card, pki_applet->key, ! 190: sign_buffer, size); ! 191: if (status != VCARD7816_STATUS_SUCCESS) { ! 192: *response = vcard_make_response(status); ! 193: break; ! 194: } ! 195: *response = vcard_response_new(card, sign_buffer, size, apdu->a_Le, ! 196: VCARD7816_STATUS_SUCCESS); ! 197: if (*response == NULL) { ! 198: *response = vcard_make_response( ! 199: VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); ! 200: } ! 201: break; ! 202: default: ! 203: *response = vcard_make_response( ! 204: VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); ! 205: break; ! 206: } ! 207: qemu_free(sign_buffer); ! 208: pki_applet->sign_buffer = NULL; ! 209: pki_applet->sign_buffer_len = 0; ! 210: return VCARD_DONE; ! 211: case CAC_READ_BUFFER: ! 212: /* new CAC call, go ahead and use the old version for now */ ! 213: /* TODO: implement */ ! 214: *response = vcard_make_response( ! 215: VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); ! 216: return VCARD_DONE; ! 217: } ! 218: return cac_common_process_apdu(card, apdu, response); ! 219: } ! 220: ! 221: ! 222: static VCardStatus ! 223: cac_applet_id_process_apdu(VCard *card, VCardAPDU *apdu, ! 224: VCardResponse **response) ! 225: { ! 226: switch (apdu->a_ins) { ! 227: case CAC_UPDATE_BUFFER: ! 228: *response = vcard_make_response( ! 229: VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); ! 230: return VCARD_DONE; ! 231: case CAC_READ_BUFFER: ! 232: /* new CAC call, go ahead and use the old version for now */ ! 233: /* TODO: implement */ ! 234: *response = vcard_make_response( ! 235: VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); ! 236: return VCARD_DONE; ! 237: } ! 238: return cac_common_process_apdu(card, apdu, response); ! 239: } ! 240: ! 241: ! 242: /* ! 243: * TODO: if we ever want to support general CAC middleware, we will need to ! 244: * implement the various containers. ! 245: */ ! 246: static VCardStatus ! 247: cac_applet_container_process_apdu(VCard *card, VCardAPDU *apdu, ! 248: VCardResponse **response) ! 249: { ! 250: switch (apdu->a_ins) { ! 251: case CAC_READ_BUFFER: ! 252: case CAC_UPDATE_BUFFER: ! 253: *response = vcard_make_response( ! 254: VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); ! 255: return VCARD_DONE; ! 256: default: ! 257: break; ! 258: } ! 259: return cac_common_process_apdu(card, apdu, response); ! 260: } ! 261: ! 262: /* ! 263: * utilities for creating and destroying the private applet data ! 264: */ ! 265: static void ! 266: cac_delete_pki_applet_private(VCardAppletPrivate *applet_private) ! 267: { ! 268: CACPKIAppletData *pki_applet_data = NULL; ! 269: if (pki_applet_data == NULL) { ! 270: return; ! 271: } ! 272: pki_applet_data = &(applet_private->u.pki_data); ! 273: if (pki_applet_data->cert != NULL) { ! 274: qemu_free(pki_applet_data->cert); ! 275: } ! 276: if (pki_applet_data->sign_buffer != NULL) { ! 277: qemu_free(pki_applet_data->sign_buffer); ! 278: } ! 279: if (pki_applet_data->key != NULL) { ! 280: vcard_emul_delete_key(pki_applet_data->key); ! 281: } ! 282: qemu_free(applet_private); ! 283: } ! 284: ! 285: static VCardAppletPrivate * ! 286: cac_new_pki_applet_private(const unsigned char *cert, ! 287: int cert_len, VCardKey *key) ! 288: { ! 289: CACPKIAppletData *pki_applet_data = NULL; ! 290: VCardAppletPrivate *applet_private = NULL; ! 291: applet_private = (VCardAppletPrivate *)qemu_malloc(sizeof(VCardAppletPrivate)); ! 292: ! 293: pki_applet_data = &(applet_private->u.pki_data); ! 294: pki_applet_data->cert_buffer = NULL; ! 295: pki_applet_data->cert_buffer_len = 0; ! 296: pki_applet_data->sign_buffer = NULL; ! 297: pki_applet_data->sign_buffer_len = 0; ! 298: pki_applet_data->key = NULL; ! 299: pki_applet_data->cert = (unsigned char *)qemu_malloc(cert_len+1); ! 300: /* ! 301: * if we want to support compression, then we simply change the 0 to a 1 ! 302: * and compress the cert data with libz ! 303: */ ! 304: pki_applet_data->cert[0] = 0; /* not compressed */ ! 305: memcpy(&pki_applet_data->cert[1], cert, cert_len); ! 306: pki_applet_data->cert_len = cert_len+1; ! 307: ! 308: pki_applet_data->key = key; ! 309: return applet_private; ! 310: } ! 311: ! 312: ! 313: /* ! 314: * create a new cac applet which links to a given cert ! 315: */ ! 316: static VCardApplet * ! 317: cac_new_pki_applet(int i, const unsigned char *cert, ! 318: int cert_len, VCardKey *key) ! 319: { ! 320: VCardAppletPrivate *applet_private = NULL; ! 321: VCardApplet *applet = NULL; ! 322: unsigned char pki_aid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 }; ! 323: int pki_aid_len = sizeof(pki_aid); ! 324: ! 325: pki_aid[pki_aid_len-1] = i; ! 326: ! 327: applet_private = cac_new_pki_applet_private(cert, cert_len, key); ! 328: if (applet_private == NULL) { ! 329: goto failure; ! 330: } ! 331: applet = vcard_new_applet(cac_applet_pki_process_apdu, cac_applet_pki_reset, ! 332: pki_aid, pki_aid_len); ! 333: if (applet == NULL) { ! 334: goto failure; ! 335: } ! 336: vcard_set_applet_private(applet, applet_private, ! 337: cac_delete_pki_applet_private); ! 338: applet_private = NULL; ! 339: ! 340: return applet; ! 341: ! 342: failure: ! 343: if (applet_private != NULL) { ! 344: cac_delete_pki_applet_private(applet_private); ! 345: } ! 346: return NULL; ! 347: } ! 348: ! 349: ! 350: static unsigned char cac_default_container_aid[] = { ! 351: 0xa0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00 }; ! 352: static unsigned char cac_id_aid[] = { ! 353: 0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00 }; ! 354: /* ! 355: * Initialize the cac card. This is the only public function in this file. All ! 356: * the rest are connected through function pointers. ! 357: */ ! 358: VCardStatus ! 359: cac_card_init(VReader *reader, VCard *card, ! 360: const char *params, ! 361: unsigned char * const *cert, ! 362: int cert_len[], ! 363: VCardKey *key[] /* adopt the keys*/, ! 364: int cert_count) ! 365: { ! 366: int i; ! 367: VCardApplet *applet; ! 368: ! 369: /* CAC Cards are VM Cards */ ! 370: vcard_set_type(card, VCARD_VM); ! 371: ! 372: /* create one PKI applet for each cert */ ! 373: for (i = 0; i < cert_count; i++) { ! 374: applet = cac_new_pki_applet(i, cert[i], cert_len[i], key[i]); ! 375: if (applet == NULL) { ! 376: goto failure; ! 377: } ! 378: vcard_add_applet(card, applet); ! 379: } ! 380: ! 381: /* create a default blank container applet */ ! 382: applet = vcard_new_applet(cac_applet_container_process_apdu, ! 383: NULL, cac_default_container_aid, ! 384: sizeof(cac_default_container_aid)); ! 385: if (applet == NULL) { ! 386: goto failure; ! 387: } ! 388: vcard_add_applet(card, applet); ! 389: ! 390: /* create a default blank container applet */ ! 391: applet = vcard_new_applet(cac_applet_id_process_apdu, ! 392: NULL, cac_id_aid, ! 393: sizeof(cac_id_aid)); ! 394: if (applet == NULL) { ! 395: goto failure; ! 396: } ! 397: vcard_add_applet(card, applet); ! 398: return VCARD_DONE; ! 399: ! 400: failure: ! 401: return VCARD_FAIL; ! 402: } ! 403:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.