qemu/libcacard/cac.c
<<
>>
Prefs
   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 */
  23typedef 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 */
  36struct 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 */
  46static VCardStatus
  47cac_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 */
  90static VCardStatus
  91cac_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        g_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
 109static VCardStatus
 110cac_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            g_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        g_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
 222static VCardStatus
 223cac_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 */
 246static VCardStatus
 247cac_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 */
 265static void
 266cac_delete_pki_applet_private(VCardAppletPrivate *applet_private)
 267{
 268    CACPKIAppletData *pki_applet_data = NULL;
 269
 270    if (applet_private == NULL) {
 271        return;
 272    }
 273    pki_applet_data = &(applet_private->u.pki_data);
 274    if (pki_applet_data->cert != NULL) {
 275        g_free(pki_applet_data->cert);
 276    }
 277    if (pki_applet_data->sign_buffer != NULL) {
 278        g_free(pki_applet_data->sign_buffer);
 279    }
 280    if (pki_applet_data->key != NULL) {
 281        vcard_emul_delete_key(pki_applet_data->key);
 282    }
 283    g_free(applet_private);
 284}
 285
 286static VCardAppletPrivate *
 287cac_new_pki_applet_private(const unsigned char *cert,
 288                           int cert_len, VCardKey *key)
 289{
 290    CACPKIAppletData *pki_applet_data = NULL;
 291    VCardAppletPrivate *applet_private = NULL;
 292    applet_private = (VCardAppletPrivate *)g_malloc(sizeof(VCardAppletPrivate));
 293
 294    pki_applet_data = &(applet_private->u.pki_data);
 295    pki_applet_data->cert_buffer = NULL;
 296    pki_applet_data->cert_buffer_len = 0;
 297    pki_applet_data->sign_buffer = NULL;
 298    pki_applet_data->sign_buffer_len = 0;
 299    pki_applet_data->key = NULL;
 300    pki_applet_data->cert = (unsigned char *)g_malloc(cert_len+1);
 301    /*
 302     * if we want to support compression, then we simply change the 0 to a 1
 303     * and compress the cert data with libz
 304     */
 305    pki_applet_data->cert[0] = 0; /* not compressed */
 306    memcpy(&pki_applet_data->cert[1], cert, cert_len);
 307    pki_applet_data->cert_len = cert_len+1;
 308
 309    pki_applet_data->key = key;
 310    return applet_private;
 311}
 312
 313
 314/*
 315 * create a new cac applet which links to a given cert
 316 */
 317static VCardApplet *
 318cac_new_pki_applet(int i, const unsigned char *cert,
 319                   int cert_len, VCardKey *key)
 320{
 321    VCardAppletPrivate *applet_private = NULL;
 322    VCardApplet *applet = NULL;
 323    unsigned char pki_aid[] = { 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00 };
 324    int pki_aid_len = sizeof(pki_aid);
 325
 326    pki_aid[pki_aid_len-1] = i;
 327
 328    applet_private = cac_new_pki_applet_private(cert, cert_len, key);
 329    if (applet_private == NULL) {
 330        goto failure;
 331    }
 332    applet = vcard_new_applet(cac_applet_pki_process_apdu, cac_applet_pki_reset,
 333                              pki_aid, pki_aid_len);
 334    if (applet == NULL) {
 335        goto failure;
 336    }
 337    vcard_set_applet_private(applet, applet_private,
 338                             cac_delete_pki_applet_private);
 339    applet_private = NULL;
 340
 341    return applet;
 342
 343failure:
 344    if (applet_private != NULL) {
 345        cac_delete_pki_applet_private(applet_private);
 346    }
 347    return NULL;
 348}
 349
 350
 351static unsigned char cac_default_container_aid[] = {
 352    0xa0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00 };
 353static unsigned char cac_id_aid[] = {
 354    0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00 };
 355/*
 356 * Initialize the cac card. This is the only public function in this file. All
 357 * the rest are connected through function pointers.
 358 */
 359VCardStatus
 360cac_card_init(VReader *reader, VCard *card,
 361              const char *params,
 362              unsigned char * const *cert,
 363              int cert_len[],
 364              VCardKey *key[] /* adopt the keys*/,
 365              int cert_count)
 366{
 367    int i;
 368    VCardApplet *applet;
 369
 370    /* CAC Cards are VM Cards */
 371    vcard_set_type(card, VCARD_VM);
 372
 373    /* create one PKI applet for each cert */
 374    for (i = 0; i < cert_count; i++) {
 375        applet = cac_new_pki_applet(i, cert[i], cert_len[i], key[i]);
 376        if (applet == NULL) {
 377            goto failure;
 378        }
 379        vcard_add_applet(card, applet);
 380    }
 381
 382    /* create a default blank container applet */
 383    applet = vcard_new_applet(cac_applet_container_process_apdu,
 384                              NULL, cac_default_container_aid,
 385                              sizeof(cac_default_container_aid));
 386    if (applet == NULL) {
 387        goto failure;
 388    }
 389    vcard_add_applet(card, applet);
 390
 391    /* create a default blank container applet */
 392    applet = vcard_new_applet(cac_applet_id_process_apdu,
 393                              NULL, cac_id_aid,
 394                              sizeof(cac_id_aid));
 395    if (applet == NULL) {
 396        goto failure;
 397    }
 398    vcard_add_applet(card, applet);
 399    return VCARD_DONE;
 400
 401failure:
 402    return VCARD_FAIL;
 403}
 404
 405