?? iso7816-2.c
字號(hào):
/* iso7816.c - ISO 7816 commands * Copyright (C) 2003, 2004 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. * * $Id$ */#include <config.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#if defined(GNUPG_SCD_MAIN_HEADER)#include GNUPG_SCD_MAIN_HEADER#elif GNUPG_MAJOR_VERSION == 1/* This is used with GnuPG version < 1.9. The code has been source copied from the current GnuPG >= 1.9 and is maintained over there. */#include "options.h"#include "errors.h"#include "memory.h"#include "util.h"#include "i18n.h"#else /* GNUPG_MAJOR_VERSION != 1 */#include "scdaemon.h"#endif /* GNUPG_MAJOR_VERSION != 1 */#include "iso7816.h"#include "apdu.h"#define CMD_SELECT_FILE 0xA4#define CMD_VERIFY ISO7816_VERIFY#define CMD_CHANGE_REFERENCE_DATA ISO7816_CHANGE_REFERENCE_DATA#define CMD_RESET_RETRY_COUNTER ISO7816_RESET_RETRY_COUNTER#define CMD_GET_DATA 0xCA#define CMD_PUT_DATA 0xDA#define CMD_MSE 0x22#define CMD_PSO 0x2A#define CMD_INTERNAL_AUTHENTICATE 0x88#define CMD_GENERATE_KEYPAIR 0x47#define CMD_GET_CHALLENGE 0x84#define CMD_READ_BINARY 0xB0#define CMD_READ_RECORD 0xB2static gpg_error_tmap_sw (int sw){ gpg_err_code_t ec; switch (sw) { case SW_EEPROM_FAILURE: ec = GPG_ERR_HARDWARE; break; case SW_WRONG_LENGTH: ec = GPG_ERR_INV_VALUE; break; case SW_CHV_WRONG: ec = GPG_ERR_BAD_PIN; break; case SW_CHV_BLOCKED: ec = GPG_ERR_PIN_BLOCKED; break; case SW_USE_CONDITIONS: ec = GPG_ERR_USE_CONDITIONS; break; case SW_NOT_SUPPORTED: ec = GPG_ERR_NOT_SUPPORTED; break; case SW_BAD_PARAMETER: ec = GPG_ERR_INV_VALUE; break; case SW_FILE_NOT_FOUND: ec = GPG_ERR_ENOENT; break; case SW_RECORD_NOT_FOUND:ec= GPG_ERR_NOT_FOUND; break; case SW_REF_NOT_FOUND: ec = GPG_ERR_NO_OBJ; break; case SW_BAD_P0_P1: ec = GPG_ERR_INV_VALUE; break; case SW_EXACT_LENGTH: ec = GPG_ERR_INV_VALUE; break; case SW_INS_NOT_SUP: ec = GPG_ERR_CARD; break; case SW_CLA_NOT_SUP: ec = GPG_ERR_CARD; break; case SW_SUCCESS: ec = 0; break; case SW_HOST_OUT_OF_CORE: ec = GPG_ERR_ENOMEM; break; case SW_HOST_INV_VALUE: ec = GPG_ERR_INV_VALUE; break; case SW_HOST_INCOMPLETE_CARD_RESPONSE: ec = GPG_ERR_CARD; break; case SW_HOST_NOT_SUPPORTED: ec = GPG_ERR_NOT_SUPPORTED; break; case SW_HOST_LOCKING_FAILED: ec = GPG_ERR_BUG; break; case SW_HOST_BUSY: ec = GPG_ERR_EBUSY; break; case SW_HOST_NO_CARD: ec = GPG_ERR_CARD_NOT_PRESENT; break; case SW_HOST_CARD_INACTIVE: ec = GPG_ERR_CARD_RESET; break; case SW_HOST_CARD_IO_ERROR: ec = GPG_ERR_EIO; break; case SW_HOST_GENERAL_ERROR: ec = GPG_ERR_GENERAL; break; case SW_HOST_NO_READER: ec = GPG_ERR_ENODEV; break; case SW_HOST_ABORTED: ec = GPG_ERR_CANCELED; break; case SW_HOST_NO_KEYPAD: ec = GPG_ERR_NOT_SUPPORTED; break; default: if ((sw & 0x010000)) ec = GPG_ERR_GENERAL; /* Should not happen. */ else if ((sw & 0xff00) == SW_MORE_DATA) ec = 0; /* This should actually never been seen here. */ else ec = GPG_ERR_CARD; } return gpg_error (ec);}/* Map a status word from the APDU layer to a gpg-error code. */gpg_error_tiso7816_map_sw (int sw){ /* All APDU functions should return 0x9000 on success but for historical reasons of the implementation some return 0 to indicate success. We allow for that here. */ return sw? map_sw (sw) : 0;}/* This function is specialized version of the SELECT FILE command. SLOT is the card and reader as created for example by apdu_open_reader (), AID is a buffer of size AIDLEN holding the requested application ID. The function can't be used to enumerate AIDs and won't return the AID on success. The return value is 0 for okay or a GPG error code. Note that ISO error codes are internally mapped. Bit 0 of FLAGS should be set if the card does not understand P2=0xC0. */gpg_error_tiso7816_select_application (int slot, const char *aid, size_t aidlen, unsigned int flags){ int sw; sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, (flags&1)? 0 :0x0c, aidlen, aid); return map_sw (sw);}gpg_error_tiso7816_select_file (int slot, int tag, int is_dir, unsigned char **result, size_t *resultlen){ int sw, p0, p1; unsigned char tagbuf[2]; tagbuf[0] = (tag >> 8) & 0xff; tagbuf[1] = tag & 0xff; if (result || resultlen) { *result = NULL; *resultlen = 0; return gpg_error (GPG_ERR_NOT_IMPLEMENTED); } else { p0 = (tag == 0x3F00)? 0: is_dir? 1:2; p1 = 0x0c; /* No FC return. */ sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, p0, p1, 2, (char*)tagbuf ); return map_sw (sw); } return 0;}/* Do a select file command with a direct path. */gpg_error_tiso7816_select_path (int slot, const unsigned short *path, size_t pathlen, unsigned char **result, size_t *resultlen){ int sw, p0, p1; unsigned char buffer[100]; int buflen; if (result || resultlen) { *result = NULL; *resultlen = 0; return gpg_error (GPG_ERR_NOT_IMPLEMENTED); } if (pathlen/2 >= sizeof buffer) return gpg_error (GPG_ERR_TOO_LARGE); for (buflen = 0; pathlen; pathlen--, path++) { buffer[buflen++] = (*path >> 8); buffer[buflen++] = *path; } p0 = 0x08; p1 = 0x0c; /* No FC return. */ sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, p0, p1, buflen, (char*)buffer ); return map_sw (sw);}/* This is a private command currently only working for TCOS cards. */gpg_error_tiso7816_list_directory (int slot, int list_dirs, unsigned char **result, size_t *resultlen){ int sw; if (!result || !resultlen) return gpg_error (GPG_ERR_INV_VALUE); *result = NULL; *resultlen = 0; sw = apdu_send (slot, 0x80, 0xAA, list_dirs? 1:2, 0, -1, NULL, result, resultlen); if (sw != SW_SUCCESS) { /* Make sure that pending buffers are released. */ xfree (*result); *result = NULL; *resultlen = 0; } return map_sw (sw);}/* Check whether the reader supports the ISO command code COMMAND on the keypad. Returns 0 on success. */gpg_error_tiso7816_check_keypad (int slot, int command, iso7816_pininfo_t *pininfo){ int sw; sw = apdu_check_keypad (slot, command, pininfo->mode, pininfo->minlen, pininfo->maxlen, pininfo->padlen); return iso7816_map_sw (sw);}/* Perform a VERIFY command on SLOT using the card holder verification vector CHVNO with a CHV of lenght CHVLEN. With PININFO non-NULL the keypad of the reader will be used. Returns 0 on success. */gpg_error_tiso7816_verify_kp (int slot, int chvno, const char *chv, size_t chvlen, iso7816_pininfo_t *pininfo){ int sw; if (pininfo && pininfo->mode) sw = apdu_send_simple_kp (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv, pininfo->mode, pininfo->minlen, pininfo->maxlen, pininfo->padlen); else sw = apdu_send_simple (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv); return map_sw (sw);}/* Perform a VERIFY command on SLOT using the card holder verification vector CHVNO with a CHV of lenght CHVLEN. Returns 0 on success. */gpg_error_tiso7816_verify (int slot, int chvno, const char *chv, size_t chvlen){ return iso7816_verify_kp (slot, chvno, chv, chvlen, NULL);}/* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder verification vector CHVNO. If the OLDCHV is NULL (and OLDCHVLEN 0), a "change reference data" is done, otherwise an "exchange reference data". The new reference data is expected in NEWCHV of length NEWCHVLEN. With PININFO non-NULL the keypad of the reader will be used. */gpg_error_tiso7816_change_reference_data_kp (int slot, int chvno, const char *oldchv, size_t oldchvlen, const char *newchv, size_t newchvlen, iso7816_pininfo_t *pininfo){ int sw; char *buf; if ((!oldchv && oldchvlen) || (oldchv && !oldchvlen) || !newchv || !newchvlen ) return gpg_error (GPG_ERR_INV_VALUE); buf = xtrymalloc (oldchvlen + newchvlen); if (!buf) return gpg_error (gpg_err_code_from_errno (errno)); if (oldchvlen) memcpy (buf, oldchv, oldchvlen); memcpy (buf+oldchvlen, newchv, newchvlen); if (pininfo && pininfo->mode) sw = apdu_send_simple_kp (slot, 0x00, CMD_CHANGE_REFERENCE_DATA, oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf, pininfo->mode, pininfo->minlen, pininfo->maxlen, pininfo->padlen); else sw = apdu_send_simple (slot, 0x00, CMD_CHANGE_REFERENCE_DATA, oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf); xfree (buf); return map_sw (sw);}/* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder verification vector CHVNO. If the OLDCHV is NULL (and OLDCHVLEN 0), a "change reference data" is done, otherwise an "exchange reference data". The new reference data is expected in NEWCHV of length NEWCHVLEN. */gpg_error_tiso7816_change_reference_data (int slot, int chvno, const char *oldchv, size_t oldchvlen, const char *newchv, size_t newchvlen){ return iso7816_change_reference_data_kp (slot, chvno, oldchv, oldchvlen, newchv, newchvlen, NULL);}gpg_error_tiso7816_reset_retry_counter_kp (int slot, int chvno, const char *newchv, size_t newchvlen, iso7816_pininfo_t *pininfo){ int sw; if (!newchv || !newchvlen ) return gpg_error (GPG_ERR_INV_VALUE); if (pininfo && pininfo->mode) sw = apdu_send_simple_kp (slot, 0x00, CMD_RESET_RETRY_COUNTER, 2, chvno, newchvlen, newchv, pininfo->mode, pininfo->minlen, pininfo->maxlen, pininfo->padlen); else sw = apdu_send_simple (slot, 0x00, CMD_RESET_RETRY_COUNTER, 2, chvno, newchvlen, newchv); return map_sw (sw);}gpg_error_tiso7816_reset_retry_counter (int slot, int chvno, const char *newchv, size_t newchvlen){ return iso7816_reset_retry_counter_kp (slot, chvno, newchv, newchvlen, NULL);}/* Perform a GET DATA command requesting TAG and storing the result in a newly allocated buffer at the address passed by RESULT. Return the length of this data at the address of RESULTLEN. */gpg_error_tiso7816_get_data (int slot, int tag, unsigned char **result, size_t *resultlen){ int sw; if (!result || !resultlen) return gpg_error (GPG_ERR_INV_VALUE); *result = NULL; *resultlen = 0; sw = apdu_send (slot, 0x00, CMD_GET_DATA, ((tag >> 8) & 0xff), (tag & 0xff), -1, NULL, result, resultlen); if (sw != SW_SUCCESS) { /* Make sure that pending buffers are released. */ xfree (*result); *result = NULL; *resultlen = 0; return map_sw (sw);
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -