diff --git a/.travis.yml b/.travis.yml index 46c471b94b..54a754d026 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,13 +9,22 @@ env: matrix: include: - compiler: clang + os: osx - compiler: gcc + os: osx + - compiler: clang + os: linux + env: ENABLE_DOC=--enable-doc + - compiler: gcc + os: linux + env: ENABLE_DOC=--enable-doc - compiler: gcc + os: linux env: HOST=i686-w64-mingw32 before_install: - if [ $TRAVIS_OS_NAME == linux ]; then - sudo apt-get update; + sudo apt-get update || true; fi install: @@ -30,11 +39,11 @@ install: before_script: - ./bootstrap - if [ -z "$HOST" ]; then - ./configure --enable-pedantic --disable-strict --enable-doc --enable-dnie-ui; + ./configure $ENABLE_DOC --enable-dnie-ui; else unset CC; unset CXX; - ./configure --enable-pedantic --disable-strict --host=$HOST --disable-openssl; + ./configure --host=$HOST --disable-openssl; fi addons: @@ -48,9 +57,13 @@ addons: script: - if [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then - make; + if [ $TRAVIS_OS_NAME == osx ]; then + ./MacOSX/build; + else + make; + fi; fi - - if [ -z "$HOST" -a "${COVERITY_SCAN_BRANCH}" != 1 ]; then + - if [ -z "$HOST" -a "${COVERITY_SCAN_BRANCH}" != 1 -a "$TRAVIS_OS_NAME" != "osx" ]; then make check; make dist; fi diff --git a/MacOSX/build-package.in b/MacOSX/build-package.in index 4f671c4553..c0db7daf98 100755 --- a/MacOSX/build-package.in +++ b/MacOSX/build-package.in @@ -70,7 +70,7 @@ fi test -L OpenSC.tokend/build/opensc-src || ln -sf ${BUILDPATH}/src OpenSC.tokend/build/opensc-src # Build and copy OpenSC.tokend -xcodebuild -configuration Deployment -project OpenSC.tokend/Tokend.xcodeproj +xcodebuild -target OpenSC -configuration Deployment -project OpenSC.tokend/Tokend.xcodeproj # Prepare target root # Copy Tokend diff --git a/doc/tools/pkcs15-tool.1.xml b/doc/tools/pkcs15-tool.1.xml index 9c5887266a..82ad7b91b7 100644 --- a/doc/tools/pkcs15-tool.1.xml +++ b/doc/tools/pkcs15-tool.1.xml @@ -185,7 +185,21 @@ Reads the public key with id id, writing the output in format suitable for - $HOME/.ssh/authorized_keys. + $HOME/.ssh/authorized_keys. + + The key label, if any will be shown in the 'Comment' field. + + + + + + + When used in conjunction with option the + output format of the public key follows rfc4716. + + + The default output format is a single line (openssh). + diff --git a/src/libopensc/card-iasecc.c b/src/libopensc/card-iasecc.c index c9d2518cda..abe8245168 100644 --- a/src/libopensc/card-iasecc.c +++ b/src/libopensc/card-iasecc.c @@ -1801,12 +1801,14 @@ iasecc_chv_verify_pinpad(struct sc_card *card, struct sc_pin_cmd_data *pin_cmd, LOG_FUNC_RETURN(ctx, SC_ERROR_READER); } - if (pin_cmd->pin1.min_length != pin_cmd->pin1.max_length) { - sc_log(ctx, "Different values for PIN min and max lengths is not actually compatible with PinPAD."); - LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, - "Different values for PIN min and max lengths is not actually compatible with PinPAD."); + sc_log(ctx, "reader %s", card->reader->name); + if (strstr(card->reader->name, "Gemalto GemPC Pinpad") == card->reader->name) { + sc_log(ctx, "reader %s", card->reader->name); + if (pin_cmd->pin1.min_length != pin_cmd->pin1.max_length) { + sc_log(ctx, "Bogus Gemalto GemPC Pinpad do not accept different values for min and max PIN lengths."); + LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); + } } - pin_cmd->pin1.len = pin_cmd->pin1.min_length; memset(buffer, 0xFF, sizeof(buffer)); @@ -2037,8 +2039,10 @@ iasecc_chv_change_pinpad(struct sc_card *card, unsigned reference, int *tries_le rv = iasecc_pin_get_policy(card, &pin_cmd); LOG_TEST_RET(ctx, rv, "Get 'PIN policy' error"); - if (pin_cmd.pin1.min_length != pin_cmd.pin1.max_length) - LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Different values for PIN min and max lengths is not allowed with PinPAD."); + if (strstr(card->reader->name, "Gemalto GemPC Pinpad") == card->reader->name) + if (pin_cmd.pin1.min_length != pin_cmd.pin1.max_length) + LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, + "Bogus Gemalto GemPC Pinpad do not accept different values for min and max PIN lengths."); if (pin_cmd.pin1.min_length < 4) pin_cmd.pin1.min_length = 4; @@ -2083,8 +2087,10 @@ iasecc_chv_set_pinpad(struct sc_card *card, unsigned char reference) rv = iasecc_pin_get_policy(card, &pin_cmd); LOG_TEST_RET(ctx, rv, "Get 'PIN policy' error"); - if (pin_cmd.pin1.min_length != pin_cmd.pin1.max_length) - LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Different values for PIN min and max lengths is not allowed with PinPAD."); + if (strstr(card->reader->name, "Gemalto GemPC Pinpad") == card->reader->name) + if (pin_cmd.pin1.min_length != pin_cmd.pin1.max_length) + LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, + "Bogus Gemalto GemPC Pinpad do not accept different values for min and max PIN lengths."); if (pin_cmd.pin1.min_length < 4) pin_cmd.pin1.min_length = 4; @@ -3385,7 +3391,7 @@ iasecc_read_public_key(struct sc_card *card, unsigned type, iasecc_sdo_free_fields(card, &sdo); - SC_FUNC_RETURN(ctx, SC_SUCCESS, rv); + LOG_FUNC_RETURN(ctx, SC_SUCCESS); } diff --git a/src/libopensc/card-myeid.c b/src/libopensc/card-myeid.c index e8c28ec95a..6a9fd7520d 100644 --- a/src/libopensc/card-myeid.c +++ b/src/libopensc/card-myeid.c @@ -344,17 +344,20 @@ static int myeid_process_fci(struct sc_card *card, struct sc_file *file, } static int encode_file_structure(sc_card_t *card, const sc_file_t *file, - u8 *out, size_t *outlen) + u8 *buf, size_t *outlen) { const sc_acl_entry_t *read, *update, *delete, *generate; - u8 buf[42]; size_t i; LOG_FUNC_CALLED(card->ctx); + + if (!buf || !outlen || *outlen < 45) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); + /* PrivateKey * 0E0000019 6217 81020400 820111 83024B01 8603000000 85028000 8A0100 RESULT 6984 * 6217 81020400 820111 83024B01 8603000000 85021000 8A0100 */ - memset(buf, 0x0, sizeof(buf)); + memset(buf, 0x0, *outlen); buf[0] = 0x62; buf[1] = 0x17; @@ -453,9 +456,9 @@ static int encode_file_structure(sc_card_t *card, const sc_file_t *file, buf[26] = (u8)file->namelen; for(i=0;i < file->namelen;i++) - buf[i + 26] = file->name[i]; + buf[i + 27] = file->name[i]; - buf[1] = 0x19 + file->namelen + 2; + buf[1] = 27 + file->namelen; } break; default: @@ -464,16 +467,15 @@ static int encode_file_structure(sc_card_t *card, const sc_file_t *file, } *outlen = buf[1]+2; - memcpy(out, buf, *outlen); - LOG_FUNC_RETURN(card->ctx, 0); + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } static int myeid_create_file(struct sc_card *card, struct sc_file *file) { sc_apdu_t apdu; - u8 sbuf[32]; - size_t buflen; + u8 sbuf[45]; + size_t buflen = sizeof sbuf; int r; LOG_FUNC_CALLED(card->ctx); @@ -808,7 +810,7 @@ static int myeid_convert_ec_signature(struct sc_context *ctx, size_t s_len, unsigned char *data, size_t datalen) { unsigned char *buf; - size_t i, buflen; + size_t buflen; int r; assert(data && datalen); diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c index 5ae66f6740..6c63a5e81f 100644 --- a/src/libopensc/card-openpgp.c +++ b/src/libopensc/card-openpgp.c @@ -305,7 +305,7 @@ pgp_init(sc_card_t *card) sc_file_t *file = NULL; struct do_info *info; int r; - struct blob *child = NULL; + struct blob *child = NULL; priv = calloc (1, sizeof *priv); if (!priv) @@ -330,8 +330,14 @@ pgp_init(sc_card_t *card) return r; } + /* defensive programming check */ + if (!file) { + pgp_finish(card); + return SC_ERROR_OBJECT_NOT_FOUND; + } + /* read information from AID */ - if (file && file->namelen == 16) { + if (file->namelen == 16) { /* OpenPGP card spec 1.1 & 2.0, section 4.2.1 & 4.1.2.1 */ priv->bcd_version = bebytes2ushort(file->name + 6); /* kludge: get card's serial number from manufacturer ID + serial number */ @@ -2166,7 +2172,9 @@ static int pgp_store_key(sc_card_t *card, sc_cardctl_openpgp_keystore_info_t *ke /* ABI: card ctl: perform special card-specific operations */ static int pgp_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) { +#ifdef ENABLE_OPENSSL int r; +#endif /* ENABLE_OPENSSL */ LOG_FUNC_CALLED(card->ctx); diff --git a/src/libopensc/ctbcs.c b/src/libopensc/ctbcs.c index 16c4336978..ad51cac8c8 100644 --- a/src/libopensc/ctbcs.c +++ b/src/libopensc/ctbcs.c @@ -58,7 +58,7 @@ ctbcs_build_perform_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *d prompt = data->pin1.prompt; if (prompt && *prompt) { len = strlen(prompt); - if (count + len + 2 > buflen || len > 254) + if (len + 2 > buflen) return SC_ERROR_BUFFER_TOO_SMALL; buf[count++] = CTBCS_TAG_PROMPT; buf[count++] = len; @@ -126,7 +126,7 @@ ctbcs_build_modify_verification_apdu(sc_apdu_t *apdu, struct sc_pin_cmd_data *da prompt = data->pin1.prompt; if (prompt && *prompt) { len = strlen(prompt); - if (count + len + 2 > buflen || len > 254) + if (len + 2 > buflen) return SC_ERROR_BUFFER_TOO_SMALL; buf[count++] = CTBCS_TAG_PROMPT; buf[count++] = len; diff --git a/src/libopensc/iso7816.c b/src/libopensc/iso7816.c index c37bbf0449..37abd1772e 100644 --- a/src/libopensc/iso7816.c +++ b/src/libopensc/iso7816.c @@ -430,6 +430,10 @@ iso7816_process_fci(struct sc_card *card, struct sc_file *file, if (tag != NULL && taglen) sc_file_set_sec_attr(file, tag, taglen); + tag = sc_asn1_find_tag(ctx, p, len, 0x88, &taglen); + if (tag != NULL && taglen == 1) + file->sid = *tag; + tag = sc_asn1_find_tag(ctx, p, len, 0x8A, &taglen); if (tag != NULL && taglen==1) { if (tag[0] == 0x01) @@ -1012,8 +1016,7 @@ iso7816_build_pin_apdu(struct sc_card *card, struct sc_apdu *apdu, * but expect the new one to be entered on the keypad. */ if (data->pin1.len && data->pin2.len == 0) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Special case - initial pin provided - but new pin asked on keypad"); + sc_log(card->ctx, "Special case - initial pin provided - but new pin asked on keypad"); data->flags |= SC_PIN_CMD_IMPLICIT_CHANGE; }; len += r; diff --git a/src/libopensc/libopensc.exports b/src/libopensc/libopensc.exports index 23f6c05ac4..7c64d9aa3b 100644 --- a/src/libopensc/libopensc.exports +++ b/src/libopensc/libopensc.exports @@ -317,6 +317,7 @@ sc_pkcs15_convert_pubkey sc_sm_parse_answer sc_sm_update_apdu_response sc_sm_single_transmit +sc_sm_stop iasecc_sm_create_file iasecc_sm_delete_file iasecc_sm_external_authentication diff --git a/src/libopensc/log.c b/src/libopensc/log.c index 32f396d8e6..9d98413b49 100644 --- a/src/libopensc/log.c +++ b/src/libopensc/log.c @@ -73,9 +73,7 @@ static void sc_do_log_va(sc_context_t *ctx, int level, const char *file, int lin FILE *outf = NULL; int n; - assert(ctx != NULL); - - if (ctx->debug < level) + if (!ctx || ctx->debug < level) return; p = buf; @@ -167,9 +165,7 @@ void sc_hex_dump(struct sc_context *ctx, int level, const u8 * in, size_t count, char *p = buf; int lines = 0; - assert(ctx != NULL); - - if (ctx->debug < level) + if (!ctx || ctx->debug < level) return; assert(buf != NULL && (in != NULL || count == 0)); diff --git a/src/libopensc/muscle-filesystem.c b/src/libopensc/muscle-filesystem.c index f54d263fef..dc618a6733 100644 --- a/src/libopensc/muscle-filesystem.c +++ b/src/libopensc/muscle-filesystem.c @@ -42,6 +42,8 @@ static const u8* ignoredFiles[] = { mscfs_t *mscfs_new(void) { mscfs_t *fs = malloc(sizeof(mscfs_t)); + if (!fs) + return NULL; memset(fs, 0, sizeof(mscfs_t)); memcpy(fs->currentPath, "\x3F\x00", 2); return fs; diff --git a/src/libopensc/pkcs15-gemsafeV1.c b/src/libopensc/pkcs15-gemsafeV1.c index aa928421f1..c1191eefda 100644 --- a/src/libopensc/pkcs15-gemsafeV1.c +++ b/src/libopensc/pkcs15-gemsafeV1.c @@ -183,11 +183,9 @@ static int gemsafe_get_cert_len(sc_card_t *card) * (allocated EF space is much greater!) */ objlen = (((size_t) ibuf[0]) << 8) | ibuf[1]; - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Stored object is of size: %d\n", objlen); + sc_log(card->ctx, "Stored object is of size: %d", objlen); if (objlen < 1 || objlen > GEMSAFE_MAX_OBJLEN) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Invalid object size: %d\n", objlen); + sc_log(card->ctx, "Invalid object size: %d", objlen); return SC_ERROR_INTERNAL; } @@ -209,15 +207,14 @@ static int gemsafe_get_cert_len(sc_card_t *card) while (ibuf[ind] == 0x01) { if (ibuf[ind+1] == 0xFE) { gemsafe_prkeys[i].ref = ibuf[ind+4]; - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Key container %d is allocated and uses key_ref %d\n", i+1, - gemsafe_prkeys[i].ref); + sc_log(card->ctx, "Key container %d is allocated and uses key_ref %d", + i+1, gemsafe_prkeys[i].ref); ind += 9; - } else { + } + else { gemsafe_prkeys[i].label = NULL; gemsafe_cert[i].label = NULL; - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Key container %d is unallocated\n", i+1); + sc_log(card->ctx, "Key container %d is unallocated", i+1); ind += 8; } i++; @@ -239,8 +236,7 @@ static int gemsafe_get_cert_len(sc_card_t *card) r = sc_read_binary(card, iptr - ibuf, iptr, MIN(GEMSAFE_READ_QUANTUM, objlen - (iptr - ibuf)), 0); if (r < 0) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Could not read cert object\n"); + sc_log(card->ctx, "Could not read cert object"); return SC_ERROR_INTERNAL; } iptr += GEMSAFE_READ_QUANTUM; @@ -254,15 +250,12 @@ static int gemsafe_get_cert_len(sc_card_t *card) while (i < gemsafe_cert_max && gemsafe_cert[i].label == NULL) i++; if (i == gemsafe_cert_max) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Warning: Found orphaned certificate at offset %d\n", ind); + sc_log(card->ctx, "Warning: Found orphaned certificate at offset %d", ind); return SC_SUCCESS; } /* DER cert len is encoded this way */ certlen = ((((size_t) ibuf[ind+2]) << 8) | ibuf[ind+3]) + 4; - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Found certificate of key container %d at offset %d, len %d\n", - i+1, ind, certlen); + sc_log(card->ctx, "Found certificate of key container %d at offset %d, len %d", i+1, ind, certlen); gemsafe_cert[i].index = ind; gemsafe_cert[i].count = certlen; ind += certlen; @@ -276,8 +269,7 @@ static int gemsafe_get_cert_len(sc_card_t *card) */ for (; i < gemsafe_cert_max; i++) { if (gemsafe_cert[i].label) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, - "Warning: Certificate of key container %d is missing\n", i+1); + sc_log(card->ctx, "Warning: Certificate of key container %d is missing", i+1); gemsafe_prkeys[i].label = NULL; gemsafe_cert[i].label = NULL; } @@ -304,7 +296,7 @@ static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card) struct sc_apdu apdu; u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; - sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "Setting pkcs15 parameters\n"); + sc_log(p15card->card->ctx, "Setting pkcs15 parameters"); if (p15card->tokeninfo->label) free(p15card->tokeninfo->label); @@ -330,7 +322,8 @@ static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card) apdu.lc = 0; apdu.datalen = 0; r = sc_transmit_apdu(card, &apdu); - SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed"); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00) return SC_ERROR_INTERNAL; if (r != SC_SUCCESS) @@ -350,7 +343,7 @@ static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card) return SC_ERROR_INTERNAL; /* set certs */ - sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "Setting certificates\n"); + sc_log(p15card->card->ctx, "Setting certificates"); for (i = 0; i < gemsafe_cert_max; i++) { struct sc_pkcs15_id p15Id; struct sc_path path; @@ -367,7 +360,7 @@ static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card) } /* set gemsafe_pin */ - sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "Setting PIN\n"); + sc_log(p15card->card->ctx, "Setting PIN"); for (i=0; i < gemsafe_pin_max; i++) { struct sc_pkcs15_id p15Id; struct sc_path path; @@ -388,11 +381,11 @@ static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card) }; /* set private keys */ - sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "Setting private keys\n"); + sc_log(p15card->card->ctx, "Setting private keys"); for (i = 0; i < gemsafe_cert_max; i++) { struct sc_pkcs15_id p15Id, authId, *pauthId; struct sc_path path; - int key_ref = 0x03; + int key_ref = 0x03; if (gemsafe_prkeys[i].label == NULL) continue; @@ -403,7 +396,7 @@ static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card) } else pauthId = NULL; sc_format_path(gemsafe_prkeys[i].path, &path); - /* + /* * The key ref may be different for different sites; * by adding flags=n where the low order 4 bits can be * the key ref we can force it. @@ -423,7 +416,7 @@ static int sc_pkcs15emu_gemsafeV1_init( sc_pkcs15_card_t *p15card) } /* select the application DF */ - sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL,"Selecting application DF\n"); + sc_log(p15card->card->ctx, "Selecting application DF"); sc_format_path(GEMSAFE_APP_PATH, &path); r = sc_select_file(card, &path, &file); if (r != SC_SUCCESS || !file) @@ -511,8 +504,7 @@ sc_pkcs15emu_add_object(sc_pkcs15_card_t *p15card, int type, df_type = SC_PKCS15_CDF; break; default: - sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, - "Unknown PKCS15 object type %d\n", type); + sc_log(p15card->card->ctx, "Unknown PKCS15 object type %d", type); free(obj); return SC_ERROR_INVALID_ARGUMENTS; } @@ -534,6 +526,9 @@ sc_pkcs15emu_add_pin(sc_pkcs15_card_t *p15card, sc_pkcs15_auth_info_t *info; info = calloc(1, sizeof(*info)); + if (!info) + LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY); + info->auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; info->auth_method = SC_AC_CHV; info->auth_id = *id; @@ -549,9 +544,7 @@ sc_pkcs15emu_add_pin(sc_pkcs15_card_t *p15card, if (path) info->path = *path; - return sc_pkcs15emu_add_object(p15card, - SC_PKCS15_TYPE_AUTH_PIN, - label, info, NULL, obj_flags); + return sc_pkcs15emu_add_object(p15card, SC_PKCS15_TYPE_AUTH_PIN, label, info, NULL, obj_flags); } static int @@ -563,6 +556,10 @@ sc_pkcs15emu_add_cert(sc_pkcs15_card_t *p15card, { sc_pkcs15_cert_info_t *info; info = calloc(1, sizeof(*info)); + if (!info) + { + LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY); + } info->id = *id; info->authority = authority; if (path) @@ -582,6 +579,10 @@ sc_pkcs15emu_add_prkey(sc_pkcs15_card_t *p15card, sc_pkcs15_prkey_info_t *info; info = calloc(1, sizeof(*info)); + if (!info) + { + LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_OUT_OF_MEMORY); + } info->id = *id; info->modulus_length = modulus_length; info->usage = usage; diff --git a/src/libopensc/pkcs15-pubkey.c b/src/libopensc/pkcs15-pubkey.c index 189e413ee2..9cf75e350f 100644 --- a/src/libopensc/pkcs15-pubkey.c +++ b/src/libopensc/pkcs15-pubkey.c @@ -1019,6 +1019,8 @@ sc_pkcs15_pubkey_from_prvkey(struct sc_context *ctx, struct sc_pkcs15_prkey *prv break; case SC_ALGORITHM_EC: pubkey->u.ec.ecpointQ.value = malloc(prvkey->u.ec.ecpointQ.len); + if (!pubkey->u.ec.ecpointQ.value) + LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); memcpy(pubkey->u.ec.ecpointQ.value, prvkey->u.ec.ecpointQ.value, prvkey->u.ec.ecpointQ.len); pubkey->u.ec.ecpointQ.len = prvkey->u.ec.ecpointQ.len; break; @@ -1583,6 +1585,8 @@ sc_pkcs15_convert_pubkey(struct sc_pkcs15_pubkey *pkcs15_key, void *evp_key) /* copy the public key */ if (buflen > 0) { dst->ecpointQ.value = malloc(buflen); + if (!dst->ecpointQ.value) + return SC_ERROR_OUT_OF_MEMORY; memcpy(dst->ecpointQ.value, buf, buflen); dst->ecpointQ.len = buflen; /* calculate the field length */ diff --git a/src/libopensc/sm.c b/src/libopensc/sm.c index 5f4bd899e6..4705ba626e 100644 --- a/src/libopensc/sm.c +++ b/src/libopensc/sm.c @@ -140,6 +140,9 @@ sc_sm_single_transmit(struct sc_card *card, struct sc_apdu *apdu) * Send plain APDU to the reader driver */ rv = card->reader->ops->transmit(card->reader, apdu); LOG_FUNC_RETURN(ctx, rv); + } else { + if (rv < 0) + sc_sm_stop(card); } LOG_TEST_RET(ctx, rv, "get SM APDU error"); @@ -147,34 +150,66 @@ sc_sm_single_transmit(struct sc_card *card, struct sc_apdu *apdu) rv = sc_check_apdu(card, sm_apdu); if (rv < 0) { card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu); + sc_sm_stop(card); LOG_TEST_RET(ctx, rv, "cannot validate SM encoded APDU"); } /* send APDU to the reader driver */ rv = card->reader->ops->transmit(card->reader, sm_apdu); - LOG_TEST_RET(ctx, rv, "unable to transmit APDU"); + if (rv < 0) { + card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu); + sc_sm_stop(card); + LOG_TEST_RET(ctx, rv, "unable to transmit APDU"); + } /* decode SM answer and free temporary SM related data */ rv = card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu); + if (rv < 0) + sc_sm_stop(card); LOG_FUNC_RETURN(ctx, rv); } + +int +sc_sm_stop(struct sc_card *card) +{ + int r = SC_SUCCESS; + + if (card) { + if (card->sm_ctx.sm_mode == SM_MODE_TRANSMIT + && card->sm_ctx.ops.close) + r = card->sm_ctx.ops.close(card); + card->sm_ctx.sm_mode = SM_MODE_NONE; + } + + return r; +} + #else + int sc_sm_parse_answer(struct sc_card *card, unsigned char *resp_data, size_t resp_len, struct sm_card_response *out) { return SC_ERROR_NOT_SUPPORTED; } + int sc_sm_update_apdu_response(struct sc_card *card, unsigned char *resp_data, size_t resp_len, int ref_rv, struct sc_apdu *apdu) { return SC_ERROR_NOT_SUPPORTED; } + int sc_sm_single_transmit(struct sc_card *card, struct sc_apdu *apdu) { return SC_ERROR_NOT_SUPPORTED; } + +int +sc_sm_stop(struct sc_card *card) +{ + return SC_ERROR_NOT_SUPPORTED; +} #endif diff --git a/src/libopensc/sm.h b/src/libopensc/sm.h index 8ff19887ef..e27725f45b 100644 --- a/src/libopensc/sm.h +++ b/src/libopensc/sm.h @@ -353,6 +353,18 @@ int sc_sm_parse_answer(struct sc_card *, unsigned char *, size_t, struct sm_card int sc_sm_update_apdu_response(struct sc_card *, unsigned char *, size_t, int, struct sc_apdu *); int sc_sm_single_transmit(struct sc_card *, struct sc_apdu *); +/** + * @brief Stops SM and frees allocated ressources. + * + * Calls \a card->sm_ctx.ops.close() if available and \c card->sm_ctx.sm_mode + * is \c SM_MODE_TRANSMIT + * + * @param[in] card + * + * @return \c SC_SUCCESS or error code if an error occurred + */ +int sc_sm_stop(struct sc_card *card); + #ifdef __cplusplus } #endif diff --git a/src/libopensc/types.h b/src/libopensc/types.h index 0bf0c29bfb..38f4c4bf00 100644 --- a/src/libopensc/types.h +++ b/src/libopensc/types.h @@ -225,7 +225,8 @@ typedef struct sc_file { unsigned int type, ef_structure, status; /* See constant values defined above */ unsigned int shareable; /* true(1), false(0) according to ISO 7816-4:2005 Table 14 */ size_t size; /* Size of file (in bytes) */ - int id; /* Short file id (2 bytes) */ + int id; /* file identifier (2 bytes) */ + int sid; /* short EF identifier (1 byte) */ struct sc_acl_entry *acl[SC_MAX_AC_OPS]; /* Access Control List */ int record_length; /* In case of fixed-length or cyclic EF */ diff --git a/src/pkcs11/mechanism.c b/src/pkcs11/mechanism.c index 63506382f4..fec1123a14 100644 --- a/src/pkcs11/mechanism.c +++ b/src/pkcs11/mechanism.c @@ -990,6 +990,9 @@ sc_pkcs11_register_sign_and_hash_mechanism(struct sc_pkcs11_card *p11card, mech_info.flags &= (CKF_SIGN | CKF_SIGN_RECOVER | CKF_VERIFY | CKF_VERIFY_RECOVER); info = calloc(1, sizeof(*info)); + if (!info) + LOG_FUNC_RETURN(p11card->card->ctx, SC_ERROR_OUT_OF_MEMORY); + info->mech = mech; info->sign_type = sign_type; info->hash_type = hash_type; diff --git a/src/pkcs15init/pkcs15-iasecc.c b/src/pkcs15init/pkcs15-iasecc.c index 99e7046812..5f9e8955c5 100644 --- a/src/pkcs15init/pkcs15-iasecc.c +++ b/src/pkcs15init/pkcs15-iasecc.c @@ -950,9 +950,7 @@ iasecc_pkcs15_fix_private_key_attributes(struct sc_profile *profile, struct sc_p IASECC_ALGORITHM_RSA_PKCS | IASECC_ALGORITHM_SHA2); LOG_TEST_RET(ctx, rv, "Cannot add RSA_PKCS SHA2 supported mechanism"); - key_info->usage |= SC_PKCS15_PRKEY_USAGE_SIGN; if (sdo_prvkey->docp.non_repudiation.value && sdo_prvkey->docp.non_repudiation.value[0]) { - key_info->usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; object->user_consent = 1; } } @@ -960,14 +958,12 @@ iasecc_pkcs15_fix_private_key_attributes(struct sc_profile *profile, struct sc_p rv = iasecc_pkcs15_add_algorithm_reference(p15card, key_info, IASECC_ALGORITHM_RSA_PKCS); LOG_TEST_RET(ctx, rv, "Cannot add RSA_PKCS supported mechanism"); - key_info->usage |= SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER; } else if (ii == IASECC_ACLS_RSAKEY_PSO_DECIPHER) { rv = iasecc_pkcs15_add_algorithm_reference(p15card, key_info, IASECC_ALGORITHM_RSA_PKCS_DECRYPT | IASECC_ALGORITHM_SHA1); LOG_TEST_RET(ctx, rv, "Cannot add decipher RSA_PKCS supported mechanism"); - key_info->usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP; } } diff --git a/src/tools/opensc-explorer.c b/src/tools/opensc-explorer.c index cefc3e16c2..fa2581bb78 100644 --- a/src/tools/opensc-explorer.c +++ b/src/tools/opensc-explorer.c @@ -786,8 +786,10 @@ static int do_info(int argc, char **argv) st = "Unknown File"; break; } - printf("\n%s ID %04X\n\n", st, file->id); - printf("%-15s%s\n", "File path:", path_to_filename(&path, '/')); + printf("\n%s ID %04X", st, file->id); + if (file->sid) + printf(", SFI %02X", file->sid); + printf("\n\n%-15s%s\n", "File path:", path_to_filename(&path, '/')); printf("%-15s%lu bytes\n", "File size:", (unsigned long) file->size); if (file->type == SC_FILE_TYPE_DF) { diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c index f5eb7f63c1..b79beeec58 100644 --- a/src/tools/pkcs11-tool.c +++ b/src/tools/pkcs11-tool.c @@ -166,6 +166,7 @@ static const struct option options[] = { { "attr-from", 1, NULL, OPT_ATTR_FROM }, { "input-file", 1, NULL, 'i' }, { "output-file", 1, NULL, 'o' }, + { "signature-format", 1, NULL, 'f' }, { "test", 0, NULL, 't' }, { "test-hotplug", 0, NULL, OPT_TEST_HOTPLUG }, @@ -223,6 +224,7 @@ static const char *option_help[] = { "Use to create some attributes when writing an object", "Specify the input file", "Specify the output file", + "Format for ECDSA signature : 'rs' (default), 'sequence', 'openssl'", "Test (best used with the --login or --pin option)", "Test hotplug capabilities (C_GetSlotList + C_WaitForSlotEvent)", @@ -262,6 +264,7 @@ static char * opt_application_id = NULL; static char * opt_issuer = NULL; static char * opt_subject = NULL; static char * opt_key_type = NULL; +static char * opt_sig_format = NULL; static int opt_is_private = 0; static int opt_test_hotplug = 0; static int opt_login_type = -1; @@ -420,7 +423,7 @@ int main(int argc, char * argv[]) CRYPTO_malloc_init(); #endif while (1) { - c = getopt_long(argc, argv, "ILMOTa:bd:e:hi:klm:o:p:scvty:w:z:r", + c = getopt_long(argc, argv, "ILMOTa:bd:e:hi:klm:o:p:scvf:ty:w:z:r", options, &long_optind); if (c == -1) break; @@ -543,6 +546,9 @@ int main(int argc, char * argv[]) do_sign = 1; action_count++; break; + case 'f': + opt_sig_format = optarg; + break; case 't': need_session |= NEED_SESSION_RO; do_test = 1; @@ -1424,33 +1430,23 @@ static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, util_fatal("failed to open %s: %m", opt_output); } -#if defined(ENABLE_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_ECDSA) -/* - * PKCS11 implies the ECDSA sig is 2nLen, - * OpenSSL expects sequence of {integer, integer} - * so we will write it for OpenSSL if built with OpenSSL - */ - if (opt_mechanism == CKM_ECDSA) { - int nLen; - ECDSA_SIG * ecsig = NULL; - unsigned char *p = NULL; - int der_len; - - nLen = sig_len/2; + if (opt_mechanism == CKM_ECDSA || opt_mechanism == CKM_ECDSA_SHA1) { + if (opt_sig_format && (!strcmp(opt_sig_format, "openssl") || !strcmp(opt_sig_format, "sequence"))) { + unsigned char *seq; + size_t seqlen; - ecsig = ECDSA_SIG_new(); - ecsig->r = BN_bin2bn(sig_buffer, nLen, ecsig->r); - ecsig->s = BN_bin2bn(sig_buffer + nLen, nLen, ecsig->s); + if (sc_asn1_sig_value_rs_to_sequence(NULL, sig_buffer, sig_len, &seq, &seqlen)) { + util_fatal("Failed to convert signature to ASN.1 sequence format."); + } - der_len = i2d_ECDSA_SIG(ecsig, &p); - printf("Writing OpenSSL ECDSA_SIG\n"); - r = write(fd, p, der_len); - free(p); - ECDSA_SIG_free(ecsig); + memcpy(sig_buffer, seq, seqlen); + sig_len = seqlen; - } else -#endif /* ENABLE_OPENSSL && !OPENSSL_NO_EC && !OPENSSL_NO_ECDSA */ + free(seq); + } + } r = write(fd, sig_buffer, sig_len); + if (r < 0) util_fatal("Failed to write to %s: %m", opt_output); if (fd != 1) diff --git a/src/tools/pkcs15-tool.c b/src/tools/pkcs15-tool.c index 409d9847db..abc64f4354 100644 --- a/src/tools/pkcs15-tool.c +++ b/src/tools/pkcs15-tool.c @@ -57,6 +57,9 @@ static const char * opt_pin = NULL; static const char * opt_puk = NULL; static int verbose = 0; static int opt_no_prompt = 0; +#if defined(ENABLE_OPENSSL) && (defined(_WIN32) || defined(HAVE_INTTYPES_H)) +static int opt_rfc4716 = 0; +#endif enum { OPT_CHANGE_PIN = 0x100, @@ -68,6 +71,7 @@ enum { OPT_READ_PUB, #if defined(ENABLE_OPENSSL) && (defined(_WIN32) || defined(HAVE_INTTYPES_H)) OPT_READ_SSH, + OPT_RFC4716, #endif OPT_PIN, OPT_NEWPIN, @@ -76,7 +80,7 @@ enum { OPT_BIND_TO_AID, OPT_LIST_APPLICATIONS, OPT_LIST_SKEYS, - OPT_NO_PROMPT + OPT_NO_PROMPT, }; #define NELEMENTS(x) (sizeof(x)/sizeof((x)[0])) @@ -100,6 +104,7 @@ static const struct option options[] = { { "read-public-key", required_argument, NULL, OPT_READ_PUB }, #if defined(ENABLE_OPENSSL) && (defined(_WIN32) || defined(HAVE_INTTYPES_H)) { "read-ssh-key", required_argument, NULL, OPT_READ_SSH }, + { "rfc4716", no_argument, NULL, OPT_RFC4716 }, #endif { "test-update", no_argument, NULL, 'T' }, { "update", no_argument, NULL, 'U' }, @@ -786,6 +791,36 @@ static int list_skeys(void) #if defined(ENABLE_OPENSSL) && (defined(_WIN32) || defined(HAVE_INTTYPES_H)) + +static void print_ssh_key(FILE *outf, const char * alg, struct sc_pkcs15_object *obj, unsigned char * buf, uint32_t len) { + unsigned char *uu; + int r; + + uu = malloc(len*2); // Way over - even if we have extra LFs; as each 6 bits take one byte. + + if (opt_rfc4716) { + r = sc_base64_encode(buf, len, uu, 2*len, 64); + + fprintf(outf,"---- BEGIN SSH2 PUBLIC KEY ----\n"); + + if (obj->label && strlen(obj->label)) + fprintf(outf,"Comment: \"%s\"\n", obj->label); + + fprintf(outf,"%s", uu); + fprintf(outf,"---- END SSH2 PUBLIC KEY ----\n"); + } else { + // Old style openssh - [ [ anything else] + // + r = sc_base64_encode(buf, len, uu, 2*len, 0); + if (obj->label && strlen(obj->label)) + fprintf(outf,"ssh-%s %s %s\n", alg, uu, obj->label); + else + fprintf(outf,"ssh-%s %s\n", alg, uu); + } + free(uu); + return; +} + static int read_ssh_key(void) { int r; @@ -844,7 +879,6 @@ static int read_ssh_key(void) if (pubkey->algorithm == SC_ALGORITHM_RSA) { unsigned char buf[2048]; - unsigned char *uu; uint32_t len, n; if (!pubkey->u.rsa.modulus.data || !pubkey->u.rsa.modulus.len || @@ -895,16 +929,11 @@ static int read_ssh_key(void) memcpy(buf+len,pubkey->u.rsa.modulus.data, pubkey->u.rsa.modulus.len); len += pubkey->u.rsa.modulus.len; - uu = malloc(len*2); - r = sc_base64_encode(buf, len, uu, 2*len, 2*len); - - fprintf(outf,"ssh-rsa %s", uu); - free(uu); + print_ssh_key(outf, "rsa", obj, buf, len); } if (pubkey->algorithm == SC_ALGORITHM_DSA) { unsigned char buf[2048]; - unsigned char *uu; uint32_t len; uint32_t n; @@ -991,11 +1020,7 @@ static int read_ssh_key(void) memcpy(buf+len,pubkey->u.dsa.pub.data, pubkey->u.dsa.pub.len); len += pubkey->u.dsa.pub.len; - uu = malloc(len*2); - r = sc_base64_encode(buf, len, uu, 2*len, 2*len); - - fprintf(outf,"ssh-dss %s", uu); - free(uu); + print_ssh_key(outf, "dss", obj, buf, len); } if (outf != stdout) @@ -1016,6 +1041,7 @@ static int read_ssh_key(void) sc_pkcs15_free_pubkey(pubkey); return SC_ERROR_OUT_OF_MEMORY; } + #endif static sc_pkcs15_object_t * @@ -1900,6 +1926,9 @@ int main(int argc, char * const argv[]) do_read_sshkey = 1; action_count++; break; + case OPT_RFC4716: + opt_rfc4716 = 1; + break; #endif case 'L': do_learn_card = 1;