int sc_pkcs15_prkey_attrs_from_cert(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *cert_object, struct sc_pkcs15_object **out_key_object) { struct sc_context *ctx = p15card->card->ctx; #ifdef ENABLE_OPENSSL struct sc_pkcs15_object *key_object = NULL; struct sc_pkcs15_prkey_info *key_info = NULL; X509 *x = NULL; BIO *mem = NULL; unsigned char *buff = NULL, *ptr = NULL; int rv; LOG_FUNC_CALLED(ctx); if (out_key_object) *out_key_object = NULL; rv = sc_pkcs15_find_prkey_by_id(p15card, &((struct sc_pkcs15_cert_info *)cert_object->data)->id, &key_object); if (rv == SC_ERROR_OBJECT_NOT_FOUND) LOG_FUNC_RETURN(ctx, SC_SUCCESS); LOG_TEST_RET(ctx, rv, "Find private key error"); key_info = (struct sc_pkcs15_prkey_info *) key_object->data; ERR_load_ERR_strings(); ERR_load_crypto_strings(); sc_log(ctx, "CertValue(%i) %p", cert_object->content.len, cert_object->content.value); mem = BIO_new_mem_buf(cert_object->content.value, cert_object->content.len); if (!mem) LOG_TEST_RET(ctx, SC_ERROR_INTERNAL, "MEM buffer allocation error"); x = d2i_X509_bio(mem, NULL); if (!x) LOG_TEST_RET(ctx, SC_ERROR_INTERNAL, "x509 parse error"); buff = OPENSSL_malloc(i2d_X509(x,NULL) + EVP_MAX_MD_SIZE); if (!buff) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "OpenSSL allocation error"); ptr = buff; rv = i2d_X509_NAME(X509_get_subject_name(x), &ptr); if (rv <= 0) LOG_TEST_RET(ctx, SC_ERROR_INTERNAL, "Get subject name error"); key_info->subject.value = malloc(rv); if (!key_info->subject.value) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Subject allocation error"); memcpy(key_info->subject.value, buff, rv); key_info->subject.len = rv; strlcpy(key_object->label, cert_object->label, sizeof(key_object->label)); rv = 0; if (x) X509_free(x); if (mem) BIO_free(mem); if (buff) OPENSSL_free(buff); ERR_clear_error(); ERR_free_strings(); if (out_key_object) *out_key_object = key_object; sc_log(ctx, "Subject %s", sc_dump_hex(key_info->subject.value, key_info->subject.len)); LOG_FUNC_RETURN(ctx, rv); #else LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); #endif }
int iasecc_sdo_convert_acl(struct sc_card *card, struct iasecc_sdo *sdo, unsigned char op, unsigned *out_method, unsigned *out_ref) { struct sc_context *ctx = card->ctx; struct acl_op { unsigned char op; unsigned char mask; } ops[] = { {SC_AC_OP_PSO_COMPUTE_SIGNATURE,IASECC_ACL_PSO_SIGNATURE}, {SC_AC_OP_INTERNAL_AUTHENTICATE,IASECC_ACL_INTERNAL_AUTHENTICATE}, {SC_AC_OP_PSO_DECRYPT, IASECC_ACL_PSO_DECIPHER}, {SC_AC_OP_GENERATE, IASECC_ACL_GENERATE_KEY}, {SC_AC_OP_UPDATE, IASECC_ACL_PUT_DATA}, {SC_AC_OP_READ, IASECC_ACL_GET_DATA}, {0x00, 0x00} }; unsigned char mask = 0x80, op_mask = 0; int ii; LOG_FUNC_CALLED(ctx); for (ii=0; ops[ii].mask; ii++) { if (op == ops[ii].op) { op_mask = ops[ii].mask; break; } } if (op_mask == 0) LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); sc_log(ctx, "OP:%i, mask:0x%X", op, op_mask); sc_log(ctx, "AMB:%X, scbs:%s", sdo->docp.amb, sc_dump_hex(sdo->docp.scbs, IASECC_MAX_SCBS)); sc_log(ctx, "docp.acls_contact:%s", sc_dump_hex(sdo->docp.acls_contact.value, sdo->docp.acls_contact.size)); if (!sdo->docp.amb && sdo->docp.acls_contact.size) { int rv = iasecc_parse_acls(card, &sdo->docp, 0); LOG_TEST_RET(ctx, rv, "Cannot parse ACLs in DOCP"); } *out_method = SC_AC_NEVER; *out_ref = SC_AC_NEVER; for (ii=0; ii<7; ii++) { mask >>= 1; if (sdo->docp.amb & mask) { if (op_mask == mask) { unsigned char scb = sdo->docp.scbs[ii]; sc_log(ctx, "ii:%i, scb:0x%X", ii, scb); *out_ref = scb & 0x0F; if (scb == 0) *out_method = SC_AC_NONE; else if (scb == 0xFF) *out_method = SC_AC_NEVER; else if ((scb & IASECC_SCB_METHOD_MASK) == IASECC_SCB_METHOD_USER_AUTH) *out_method = SC_AC_SEN; else if ((scb & IASECC_SCB_METHOD_MASK) == IASECC_SCB_METHOD_EXT_AUTH) *out_method = SC_AC_AUT; else if ((scb & IASECC_SCB_METHOD_MASK) == IASECC_SCB_METHOD_SM) *out_method = SC_AC_PRO; else *out_method = SC_AC_SCB, *out_ref = scb; break; } } } sc_log(ctx, "returns method %X; ref %X", *out_method, *out_ref); LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
int sm_cwa_securize_apdu(struct sc_context *ctx, struct sm_info *sm_info, struct sc_remote_apdu *rapdu) { struct sm_cwa_session *session_data = &sm_info->session.cwa; struct sc_apdu *apdu = &rapdu->apdu; unsigned char sbuf[0x400]; DES_cblock cblock, icv; unsigned char *encrypted = NULL, edfb_data[0x200], mac_data[0x200]; size_t encrypted_len, edfb_len = 0, mac_len = 0, offs; int rv; LOG_FUNC_CALLED(ctx); sc_debug(ctx, SC_LOG_DEBUG_SM, "securize APDU (cla:%X,ins:%X,p1:%X,p2:%X,data(%"SC_FORMAT_LEN_SIZE_T"u):%p)", apdu->cla, apdu->ins, apdu->p1, apdu->p2, apdu->datalen, apdu->data); sm_incr_ssc(session_data->ssc, sizeof(session_data->ssc)); rv = sm_encrypt_des_cbc3(ctx, session_data->session_enc, apdu->data, apdu->datalen, &encrypted, &encrypted_len, 0); LOG_TEST_RET(ctx, rv, "securize APDU: DES CBC3 encryption failed"); sc_debug(ctx, SC_LOG_DEBUG_SM, "encrypted data (len:%"SC_FORMAT_LEN_SIZE_T"u, %s)", encrypted_len, sc_dump_hex(encrypted, encrypted_len)); offs = 0; if (apdu->ins & 0x01) { edfb_data[offs++] = IASECC_SM_DO_TAG_TCG_ODD_INS; if (encrypted_len + 1 > 0x7F) edfb_data[offs++] = 0x81; edfb_data[offs++] = encrypted_len; } else { edfb_data[offs++] = IASECC_SM_DO_TAG_TCG_EVEN_INS; if (encrypted_len + 1 > 0x7F) edfb_data[offs++] = 0x81; edfb_data[offs++] = encrypted_len + 1; edfb_data[offs++] = 0x01; } memcpy(edfb_data + offs, encrypted, encrypted_len); offs += encrypted_len; edfb_len = offs; sc_debug(ctx, SC_LOG_DEBUG_SM, "securize APDU: EDFB(len:%"SC_FORMAT_LEN_SIZE_T"u,%s)", edfb_len, sc_dump_hex(edfb_data, edfb_len)); free(encrypted); encrypted = NULL; offs = 0; memcpy(mac_data + offs, session_data->ssc, 8); offs += 8; mac_data[offs++] = apdu->cla | 0x0C; mac_data[offs++] = apdu->ins; mac_data[offs++] = apdu->p1; mac_data[offs++] = apdu->p2; mac_data[offs++] = 0x80; mac_data[offs++] = 0x00; mac_data[offs++] = 0x00; mac_data[offs++] = 0x00; memcpy(mac_data + offs, edfb_data, edfb_len); offs += edfb_len; /* if (apdu->le) { */ mac_data[offs++] = IASECC_SM_DO_TAG_TLE; mac_data[offs++] = 1; mac_data[offs++] = apdu->le; /* } */ mac_len = offs; sc_debug(ctx, SC_LOG_DEBUG_SM, "securize APDU: MAC data(len:%"SC_FORMAT_LEN_SIZE_T"u,%s)", mac_len, sc_dump_hex(mac_data, mac_len)); memset(icv, 0, sizeof(icv)); rv = sm_cwa_get_mac(ctx, session_data->session_mac, &icv, mac_data, mac_len, &cblock, 0); LOG_TEST_RET(ctx, rv, "securize APDU: MAC calculation error"); sc_debug(ctx, SC_LOG_DEBUG_SM, "securize APDU: MAC:%s", sc_dump_hex(cblock, sizeof(cblock))); offs = 0; if (edfb_len) { memcpy(sbuf + offs, edfb_data, edfb_len); offs += edfb_len; } /* if (apdu->le) { */ sbuf[offs++] = IASECC_SM_DO_TAG_TLE; sbuf[offs++] = 1; sbuf[offs++] = apdu->le; /* } */ sbuf[offs++] = IASECC_SM_DO_TAG_TCC; sbuf[offs++] = 8; memcpy(sbuf + offs, cblock, 8); offs += 8; sc_debug(ctx, SC_LOG_DEBUG_SM, "securize APDU: SM data(len:%"SC_FORMAT_LEN_SIZE_T"u,%s)", offs, sc_dump_hex(sbuf, offs)); if (offs > sizeof(rapdu->sbuf)) LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "securize APDU: buffer too small for encrypted data"); apdu->cse = SC_APDU_CASE_4_SHORT; apdu->cla |= 0x0C; apdu->lc = offs; apdu->datalen = offs; memcpy((unsigned char *)apdu->data, sbuf, offs); sm_incr_ssc(session_data->ssc, sizeof(session_data->ssc)); LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *obj, const u8 ** buf, size_t *buflen) { sc_context_t *ctx = p15card->card->ctx; struct sc_pkcs15_prkey_info info; int r, i, gostr3410_params[3]; struct sc_pkcs15_keyinfo_gostparams *keyinfo_gostparams; size_t usage_len = sizeof(info.usage); size_t af_len = sizeof(info.access_flags); struct sc_asn1_entry asn1_com_key_attr[C_ASN1_COM_KEY_ATTR_SIZE]; struct sc_asn1_entry asn1_com_prkey_attr[C_ASN1_COM_PRKEY_ATTR_SIZE]; struct sc_asn1_entry asn1_rsakey_attr[C_ASN1_RSAKEY_ATTR_SIZE]; struct sc_asn1_entry asn1_prk_rsa_attr[C_ASN1_PRK_RSA_ATTR_SIZE]; struct sc_asn1_entry asn1_dsakey_attr[C_ASN1_DSAKEY_ATTR_SIZE]; struct sc_asn1_entry asn1_prk_dsa_attr[C_ASN1_PRK_DSA_ATTR_SIZE]; struct sc_asn1_entry asn1_dsakey_i_p_attr[C_ASN1_DSAKEY_I_P_ATTR_SIZE]; struct sc_asn1_entry asn1_dsakey_value_attr[C_ASN1_DSAKEY_VALUE_ATTR_SIZE]; struct sc_asn1_entry asn1_gostr3410key_attr[C_ASN1_GOSTR3410KEY_ATTR_SIZE]; struct sc_asn1_entry asn1_prk_gostr3410_attr[C_ASN1_PRK_GOSTR3410_ATTR_SIZE]; struct sc_asn1_entry asn1_ecckey_attr[C_ASN1_ECCKEY_ATTR]; struct sc_asn1_entry asn1_prk_ecc_attr[C_ASN1_PRK_ECC_ATTR]; struct sc_asn1_entry asn1_prkey[C_ASN1_PRKEY_SIZE]; struct sc_asn1_entry asn1_supported_algorithms[C_ASN1_SUPPORTED_ALGORITHMS_SIZE]; struct sc_asn1_pkcs15_object rsa_prkey_obj = {obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_rsa_attr}; struct sc_asn1_pkcs15_object dsa_prkey_obj = {obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_dsa_attr}; struct sc_asn1_pkcs15_object gostr3410_prkey_obj = {obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_gostr3410_attr}; struct sc_asn1_pkcs15_object ecc_prkey_obj = { obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_ecc_attr }; sc_copy_asn1_entry(c_asn1_prkey, asn1_prkey); sc_copy_asn1_entry(c_asn1_supported_algorithms, asn1_supported_algorithms); sc_copy_asn1_entry(c_asn1_prk_rsa_attr, asn1_prk_rsa_attr); sc_copy_asn1_entry(c_asn1_rsakey_attr, asn1_rsakey_attr); sc_copy_asn1_entry(c_asn1_prk_dsa_attr, asn1_prk_dsa_attr); sc_copy_asn1_entry(c_asn1_dsakey_attr, asn1_dsakey_attr); sc_copy_asn1_entry(c_asn1_dsakey_value_attr, asn1_dsakey_value_attr); sc_copy_asn1_entry(c_asn1_dsakey_i_p_attr, asn1_dsakey_i_p_attr); sc_copy_asn1_entry(c_asn1_prk_gostr3410_attr, asn1_prk_gostr3410_attr); sc_copy_asn1_entry(c_asn1_gostr3410key_attr, asn1_gostr3410key_attr); sc_copy_asn1_entry(c_asn1_prk_ecc_attr, asn1_prk_ecc_attr); sc_copy_asn1_entry(c_asn1_ecckey_attr, asn1_ecckey_attr); sc_copy_asn1_entry(c_asn1_com_prkey_attr, asn1_com_prkey_attr); sc_copy_asn1_entry(c_asn1_com_key_attr, asn1_com_key_attr); sc_format_asn1_entry(asn1_prkey + 0, &rsa_prkey_obj, NULL, 0); sc_format_asn1_entry(asn1_prkey + 1, &ecc_prkey_obj, NULL, 0); sc_format_asn1_entry(asn1_prkey + 2, &dsa_prkey_obj, NULL, 0); sc_format_asn1_entry(asn1_prkey + 3, &gostr3410_prkey_obj, NULL, 0); sc_format_asn1_entry(asn1_prk_rsa_attr + 0, asn1_rsakey_attr, NULL, 0); sc_format_asn1_entry(asn1_prk_dsa_attr + 0, asn1_dsakey_attr, NULL, 0); sc_format_asn1_entry(asn1_prk_gostr3410_attr + 0, asn1_gostr3410key_attr, NULL, 0); sc_format_asn1_entry(asn1_prk_ecc_attr + 0, asn1_ecckey_attr, NULL, 0); sc_format_asn1_entry(asn1_rsakey_attr + 0, &info.path, NULL, 0); sc_format_asn1_entry(asn1_rsakey_attr + 1, &info.modulus_length, NULL, 0); sc_format_asn1_entry(asn1_dsakey_attr + 0, asn1_dsakey_value_attr, NULL, 0); sc_format_asn1_entry(asn1_dsakey_value_attr + 0, &info.path, NULL, 0); sc_format_asn1_entry(asn1_dsakey_value_attr + 1, asn1_dsakey_i_p_attr, NULL, 0); sc_format_asn1_entry(asn1_dsakey_i_p_attr + 0, &info.path, NULL, 0); sc_format_asn1_entry(asn1_gostr3410key_attr + 0, &info.path, NULL, 0); sc_format_asn1_entry(asn1_gostr3410key_attr + 1, &gostr3410_params[0], NULL, 0); sc_format_asn1_entry(asn1_gostr3410key_attr + 2, &gostr3410_params[1], NULL, 0); sc_format_asn1_entry(asn1_gostr3410key_attr + 3, &gostr3410_params[2], NULL, 0); sc_format_asn1_entry(asn1_ecckey_attr + 0, &info.path, NULL, 0); sc_format_asn1_entry(asn1_ecckey_attr + 1, &info.field_length, NULL, 0); sc_format_asn1_entry(asn1_com_key_attr + 0, &info.id, NULL, 0); sc_format_asn1_entry(asn1_com_key_attr + 1, &info.usage, &usage_len, 0); sc_format_asn1_entry(asn1_com_key_attr + 2, &info.native, NULL, 0); sc_format_asn1_entry(asn1_com_key_attr + 3, &info.access_flags, &af_len, 0); sc_format_asn1_entry(asn1_com_key_attr + 4, &info.key_reference, NULL, 0); for (i=0; i<SC_MAX_SUPPORTED_ALGORITHMS && (asn1_supported_algorithms + i)->name; i++) sc_format_asn1_entry(asn1_supported_algorithms + i, &info.algo_refs[i], NULL, 0); sc_format_asn1_entry(asn1_com_key_attr + 5, asn1_supported_algorithms, NULL, 0); sc_format_asn1_entry(asn1_com_prkey_attr + 0, &info.subject.value, &info.subject.len, 0); /* Fill in defaults */ memset(&info, 0, sizeof(info)); info.key_reference = -1; info.native = 1; memset(gostr3410_params, 0, sizeof(gostr3410_params)); r = sc_asn1_decode_choice(ctx, asn1_prkey, *buf, *buflen, buf, buflen); if (r == SC_ERROR_ASN1_END_OF_CONTENTS) return r; LOG_TEST_RET(ctx, r, "PrKey DF ASN.1 decoding failed"); if (asn1_prkey[0].flags & SC_ASN1_PRESENT) { obj->type = SC_PKCS15_TYPE_PRKEY_RSA; } else if (asn1_prkey[1].flags & SC_ASN1_PRESENT) { obj->type = SC_PKCS15_TYPE_PRKEY_EC; } else if (asn1_prkey[2].flags & SC_ASN1_PRESENT) { obj->type = SC_PKCS15_TYPE_PRKEY_DSA; /* If the value was indirect-protected, mark the path */ if (asn1_dsakey_i_p_attr[0].flags & SC_ASN1_PRESENT) info.path.type = SC_PATH_TYPE_PATH_PROT; } else if (asn1_prkey[3].flags & SC_ASN1_PRESENT) { obj->type = SC_PKCS15_TYPE_PRKEY_GOSTR3410; assert(info.modulus_length == 0); info.modulus_length = SC_PKCS15_GOSTR3410_KEYSIZE; assert(info.params.len == 0); info.params.len = sizeof(struct sc_pkcs15_keyinfo_gostparams); info.params.data = malloc(info.params.len); if (info.params.data == NULL) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); assert(sizeof(*keyinfo_gostparams) == info.params.len); keyinfo_gostparams = info.params.data; keyinfo_gostparams->gostr3410 = gostr3410_params[0]; keyinfo_gostparams->gostr3411 = gostr3410_params[1]; keyinfo_gostparams->gost28147 = gostr3410_params[2]; } else { sc_log(ctx, "Neither RSA or DSA or GOSTR3410 or ECC key in PrKDF entry."); LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ASN1_OBJECT); } if (!p15card->app || !p15card->app->ddo.aid.len) { r = sc_pkcs15_make_absolute_path(&p15card->file_app->path, &info.path); if (r < 0) { sc_pkcs15_free_key_params(&info.params); return r; } } else { info.path.aid = p15card->app->ddo.aid; } sc_log(ctx, "PrivKey path '%s'", sc_print_path(&info.path)); /* OpenSC 0.11.4 and older encoded "keyReference" as a negative value. * Fixed in 0.11.5 we need to add a hack, so old cards continue to work. */ if (info.key_reference < -1) info.key_reference += 256; /* Check the auth_id - if not present, try and find it in access rules */ if ((obj->flags & SC_PKCS15_CO_FLAG_PRIVATE) && (obj->auth_id.len == 0)) { sc_log(ctx, "Private key %s has no auth ID - checking AccessControlRules", sc_pkcs15_print_id(&info.id)); /* Search in the access_rules for an appropriate auth ID */ for (i = 0; i < SC_PKCS15_MAX_ACCESS_RULES; i++) { /* If access_mode is one of the private key usage modes */ if (obj->access_rules[i].access_mode & (SC_PKCS15_ACCESS_RULE_MODE_EXECUTE | SC_PKCS15_ACCESS_RULE_MODE_PSO_CDS | SC_PKCS15_ACCESS_RULE_MODE_PSO_DECRYPT | SC_PKCS15_ACCESS_RULE_MODE_INT_AUTH)) { if (obj->access_rules[i].auth_id.len != 0) { /* Found an auth ID to use for private key access */ obj->auth_id = obj->access_rules[i].auth_id; sc_log(ctx, "Auth ID found - %s", sc_pkcs15_print_id(&obj->auth_id)); break; } } } /* No auth ID found */ if (i == SC_PKCS15_MAX_ACCESS_RULES) sc_log(ctx, "Warning: No auth ID found"); } obj->data = malloc(sizeof(info)); if (obj->data == NULL) { sc_pkcs15_free_key_params(&info.params); LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); } memcpy(obj->data, &info, sizeof(info)); sc_log(ctx, "Key Subject %s", sc_dump_hex(info.subject.value, info.subject.len)); sc_log(ctx, "Key path %s", sc_print_path(&info.path)); return 0; }
static int openpgp_store_data(struct sc_pkcs15_card *p15card, struct sc_profile *profile, struct sc_pkcs15_object *obj, struct sc_pkcs15_der *content, struct sc_path *path) { sc_card_t *card = p15card->card; sc_context_t *ctx = card->ctx; sc_file_t *file; sc_pkcs15_cert_info_t *cinfo; sc_pkcs15_id_t *cid; sc_pkcs15_data_info_t *dinfo; u8 buf[254]; int r; LOG_FUNC_CALLED(card->ctx); switch (obj->type & SC_PKCS15_TYPE_CLASS_MASK) { case SC_PKCS15_TYPE_PRKEY: case SC_PKCS15_TYPE_PUBKEY: /* For these two type, store_data just don't need to do anything. * All have been done already before this function is called */ r = SC_SUCCESS; break; case SC_PKCS15_TYPE_CERT: cinfo = (sc_pkcs15_cert_info_t *) obj->data; cid = &(cinfo->id); if (cid->len != 1) { sc_log(card->ctx, "ID=%s is not valid.", sc_dump_hex(cid->value, cid->len)); LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); } /* OpenPGP card v.2 contains only 1 certificate */ if (cid->value[0] != 3) { sc_log(card->ctx, "This version does not support certificate ID = %d (only ID=3 is supported).", cid->value[0]); LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); } /* Just update the certificate DO */ sc_format_path("7F21", path); r = sc_select_file(card, path, &file); LOG_TEST_RET(card->ctx, r, "Cannot select cert file"); r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE); sc_log(card->ctx, "Data to write is %d long", content->len); if (r >= 0 && content->len) r = sc_put_data(p15card->card, 0x7F21, (const unsigned char *) content->value, content->len); break; case SC_PKCS15_TYPE_DATA_OBJECT: dinfo = (sc_pkcs15_data_info_t *) obj->data; /* dinfo->app_label contains filename */ sc_log(ctx, "===== App label %s", dinfo->app_label); /* Currently, we only support DO 0101. The reason is that when initializing this * pkcs15 emulation, PIN authentication is not applied and we can expose only this DO, * which is "read always". * If we support other DOs, they will not be exposed, and not helpful to user. * I haven't found a way to refresh the list of exposed DOs after verifying PIN yet. * http://sourceforge.net/mailarchive/message.php?msg_id=30646373 **/ sc_log(ctx, "About to write to DO 0101"); sc_format_path("0101", path); r = sc_select_file(card, path, &file); LOG_TEST_RET(card->ctx, r, "Cannot select private DO"); r = sc_read_binary(card, 0, buf, sizeof(buf), 0); if (r < 0) { sc_log(ctx, "Cannot read DO 0101"); break; } if (r > 0) { sc_log(ctx, "DO 0101 is full."); r = SC_ERROR_NOT_ENOUGH_MEMORY; break; } r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE); if (r >= 0 && content->len) { r = sc_update_binary(p15card->card, 0, (const unsigned char *) content->value, content->len, 0); } break; default: r = SC_ERROR_NOT_IMPLEMENTED; } LOG_FUNC_RETURN(card->ctx, r); }
int sm_cwa_initialize(struct sc_context *ctx, struct sm_info *sm_info, struct sc_remote_data *rdata) { struct sm_cwa_session *cwa_session = &sm_info->session.cwa; struct sm_cwa_keyset *cwa_keyset = &sm_info->session.cwa.cwa_keyset; struct sc_serial_number sn = sm_info->serialnr; size_t icc_sn_len = sizeof(cwa_session->icc.sn); struct sc_remote_apdu *new_rapdu = NULL; struct sc_apdu *apdu = NULL; unsigned char buf[0x100], *encrypted; size_t encrypted_len; DES_cblock icv = {0, 0, 0, 0, 0, 0, 0, 0}, cblock; int rv, offs; LOG_FUNC_CALLED(ctx); sc_debug(ctx, SC_LOG_DEBUG_SM, "SM IAS/ECC initialize: serial %s", sc_dump_hex(sm_info->serialnr.value, sm_info->serialnr.len)); sc_debug(ctx, SC_LOG_DEBUG_SM, "SM IAS/ECC initialize: card challenge %s", sc_dump_hex(cwa_session->card_challenge, 8)); sc_debug(ctx, SC_LOG_DEBUG_SM, "SM IAS/ECC initialize: current_df_path %s", sc_print_path(&sm_info->current_path_df)); sc_debug(ctx, SC_LOG_DEBUG_SM, "SM IAS/ECC initialize: CRT_AT reference 0x%X", cwa_session->params.crt_at.refs[0]); if (!rdata || !rdata->alloc) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); rv = rdata->alloc(rdata, &new_rapdu); LOG_TEST_RET(ctx, rv, "SM GP decode card answer: cannot allocate remote APDU"); apdu = &new_rapdu->apdu; memcpy(&cwa_session->icc.rnd[0], cwa_session->card_challenge, 8); if (sn.len > icc_sn_len) memcpy(&cwa_session->icc.sn[0], &sn.value[sn.len - icc_sn_len], icc_sn_len); else memcpy(&cwa_session->icc.sn[icc_sn_len - sn.len], &sn.value[0], sn.len); if (sm_info->cmd == SM_CMD_EXTERNAL_AUTH) { offs = sm_cwa_encode_external_auth_data(ctx, cwa_session, buf, sizeof(buf)); if (offs != 0x10) LOG_FUNC_RETURN(ctx, offs); } else { offs = sm_cwa_encode_mutual_auth_data(ctx, cwa_session, buf, sizeof(buf)); if (offs != 0x40) LOG_FUNC_RETURN(ctx, offs); } sc_debug(ctx, SC_LOG_DEBUG_SM, "S(%i) %s", offs, sc_dump_hex(buf, offs)); rv = sm_encrypt_des_cbc3(ctx, cwa_keyset->enc, buf, offs, &encrypted, &encrypted_len, 1); LOG_TEST_RET(ctx, rv, "_encrypt_des_cbc3() failed"); sc_debug(ctx, SC_LOG_DEBUG_SM, "ENCed(%"SC_FORMAT_LEN_SIZE_T"u) %s", encrypted_len, sc_dump_hex(encrypted, encrypted_len)); memcpy(buf, encrypted, encrypted_len); offs = encrypted_len; rv = sm_cwa_get_mac(ctx, cwa_keyset->mac, &icv, buf, offs, &cblock, 1); LOG_TEST_RET(ctx, rv, "sm_ecc_get_mac() failed"); sc_debug(ctx, SC_LOG_DEBUG_SM, "MACed(%"SC_FORMAT_LEN_SIZE_T"u) %s", sizeof(cblock), sc_dump_hex(cblock, sizeof(cblock))); apdu->cse = SC_APDU_CASE_4_SHORT; apdu->cla = 0x00; apdu->ins = 0x82; apdu->p1 = 0x00; apdu->p2 = 0x00; apdu->lc = encrypted_len + sizeof(cblock); apdu->le = encrypted_len + sizeof(cblock); apdu->datalen = encrypted_len + sizeof(cblock); memcpy(new_rapdu->sbuf, encrypted, encrypted_len); memcpy(new_rapdu->sbuf + encrypted_len, cblock, sizeof(cblock)); free(encrypted); LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
/** * Generates a new (RSA) key pair using an existing key file. * @param profile IN profile information for this card * @param card IN sc_card_t object to use * @param obj IN sc_pkcs15_object_t object with pkcs15 information * @param pukkey OUT the newly created public key * @return SC_SUCCESS on success and an error code otherwise **/ static int openpgp_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey) { sc_card_t *card = p15card->card; sc_context_t *ctx = card->ctx; sc_cardctl_openpgp_keygen_info_t key_info; sc_pkcs15_prkey_info_t *required = (sc_pkcs15_prkey_info_t *)obj->data; sc_pkcs15_id_t *kid = &(required->id); int r; LOG_FUNC_CALLED(ctx); memset(&key_info, 0, sizeof(key_info)); sc_log(ctx, "Key ID to be generated: %s", sc_dump_hex(kid->value, kid->len)); /* Accept KeyID = 45, which is default value set by pkcs15init */ if (kid->len == 1 && kid->value[0] == 0x45) { /* Default key is authentication key. We choose this because the common use * is to generate from PKCS#11 (Firefox/Thunderbird) */ sc_log(ctx, "Authentication key is to be generated."); key_info.keytype = 3; } if (!key_info.keytype && (kid->len > 1 || kid->value[0] > 3)) { sc_log(ctx, "Key ID must be 1, 2 or 3!"); LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); } if (!key_info.keytype) key_info.keytype = kid->value[0]; /* Prepare buffer */ key_info.modulus_len = required->modulus_length; key_info.modulus = calloc(required->modulus_length >> 3, 1); if (key_info.modulus == NULL) LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY); /* The OpenPGP supports only 32-bit exponent. */ key_info.exponent_len = 32; key_info.exponent = calloc(key_info.exponent_len>>3, 1); /* 1/8 */ if (key_info.exponent == NULL) LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY); r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_GENERATE_KEY, &key_info); if (r < 0) goto out; sc_log(ctx, "Set output modulus info"); pubkey->u.rsa.modulus.len = key_info.modulus_len; pubkey->u.rsa.modulus.data = calloc(key_info.modulus_len, 1); if (pubkey->u.rsa.modulus.data == NULL) goto out; memcpy(pubkey->u.rsa.modulus.data, key_info.modulus, key_info.modulus_len); sc_log(ctx, "Set output exponent info"); pubkey->u.rsa.exponent.len = key_info.exponent_len; pubkey->u.rsa.exponent.data = calloc(key_info.exponent_len>>3, 1); /* 1/8 */ if (pubkey->u.rsa.exponent.data == NULL) goto out; memcpy(pubkey->u.rsa.exponent.data, key_info.exponent, key_info.exponent_len>>3); /* 1/8 */ out: if (key_info.modulus) free(key_info.modulus); if (key_info.exponent) free(key_info.exponent); LOG_FUNC_RETURN(ctx, r); }
int sm_iasecc_decode_card_data(struct sc_context *ctx, struct sm_info *sm_info, struct sc_remote_data *rdata, unsigned char *out, size_t out_len) { struct sm_cwa_session *session_data = &sm_info->session.cwa; struct sc_asn1_entry asn1_iasecc_sm_data_object[4]; struct sc_remote_apdu *rapdu = NULL; int rv, offs = 0; LOG_FUNC_CALLED(ctx); sc_log(ctx, "IAS/ECC decode answer() rdata length %i, out length %i", rdata->length, out_len); for (rapdu = rdata->data; rapdu; rapdu = rapdu->next) { unsigned char *decrypted; size_t decrypted_len; unsigned char resp_data[SC_MAX_APDU_BUFFER_SIZE]; size_t resp_len = sizeof(resp_data); unsigned char status[2] = {0, 0}; size_t status_len = sizeof(status); unsigned char ticket[8]; size_t ticket_len = sizeof(ticket); sc_log(ctx, "IAS/ECC decode response(%i) %s", rapdu->apdu.resplen, sc_dump_hex(rapdu->apdu.resp, rapdu->apdu.resplen)); sc_copy_asn1_entry(c_asn1_iasecc_sm_data_object, asn1_iasecc_sm_data_object); sc_format_asn1_entry(asn1_iasecc_sm_data_object + 0, resp_data, &resp_len, 0); sc_format_asn1_entry(asn1_iasecc_sm_data_object + 1, status, &status_len, 0); sc_format_asn1_entry(asn1_iasecc_sm_data_object + 2, ticket, &ticket_len, 0); rv = sc_asn1_decode(ctx, asn1_iasecc_sm_data_object, rapdu->apdu.resp, rapdu->apdu.resplen, NULL, NULL); LOG_TEST_RET(ctx, rv, "IAS/ECC decode answer(s): ASN1 decode error"); sc_log(ctx, "IAS/ECC decode response() SW:%02X%02X, MAC:%s", status[0], status[1], sc_dump_hex(ticket, ticket_len)); if (status[0] != 0x90 || status[1] != 0x00) continue; if (asn1_iasecc_sm_data_object[0].flags & SC_ASN1_PRESENT) { sc_log(ctx, "IAS/ECC decode answer() object present"); if (resp_data[0] != 0x01) LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "IAS/ECC decode answer(s): invalid encrypted data format"); decrypted_len = sizeof(decrypted); rv = sm_decrypt_des_cbc3(ctx, session_data->session_enc, &resp_data[1], resp_len - 1, &decrypted, &decrypted_len); LOG_TEST_RET(ctx, rv, "IAS/ECC decode answer(s): cannot decrypt card answer data"); sc_log(ctx, "IAS/ECC decrypted data(%i) %s", decrypted_len, sc_dump_hex(decrypted, decrypted_len)); while(*(decrypted + decrypted_len - 1) == 0x00) decrypted_len--; if (*(decrypted + decrypted_len - 1) != 0x80) LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "IAS/ECC decode answer(s): invalid card data padding "); decrypted_len--; if (out && out_len) { if (out_len < offs + decrypted_len) LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "IAS/ECC decode answer(s): unsufficient output buffer size"); memcpy(out + offs, decrypted, decrypted_len); offs += decrypted_len; sc_log(ctx, "IAS/ECC decode card answer(s): out_len/offs %i/%i", out_len, offs); } free(decrypted); } } LOG_FUNC_RETURN(ctx, offs); }
int sm_iasecc_get_apdus(struct sc_context *ctx, struct sm_info *sm_info, unsigned char *init_data, size_t init_len, struct sc_remote_data *rdata, int release_sm) { struct sm_cwa_session *cwa_session = &sm_info->session.cwa; struct sm_cwa_keyset *cwa_keyset = &sm_info->session.cwa.cwa_keyset; int rv; LOG_FUNC_CALLED(ctx); if (!sm_info) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); sc_log(ctx, "SM IAS/ECC get APDUs: init_len:%i", init_len); sc_log(ctx, "SM IAS/ECC get APDUs: rdata:%p", rdata); sc_log(ctx, "SM IAS/ECC get APDUs: serial %s", sc_dump_hex(sm_info->serialnr.value, sm_info->serialnr.len)); rv = sm_cwa_decode_authentication_data(ctx, cwa_keyset, cwa_session, init_data); LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: decode authentication data error"); rv = sm_cwa_init_session_keys(ctx, cwa_session, cwa_session->params.crt_at.algo); LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: cannot get session keys"); sc_log(ctx, "SKENC %s", sc_dump_hex(cwa_session->session_enc, sizeof(cwa_session->session_enc))); sc_log(ctx, "SKMAC %s", sc_dump_hex(cwa_session->session_mac, sizeof(cwa_session->session_mac))); sc_log(ctx, "SSC %s", sc_dump_hex(cwa_session->ssc, sizeof(cwa_session->ssc))); switch (sm_info->cmd) { case SM_CMD_FILE_READ: rv = sm_iasecc_get_apdu_read_binary(ctx, sm_info, rdata); LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'READ BINARY' failed"); break; case SM_CMD_FILE_UPDATE: rv = sm_iasecc_get_apdu_update_binary(ctx, sm_info, rdata); LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'UPDATE BINARY' failed"); break; case SM_CMD_FILE_CREATE: rv = sm_iasecc_get_apdu_create_file(ctx, sm_info, rdata); LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'CREATE FILE' failed"); break; case SM_CMD_FILE_DELETE: rv = sm_iasecc_get_apdu_delete_file(ctx, sm_info, rdata); LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'DELETE FILE' failed"); break; case SM_CMD_PIN_RESET: rv = sm_iasecc_get_apdu_reset_pin(ctx, sm_info, rdata); LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'RESET PIN' failed"); break; case SM_CMD_RSA_GENERATE: rv = sm_iasecc_get_apdu_generate_rsa(ctx, sm_info, rdata); LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'GENERATE RSA' failed"); break; case SM_CMD_RSA_UPDATE: rv = sm_iasecc_get_apdu_update_rsa(ctx, sm_info, rdata); LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'UPDATE RSA' failed"); break; case SM_CMD_SDO_UPDATE: rv = sm_iasecc_get_apdu_sdo_update(ctx, sm_info, rdata); LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'SDO UPDATE' failed"); break; case SM_CMD_PIN_VERIFY: rv = sm_iasecc_get_apdu_verify_pin(ctx, sm_info, rdata); LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'RAW APDU' failed"); break; default: LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "unsupported SM command"); } if (release_sm) { /* Apparently useless for this card */ } LOG_FUNC_RETURN(ctx, rv); }
static int sm_iasecc_get_apdu_update_rsa(struct sc_context *ctx, struct sm_info *sm_info, struct sc_remote_data *rdata) { struct iasecc_sdo_rsa_update *cmd_data = (struct iasecc_sdo_rsa_update *)sm_info->cmd_data; struct iasecc_sdo_update *to_update[2] = {NULL, NULL}; int rv = 0, ii = 0, jj = 0; LOG_FUNC_CALLED(ctx); if (cmd_data->update_prv.sdo_class) { to_update[ii++] = &cmd_data->update_prv; sc_log(ctx, "SM get 'UPDATE RSA' APDU: SDO(class:%X,ref:%X)", cmd_data->update_prv.sdo_class, cmd_data->update_prv.sdo_ref); } if (cmd_data->update_pub.sdo_class) { to_update[ii++] = &cmd_data->update_pub; sc_log(ctx, "SM get 'UPDATE RSA' APDU: SDO(class:%X,ref:%X)", cmd_data->update_pub.sdo_class, cmd_data->update_pub.sdo_ref); } for (jj=0;jj<2 && to_update[jj];jj++) { for (ii=0; to_update[jj]->fields[ii].tag && ii < IASECC_SDO_TAGS_UPDATE_MAX; ii++) { unsigned char *encoded = NULL; size_t encoded_len, offs; sc_log(ctx, "SM IAS/ECC get APDUs: component(num %i:%i) class:%X, ref:%X", jj, ii, to_update[jj]->sdo_class, to_update[jj]->sdo_ref); encoded_len = iasecc_sdo_encode_update_field(ctx, to_update[jj]->sdo_class, to_update[jj]->sdo_ref, &to_update[jj]->fields[ii], &encoded); LOG_TEST_RET(ctx, encoded_len, "SM get 'UPDATE RSA' APDU: cannot encode key component"); sc_log(ctx, "SM IAS/ECC get APDUs: component encoded %s", sc_dump_hex(encoded, encoded_len)); for (offs = 0; offs < encoded_len; ) { int len = (encoded_len - offs) > SM_MAX_DATA_SIZE ? SM_MAX_DATA_SIZE : (encoded_len - offs); struct sc_remote_apdu *rapdu = NULL; rv = rdata->alloc(rdata, &rapdu); LOG_TEST_RET(ctx, rv, "SM get 'UPDATE RSA' APDUs: cannot allocate remote APDU"); rapdu->apdu.cse = SC_APDU_CASE_3_SHORT; rapdu->apdu.cla = len + offs < encoded_len ? 0x10 : 0x00; rapdu->apdu.ins = 0xDB; rapdu->apdu.p1 = 0x3F; rapdu->apdu.p2 = 0xFF; memcpy((unsigned char *)rapdu->apdu.data, encoded + offs, len); rapdu->apdu.datalen = len; rapdu->apdu.lc = len; /** 99 02 SW 8E 08 MAC **/ rapdu->apdu.le = 0x0E; rv = sm_cwa_securize_apdu(ctx, sm_info, rapdu); LOG_TEST_RET(ctx, rv, "SM get 'UPDATE RSA' APDUs: securize APDU error"); rapdu->flags |= SC_REMOTE_APDU_FLAG_RETURN_ANSWER; offs += len; } free(encoded); } } LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
int sc_asn1_encode_algorithm_id(struct sc_context *ctx, u8 **buf, size_t *len, const struct sc_algorithm_id *id, int depth) { struct sc_asn1_pkcs15_algorithm_info *alg_info; struct sc_algorithm_id temp_id; struct sc_asn1_entry asn1_alg_id[3]; u8 *obj = NULL; size_t obj_len = 0; int r; u8 *tmp; LOG_FUNC_CALLED(ctx); sc_log(ctx, "type of algorithm to encode: %i", id->algorithm); alg_info = sc_asn1_get_algorithm_info(id); if (alg_info == NULL) { sc_log(ctx, "Cannot encode unknown algorithm %u", id->algorithm); LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); } /* Set the oid if not yet given */ if (!sc_valid_oid(&id->oid)) { temp_id = *id; temp_id.oid = alg_info->oid; id = &temp_id; } sc_log(ctx, "encode algo %s", sc_dump_oid(&(id->oid))); sc_copy_asn1_entry(c_asn1_alg_id, asn1_alg_id); sc_format_asn1_entry(asn1_alg_id + 0, (void *) &id->oid, NULL, 1); /* no parameters, write NULL tag */ if (!id->params || !alg_info->encode) asn1_alg_id[1].flags |= SC_ASN1_PRESENT; r = _sc_asn1_encode(ctx, asn1_alg_id, buf, len, depth + 1); LOG_TEST_RET(ctx, r, "ASN.1 encode of algorithm failed"); /* Encode any parameters */ if (id->params && alg_info->encode) { r = alg_info->encode(ctx, id->params, &obj, &obj_len, depth+1); if (r < 0) { if (obj) free(obj); LOG_FUNC_RETURN(ctx, r); } } if (obj_len) { tmp = (u8 *) realloc(*buf, *len + obj_len); if (!tmp) { free(*buf); *buf = NULL; free(obj); LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); } *buf = tmp; memcpy(*buf + *len, obj, obj_len); *len += obj_len; free(obj); } sc_log(ctx, "return encoded algorithm ID: %s", sc_dump_hex(*buf, *len)); LOG_FUNC_RETURN(ctx, SC_SUCCESS); }