diff --git a/.travis.yml b/.travis.yml index 9942ca5d..28734919 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ addons: - wine - xsltproc - gengetopt + - help2man coverity_scan: project: name: "OpenSC/OpenSC" @@ -51,7 +52,7 @@ before_install: brew update; brew uninstall libtool; brew install libtool; - brew install gengetopt; + brew install gengetopt help2man; fi before_script: diff --git a/MacOSX/build-package.in b/MacOSX/build-package.in index 551d6ca0..e0ab9fb3 100755 --- a/MacOSX/build-package.in +++ b/MacOSX/build-package.in @@ -40,9 +40,24 @@ if ! pkg-config libcrypto --atleast-version=1.0.1; then export OPENSSL_LIBS="` env PKG_CONFIG_PATH=$BUILDPATH/openssl_bin/$PREFIX/lib/pkgconfig PKG_CONFIG_SYSROOT_DIR=$BUILDPATH/openssl_bin pkg-config --static --libs libcrypto`" fi +if ! test -e $BUILDPATH/openpace_bin/$PREFIX/lib/pkgconfig; then + if ! test -e openpace; then + git clone --depth=1 https://github.com/frankmorgner/openpace.git + fi + cd openpace + autoreconf -vis + ./configure --disable-shared --prefix=$PREFIX CRYPTO_CFLAGS="$OPENSSL_CFLAGS" CRYPTO_LIBS="$OPENSSL_LIBS" + make DESTDIR=$BUILDPATH/openpace_bin install + cd .. + export OPENPACE_CFLAGS="`env PKG_CONFIG_PATH=$BUILDPATH/openpace_bin/$PREFIX/lib/pkgconfig PKG_CONFIG_SYSROOT_DIR=$BUILDPATH/openpace_bin pkg-config --static --cflags libeac` $OPENSSL_CFLAGS" + export OPENPACE_LIBS="` env PKG_CONFIG_PATH=$BUILDPATH/openpace_bin/$PREFIX/lib/pkgconfig PKG_CONFIG_SYSROOT_DIR=$BUILDPATH/openpace_bin pkg-config --static --libs libeac` $OPENSSL_LIBS" +fi + if ! test -e ${BUILDPATH}/target/$PREFIX/lib/pkgconfig; then ./configure --prefix=$PREFIX \ --sysconfdir=$PREFIX/etc \ + --enable-cvcdir=$PREFIX/etc/cvc \ + --enable-x509dir=$PREFIX/etc/x509 \ --disable-dependency-tracking \ --enable-shared \ --disable-static \ diff --git a/appveyor.yml b/appveyor.yml index a599e528..ae8c3308 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -30,6 +30,7 @@ install: - date /T & time /T - set PATH=C:\cygwin\bin;%PATH% - set OPENSSL_VER=1_0_2e + - set OPENPACE_VER=1.0.1 - set ZLIB_VER_DOT=1.2.8 - ps: $env:PACKAGE_NAME=(git describe --tags) - ps: >- @@ -62,6 +63,11 @@ install: } 7z x zlib.zip -oC:\ Rename-Item -path "c:\zlib-${env:ZLIB_VER_DOT}" -newName "zlib" + If (!(Test-Path openpace.zip )) { + appveyor DownloadFile "https://github.com/frankmorgner/openpace/archive/${env:OPENPACE_VER}.zip" -FileName openpace.zip + } + 7z x openpace.zip -oC:\ + Rename-Item -path "c:\openpace-${env:OPENPACE_VER}" -newName "openpace" } - ps: $env:VSCOMNTOOLS=(Get-Content ("env:VS" + "$env:VSVER" + "0COMNTOOLS")) - echo "Using Visual Studio %VSVER%.0 at %VSCOMNTOOLS%" @@ -72,9 +78,9 @@ install: - set build_script: - # build zlib.lib as a static library - ps: >- if (!($env:Configuration -Like "*Light*")) { + # build zlib.lib as a static library cd C:\zlib (Get-Content win32/Makefile.msc).replace('-MD', '-MT') | Set-Content win32/Makefile.msc If ($env:Platform -Match "x86") { @@ -83,7 +89,12 @@ build_script: nmake -f win32/Makefile.msc AS=ml64 LOC="-DASMV -DASMINF -I." OBJA="inffasx64.obj gvmat64.obj inffas8664.obj" zlib.lib } $env:NMAKE_EXTRA="ZLIBSTATIC_DEF=/DENABLE_ZLIB_STATIC ${env:NMAKE_EXTRA}" - cd c:\projects\Opensc + # build libeac.lib as a static library + cd C:\openpace\src + cl /IC:\OpenSSL-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c + lib /out:libeac.lib ca_lib.obj cv_cert.obj cvc_lookup.obj x509_lookup.obj eac_asn1.obj eac.obj eac_ca.obj eac_dh.obj eac_ecdh.obj eac_kdf.obj eac_lib.obj eac_print.obj eac_util.obj misc.obj pace.obj pace_lib.obj pace_mappings.obj ri.obj ri_lib.obj ta.obj ta_lib.obj objects.obj + $env:NMAKE_EXTRA="OPENPACE_DEF=/DENABLE_OPENPACE ${env:NMAKE_EXTRA}" + cd C:\projects\OpenSC } - bash -c "exec 0drv_data; + sc_file_t *file = NULL; + sc_path_t cpath; + + if (file_out == NULL) { // Versions before 0.16 of the SmartCard-HSM do not support P2='0C' + rv = sc_hsm_select_file_ex(card, in_path, forceselect, &file); + if (file != NULL) { + sc_file_free(file); + } + return rv; + } + + if ((in_path->type == SC_PATH_TYPE_FILE_ID) && in_path->aid.len) { + // Split applet selection and file selection into two separate calls + cpath = *in_path; + cpath.len = 0; + cpath.type = SC_PATH_TYPE_DF_NAME; + rv = sc_hsm_select_file_ex(card, &cpath, forceselect, NULL); + LOG_TEST_RET(card->ctx, rv, "Could not select SmartCard-HSM application"); + + if (in_path->len) { + cpath = *in_path; + cpath.aid.len = 0; + rv = sc_hsm_select_file_ex(card, &cpath, forceselect, file_out); + } + return rv; + } + + // Prevent selection of applet unless this is the first time, selection is forced or the device is not authenticated + if (in_path->type == SC_PATH_TYPE_DF_NAME + || (in_path->type == SC_PATH_TYPE_PATH + && in_path->len == sc_hsm_aid.len + && !memcmp(in_path->value, sc_hsm_aid.value, sc_hsm_aid.len)) + || (in_path->type == SC_PATH_TYPE_PATH + && in_path->len == 0 + && in_path->aid.len == sc_hsm_aid.len + && !memcmp(in_path->aid.value, sc_hsm_aid.value, sc_hsm_aid.len))) { + if ((priv->dffcp == NULL) || forceselect) { + rv = (*iso_ops->select_file)(card, in_path, file_out); + LOG_TEST_RET(card->ctx, rv, "Could not select SmartCard-HSM application"); + + if (priv->dffcp != NULL) { + sc_file_free(priv->dffcp); + } + // Cache the FCP returned when selecting the applet + sc_file_dup(&priv->dffcp, *file_out); + } else { + sc_file_dup(file_out, priv->dffcp); + rv = SC_SUCCESS; + } + return rv; + } + + if ((in_path->value[0] == 0x3F) && (in_path->value[1] == 0x00)) { + // The SmartCard-HSM is an applet that is not default selected. Simulate selection of the MF + if (in_path->len == 2) { + file = sc_file_new(); + if (file == NULL) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); + file->path = *in_path; + file->id = 0x3F00; + file->type = SC_FILE_TYPE_DF; + file->magic = SC_FILE_MAGIC; + + *file_out = file; + return SC_SUCCESS; + } else { + sc_path_t truncated; + memcpy(&truncated, in_path, sizeof truncated); + truncated.len = in_path->len - 2; + memcpy(truncated.value, in_path->value+2, truncated.len); + return (*iso_ops->select_file)(card, &truncated, file_out); + } + } + return (*iso_ops->select_file)(card, in_path, file_out); +} + + + static int sc_hsm_select_file(sc_card_t *card, const sc_path_t *in_path, sc_file_t **file_out) { - int rv; - sc_file_t *file = NULL; - - if (file_out == NULL) { // Versions before 0.16 of the SmartCard-HSM do not support P2='0C' - rv = sc_hsm_select_file(card, in_path, &file); - sc_file_free(file); - return rv; - } - - if ((in_path->len == 2) && (in_path->value[0] == 0x3F) && (in_path->value[1] == 0x00)) { - // The SmartCard-HSM is an applet that is not default selected. Simulate selection of the MF - file = sc_file_new(); - if (file == NULL) - LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); - file->path = *in_path; - file->id = 0x3F00; - file->type = SC_FILE_TYPE_DF; - file->magic = SC_FILE_MAGIC; - - *file_out = file; - return SC_SUCCESS; - } - return (*iso_ops->select_file)(card, in_path, file_out); + return sc_hsm_select_file_ex(card, in_path, 0, file_out); } static int sc_hsm_match_card(struct sc_card *card) { + sc_hsm_private_data_t *priv; sc_path_t path; int i, r; @@ -121,10 +185,44 @@ static int sc_hsm_match_card(struct sc_card *card) if (i < 0) return 0; + priv = calloc(1, sizeof(sc_hsm_private_data_t)); + if (!priv) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); + + card->drv_data = priv; + sc_path_set(&path, SC_PATH_TYPE_DF_NAME, sc_hsm_aid.value, sc_hsm_aid.len, 0, 0); - r = sc_hsm_select_file(card, &path, NULL); + r = (*iso_ops->select_file)(card, &path, &priv->dffcp); LOG_TEST_RET(card->ctx, r, "Could not select SmartCard-HSM application"); + if (priv->dffcp) { + if (priv->dffcp->prop_attr && priv->dffcp->prop_attr_len >= 5) { + static char card_name[SC_MAX_APDU_BUFFER_SIZE]; + u8 type = priv->dffcp->prop_attr[2]; + u8 major = priv->dffcp->prop_attr[3]; + u8 minor = priv->dffcp->prop_attr[4]; + char p00[] = "SmartCard-HSM Applet for JCOP"; + char p01[] = "SmartCard-HSM Demo Applet for JCOP"; + char *p = "SmartCard-HSM"; + switch (type) { + case 0x00: + p = p00; + break; + case 0x01: + p = p01; + break; + default: + break; + } + snprintf(card_name, sizeof card_name, "%s version %u.%u", p, major, minor); + card->name = card_name; + + if (priv->dffcp->prop_attr[1] & 0x04) { + card->caps |= SC_CARD_CAP_SESSION_PIN; + } + } + } + // Select Applet to be sure return 1; } @@ -162,6 +260,258 @@ static int sc_hsm_encode_sopin(const u8 *sopin, u8 *sopinbin) } +static int sc_hsm_soc_select_minbioclient(sc_card_t *card) +{ + sc_apdu_t apdu; + struct sc_aid minBioClient_aid = { + { 0xFF,'m','i','n','B','i','o','C','l','i','e','n','t',0x01 }, 14 + }; + + /* Select MinBioClient */ + sc_sm_stop(card); + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x04, 0x0C); + apdu.data = minBioClient_aid.value; + apdu.datalen = minBioClient_aid.len; + apdu.lc = minBioClient_aid.len; + LOG_TEST_RET(card->ctx, + sc_transmit_apdu(card, &apdu), + "APDU transmit failed"); + + return sc_check_sw(card, apdu.sw1, apdu.sw2); +} + +static int sc_hsm_soc_change(sc_card_t *card, struct sc_pin_cmd_data *data, + int *tries_left) +{ + sc_apdu_t apdu; + sc_path_t path; + int r; + + /* Select MinBioClient */ + r = sc_hsm_soc_select_minbioclient(card); + LOG_TEST_RET(card->ctx, r, "Could not select MinBioClient application"); + + /* verify PIN */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, 0x80); + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_GOTO_ERR(card->ctx, r, "APDU transmit failed"); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + LOG_TEST_GOTO_ERR(card->ctx, r, "Could not verify PIN"); + + /* change PIN */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x24, 0x01, 0x80); + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_GOTO_ERR(card->ctx, r, "APDU transmit failed"); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + LOG_TEST_GOTO_ERR(card->ctx, r, "Could not change PIN"); + +err: + /* Select SC-HSM */ + sc_path_set(&path, SC_PATH_TYPE_DF_NAME, sc_hsm_aid.value, sc_hsm_aid.len, 0, 0); + LOG_TEST_RET(card->ctx, + sc_hsm_select_file_ex(card, &path, 1, NULL), + "Could not select SmartCard-HSM application"); + + return r; +} + +static int sc_hsm_soc_unblock(sc_card_t *card, struct sc_pin_cmd_data *data, + int *tries_left) +{ + sc_apdu_t apdu; + sc_path_t path; + int r; + + /* Select MinBioClient */ + r = sc_hsm_soc_select_minbioclient(card); + LOG_TEST_RET(card->ctx, r, "Could not select MinBioClient application"); + + /* verify PUK */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, 0x81); + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_GOTO_ERR(card->ctx, r, "APDU transmit failed"); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + LOG_TEST_GOTO_ERR(card->ctx, r, "Could not verify PUK"); + + /* reset retry counter */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x2c, 0x03, 0x00); + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_GOTO_ERR(card->ctx, r, "APDU transmit failed"); + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + LOG_TEST_GOTO_ERR(card->ctx, r, "Could not unblock PIN"); + +err: + /* Select SC-HSM */ + sc_path_set(&path, SC_PATH_TYPE_DF_NAME, sc_hsm_aid.value, sc_hsm_aid.len, 0, 0); + LOG_TEST_RET(card->ctx, + sc_hsm_select_file_ex(card, &path, 1, NULL), + "Could not select SmartCard-HSM application"); + + return r; +} + +static int sc_hsm_soc_biomatch(sc_card_t *card, struct sc_pin_cmd_data *data, + int *tries_left) +{ + sc_apdu_t apdu; + u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; + int r; + + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x20, 0x00, 0x85); + apdu.cla = 0x80; + apdu.data = (unsigned char*)"\x7F\x24\x00"; + apdu.datalen = 3; + apdu.lc = 3; + apdu.resplen = 0; + + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + /* ignore the actual status bytes */ + + /* JCOP's SM accelerator is incapable of using case 1 APDU in SM */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x20, 0x00, 0x81); + apdu.resp = rbuf; + apdu.resplen = sizeof rbuf; + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + + /* now check the status bytes */ + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + if (r == SC_SUCCESS) { + LOG_FUNC_RETURN(card->ctx, r); + } + + LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT); +} + + + +#ifdef ENABLE_OPENPACE +#include "sm/sm-eac.h" +#include +#include +#include +#include +#include + +static int sc_hsm_perform_chip_authentication(sc_card_t *card) +{ + int r, protocol; + sc_path_t path; + u8 all_certs[1024]; + EAC_CTX *ctx = NULL; + size_t all_certs_len = sizeof all_certs, left, device_cert_len, issuer_cert_len; + const unsigned char *cert = all_certs, *device_cert, *issuer_cert; + BUF_MEM *comp_pub_key = NULL; + sc_cvc_t cvc_device, cvc_issuer; + /* this is only needed to call sc_pkcs15emu_sc_hsm_decode_cvc */ + sc_pkcs15_card_t p15card; + sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data; + /* we know that sc_pkcs15emu_sc_hsm_decode_cvc does not require anything + * else to be initialized than p15card->card */ + p15card.card = card; + + memset(&cvc_device, 0, sizeof(cvc_device)); + memset(&cvc_issuer, 0, sizeof(cvc_issuer)); + + + if (priv->EF_C_DevAut && priv->EF_C_DevAut_len) { + all_certs_len = priv->EF_C_DevAut_len; + cert = priv->EF_C_DevAut; + } else { + /* get issuer and device certificate from the card */ + r = sc_path_set(&path, SC_PATH_TYPE_FILE_ID, (u8 *) "\x2F\x02", 2, 0, 0); + if (r < 0) + goto err; + r = sc_select_file(card, &path, NULL); + if (r < 0) + goto err; + r = sc_read_binary(card, 0, all_certs, all_certs_len, 0); + if (r < 0) + goto err; + + all_certs_len = r; + + /* save EF_C_DevAut for further use */ + cert = realloc(priv->EF_C_DevAut, all_certs_len); + if (cert) { + memcpy((unsigned char *) cert, all_certs, all_certs_len); + priv->EF_C_DevAut = (unsigned char *) cert; + priv->EF_C_DevAut_len = all_certs_len; + } + + cert = all_certs; + } + left = all_certs_len; + + device_cert = cert; + r = sc_pkcs15emu_sc_hsm_decode_cvc(&p15card, &cert, &left, &cvc_device); + if (r < 0) + goto err; + device_cert_len = all_certs_len - left; + + issuer_cert = cert; + r = sc_pkcs15emu_sc_hsm_decode_cvc(&p15card, &cert, &left, &cvc_issuer); + if (r < 0) + goto err; + issuer_cert_len = all_certs_len - device_cert_len - left; + + ctx = EAC_CTX_new(); + if (!ctx) { + r = SC_ERROR_INTERNAL; + goto err; + } + + + /* check all CVCs given of the document's pki */ + if (!TA_STEP2_import_certificate(ctx, issuer_cert, issuer_cert_len) + || !TA_STEP2_import_certificate(ctx, device_cert, device_cert_len)) { + r = SC_ERROR_INTERNAL; + goto err; + } + + if (card->type == SC_CARD_TYPE_SC_HSM_SOC) { + /* SoC cards are known to be implemented on newer JCOPs */ + protocol = NID_id_CA_ECDH_AES_CBC_CMAC_128; + } else { + /* Older cards may not support AES accelerator */ + protocol = NID_id_CA_ECDH_3DES_CBC_CBC; + } + + /* initialize CA domain parameter with the document's public key */ + if (!EAC_CTX_init_ca(ctx, protocol, 8)) { + r = SC_ERROR_INTERNAL; + goto err; + } + EVP_PKEY_free(ctx->ca_ctx->ka_ctx->key); + CRYPTO_add(&ctx->ta_ctx->pub_key->references, 1, CRYPTO_LOCK_EVP_PKEY); + ctx->ca_ctx->ka_ctx->key = ctx->ta_ctx->pub_key; + + /* generate keys for CA */ + comp_pub_key = TA_STEP3_generate_ephemeral_key(ctx); + r = perform_chip_authentication_ex(card, ctx, + cvc_device.publicPoint, cvc_device.publicPointlen); + +err: + if (r < 0) + EAC_CTX_clear_free(ctx); + if (comp_pub_key) + BUF_MEM_free(comp_pub_key); + sc_pkcs15emu_sc_hsm_free_cvc(&cvc_device); + sc_pkcs15emu_sc_hsm_free_cvc(&cvc_issuer); + + return r; +} + +#else + +static int sc_hsm_perform_chip_authentication(sc_card_t *card) +{ + return SC_ERROR_NOT_SUPPORTED; +} +#endif + + static int sc_hsm_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left) @@ -169,43 +519,132 @@ static int sc_hsm_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data; sc_apdu_t apdu; u8 cmdbuff[16]; + u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; int r; + int cmd = data->cmd; + size_t pin2_len = data->pin2.len; - if ((data->cmd == SC_PIN_CMD_VERIFY) && (data->pin_reference == 0x88)) { - if (data->pin1.len != 16) - return SC_ERROR_INVALID_PIN_LENGTH; - - // Save SO PIN for later use in sc_hsm_init_pin() - r = sc_hsm_encode_sopin(data->pin1.data, priv->sopin); - LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); - - LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); + if (cmd == SC_PIN_CMD_GET_SESSION_PIN) { + /* First, perform a standard VERIFY */ + data->cmd = SC_PIN_CMD_VERIFY; + /* we assign pin2.len to 0 early on so that in case of an error we are + * not exiting with an undefined session PIN */ + data->pin2.len = 0; } - if ((data->cmd == SC_PIN_CMD_CHANGE) && (data->pin_reference == 0x88)) { - if ((data->pin1.len != 16) || (data->pin2.len != 16)) - return SC_ERROR_INVALID_PIN_LENGTH; - - r = sc_hsm_encode_sopin(data->pin1.data, cmdbuff); - LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); - - r = sc_hsm_encode_sopin(data->pin2.data, cmdbuff + 8); - LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); - - sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x00, data->pin_reference); - apdu.data = cmdbuff; - apdu.datalen = sizeof(cmdbuff); - apdu.lc = 16; - apdu.resplen = 0; - data->apdu = &apdu; + if ((card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH) + && (data->cmd == SC_PIN_CMD_CHANGE) + && (data->pin_reference == 0x81) + && (!data->pin1.data || data->pin1.len <= 0)) { + return sc_hsm_soc_change(card, data, tries_left); + } else if ((card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH) + && (data->cmd == SC_PIN_CMD_UNBLOCK) + && (data->pin_reference == 0x81) + && (!data->pin1.data || data->pin1.len <= 0)) { + return sc_hsm_soc_unblock(card, data, tries_left); } - data->pin1.offset = 5; - data->pin1.length_offset = 4; - data->pin2.offset = 5; - data->pin2.length_offset = 4; + /* For contactless cards always establish a secure channel before PIN + * verification */ + if (card->type == SC_CARD_TYPE_SC_HSM_SOC + && (data->cmd != SC_PIN_CMD_GET_INFO) + && card->sm_ctx.sm_mode != SM_MODE_TRANSMIT) { + LOG_TEST_RET(card->ctx, + sc_hsm_perform_chip_authentication(card), + "Could not perform chip authentication"); + } - return (*iso_ops->pin_cmd)(card, data, tries_left); + if ((card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH) + && (data->cmd == SC_PIN_CMD_VERIFY) + && (data->pin_reference == 0x81) + && (!data->pin1.data || data->pin1.len <= 0)) { + r = sc_hsm_soc_biomatch(card, data, tries_left); + } else { + if ((data->cmd == SC_PIN_CMD_VERIFY) && (data->pin_reference == 0x88)) { + if (data->pin1.len != 16) + return SC_ERROR_INVALID_PIN_LENGTH; + + // Save SO PIN for later use in sc_hsm_init_pin() + r = sc_hsm_encode_sopin(data->pin1.data, priv->sopin); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); + } + + if ((data->cmd == SC_PIN_CMD_CHANGE) && (data->pin_reference == 0x88)) { + if ((data->pin1.len != 16) || (data->pin2.len != 16)) + return SC_ERROR_INVALID_PIN_LENGTH; + + r = sc_hsm_encode_sopin(data->pin1.data, cmdbuff); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + + r = sc_hsm_encode_sopin(data->pin2.data, cmdbuff + 8); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x00, data->pin_reference); + apdu.data = cmdbuff; + apdu.datalen = sizeof(cmdbuff); + apdu.lc = 16; + apdu.resplen = 0; + data->apdu = &apdu; + } + + if ((data->cmd == SC_PIN_CMD_GET_INFO) + && (card->sm_ctx.sm_mode == SM_MODE_TRANSMIT)) { + /* JCOP's SM accelerator is incapable of using case 1 APDU in SM */ + sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x20, 0x00, data->pin_reference); + apdu.resp = rbuf; + apdu.resplen = sizeof rbuf; + data->apdu = &apdu; + } + + data->pin1.offset = 5; + data->pin1.length_offset = 4; + data->pin2.offset = 5; + data->pin2.length_offset = 4; + + r = (*iso_ops->pin_cmd)(card, data, tries_left); + } + LOG_TEST_RET(card->ctx, r, "Verification failed"); + + if (cmd == SC_PIN_CMD_GET_SESSION_PIN) { + /* reset data->cmd to its original value */ + data->cmd = SC_PIN_CMD_GET_SESSION_PIN; + if (data->pin_reference == 0x81) { + u8 recvbuf[SC_MAX_APDU_BUFFER_SIZE]; + if (card->sm_ctx.sm_mode != SM_MODE_TRANSMIT) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, + "Session PIN generation only supported in SM"); + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); + } + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x5A, 0x01, data->pin_reference); + apdu.cla = 0x80; + apdu.resp = recvbuf; + apdu.resplen = sizeof recvbuf; + apdu.le = 0; + if (sc_transmit_apdu(card, &apdu) != SC_SUCCESS + || sc_check_sw(card, apdu.sw1, apdu.sw2) != SC_SUCCESS) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, + "Generating session PIN failed"); + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); + } + if (data->pin2.data && pin2_len > 0) { + if (pin2_len >= apdu.resplen) { + memcpy((unsigned char *) data->pin2.data, apdu.resp, + apdu.resplen); + data->pin2.len = apdu.resplen; + } else { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, + "Buffer too small for session PIN"); + } + } + } else { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, + "Session PIN not supported for this PIN (0x%02X)", + data->pin_reference); + } + } + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } @@ -215,10 +654,11 @@ static int sc_hsm_logout(sc_card_t * card) sc_path_t path; sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data; memset(priv->sopin, 0, sizeof(priv->sopin)); + sc_sm_stop(card); sc_path_set(&path, SC_PATH_TYPE_DF_NAME, sc_hsm_aid.value, sc_hsm_aid.len, 0, 0); - return sc_hsm_select_file(card, &path, NULL); + return sc_hsm_select_file_ex(card, &path, 1, NULL); } @@ -409,7 +849,6 @@ static int sc_hsm_delete_file(sc_card_t *card, const sc_path_t *path) } - static int sc_hsm_set_security_env(sc_card_t *card, const sc_security_env_t *env, int se_num) @@ -565,6 +1004,7 @@ static int sc_hsm_compute_signature(sc_card_t *card, apdu.lc = datalen; apdu.datalen = datalen; r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) { int len; @@ -1029,17 +1469,17 @@ static int sc_hsm_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) static int sc_hsm_init(struct sc_card *card) { - sc_hsm_private_data_t *priv; +#ifdef _WIN32 + char expanded_val[PATH_MAX]; + size_t expanded_len = PATH_MAX; +#endif int flags,ext_flags; + sc_file_t *file; + sc_path_t path; + sc_hsm_private_data_t *priv = card->drv_data; LOG_FUNC_CALLED(card->ctx); - priv = calloc(1, sizeof(sc_hsm_private_data_t)); - if (!priv) - LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); - - card->drv_data = priv; - flags = SC_ALGORITHM_RSA_RAW|SC_ALGORITHM_ONBOARD_KEY_GEN; _sc_card_add_rsa_alg(card, 1024, flags, 0); @@ -1066,8 +1506,56 @@ static int sc_hsm_init(struct sc_card *card) card->caps |= SC_CARD_CAP_RNG|SC_CARD_CAP_APDU_EXT|SC_CARD_CAP_ISO7816_PIN_INFO; + sc_path_set(&path, SC_PATH_TYPE_DF_NAME, sc_hsm_aid.value, sc_hsm_aid.len, 0, 0); + if (sc_hsm_select_file_ex(card, &path, 0, &file) == SC_SUCCESS + && file->prop_attr && file->prop_attr_len >= 5) { + static char card_name[SC_MAX_APDU_BUFFER_SIZE]; + u8 type = file->prop_attr[2]; + u8 major = file->prop_attr[3]; + u8 minor = file->prop_attr[4]; + char p00[] = "SmartCard-HSM Applet for JCOP"; + char p01[] = "SmartCard-HSM Demo Applet for JCOP"; + char *p = "SmartCard-HSM"; + switch (type) { + case 0x00: + p = p00; + break; + case 0x01: + p = p01; + break; + default: + break; + } + snprintf(card_name, sizeof card_name, "%s version %u.%u", p, major, minor); + card->name = card_name; + + if (file->prop_attr[1] & 0x04) { + card->caps |= SC_CARD_CAP_SESSION_PIN; + } + sc_file_free(file); + } + card->max_send_size = 1431; // 1439 buffer size - 8 byte TLV because of odd ins in UPDATE BINARY - card->max_recv_size = 0; // Card supports sending with extended length APDU and without limit + if (card->type == SC_CARD_TYPE_SC_HSM_SOC) { + card->max_recv_size = 0x0630; // SoC Proxy forces this limit + } else { + card->max_recv_size = 0; // Card supports sending with extended length APDU and without limit + } + + priv->EF_C_DevAut = NULL; + priv->EF_C_DevAut_len = 0; + +#ifdef ENABLE_OPENPACE + EAC_init(); +#ifdef _WIN32 + expanded_len = ExpandEnvironmentStringsA(CVCDIR, expanded_val, sizeof expanded_val); + if (0 < expanded_len && expanded_len < sizeof expanded_val) + EAC_set_cvc_default_dir(expanded_val); +#else + EAC_set_cvc_default_dir(CVCDIR); +#endif +#endif + return 0; } @@ -1076,10 +1564,20 @@ static int sc_hsm_init(struct sc_card *card) static int sc_hsm_finish(sc_card_t * card) { sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data; + sc_sm_stop(card); if (priv->serialno) { free(priv->serialno); } + if (priv->dffcp) { + sc_file_free(priv->dffcp); + } + free(priv->EF_C_DevAut); free(priv); + +#ifdef ENABLE_OPENPACE + EAC_cleanup(); +#endif + return SC_SUCCESS; } diff --git a/src/libopensc/card-sc-hsm.h b/src/libopensc/card-sc-hsm.h index 325f73fd..39efb461 100644 --- a/src/libopensc/card-sc-hsm.h +++ b/src/libopensc/card-sc-hsm.h @@ -56,10 +56,13 @@ /* Information the driver maintains between calls */ typedef struct sc_hsm_private_data { const sc_security_env_t *env; + sc_file_t *dffcp; u8 algorithm; int noExtLength; char *serialno; u8 sopin[8]; + u8 *EF_C_DevAut; + size_t EF_C_DevAut_len; } sc_hsm_private_data_t; diff --git a/src/libopensc/cards.h b/src/libopensc/cards.h index 992826cc..691182f3 100644 --- a/src/libopensc/cards.h +++ b/src/libopensc/cards.h @@ -204,6 +204,7 @@ enum { /* SmartCard-HSM */ SC_CARD_TYPE_SC_HSM = 26000, + SC_CARD_TYPE_SC_HSM_SOC = 26001, /* Spanish DNIe card */ SC_CARD_TYPE_DNIE_BASE = 27000, diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c index e74619a8..21801712 100644 --- a/src/libopensc/ctx.c +++ b/src/libopensc/ctx.c @@ -338,7 +338,7 @@ load_parameters(sc_context_t *ctx, scconf_block *block, struct _sc_ctx_options * #ifdef _WIN32 expanded_len = PATH_MAX; expanded_len = ExpandEnvironmentStringsA(val, expanded_val, expanded_len); - if (expanded_len > 0) + if (0 < expanded_len && expanded_len < sizeof expanded_val) val = expanded_val; #endif sc_ctx_log_to_file(ctx, val); diff --git a/src/libopensc/iso7816.c b/src/libopensc/iso7816.c index f0355a69..b1d2c91d 100644 --- a/src/libopensc/iso7816.c +++ b/src/libopensc/iso7816.c @@ -999,6 +999,8 @@ iso7816_build_pin_apdu(struct sc_card *card, struct sc_apdu *apdu, switch (data->pin_type) { case SC_AC_CHV: + /* fall through */ + case SC_AC_SESSION: break; default: return SC_ERROR_INVALID_ARGUMENTS; diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index 3aff3d2b..c96c410d 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -342,6 +342,7 @@ typedef struct sc_reader { #define SC_PIN_CMD_CHANGE 1 #define SC_PIN_CMD_UNBLOCK 2 #define SC_PIN_CMD_GET_INFO 3 +#define SC_PIN_CMD_GET_SESSION_PIN 4 #define SC_PIN_CMD_USE_PINPAD 0x0001 #define SC_PIN_CMD_NEED_PADDING 0x0002 @@ -475,6 +476,12 @@ struct sc_reader_operations { #define SC_CARD_CAP_ONLY_RAW_HASH 0x00000040 #define SC_CARD_CAP_ONLY_RAW_HASH_STRIPPED 0x00000080 +/* Card (or card driver) supports an protected authentication mechanism */ +#define SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH 0x00000100 + +/* Card (or card driver) supports generating a session PIN */ +#define SC_CARD_CAP_SESSION_PIN 0x00000200 + typedef struct sc_card { struct sc_context *ctx; struct sc_reader *reader; diff --git a/src/libopensc/pkcs15-pin.c b/src/libopensc/pkcs15-pin.c index 17c73041..28a39b70 100644 --- a/src/libopensc/pkcs15-pin.c +++ b/src/libopensc/pkcs15-pin.c @@ -270,7 +270,9 @@ _validate_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_auth_info *auth_i return SC_ERROR_BUFFER_TOO_SMALL; /* if we use pinpad, no more checks are needed */ - if (p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD && !pinlen) + if ((p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD + || p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH) + && !pinlen) return SC_SUCCESS; /* If pin is given, make sure it is within limits */ @@ -391,7 +393,9 @@ _sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *p data.pin_reference = skey_info->key_reference; } - if(p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD && !pinlen) { + if((p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD + || p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH) + && !pinlen) { data.flags |= SC_PIN_CMD_USE_PINPAD; if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) @@ -487,7 +491,8 @@ int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card, } if((!oldpin || !newpin) - && p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) { + && (p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD + || p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) { data.flags |= SC_PIN_CMD_USE_PINPAD; if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) { data.pin1.prompt = "Please enter SO PIN"; @@ -600,7 +605,8 @@ int sc_pkcs15_unblock_pin(struct sc_pkcs15_card *p15card, break; } - if(p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) { + if((p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD + || p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) { data.flags |= SC_PIN_CMD_USE_PINPAD; if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) { data.pin1.prompt = "Please enter PUK"; @@ -743,7 +749,8 @@ sc_pkcs15_pincache_revalidate(struct sc_pkcs15_card *p15card, const sc_pkcs15_ob return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; } - if (p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) + if ((p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD + || p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) return SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; r = sc_pkcs15_find_pin_by_auth_id(p15card, &obj->auth_id, &pin_obj); diff --git a/src/libopensc/pkcs15-sc-hsm.c b/src/libopensc/pkcs15-sc-hsm.c index a0dd3bf4..b71c9390 100644 --- a/src/libopensc/pkcs15-sc-hsm.c +++ b/src/libopensc/pkcs15-sc-hsm.c @@ -181,7 +181,7 @@ static const struct sc_asn1_entry c_asn1_req[C_ASN1_REQ_SIZE] = { static int read_file(sc_pkcs15_card_t * p15card, u8 fid[2], - u8 *efbin, size_t *len) + u8 *efbin, size_t *len, int optional) { sc_path_t path; int r; @@ -196,12 +196,24 @@ static int read_file(sc_pkcs15_card_t * p15card, u8 fid[2], /* avoid re-selection of SC-HSM */ path.aid.len = 0; r = sc_select_file(p15card->card, &path, NULL); - LOG_TEST_RET(p15card->card->ctx, r, "Could not select EF"); + if (r < 0) { + sc_log(p15card->card->ctx, "Could not select EF"); + } else { + r = sc_read_binary(p15card->card, 0, efbin, *len, 0); + } - r = sc_read_binary(p15card->card, 0, efbin, *len, 0); - LOG_TEST_RET(p15card->card->ctx, r, "Could not read EF"); - - *len = r; + if (r < 0) { + sc_log(p15card->card->ctx, "Could not read EF"); + if (!optional) { + return r; + } + /* optional files are saved as empty files to avoid card + * transactions. Parsing the file's data will reveal that they were + * missing. */ + *len = 0; + } else { + *len = r; + } if (p15card->opts.use_file_cache) { /* save this with our AID */ @@ -593,7 +605,7 @@ static int sc_pkcs15emu_sc_hsm_add_prkd(sc_pkcs15_card_t * p15card, u8 keyid) { /* Try to select a related EF containing the PKCS#15 description of the key */ len = sizeof efbin; - r = read_file(p15card, fid, efbin, &len); + r = read_file(p15card, fid, efbin, &len, 1); LOG_TEST_RET(card->ctx, r, "Could not read EF.PRKD"); ptr = efbin; @@ -627,7 +639,8 @@ static int sc_pkcs15emu_sc_hsm_add_prkd(sc_pkcs15_card_t * p15card, u8 keyid) { fid[0] = EE_CERTIFICATE_PREFIX; len = sizeof efbin; - r = read_file(p15card, fid, efbin, &len); + r = read_file(p15card, fid, efbin, &len, 0); + LOG_TEST_RET(card->ctx, r, "Could not read EF"); LOG_TEST_RET(card->ctx, r, "Could not read EF"); @@ -683,7 +696,7 @@ static int sc_pkcs15emu_sc_hsm_add_dcod(sc_pkcs15_card_t * p15card, u8 id) { /* Try to select a related EF containing the PKCS#15 description of the data */ len = sizeof efbin; - r = read_file(p15card, fid, efbin, &len); + r = read_file(p15card, fid, efbin, &len, 1); LOG_TEST_RET(card->ctx, r, "Could not read EF.DCOD"); ptr = efbin; @@ -722,7 +735,7 @@ static int sc_pkcs15emu_sc_hsm_add_cd(sc_pkcs15_card_t * p15card, u8 id) { /* Try to select a related EF containing the PKCS#15 description of the data */ len = sizeof efbin; - r = read_file(p15card, fid, efbin, &len); + r = read_file(p15card, fid, efbin, &len, 1); LOG_TEST_RET(card->ctx, r, "Could not read EF.DCOD"); ptr = efbin; @@ -753,7 +766,7 @@ static int sc_pkcs15emu_sc_hsm_read_tokeninfo (sc_pkcs15_card_t * p15card) /* Read token info */ len = sizeof efbin; - r = read_file(p15card, (u8 *) "\x2F\x03", efbin, &len); + r = read_file(p15card, (u8 *) "\x2F\x03", efbin, &len, 1); LOG_TEST_RET(card->ctx, r, "Could not read EF.TokenInfo"); r = sc_pkcs15_parse_tokeninfo(card->ctx, p15card->tokeninfo, efbin, len); @@ -771,6 +784,7 @@ static int sc_pkcs15emu_sc_hsm_read_tokeninfo (sc_pkcs15_card_t * p15card) static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card) { sc_card_t *card = p15card->card; + sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data; sc_file_t *file = NULL; sc_path_t path; u8 filelist[MAX_EXT_APDU_LENGTH]; @@ -780,7 +794,8 @@ static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card) struct sc_app_info *appinfo; struct sc_pkcs15_auth_info pin_info; struct sc_pkcs15_object pin_obj; - u8 efbin[512]; + struct sc_pin_cmd_data pindata; + u8 efbin[1024]; u8 *ptr; size_t len; @@ -809,11 +824,24 @@ static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card) sc_file_free(file); /* Read device certificate to determine serial number */ - len = sizeof efbin; - r = read_file(p15card, (u8 *) "\x2F\x02", efbin, &len); - LOG_TEST_RET(card->ctx, r, "Could not select EF.C_DevAut"); + if (priv->EF_C_DevAut && priv->EF_C_DevAut_len) { + ptr = priv->EF_C_DevAut; + len = priv->EF_C_DevAut_len; + } else { + len = sizeof efbin; + r = read_file(p15card, (u8 *) "\x2F\x02", efbin, &len, 1); + LOG_TEST_RET(card->ctx, r, "Could not select EF.C_DevAut"); - ptr = efbin; + /* save EF_C_DevAut for further use */ + ptr = realloc(priv->EF_C_DevAut, len); + if (ptr) { + memcpy(ptr, efbin, len); + priv->EF_C_DevAut = ptr; + priv->EF_C_DevAut_len = len; + } + + ptr = efbin; + } memset(&devcert, 0 ,sizeof(devcert)); r = sc_pkcs15emu_sc_hsm_decode_cvc(p15card, (const u8 **)&ptr, &len, &devcert); @@ -883,7 +911,6 @@ static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card) if (r < 0) LOG_FUNC_RETURN(card->ctx, r); - memset(&pin_info, 0, sizeof(pin_info)); memset(&pin_obj, 0, sizeof(pin_obj)); @@ -909,6 +936,30 @@ static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card) LOG_FUNC_RETURN(card->ctx, r); + if (card->type == SC_CARD_TYPE_SC_HSM_SOC) { + /* SC-HSM of this type always has a PIN-Pad */ + r = SC_SUCCESS; + } else { + memset(&pindata, 0, sizeof(pindata)); + pindata.cmd = SC_PIN_CMD_GET_INFO; + pindata.pin_type = SC_AC_CHV; + pindata.pin_reference = 0x85; + + r = sc_pin_cmd(card, &pindata, NULL); + } + if (r == SC_ERROR_DATA_OBJECT_NOT_FOUND) { + memset(&pindata, 0, sizeof(pindata)); + pindata.cmd = SC_PIN_CMD_GET_INFO; + pindata.pin_type = SC_AC_CHV; + pindata.pin_reference = 0x86; + + r = sc_pin_cmd(card, &pindata, NULL); + } + + if (r != SC_ERROR_DATA_OBJECT_NOT_FOUND) + card->caps |= SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH; + + filelistlength = sc_list_files(card, filelist, sizeof(filelist)); LOG_TEST_RET(card->ctx, filelistlength, "Could not enumerate file and key identifier"); @@ -941,7 +992,8 @@ int sc_pkcs15emu_sc_hsm_init_ex(sc_pkcs15_card_t *p15card, if (opts && (opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK)) { return sc_pkcs15emu_sc_hsm_init(p15card); } else { - if (p15card->card->type != SC_CARD_TYPE_SC_HSM) { + if (p15card->card->type != SC_CARD_TYPE_SC_HSM + && p15card->card->type != SC_CARD_TYPE_SC_HSM_SOC) { return SC_ERROR_WRONG_CARD; } return sc_pkcs15emu_sc_hsm_init(p15card); diff --git a/src/libopensc/pkcs15-syn.c b/src/libopensc/pkcs15-syn.c index 0fdcbed0..d72fc313 100644 --- a/src/libopensc/pkcs15-syn.c +++ b/src/libopensc/pkcs15-syn.c @@ -82,6 +82,7 @@ int sc_pkcs15_is_emulation_only(sc_card_t *card) case SC_CARD_TYPE_OPENPGP_V2: case SC_CARD_TYPE_OPENPGP_GNUK: case SC_CARD_TYPE_SC_HSM: + case SC_CARD_TYPE_SC_HSM_SOC: case SC_CARD_TYPE_DNIE_BASE: case SC_CARD_TYPE_DNIE_BLANK: case SC_CARD_TYPE_DNIE_ADMIN: diff --git a/src/libopensc/types.h b/src/libopensc/types.h index 7368422c..e665c54b 100644 --- a/src/libopensc/types.h +++ b/src/libopensc/types.h @@ -148,6 +148,7 @@ struct sc_crt { #define SC_AC_SEN 0x00000020 /* Security Environment. */ #define SC_AC_SCB 0x00000040 /* IAS/ECC SCB byte. */ #define SC_AC_IDA 0x00000080 /* PKCS#15 authentication ID */ +#define SC_AC_SESSION 0x00000100 /* Session PIN */ #define SC_AC_UNKNOWN 0xFFFFFFFE #define SC_AC_NEVER 0xFFFFFFFF diff --git a/src/minidriver/Makefile.mak b/src/minidriver/Makefile.mak index ee8fa274..5ce80ef5 100644 --- a/src/minidriver/Makefile.mak +++ b/src/minidriver/Makefile.mak @@ -14,5 +14,5 @@ $(TARGET): $(OBJECTS) $(LIBS) echo LIBRARY $* > $*.def echo EXPORTS >> $*.def type minidriver.exports >> $*.def - link /dll $(LINKFLAGS) /def:$*.def /out:$(TARGET) $(OBJECTS) $(LIBS) $(ZLIB_LIB) $(OPENSSL_LIB) ws2_32.lib gdi32.lib advapi32.lib Crypt32.lib User32.lib bcrypt.lib DelayImp.lib Rpcrt4.lib /DELAYLOAD:bcrypt.dll + link /dll $(LINKFLAGS) /def:$*.def /out:$(TARGET) $(OBJECTS) $(LIBS) $(ZLIB_LIB) $(OPENPACE_LIB) $(OPENSSL_LIB) ws2_32.lib gdi32.lib advapi32.lib Crypt32.lib User32.lib bcrypt.lib DelayImp.lib Rpcrt4.lib /DELAYLOAD:bcrypt.dll if EXIST $(TARGET).manifest mt -manifest $(TARGET).manifest -outputresource:$(TARGET);2 diff --git a/src/minidriver/minidriver.c b/src/minidriver/minidriver.c index 705b7340..34b12887 100644 --- a/src/minidriver/minidriver.c +++ b/src/minidriver/minidriver.c @@ -4774,7 +4774,8 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, return SCARD_F_INTERNAL_ERROR; if (dwFlags == CARD_AUTHENTICATE_GENERATE_SESSION_PIN || dwFlags == CARD_AUTHENTICATE_SESSION_PIN) { - if (! (vs->reader->capabilities & SC_READER_CAP_PIN_PAD)) + if (! (vs->reader->capabilities & SC_READER_CAP_PIN_PAD + || vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) return SCARD_E_UNSUPPORTED_FEATURE; } @@ -4783,7 +4784,8 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, /* using a pin pad */ if (NULL == pbPinData) { - if (!(vs->reader->capabilities & SC_READER_CAP_PIN_PAD)) + if (!(vs->reader->capabilities & SC_READER_CAP_PIN_PAD + || vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) return SCARD_E_INVALID_PARAMETER; if (!(dwFlags & CARD_PIN_SILENT_CONTEXT) && !(vs->ctx->flags & SC_CTX_FLAG_DISABLE_POPUPS)) { @@ -4809,7 +4811,9 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, /* Do we need to display a prompt to enter PIN on pin pad? */ logprintf(pCardData, 7, "PIN pad=%s, pbPinData=%p, hwndParent=%p\n", - vs->reader->capabilities & SC_READER_CAP_PIN_PAD ? "yes" : "no", pbPinData, vs->hwndParent); + vs->reader->capabilities & SC_READER_CAP_PIN_PAD + || vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH + ? "yes" : "no", pbPinData, vs->hwndParent); /* check if the pin is the session pin generated by a previous authentication with a pinpad */ if (pbPinData != NULL && cbPinData == sizeof(MAGIC_SESSION_PIN) && memcmp(MAGIC_SESSION_PIN, pbPinData, sizeof(MAGIC_SESSION_PIN)) == 0) { @@ -4836,7 +4840,9 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, logprintf(pCardData, 2, "Pin code correct.\n"); /* set the session pin according to the minidriver specification */ - if (dwFlags == CARD_AUTHENTICATE_GENERATE_SESSION_PIN && (vs->reader->capabilities & SC_READER_CAP_PIN_PAD)) { + if (dwFlags == CARD_AUTHENTICATE_GENERATE_SESSION_PIN + && (vs->reader->capabilities & SC_READER_CAP_PIN_PAD + || vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) { /* we set it to a special value for pinpad authentication to force a new pinpad authentication */ if (pcbSessionPin) *pcbSessionPin = sizeof(MAGIC_SESSION_PIN); if (ppbSessionPin) { @@ -4907,7 +4913,8 @@ DWORD WINAPI CardChangeAuthenticatorEx(__in PCARD_DATA pCardData, vs = (VENDOR_SPECIFIC*)(pCardData->pvVendorSpecific); - if (!(vs->reader->capabilities & SC_READER_CAP_PIN_PAD)) { + if (!(vs->reader->capabilities & SC_READER_CAP_PIN_PAD + || vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) { if (pbAuthenticatingPinData == NULL || cbAuthenticatingPinData == 0) { logprintf(pCardData, 1, "Invalid current PIN data\n"); return SCARD_E_INVALID_PARAMETER; @@ -5192,7 +5199,9 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, if (p->dwVersion != PIN_INFO_CURRENT_VERSION) return ERROR_REVISION_MISMATCH; - p->PinType = vs->reader->capabilities & SC_READER_CAP_PIN_PAD ? ExternalPinType : AlphaNumericPinType; + p->PinType = vs->reader->capabilities & SC_READER_CAP_PIN_PAD + || vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH + ? ExternalPinType : AlphaNumericPinType; p->dwFlags = 0; switch (dwFlags) { case ROLE_USER: diff --git a/src/pkcs11/Makefile.mak b/src/pkcs11/Makefile.mak index 8fd0ff9e..1aeb9e66 100644 --- a/src/pkcs11/Makefile.mak +++ b/src/pkcs11/Makefile.mak @@ -17,15 +17,15 @@ all: $(TARGET1) $(TARGET2) $(TARGET3) !INCLUDE $(TOPDIR)\win32\Make.rules.mak $(TARGET1): $(OBJECTS) $(LIBS) - link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET1) $(OBJECTS) $(LIBS) $(OPENSSL_LIB) gdi32.lib + link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET1) $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib if EXIST $(TARGET1).manifest mt -manifest $(TARGET1).manifest -outputresource:$(TARGET1);2 $(TARGET2): $(OBJECTS) $(LIBS) del pkcs11-global.obj cl $(CODE_OPTIMIZATION) $(COPTS) /DMODULE_APP_NAME=\"onepin-opensc-pkcs11\" /c pkcs11-global.c - link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET2) $(OBJECTS) $(LIBS) $(OPENSSL_LIB) gdi32.lib + link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET2) $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib if EXIST $(TARGET2).manifest mt -manifest $(TARGET2).manifest -outputresource:$(TARGET2);2 $(TARGET3): $(OBJECTS3) $(LIBS3) - link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET3) $(OBJECTS3) $(LIBS3) $(OPENSSL_LIB) gdi32.lib advapi32.lib + link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET3) $(OBJECTS3) $(LIBS3) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib advapi32.lib if EXIST $(TARGET3).manifest mt -manifest $(TARGET3).manifest -outputresource:$(TARGET3);2 diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c index 42c50935..19a72869 100644 --- a/src/pkcs11/framework-pkcs15.c +++ b/src/pkcs11/framework-pkcs15.c @@ -961,7 +961,7 @@ pkcs15_init_slot(struct sc_pkcs15_card *p15card, struct sc_pkcs11_slot *slot, if (auth != NULL) slot->token_info.flags |= CKF_USER_PIN_INITIALIZED; - if (p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) + if ((p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) || (p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) slot->token_info.flags |= CKF_PROTECTED_AUTHENTICATION_PATH; if (p15card->card->caps & SC_CARD_CAP_RNG && p15card->card->ops->get_challenge != NULL) @@ -1489,7 +1489,8 @@ pkcs15_login(struct sc_pkcs11_slot *slot, CK_USER_TYPE userType, if (pin_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) return CKR_FUNCTION_REJECTED; - if (p11card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) { + if (p11card->card->reader->capabilities & SC_READER_CAP_PIN_PAD + || (p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) { /* pPin should be NULL in case of a pin pad reader, but * some apps (e.g. older Netscapes) don't know about it. * So we don't require that pPin == NULL, but set it to @@ -1650,7 +1651,8 @@ pkcs15_change_pin(struct sc_pkcs11_slot *slot, return CKR_USER_PIN_NOT_INITIALIZED; sc_log(context, "Change '%.*s' (ref:%i,type:%i)", (int) sizeof pin_obj->label, pin_obj->label, auth_info->attrs.pin.reference, login_user); - if (p11card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) { + if ((p11card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) + || (p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) { /* pPin should be NULL in case of a pin pad reader, but * some apps (e.g. older Netscapes) don't know about it. * So we don't require that pPin == NULL, but set it to diff --git a/src/sm/sm-eac.c b/src/sm/sm-eac.c index c51b4b84..a5561055 100644 --- a/src/sm/sm-eac.c +++ b/src/sm/sm-eac.c @@ -1762,13 +1762,11 @@ int perform_chip_authentication(sc_card_t *card, unsigned char **ef_cardsecurity, size_t *ef_cardsecurity_len) { int r; - BUF_MEM *picc_pubkey = NULL, *nonce = NULL, *token = NULL, - *eph_pub_key = NULL; + BUF_MEM *picc_pubkey = NULL; struct iso_sm_ctx *isosmctx; struct npa_sm_ctx *eacsmctx; - if (!card || !card->sm_ctx.info.cmd_data - || !ef_cardsecurity || !ef_cardsecurity_len) { + if (!card || !ef_cardsecurity || !ef_cardsecurity_len) { r = SC_ERROR_INVALID_ARGUMENTS; goto err; } @@ -1779,7 +1777,6 @@ int perform_chip_authentication(sc_card_t *card, } eacsmctx = isosmctx->priv_data; - /* Passive Authentication */ if (!*ef_cardsecurity && !*ef_cardsecurity_len) { r = get_ef_card_security(card, ef_cardsecurity, ef_cardsecurity_len); @@ -1796,8 +1793,42 @@ int perform_chip_authentication(sc_card_t *card, goto err; } + r = perform_chip_authentication_ex(card, eacsmctx->ctx, + (unsigned char *) picc_pubkey->data, picc_pubkey->length); - r = npa_mse_set_at_ca(card, eacsmctx->ctx->ca_ctx->protocol); +err: + BUF_MEM_clear_free(picc_pubkey); + + if (card) + SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); + else + return r; +} + +int perform_chip_authentication_ex(sc_card_t *card, void *eac_ctx, + unsigned char *picc_pubkey, size_t picc_pubkey_len) +{ + int r; + BUF_MEM *picc_pubkey_buf = NULL, *nonce = NULL, *token = NULL, + *eph_pub_key = NULL; + EAC_CTX *ctx = eac_ctx; + + if (!card || !ctx) { + r = SC_ERROR_INVALID_ARGUMENTS; + goto err; + } + + + picc_pubkey_buf = BUF_MEM_create_init(picc_pubkey, picc_pubkey_len); + if (!picc_pubkey_buf) { + sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not verify EF.CardSecurity."); + ssl_error(card->ctx); + r = SC_ERROR_INTERNAL; + goto err; + } + + + r = npa_mse_set_at_ca(card, ctx->ca_ctx->protocol); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not select protocol proberties " "(MSE: Set AT failed)."); @@ -1805,7 +1836,7 @@ int perform_chip_authentication(sc_card_t *card, } - eph_pub_key = CA_STEP2_get_eph_pubkey(eacsmctx->ctx); + eph_pub_key = CA_STEP2_get_eph_pubkey(ctx); if (!eph_pub_key) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not derive keys."); ssl_error(card->ctx); @@ -1819,7 +1850,7 @@ int perform_chip_authentication(sc_card_t *card, } - if (!CA_STEP4_compute_shared_secret(eacsmctx->ctx, picc_pubkey)) { + if (!CA_STEP4_compute_shared_secret(ctx, picc_pubkey_buf)) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not compute shared secret."); ssl_error(card->ctx); r = SC_ERROR_INTERNAL; @@ -1827,7 +1858,7 @@ int perform_chip_authentication(sc_card_t *card, } - if (!CA_STEP6_derive_keys(eacsmctx->ctx, nonce, token)) { + if (!CA_STEP6_derive_keys(ctx, nonce, token)) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not derive keys."); ssl_error(card->ctx); r = SC_ERROR_INTERNAL; @@ -1836,15 +1867,19 @@ int perform_chip_authentication(sc_card_t *card, /* Initialize secure channel */ - if (!EAC_CTX_set_encryption_ctx(eacsmctx->ctx, EAC_ID_CA)) { + if (!EAC_CTX_set_encryption_ctx(ctx, EAC_ID_CA)) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not initialize encryption."); ssl_error(card->ctx); r = SC_ERROR_INTERNAL; goto err; } + if (card->sm_ctx.sm_mode != SM_MODE_TRANSMIT) { + r = npa_sm_start(card, ctx, NULL, 0, NULL, 0); + } + err: - BUF_MEM_clear_free(picc_pubkey); + BUF_MEM_clear_free(picc_pubkey_buf); BUF_MEM_clear_free(nonce); BUF_MEM_clear_free(token); BUF_MEM_clear_free(eph_pub_key); @@ -2371,6 +2406,12 @@ int perform_chip_authentication(sc_card_t *card, return SC_ERROR_NOT_SUPPORTED; } +int perform_chip_authentication_ex(sc_card_t *card, void *eac_ctx, + unsigned char *picc_pubkey, size_t picc_pubkey_len) +{ + return SC_ERROR_NOT_SUPPORTED; +} + #endif static const char *MRZ_name = "MRZ"; diff --git a/src/sm/sm-eac.h b/src/sm/sm-eac.h index 755dd2a2..fcb35773 100644 --- a/src/sm/sm-eac.h +++ b/src/sm/sm-eac.h @@ -230,6 +230,8 @@ int perform_terminal_authentication(sc_card_t *card, */ int perform_chip_authentication(sc_card_t *card, unsigned char **ef_cardsecurity, size_t *ef_cardsecurity_len); +int perform_chip_authentication_ex(sc_card_t *card, void *eacsmctx, + unsigned char *picc_pubkey, size_t picc_pubkey_len); /** * @brief Sends a reset retry counter APDU diff --git a/src/smm/Makefile.mak b/src/smm/Makefile.mak index d0eb9921..a50ccbc3 100644 --- a/src/smm/Makefile.mak +++ b/src/smm/Makefile.mak @@ -14,7 +14,7 @@ $(TARGET): $(OBJECTS) $(LIBS) echo LIBRARY $* > $*.def echo EXPORTS >> $*.def type $*.exports >> $*.def - link /dll $(LINKFLAGS) /def:$*.def /out:$(TARGET) $(OBJECTS) $(LIBS) $(ZLIB_LIB) $(OPENSSL_LIB) ws2_32.lib gdi32.lib advapi32.lib Crypt32.lib User32.lib + link /dll $(LINKFLAGS) /def:$*.def /out:$(TARGET) $(OBJECTS) $(LIBS) $(ZLIB_LIB) $(OPENPACE_LIB) $(OPENSSL_LIB) ws2_32.lib gdi32.lib advapi32.lib Crypt32.lib User32.lib if EXIST $(TARGET).manifest mt -manifest $(TARGET).manifest -outputresource:$(TARGET);2 !ELSE diff --git a/src/tools/npa-tool.c b/src/tools/npa-tool.c index a2a74a04..11b55759 100644 --- a/src/tools/npa-tool.c +++ b/src/tools/npa-tool.c @@ -486,7 +486,7 @@ main (int argc, char **argv) } else if (cmdline.puk_given) { pace_input.pin_id = PACE_PUK; pace_input.pin_length = 10; - maxsecret = 9999999999LLU; + maxsecret = 9999999999; if (puk) { if (sscanf(puk, "%llu", &secret) != 1) { fprintf(stderr, "%s is not an unsigned long long.\n", diff --git a/src/tools/pkcs15-tool.c b/src/tools/pkcs15-tool.c index 98410355..0f1cfebd 100644 --- a/src/tools/pkcs15-tool.c +++ b/src/tools/pkcs15-tool.c @@ -1541,7 +1541,8 @@ static int unblock_pin(void) u8 *pin, *puk; int r, pinpad_present = 0; - pinpad_present = p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD; + pinpad_present = p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD + || p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH; if (!(pin_obj = get_pin_info())) return 2; @@ -1638,7 +1639,8 @@ static int change_pin(void) u8 *pincode, *newpin; int r, pinpad_present = 0; - pinpad_present = p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD; + pinpad_present = p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD + || p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH; if (!(pin_obj = get_pin_info())) return 2; diff --git a/win32/Make.rules.mak b/win32/Make.rules.mak index 621beb44..5a10278b 100644 --- a/win32/Make.rules.mak +++ b/win32/Make.rules.mak @@ -80,9 +80,10 @@ CANDLEFLAGS = -dzlib="C:\zlib-dll" $(CANDLEFLAGS) # - set the OPENPACE_LIB below to your OpenPACE lib file #OPENPACE_DEF= /DENABLE_OPENPACE !IF "$(OPENPACE_DEF)" == "/DENABLE_OPENPACE" -OPENPACE_DIR = C:\OpenPACE -OPENPACE_INCL_DIR = /I$(OPENPACE_DIR)\include -OPENPACE_LIB = $(OPENPACE_DIR)\lib\libeac.lib +OPENPACE_DIR = C:\openpace +OPENPACE_INCL_DIR = /I$(OPENPACE_DIR)\src +OPENPACE_LIB = $(OPENPACE_DIR)\src\libeac.lib +CANDLEFLAGS = -dOpenPACE="$(OPENPACE_DIR)" $(CANDLEFLAGS) !ENDIF diff --git a/win32/OpenSC.wxs.in b/win32/OpenSC.wxs.in index 1a024e31..29beecc8 100644 --- a/win32/OpenSC.wxs.in +++ b/win32/OpenSC.wxs.in @@ -280,6 +280,16 @@ + + + + + + + + + + @@ -304,6 +314,10 @@ + + + + diff --git a/win32/customactions.cpp b/win32/customactions.cpp index 2eaa0fda..9c8377c3 100644 --- a/win32/customactions.cpp +++ b/win32/customactions.cpp @@ -74,6 +74,8 @@ MD_REGISTRATION minidriver_registration[] = { 24, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, {TEXT("SmartCard-HSM-CL"), {0x3B,0x8E,0x80,0x01,0x80,0x31,0x81,0x54,0x48,0x53,0x4D,0x31,0x73,0x80,0x21,0x40,0x81,0x07,0x18}, 19, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}}, + {TEXT("SmartCard-HSM-FP"), {0x3B,0x80,0x80,0x01,0x01}, + 5, {0xff,0xff,0xff,0xff,0xff}}, /* from minidriver-westcos.reg */ {TEXT("CEV WESTCOS"), {0x3f,0x69,0x00,0x00,0x00,0x64,0x01,0x00,0x00,0x00,0x80,0x90,0x00}, 13, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xf0,0xff,0xff}}, diff --git a/win32/winconfig.h.in b/win32/winconfig.h.in index 55f74fdb..f1706661 100644 --- a/win32/winconfig.h.in +++ b/win32/winconfig.h.in @@ -118,6 +118,10 @@ #define OPENSC_VS_FF_PRODUCT_NAME "@OPENSC_VS_FF_PRODUCT_NAME@" #endif +#ifndef CVCDIR +#define CVCDIR "%PROGRAMFILES%\\OpenSC Project\\OpenSC\\cvc" +#endif + #ifndef DEFAULT_PKCS11_PROVIDER #define DEFAULT_PKCS11_PROVIDER "@DEFAULT_PKCS11_PROVIDER@" #endif