Annotation of qemu/libcacard/cac.c, revision 1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.