diff options
Diffstat (limited to 'qemu/libcacard/cac.c')
-rw-r--r-- | qemu/libcacard/cac.c | 414 |
1 files changed, 0 insertions, 414 deletions
diff --git a/qemu/libcacard/cac.c b/qemu/libcacard/cac.c deleted file mode 100644 index bc84534f9..000000000 --- a/qemu/libcacard/cac.c +++ /dev/null @@ -1,414 +0,0 @@ -/* - * implement the applets for the CAC card. - * - * This code is licensed under the GNU LGPL, version 2.1 or later. - * See the COPYING.LIB file in the top-level directory. - */ - -#include "glib-compat.h" - -#include <string.h> -#include <stdbool.h> - -#include "cac.h" -#include "vcard.h" -#include "vcard_emul.h" -#include "card_7816.h" - -/* private data for PKI applets */ -typedef struct CACPKIAppletDataStruct { - unsigned char *cert; - int cert_len; - unsigned char *cert_buffer; - int cert_buffer_len; - unsigned char *sign_buffer; - int sign_buffer_len; - VCardKey *key; -} CACPKIAppletData; - -/* - * CAC applet private data - */ -struct VCardAppletPrivateStruct { - union { - CACPKIAppletData pki_data; - void *reserved; - } u; -}; - -/* - * handle all the APDU's that are common to all CAC applets - */ -static VCardStatus -cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response) -{ - int ef; - VCardStatus ret = VCARD_FAIL; - - switch (apdu->a_ins) { - case VCARD7816_INS_SELECT_FILE: - if (apdu->a_p1 != 0x02) { - /* let the 7816 code handle applet switches */ - ret = VCARD_NEXT; - break; - } - /* handle file id setting */ - if (apdu->a_Lc != 2) { - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_DATA_INVALID); - ret = VCARD_DONE; - break; - } - /* CAC 1.0 only supports ef = 0 */ - ef = apdu->a_body[0] | (apdu->a_body[1] << 8); - if (ef != 0) { - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_FILE_NOT_FOUND); - ret = VCARD_DONE; - break; - } - *response = vcard_make_response(VCARD7816_STATUS_SUCCESS); - ret = VCARD_DONE; - break; - case VCARD7816_INS_GET_RESPONSE: - case VCARD7816_INS_VERIFY: - /* let the 7816 code handle these */ - ret = VCARD_NEXT; - break; - case CAC_GET_PROPERTIES: - case CAC_GET_ACR: - /* skip these for now, this will probably be needed */ - *response = vcard_make_response(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); - ret = VCARD_DONE; - break; - default: - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); - ret = VCARD_DONE; - break; - } - return ret; -} - -/* - * reset the inter call state between applet selects - */ -static VCardStatus -cac_applet_pki_reset(VCard *card, int channel) -{ - VCardAppletPrivate *applet_private; - CACPKIAppletData *pki_applet; - applet_private = vcard_get_current_applet_private(card, channel); - assert(applet_private); - pki_applet = &(applet_private->u.pki_data); - - pki_applet->cert_buffer = NULL; - g_free(pki_applet->sign_buffer); - pki_applet->sign_buffer = NULL; - pki_applet->cert_buffer_len = 0; - pki_applet->sign_buffer_len = 0; - return VCARD_DONE; -} - -static VCardStatus -cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu, - VCardResponse **response) -{ - CACPKIAppletData *pki_applet; - VCardAppletPrivate *applet_private; - int size, next; - unsigned char *sign_buffer; - bool retain_sign_buffer = FALSE; - vcard_7816_status_t status; - VCardStatus ret = VCARD_FAIL; - - applet_private = vcard_get_current_applet_private(card, apdu->a_channel); - assert(applet_private); - pki_applet = &(applet_private->u.pki_data); - - switch (apdu->a_ins) { - case CAC_UPDATE_BUFFER: - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); - ret = VCARD_DONE; - break; - case CAC_GET_CERTIFICATE: - if ((apdu->a_p2 != 0) || (apdu->a_p1 != 0)) { - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); - break; - } - assert(pki_applet->cert != NULL); - size = apdu->a_Le; - if (pki_applet->cert_buffer == NULL) { - pki_applet->cert_buffer = pki_applet->cert; - pki_applet->cert_buffer_len = pki_applet->cert_len; - } - size = MIN(size, pki_applet->cert_buffer_len); - next = MIN(255, pki_applet->cert_buffer_len - size); - *response = vcard_response_new_bytes( - card, pki_applet->cert_buffer, size, - apdu->a_Le, next ? - VCARD7816_SW1_WARNING_CHANGE : - VCARD7816_SW1_SUCCESS, - next); - pki_applet->cert_buffer += size; - pki_applet->cert_buffer_len -= size; - if ((*response == NULL) || (next == 0)) { - pki_applet->cert_buffer = NULL; - } - if (*response == NULL) { - *response = vcard_make_response( - VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); - } - ret = VCARD_DONE; - break; - case CAC_SIGN_DECRYPT: - if (apdu->a_p2 != 0) { - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); - break; - } - size = apdu->a_Lc; - - sign_buffer = g_realloc(pki_applet->sign_buffer, - pki_applet->sign_buffer_len + size); - memcpy(sign_buffer+pki_applet->sign_buffer_len, apdu->a_body, size); - size += pki_applet->sign_buffer_len; - switch (apdu->a_p1) { - case 0x80: - /* p1 == 0x80 means we haven't yet sent the whole buffer, wait for - * the rest */ - pki_applet->sign_buffer = sign_buffer; - pki_applet->sign_buffer_len = size; - *response = vcard_make_response(VCARD7816_STATUS_SUCCESS); - retain_sign_buffer = TRUE; - break; - case 0x00: - /* we now have the whole buffer, do the operation, result will be - * in the sign_buffer */ - status = vcard_emul_rsa_op(card, pki_applet->key, - sign_buffer, size); - if (status != VCARD7816_STATUS_SUCCESS) { - *response = vcard_make_response(status); - break; - } - *response = vcard_response_new(card, sign_buffer, size, apdu->a_Le, - VCARD7816_STATUS_SUCCESS); - if (*response == NULL) { - *response = vcard_make_response( - VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE); - } - break; - default: - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_P1_P2_INCORRECT); - break; - } - if (!retain_sign_buffer) { - g_free(sign_buffer); - pki_applet->sign_buffer = NULL; - pki_applet->sign_buffer_len = 0; - } - ret = VCARD_DONE; - break; - case CAC_READ_BUFFER: - /* new CAC call, go ahead and use the old version for now */ - /* TODO: implement */ - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); - ret = VCARD_DONE; - break; - default: - ret = cac_common_process_apdu(card, apdu, response); - break; - } - return ret; -} - - -static VCardStatus -cac_applet_id_process_apdu(VCard *card, VCardAPDU *apdu, - VCardResponse **response) -{ - VCardStatus ret = VCARD_FAIL; - - switch (apdu->a_ins) { - case CAC_UPDATE_BUFFER: - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED); - ret = VCARD_DONE; - break; - case CAC_READ_BUFFER: - /* new CAC call, go ahead and use the old version for now */ - /* TODO: implement */ - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); - ret = VCARD_DONE; - break; - default: - ret = cac_common_process_apdu(card, apdu, response); - break; - } - return ret; -} - - -/* - * TODO: if we ever want to support general CAC middleware, we will need to - * implement the various containers. - */ -static VCardStatus -cac_applet_container_process_apdu(VCard *card, VCardAPDU *apdu, - VCardResponse **response) -{ - VCardStatus ret = VCARD_FAIL; - - switch (apdu->a_ins) { - case CAC_READ_BUFFER: - case CAC_UPDATE_BUFFER: - *response = vcard_make_response( - VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED); - ret = VCARD_DONE; - break; - default: - ret = cac_common_process_apdu(card, apdu, response); - break; - } - return ret; -} - -/* - * utilities for creating and destroying the private applet data - */ -static void -cac_delete_pki_applet_private(VCardAppletPrivate *applet_private) -{ - CACPKIAppletData *pki_applet_data; - - if (applet_private == NULL) { - return; - } - pki_applet_data = &(applet_private->u.pki_data); - g_free(pki_applet_data->cert); - g_free(pki_applet_data->sign_buffer); - if (pki_applet_data->key != NULL) { - vcard_emul_delete_key(pki_applet_data->key); - } - g_free(applet_private); -} - -static VCardAppletPrivate * -cac_new_pki_applet_private(const unsigned char *cert, - int cert_len, VCardKey *key) -{ - CACPKIAppletData *pki_applet_data; - VCardAppletPrivate *applet_private; - - applet_private = g_new0(VCardAppletPrivate, 1); - pki_applet_data = &(applet_private->u.pki_data); - pki_applet_data->cert = (unsigned char *)g_malloc(cert_len+1); - /* - * if we want to support compression, then we simply change the 0 to a 1 - * and compress the cert data with libz - */ - pki_applet_data->cert[0] = 0; /* not compressed */ - memcpy(&pki_applet_data->cert[1], cert, cert_len); - pki_applet_data->cert_len = cert_len+1; - - pki_applet_data->key = key; - return applet_private; -} - - -/* - * create a new cac applet which links to a given cert - */ -static VCardApplet * -cac_new_pki_applet(int i, const unsigned char *cert, - int cert_len, VCardKey *key) -{ - VCardAppletPrivate *applet_private; - VCardApplet *applet; - unsigned char pki_aid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 }; - int pki_aid_len = sizeof(pki_aid); - - pki_aid[pki_aid_len-1] = i; - - applet_private = cac_new_pki_applet_private(cert, cert_len, key); - if (applet_private == NULL) { - goto failure; - } - applet = vcard_new_applet(cac_applet_pki_process_apdu, cac_applet_pki_reset, - pki_aid, pki_aid_len); - if (applet == NULL) { - goto failure; - } - vcard_set_applet_private(applet, applet_private, - cac_delete_pki_applet_private); - applet_private = NULL; - - return applet; - -failure: - if (applet_private != NULL) { - cac_delete_pki_applet_private(applet_private); - } - return NULL; -} - - -static unsigned char cac_default_container_aid[] = { - 0xa0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00 }; -static unsigned char cac_id_aid[] = { - 0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00 }; -/* - * Initialize the cac card. This is the only public function in this file. All - * the rest are connected through function pointers. - */ -VCardStatus -cac_card_init(VReader *reader, VCard *card, - const char *params, - unsigned char * const *cert, - int cert_len[], - VCardKey *key[] /* adopt the keys*/, - int cert_count) -{ - int i; - VCardApplet *applet; - - /* CAC Cards are VM Cards */ - vcard_set_type(card, VCARD_VM); - - /* create one PKI applet for each cert */ - for (i = 0; i < cert_count; i++) { - applet = cac_new_pki_applet(i, cert[i], cert_len[i], key[i]); - if (applet == NULL) { - goto failure; - } - vcard_add_applet(card, applet); - } - - /* create a default blank container applet */ - applet = vcard_new_applet(cac_applet_container_process_apdu, - NULL, cac_default_container_aid, - sizeof(cac_default_container_aid)); - if (applet == NULL) { - goto failure; - } - vcard_add_applet(card, applet); - - /* create a default blank container applet */ - applet = vcard_new_applet(cac_applet_id_process_apdu, - NULL, cac_id_aid, - sizeof(cac_id_aid)); - if (applet == NULL) { - goto failure; - } - vcard_add_applet(card, applet); - return VCARD_DONE; - -failure: - return VCARD_FAIL; -} - |