/* * @brief Use PUT DATA to import a private EC key. * * Format of transmitted data: * 0xE0 - Private class, constructed encoding, number one. * 0x81 - prime * 0x82 - coefficient A * 0x83 - coefficient B * 0x84 - base point G * 0x85 - order * 0x87 - cofactor * 0x88 - private D (private key) * * @param card * @param ec The EC private key to import. * * @return SC_ERROR_INVALID_ARGUMENTS: Curve parameters or private component is missing. * other errors: Transmit errors / errors returned by card. * ASN1 errors. */ static int isoApplet_put_data_prkey_ec(sc_card_t *card, sc_cardctl_isoApplet_import_key_t *args) { sc_apdu_t apdu; u8 sbuf[SC_MAX_EXT_APDU_BUFFER_SIZE]; int r; u8 *p; size_t tags_len; LOG_FUNC_CALLED(card->ctx); if(!args->privkey.ec.privateD.value || !args->privkey.ec.params.prime.value || !args->privkey.ec.params.coefficientA.value || !args->privkey.ec.params.coefficientB.value || !args->privkey.ec.params.basePointG.value || !args->privkey.ec.params.order.value || !args->privkey.ec.params.coFactor.value ) { LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Missing information about EC private key."); } /* Calculate the length of all inner tag-length-value entries, but do not write anything yet. */ tags_len = 0; r = sc_asn1_put_tag(0x81, NULL, args->privkey.ec.params.prime.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x82, NULL, args->privkey.ec.params.coefficientA.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x83, NULL, args->privkey.ec.params.coefficientB.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x84, NULL, args->privkey.ec.params.basePointG.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x85, NULL, args->privkey.ec.params.order.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x87, NULL, args->privkey.ec.params.coFactor.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x88, NULL, args->privkey.ec.privateD.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; /* Write the outer tag and length information. */ p = sbuf; r = sc_asn1_put_tag(0xE0, NULL, tags_len, p, sizeof(sbuf), &p); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); /* Write inner tags. */ r = isoApplet_put_ec_params(card, &args->privkey.ec.params, p, sizeof(sbuf) - (p - sbuf), &p); if(r < 0) { sc_log(card->ctx, "Error composing EC params."); goto out; } r = sc_asn1_put_tag(0x88, args->privkey.ec.privateD.value, args->privkey.ec.privateD.len, p, sizeof(sbuf) - (p - sbuf), &p); if(r < 0) goto out; /* Send to card. */ sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xDB, 0x3F, 0xFF); apdu.lc = p - sbuf; apdu.datalen = p - sbuf; apdu.data = sbuf; r = sc_transmit_apdu(card, &apdu); if(r < 0) { sc_log(card->ctx, "APDU transmit failed"); goto out; } r = sc_check_sw(card, apdu.sw1, apdu.sw2); if(apdu.sw1 == 0x6D && apdu.sw2 == 0x00) { sc_log(card->ctx, "The applet returned that the PUT DATA instruction byte is not supported. " "If you are using an older applet version and are trying to import keys, please update your applet first."); } else if(apdu.sw1 == 0x6A && apdu.sw2 == 0x81) { sc_log(card->ctx, "Key import not supported by the card with that particular key type. " "Your card may not support the specified algorithm used by the applet / specified by you. " "In most cases, this happens when trying to import EC keys not supported by your java card. " "In this case, look for supported field lengths and whether FP and/or F2M are supported. " "If you tried to import a private RSA key, check the key length."); } else if(apdu.sw1 == 0x69 && apdu.sw2 == 0x00) { sc_log(card->ctx, "Key import not allowed by the applet's security policy. " "If you want to allow key import, set DEF_PRIVATE_KEY_IMPORT_ALLOWED in the IsoApplet," " rebuild and reinstall the applet."); } if(r < 0) { sc_log(card->ctx, "Card returned error"); goto out; } r = SC_SUCCESS; out: sc_mem_clear(sbuf, sizeof(sbuf)); LOG_FUNC_RETURN(card->ctx, r); }
static int sc_oberthur_read_file(struct sc_pkcs15_card *p15card, const char *in_path, unsigned char **out, size_t *out_len, int verify_pin) { struct sc_context *ctx = p15card->card->ctx; struct sc_card *card = p15card->card; struct sc_file *file = NULL; struct sc_path path; size_t sz; int rv; LOG_FUNC_CALLED(ctx); if (!in_path || !out || !out_len) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Cannot read oberthur file"); sc_log(ctx, "read file '%s'; verify_pin:%i", in_path, verify_pin); *out = NULL; *out_len = 0; sc_format_path(in_path, &path); rv = sc_select_file(card, &path, &file); LOG_TEST_RET(ctx, rv, "Cannot select oberthur file to read"); if (file->ef_structure == SC_FILE_EF_TRANSPARENT) sz = file->size; else sz = (file->record_length + 2) * file->record_count; *out = calloc(sz, 1); if (*out == NULL) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot read oberthur file"); if (file->ef_structure == SC_FILE_EF_TRANSPARENT) { rv = sc_read_binary(card, 0, *out, sz, 0); } else { int rec; int offs = 0; int rec_len = file->record_length; for (rec = 1; ; rec++) { rv = sc_read_record(card, rec, *out + offs + 2, rec_len, SC_RECORD_BY_REC_NR); if (rv == SC_ERROR_RECORD_NOT_FOUND) { rv = 0; break; } else if (rv < 0) { break; } rec_len = rv; *(*out + offs) = 'R'; *(*out + offs + 1) = rv; offs += rv + 2; } sz = offs; } sc_log(ctx, "read oberthur file result %i", rv); if (verify_pin && rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) { struct sc_pkcs15_object *objs[0x10], *pin_obj = NULL; const struct sc_acl_entry *acl = sc_file_get_acl_entry(file, SC_AC_OP_READ); int ii; rv = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_AUTH_PIN, objs, 0x10); LOG_TEST_RET(ctx, rv, "Cannot read oberthur file: get AUTH objects error"); for (ii=0; ii<rv; ii++) { struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *) objs[ii]->data; sc_log(ctx, "compare PIN/ACL refs:%i/%i, method:%i/%i", auth_info->attrs.pin.reference, acl->key_ref, auth_info->auth_method, acl->method); if (auth_info->attrs.pin.reference == (int)acl->key_ref && auth_info->auth_method == (unsigned)acl->method) { pin_obj = objs[ii]; break; } } if (!pin_obj || !pin_obj->content.value) { rv = SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; } else { rv = sc_pkcs15_verify_pin(p15card, pin_obj, pin_obj->content.value, pin_obj->content.len); if (!rv) rv = sc_oberthur_read_file(p15card, in_path, out, out_len, 0); } }; sc_file_free(file); if (rv < 0) { free(*out); *out = NULL; *out_len = 0; } *out_len = sz; LOG_FUNC_RETURN(ctx, rv); }
/* Public key info: * flags:2, * CN(len:2,value:<variable length>), * ID(len:2,value:(SHA1 value)), * StartDate(Ascii:8) * EndDate(Ascii:8) * ??(0x00:2) */ static int sc_pkcs15emu_oberthur_add_pubkey(struct sc_pkcs15_card *p15card, unsigned int file_id, unsigned int size) { struct sc_context *ctx = p15card->card->ctx; struct sc_pkcs15_pubkey_info key_info; struct sc_pkcs15_object key_obj; char ch_tmp[0x100]; unsigned char *info_blob; size_t len, info_len, offs; unsigned flags; int rv; LOG_FUNC_CALLED(ctx); sc_log(ctx, "public key(file-id:%04X,size:%X)", file_id, size); memset(&key_info, 0, sizeof(key_info)); memset(&key_obj, 0, sizeof(key_obj)); snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PUB, file_id | 0x100); rv = sc_oberthur_read_file(p15card, ch_tmp, &info_blob, &info_len, 1); LOG_TEST_RET(ctx, rv, "Failed to add public key: read oberthur file error"); /* Flags */ offs = 2; if (offs > info_len) LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add public key: no 'tag'"); flags = *(info_blob + 0) * 0x100 + *(info_blob + 1); key_info.usage = sc_oberthur_decode_usage(flags); if (flags & OBERTHUR_ATTR_MODIFIABLE) key_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE; sc_log(ctx, "Public key key-usage:%04X", key_info.usage); /* Label */ if (offs + 2 > info_len) LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add public key: no 'Label'"); len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; if (len) { if (len > sizeof(key_obj.label) - 1) len = sizeof(key_obj.label) - 1; memcpy(key_obj.label, info_blob + offs + 2, len); } offs += 2 + len; /* ID */ if (offs > info_len) LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add public key: no 'ID'"); len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; if (!len || len > sizeof(key_info.id.value)) LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Failed to add public key: invalie 'ID' length"); memcpy(key_info.id.value, info_blob + offs + 2, len); key_info.id.len = len; /* Ignore Start/End dates */ snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PUB, file_id); sc_format_path(ch_tmp, &key_info.path); key_info.native = 1; key_info.key_reference = file_id & 0xFF; key_info.modulus_length = size; rv = sc_pkcs15emu_add_rsa_pubkey(p15card, &key_obj, &key_info); LOG_FUNC_RETURN(ctx, rv); }
/** * Ask for user consent. * * Check for user consent configuration, * Invoke proper gui app and check result * * @param card pointer to sc_card structure * @param title Text to appear in the window header * @param text Message to show to the user * @return SC_SUCCESS on user consent OK , else error code */ int sc_ask_user_consent(struct sc_card * card, const char *title, const char *message) { #ifdef __APPLE__ CFOptionFlags result; /* result code from the message box */ /* convert the strings from char* to CFStringRef */ CFStringRef header_ref; /* to store title */ CFStringRef message_ref; /* to store message */ #endif #ifdef linux pid_t pid; FILE *fin=NULL; FILE *fout=NULL; /* to handle pipes as streams */ struct stat st_file; /* to verify that executable exists */ int srv_send[2]; /* to send data from server to client */ int srv_recv[2]; /* to receive data from client to server */ char outbuf[1024]; /* to compose and send messages */ char buf[1024]; /* to store client responses */ int n = 0; /* to iterate on to-be-sent messages */ #endif int res = SC_ERROR_INTERNAL; /* by default error :-( */ char *msg = NULL; /* to makr errors */ if ((card == NULL) || (card->ctx == NULL)) return SC_ERROR_INVALID_ARGUMENTS; LOG_FUNC_CALLED(card->ctx); if ((title==NULL) || (message==NULL)) LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); if (GET_DNIE_UI_CTX(card).user_consent_enabled == 0) { sc_log(card->ctx, "User Consent is disabled in configuration file"); LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } #ifdef _WIN32 /* in Windows, do not use pinentry, but MessageBox system call */ res = MessageBox ( NULL, TEXT(message), TEXT(title), MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2 | MB_APPLMODAL ); if ( res == IDOK ) LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ALLOWED); #elif __APPLE__ /* Also in Mac OSX use native functions */ /* convert the strings from char* to CFStringRef */ header_ref = CFStringCreateWithCString( NULL, title, strlen(title) ); message_ref = CFStringCreateWithCString( NULL,message, strlen(message) ); /* Displlay user notification alert */ CFUserNotificationDisplayAlert( 0, /* no timeout */ kCFUserNotificationNoteAlertLevel, /* Alert level */ NULL, /* IconURL, use default, you can change */ /* it depending message_type flags */ NULL, /* SoundURL (not used) */ NULL, /* localization of strings */ header_ref, /* header. Cannot be null */ message_ref, /* message text */ CFSTR("Cancel"), /* default ( "OK" if null) button text */ CFSTR("OK"), /* second button title */ NULL, /* third button title, null--> no other button */ &result /* response flags */ ); /* Clean up the strings */ CFRelease( header_ref ); CFRelease( message_ref ); /* Return 0 only if "OK" is selected */ if( result == kCFUserNotificationAlternateResponse ) LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ALLOWED); #elif linux /* check that user_consent_app exists. TODO: check if executable */ res = stat(GET_DNIE_UI_CTX(card).user_consent_app, &st_file); if (res != 0) { sc_log(card->ctx, "Invalid pinentry application: %s\n", GET_DNIE_UI_CTX(card).user_consent_app); LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); } /* just a simple bidirectional pipe+fork+exec implementation */ /* In a pipe, xx[0] is for reading, xx[1] is for writing */ if (pipe(srv_send) < 0) { msg = "pipe(srv_send)"; goto do_error; } if (pipe(srv_recv) < 0) { msg = "pipe(srv_recv)"; goto do_error; } pid = fork(); switch (pid) { case -1: /* error */ msg = "fork()"; goto do_error; case 0: /* child */ /* make our pipes, our new stdin & stderr, closing older ones */ dup2(srv_send[0], STDIN_FILENO); /* map srv send for input */ dup2(srv_recv[1], STDOUT_FILENO); /* map srv_recv for output */ /* once dup2'd pipes are no longer needed on client; so close */ close(srv_send[0]); close(srv_send[1]); close(srv_recv[0]); close(srv_recv[1]); /* call exec() with proper user_consent_app from configuration */ /* if ok should never return */ execlp(GET_DNIE_UI_CTX(card).user_consent_app, GET_DNIE_UI_CTX(card).user_consent_app, (char *)NULL); res = SC_ERROR_INTERNAL; msg = "execlp() error"; /* exec() failed */ goto do_error; default: /* parent */ /* Close the pipe ends that the child uses to read from / write to * so when we close the others, an EOF will be transmitted properly. */ close(srv_send[0]); close(srv_recv[1]); /* use iostreams to take care on newlines and text based data */ fin = fdopen(srv_recv[0], "r"); if (fin == NULL) { msg = "fdopen(in)"; goto do_error; } fout = fdopen(srv_send[1], "w"); if (fout == NULL) { msg = "fdopen(out)"; goto do_error; } /* read and ignore first line */ fflush(stdin); for (n = 0; n<4; n++) { char *pt; memset(outbuf, 0, sizeof(outbuf)); if (n==0) snprintf(outbuf,1023,"%s %s\n",user_consent_msgs[0],title); else if (n==1) snprintf(outbuf,1023,"%s %s\n",user_consent_msgs[1],message); else snprintf(outbuf,1023,"%s\n",user_consent_msgs[n]); /* send message */ fputs(outbuf, fout); fflush(fout); /* get response */ memset(buf, 0, sizeof(buf)); pt=fgets(buf, sizeof(buf) - 1, fin); if (pt==NULL) { res = SC_ERROR_INTERNAL; msg = "fgets() Unexpected IOError/EOF"; goto do_error; } if (strstr(buf, "OK") == NULL) { res = SC_ERROR_NOT_ALLOWED; msg = "fail/cancel"; goto do_error; } } } /* switch */ /* arriving here means signature has been accepted by user */ res = SC_SUCCESS; msg = NULL; do_error: /* close out channel to force client receive EOF and also die */ if (fout != NULL) fclose(fout); if (fin != NULL) fclose(fin); #else #error "Don't know how to handle user consent in this (rare) Operating System" #endif if (msg != NULL) sc_log(card->ctx, "%s", msg); LOG_FUNC_RETURN(card->ctx, res); }
static int parse_dir_record(sc_card_t *card, u8 ** buf, size_t *buflen, int rec_nr) { struct sc_context *ctx = card->ctx; struct sc_asn1_entry asn1_dirrecord[5], asn1_dir[2]; scconf_block *conf_block = NULL; sc_app_info_t *app = NULL; struct sc_aid aid; u8 label[128], path[128], ddo[128]; size_t label_len = sizeof(label) - 1, path_len = sizeof(path), ddo_len = sizeof(ddo); int r; LOG_FUNC_CALLED(ctx); aid.len = sizeof(aid.value); memset(label, 0, sizeof(label)); sc_copy_asn1_entry(c_asn1_dirrecord, asn1_dirrecord); sc_copy_asn1_entry(c_asn1_dir, asn1_dir); sc_format_asn1_entry(asn1_dir + 0, asn1_dirrecord, NULL, 0); sc_format_asn1_entry(asn1_dirrecord + 0, aid.value, &aid.len, 0); sc_format_asn1_entry(asn1_dirrecord + 1, label, &label_len, 0); sc_format_asn1_entry(asn1_dirrecord + 2, path, &path_len, 0); sc_format_asn1_entry(asn1_dirrecord + 3, ddo, &ddo_len, 0); r = sc_asn1_decode(ctx, asn1_dir, *buf, *buflen, (const u8 **) buf, buflen); if (r == SC_ERROR_ASN1_END_OF_CONTENTS) LOG_FUNC_RETURN(ctx, r); LOG_TEST_RET(ctx, r, "EF(DIR) parsing failed"); conf_block = sc_get_conf_block(ctx, "framework", "pkcs15", 1); if (conf_block) { scconf_block **blocks = NULL; char aid_str[SC_MAX_AID_STRING_SIZE]; int ignore_app = 0; sc_bin_to_hex(aid.value, aid.len, aid_str, sizeof(aid_str), 0); blocks = scconf_find_blocks(card->ctx->conf, conf_block, "application", aid_str); if (blocks) { ignore_app = (blocks[0] && scconf_get_str(blocks[0], "disable", 0)); free(blocks); } if (ignore_app) { sc_log(ctx, "Application '%s' ignored", aid_str); LOG_FUNC_RETURN(ctx, SC_SUCCESS); } } app = calloc(1, sizeof(struct sc_app_info)); if (app == NULL) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); memcpy(&app->aid, &aid, sizeof(struct sc_aid)); if (asn1_dirrecord[1].flags & SC_ASN1_PRESENT) app->label = strdup((char *) label); else app->label = NULL; if (asn1_dirrecord[2].flags & SC_ASN1_PRESENT && path_len > 0) { /* application path present: ignore AID */ if (path_len > SC_MAX_PATH_SIZE) { free(app); LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "Application path is too long."); } memcpy(app->path.value, path, path_len); app->path.len = path_len; app->path.type = SC_PATH_TYPE_PATH; } else { /* application path not present: use AID as application path */ memcpy(app->path.value, aid.value, aid.len); app->path.len = aid.len; app->path.type = SC_PATH_TYPE_DF_NAME; } if (asn1_dirrecord[3].flags & SC_ASN1_PRESENT) { app->ddo.value = malloc(ddo_len); if (app->ddo.value == NULL) { free(app); LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate DDO value"); } memcpy(app->ddo.value, ddo, ddo_len); app->ddo.len = ddo_len; } else { app->ddo.value = NULL; app->ddo.len = 0; } app->rec_nr = rec_nr; card->app[card->app_count] = app; card->app_count++; LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
LIBOPENSC_API int sc_transmit_apdu(sc_card_t *card, sc_apdu_t *apdu) { int r = SC_SUCCESS; if (card == NULL || apdu == NULL) return SC_ERROR_INVALID_ARGUMENTS; LOG_FUNC_CALLED(card->ctx); /* determine the APDU type if necessary, i.e. to use * short or extended APDUs */ sc_detect_apdu_cse(card, apdu); /* basic APDU consistency check */ r = sc_check_apdu(card, apdu); if (r != SC_SUCCESS) return SC_ERROR_INVALID_ARGUMENTS; r = sc_lock(card); /* acquire card lock*/ if (r != SC_SUCCESS) { sc_log(card->ctx, "unable to acquire lock"); return r; } if ((apdu->flags & SC_APDU_FLAGS_CHAINING) != 0) { /* divide et impera: transmit APDU in chunks with Lc <= max_send_size * bytes using command chaining */ size_t len = apdu->datalen; const u8 *buf = apdu->data; size_t max_send_size = card->max_send_size > 0 ? card->max_send_size : 255; while (len != 0) { size_t plen; sc_apdu_t tapdu; int last = 0; tapdu = *apdu; /* clear chaining flag */ tapdu.flags &= ~SC_APDU_FLAGS_CHAINING; if (len > max_send_size) { /* adjust APDU case: in case of CASE 4 APDU * the intermediate APDU are of CASE 3 */ if ((tapdu.cse & SC_APDU_SHORT_MASK) == SC_APDU_CASE_4_SHORT) tapdu.cse--; /* XXX: the chunk size must be adjusted when * secure messaging is used */ plen = max_send_size; tapdu.cla |= 0x10; tapdu.le = 0; /* the intermediate APDU don't expect data */ tapdu.lc = 0; tapdu.resplen = 0; tapdu.resp = NULL; } else { plen = len; last = 1; } tapdu.data = buf; tapdu.datalen = tapdu.lc = plen; r = sc_check_apdu(card, &tapdu); if (r != SC_SUCCESS) { sc_log(card->ctx, "inconsistent APDU while chaining"); break; } r = sc_transmit(card, &tapdu); if (r != SC_SUCCESS) break; if (last != 0) { /* in case of the last APDU set the SW1 * and SW2 bytes in the original APDU */ apdu->sw1 = tapdu.sw1; apdu->sw2 = tapdu.sw2; apdu->resplen = tapdu.resplen; } else { /* otherwise check the status bytes */ r = sc_check_sw(card, tapdu.sw1, tapdu.sw2); if (r != SC_SUCCESS) break; } len -= plen; buf += plen; } } else /* transmit single APDU */ r = sc_transmit(card, apdu); /* all done => release lock */ if (sc_unlock(card) != SC_SUCCESS) sc_log(card->ctx, "sc_unlock failed"); return r; }
int iasecc_sm_initialize(struct sc_card *card, unsigned se_num, unsigned cmd) { struct sc_context *ctx = card->ctx; #ifdef ENABLE_SM struct sm_info *sm_info = &card->sm_ctx.info; struct sm_cwa_session *cwa_session = &sm_info->session.cwa; struct sc_remote_data rdata; int rv; LOG_FUNC_CALLED(ctx); strlcpy(sm_info->config_section, card->sm_ctx.config_section, sizeof(sm_info->config_section)); sm_info->cmd = cmd; sm_info->serialnr = card->serialnr; sm_info->card_type = card->type; sm_info->sm_type = SM_TYPE_CWA14890; rv = iasecc_sm_se_mutual_authentication(card, se_num); LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() MUTUAL AUTHENTICATION failed"); rv = iasecc_sm_get_challenge(card, cwa_session->card_challenge, SM_SMALL_CHALLENGE_LEN); LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() GET CHALLENGE failed"); sc_remote_data_init(&rdata); rv = sm_save_sc_context(card, sm_info); LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() cannot save current context"); if (!card->sm_ctx.module.ops.initialize) LOG_TEST_RET(ctx, SC_ERROR_SM_NOT_INITIALIZED, "iasecc_sm_initialize() no SM module"); rv = card->sm_ctx.module.ops.initialize(ctx, sm_info, &rdata); LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() INITIALIZE failed"); if (rdata.length == 1) { rdata.data->flags |= SC_REMOTE_APDU_FLAG_RETURN_ANSWER; rdata.data->apdu.flags &= ~SC_APDU_FLAGS_NO_GET_RESP; } else { LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "TODO: SM init with more then one APDU"); } cwa_session->mdata_len = sizeof(cwa_session->mdata); rv = iasecc_sm_transmit_apdus (card, &rdata, cwa_session->mdata, &cwa_session->mdata_len); if (rv == SC_ERROR_PIN_CODE_INCORRECT) sc_log(ctx, "SM initialization failed, %i tries left", (rdata.data + rdata.length - 1)->apdu.sw2 & 0x0F); LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() transmit APDUs failed"); rdata.free(&rdata); sc_log(ctx, "MA data(len:%"SC_FORMAT_LEN_SIZE_T"u) '%s'", cwa_session->mdata_len, sc_dump_hex(cwa_session->mdata, cwa_session->mdata_len)); if (cwa_session->mdata_len != 0x48) LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "iasecc_sm_initialize() invalid MUTUAL AUTHENTICATE result data"); LOG_FUNC_RETURN(ctx, SC_SUCCESS); #else LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging"); return SC_ERROR_NOT_SUPPORTED; #endif }
/* Finish initialization. After this ACL is in affect */ static int myeid_finalize_card(sc_card_t *card) { LOG_FUNC_CALLED(card->ctx); LOG_FUNC_RETURN(card->ctx, sc_card_ctl(card, SC_CARDCTL_MYEID_ACTIVATE_CARD, NULL)); }
static int iasecc_sdo_parse_data(struct sc_card *card, unsigned char *data, struct iasecc_sdo *sdo) { struct sc_context *ctx = card->ctx; struct iasecc_extended_tlv tlv; int tlv_size, rv; LOG_FUNC_CALLED(ctx); sc_log(ctx, "iasecc_sdo_parse_data() class %X; ref %X", sdo->sdo_class, sdo->sdo_ref); tlv_size = iasecc_parse_get_tlv(card, data, &tlv); LOG_TEST_RET(ctx, tlv_size, "parse error: get TLV"); sc_log(ctx, "iasecc_sdo_parse_data() tlv.tag 0x%X", tlv.tag); if (tlv.tag == IASECC_DOCP_TAG) { sc_log(ctx, "iasecc_sdo_parse_data() parse IASECC_DOCP_TAG: 0x%X; size %i", tlv.tag, tlv.size); rv = iasecc_parse_docp(card, tlv.value, tlv.size, sdo); sc_log(ctx, "iasecc_sdo_parse_data() parsed IASECC_DOCP_TAG rv %i", rv); free(tlv.value); LOG_TEST_RET(ctx, rv, "parse error: cannot parse DOCP"); } else if (tlv.tag == IASECC_DOCP_TAG_NON_REPUDATION) { sdo->docp.non_repudiation = tlv; } else if (tlv.tag == IASECC_DOCP_TAG_USAGE_REMAINING) { sdo->docp.usage_remaining = tlv; } else if (tlv.tag == IASECC_DOCP_TAG_TRIES_MAXIMUM) { sdo->docp.tries_maximum = tlv; } else if (tlv.tag == IASECC_DOCP_TAG_TRIES_REMAINING) { sdo->docp.tries_remaining = tlv; } else if (tlv.tag == IASECC_SDO_CHV_TAG) { if (sdo->sdo_class != IASECC_SDO_CLASS_CHV) LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: IASECC_SDO_CHV_TAG tag in non User CHV SDO"); rv = iasecc_parse_chv(card, tlv.value, tlv.size, &sdo->data.chv); LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO CHV data"); free(tlv.value); } else if (tlv.tag == IASECC_SDO_PUBKEY_TAG) { if (sdo->sdo_class != IASECC_SDO_CLASS_RSA_PUBLIC) LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: SDO_PUBLIC_KEY tag in non PUBLIC_KEY SDO"); rv = iasecc_parse_pubkey(card, tlv.value, tlv.size, &sdo->data.pub_key); LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO PUBLIC KEY data"); free(tlv.value); } else if (tlv.tag == IASECC_SDO_PRVKEY_TAG) { if (sdo->sdo_class != IASECC_SDO_CLASS_RSA_PRIVATE) LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: SDO_PRIVATE_KEY tag in non PRIVATE_KEY SDO"); rv = iasecc_parse_prvkey(card, tlv.value, tlv.size, &sdo->data.prv_key); LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO PRIVATE KEY data"); free(tlv.value); } else if (tlv.tag == IASECC_SDO_KEYSET_TAG) { if (sdo->sdo_class != IASECC_SDO_CLASS_KEYSET) LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: SDO_KEYSET tag in non KEYSET SDO"); rv = iasecc_parse_keyset(card, tlv.value, tlv.size, &sdo->data.keyset); LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO KEYSET data"); free(tlv.value); } else { sc_log(ctx, "iasecc_sdo_parse_data() non supported tag 0x%X", tlv.tag); LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); } return tlv_size; }
/* * Get 'Initialize Applet' data * using the ACLs defined in card profile. */ static int myeid_get_init_applet_data(struct sc_profile *profile, struct sc_pkcs15_card *p15card, unsigned char *data, size_t data_len) { struct sc_context *ctx = p15card->card->ctx; struct sc_file *tmp_file = NULL; const struct sc_acl_entry *entry = NULL; int r; LOG_FUNC_CALLED(ctx); if (data_len < 8) LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "Cannot get init applet data"); *(data + 0) = 0xFF; *(data + 1) = 0xFF; /* MF acls */ sc_file_dup(&tmp_file, profile->mf_info->file); if (tmp_file == NULL) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot duplicate MF file"); r = sc_pkcs15init_fixup_file(profile, p15card, tmp_file); LOG_TEST_RET(ctx, r, "MF fixup failed"); /* AC 'Create DF' and 'Create EF' */ *(data + 2) = 0x00; /* 'NONE' */ entry = sc_file_get_acl_entry(tmp_file, SC_AC_OP_CREATE); if (entry->method == SC_AC_CHV) *(data + 2) = entry->key_ref | (entry->key_ref << 4); /* 'CHVx'. */ else if (entry->method == SC_AC_NEVER) *(data + 2) = 0xFF; /* 'NEVER'. */ /* AC 'INITIALISE APPLET'. */ *(data + 3) = 0x0F; /* 'NONE' */ #ifndef KEEP_AC_NONE_FOR_INIT_APPLET entry = sc_file_get_acl_entry(tmp_file, SC_AC_OP_DELETE); if (entry->method == SC_AC_CHV) *(data + 3) = (entry->key_ref << 4) | 0xF; else if (entry->method == SC_AC_NEVER) *(data + 3) = 0xFF; #endif *(data + 4) = 0xFF; sc_file_free(tmp_file); tmp_file = NULL; /* Application DF (5015) acls */ sc_file_dup(&tmp_file, profile->df_info->file); if (tmp_file == NULL) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot duplicate Application DF file"); r = sc_pkcs15init_fixup_file(profile, p15card, tmp_file); LOG_TEST_RET(ctx, r, "Application DF fixup failed"); /* AC 'Create DF' and 'Create EF' */ *(data + 5) = 0x00; /* 'NONE' */ entry = sc_file_get_acl_entry(tmp_file, SC_AC_OP_CREATE); if (entry->method == SC_AC_CHV) *(data + 5) = entry->key_ref | (entry->key_ref << 4); /* 'CHVx' */ else if (entry->method == SC_AC_NEVER) *(data + 5) = 0xFF; /* 'NEVER'. */ /* AC 'Self delete' */ *(data + 6) = 0x0F; /* 'NONE' */ entry = sc_file_get_acl_entry(tmp_file, SC_AC_OP_DELETE); if (entry->method == SC_AC_CHV) *(data + 6) = (entry->key_ref << 4) | 0xF; /* 'CHVx' */ else if (entry->method == SC_AC_NEVER) *(data + 6) = 0xFF; /* 'NEVER'. */ *(data + 7) = 0xFF; sc_file_free(tmp_file); LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS); }
static int myeid_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *object, struct sc_pkcs15_pubkey *pubkey) { struct sc_context *ctx = p15card->card->ctx; struct sc_card *card = p15card->card; struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *) object->data; struct sc_cardctl_myeid_gen_store_key_info args; struct sc_file *file = NULL; int r; size_t keybits = key_info->modulus_length; unsigned char raw_pubkey[256]; LOG_FUNC_CALLED(ctx); if (object->type != SC_PKCS15_TYPE_PRKEY_RSA && object->type != SC_PKCS15_TYPE_PRKEY_EC) LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Generate key failed: only RSA and EC supported"); /* Check that the card supports the requested modulus length */ switch (object->type) { case SC_PKCS15_TYPE_PRKEY_RSA: if (sc_card_find_rsa_alg(p15card->card, keybits) == NULL) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported RSA key size"); break; case SC_PKCS15_TYPE_PRKEY_EC: if (sc_card_find_ec_alg(p15card->card, keybits) == NULL) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported EC key size"); if(key_info->field_length != 0) keybits = key_info->field_length; else key_info->field_length = keybits; break; default: LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported key type"); break; } sc_log(ctx, "Generate key with ID:%s and path:%s", sc_pkcs15_print_id(&key_info->id), sc_print_path(&key_info->path)); r = sc_select_file(card, &key_info->path, &file); LOG_TEST_RET(ctx, r, "Cannot generate key: failed to select key file"); r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_GENERATE); LOG_TEST_RET(ctx, r, "No authorisation to generate private key"); /* Fill in data structure */ memset(&args, 0, sizeof (args)); args.key_len_bits = keybits; args.op_type = OP_TYPE_GENERATE; if (object->type == SC_PKCS15_TYPE_PRKEY_RSA) { args.key_type = SC_CARDCTL_MYEID_KEY_RSA; args.pubexp_len = MYEID_DEFAULT_PUBKEY_LEN; args.pubexp = MYEID_DEFAULT_PUBKEY; } else if (object->type == SC_PKCS15_TYPE_PRKEY_EC) { args.key_type = SC_CARDCTL_MYEID_KEY_EC; } /* Generate RSA key */ r = sc_card_ctl(card, SC_CARDCTL_MYEID_GENERATE_STORE_KEY, &args); LOG_TEST_RET(ctx, r, "Card control 'MYEID_GENERATE_STORE_KEY' failed"); /* Keypair generation -> collect public key info */ if (pubkey != NULL) { struct sc_cardctl_myeid_data_obj data_obj; if (object->type == SC_PKCS15_TYPE_PRKEY_RSA) { pubkey->algorithm = SC_ALGORITHM_RSA; pubkey->u.rsa.modulus.len = (keybits + 7) / 8; pubkey->u.rsa.modulus.data = malloc(pubkey->u.rsa.modulus.len); pubkey->u.rsa.exponent.len = MYEID_DEFAULT_PUBKEY_LEN; pubkey->u.rsa.exponent.data = malloc(MYEID_DEFAULT_PUBKEY_LEN); memcpy(pubkey->u.rsa.exponent.data, MYEID_DEFAULT_PUBKEY, MYEID_DEFAULT_PUBKEY_LEN); /* Get public key modulus */ r = sc_select_file(card, &file->path, NULL); LOG_TEST_RET(ctx, r, "Cannot get key modulus: select key file failed"); data_obj.P1 = 0x01; data_obj.P2 = 0x01; data_obj.Data = raw_pubkey; data_obj.DataLen = sizeof (raw_pubkey); r = sc_card_ctl(card, SC_CARDCTL_MYEID_GETDATA, &data_obj); LOG_TEST_RET(ctx, r, "Cannot get RSA key modulus: 'MYEID_GETDATA' failed"); if ((data_obj.DataLen * 8) != key_info->modulus_length) LOG_TEST_RET(ctx, SC_ERROR_PKCS15INIT, "Cannot get RSA key modulus: invalid key-size"); memcpy(pubkey->u.rsa.modulus.data, raw_pubkey, pubkey->u.rsa.modulus.len); } else if (object->type == SC_PKCS15_TYPE_PRKEY_EC) { pubkey->algorithm = SC_ALGORITHM_EC; r = sc_select_file(card, &file->path, NULL); LOG_TEST_RET(ctx, r, "Cannot get public key: select key file failed"); data_obj.P1 = 0x01; data_obj.P2 = 0x86; /* Get public EC key (Q) */ data_obj.Data = raw_pubkey; data_obj.DataLen = sizeof (raw_pubkey); r = sc_card_ctl(card, SC_CARDCTL_MYEID_GETDATA, &data_obj); LOG_TEST_RET(ctx, r, "Cannot get EC public key: 'MYEID_GETDATA' failed"); pubkey->u.ec.ecpointQ.value = malloc(data_obj.DataLen - 2); pubkey->u.ec.ecpointQ.len = data_obj.DataLen - 2; pubkey->data.value = malloc(data_obj.DataLen); pubkey->data.len = data_obj.DataLen; pubkey->u.ec.params.field_length = keybits; /* Omit the first 2 bytes (0x86??) */ memcpy(pubkey->u.ec.ecpointQ.value, data_obj.Data + 2, data_obj.DataLen - 2); memcpy(pubkey->data.value, data_obj.Data, data_obj.DataLen); } } if (file) sc_file_free(file); LOG_FUNC_RETURN(ctx, r); }
/* * Store a private key */ static int myeid_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *object, struct sc_pkcs15_prkey *prkey) { struct sc_context *ctx = p15card->card->ctx; struct sc_card *card = p15card->card; struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *) object->data; struct sc_cardctl_myeid_gen_store_key_info args; struct sc_file *file = NULL; int r, keybits = key_info->modulus_length; LOG_FUNC_CALLED(ctx); switch (object->type) { case SC_PKCS15_TYPE_PRKEY_RSA: if (sc_card_find_rsa_alg(p15card->card, keybits) == NULL) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported RSA key size"); break; case SC_PKCS15_TYPE_PRKEY_EC: if (sc_card_find_ec_alg(p15card->card, keybits) == NULL) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported EC key size"); if(key_info->field_length != 0) keybits = key_info->field_length; else key_info->field_length = keybits; break; default: LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Store key failed: Unsupported key type"); break; } sc_log(ctx, "store MyEID key with ID:%s and path:%s", sc_pkcs15_print_id(&key_info->id), sc_print_path(&key_info->path)); r = sc_select_file(card, &key_info->path, &file); LOG_TEST_RET(ctx, r, "Cannot store MyEID key: select key file failed"); r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE); LOG_TEST_RET(ctx, r, "No authorisation to store MyEID private key"); if (file) sc_file_free(file); /* Fill in data structure */ memset(&args, 0, sizeof (args)); args.op_type = OP_TYPE_STORE; if(object->type == SC_PKCS15_TYPE_PRKEY_RSA) { //args.key_len_bits = keybits; args.key_type = SC_CARDCTL_MYEID_KEY_RSA; args.pubexp_len = prkey->u.rsa.exponent.len; args.pubexp = prkey->u.rsa.exponent.data; args.primep_len = prkey->u.rsa.p.len; args.primep = prkey->u.rsa.p.data; args.primeq_len = prkey->u.rsa.q.len; args.primeq = prkey->u.rsa.q.data; args.dp1_len = prkey->u.rsa.dmp1.len; args.dp1 = prkey->u.rsa.dmp1.data; args.dq1_len = prkey->u.rsa.dmq1.len; args.dq1 = prkey->u.rsa.dmq1.data; args.invq_len = prkey->u.rsa.iqmp.len; args.invq = prkey->u.rsa.iqmp.data; args.key_len_bits = prkey->u.rsa.modulus.len; args.mod = prkey->u.rsa.modulus.data; } else { args.key_type = SC_CARDCTL_MYEID_KEY_EC; args.d = prkey->u.ec.privateD.data; args.d_len = prkey->u.ec.privateD.len; args.ecpublic_point = prkey->u.ec.ecpointQ.value; args.ecpublic_point_len = prkey->u.ec.ecpointQ.len; args.key_len_bits = prkey->u.ec.params.field_length; } /* Store RSA key */ r = sc_card_ctl(card, SC_CARDCTL_MYEID_GENERATE_STORE_KEY, &args); LOG_TEST_RET(ctx, r, "Card control 'MYEID_GENERATE_STORE_KEY' failed"); LOG_FUNC_RETURN(ctx, r); }
/* For Myeid, all objects are files that can be deleted in any order */ static int myeid_delete_object(struct sc_profile *profile, struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *object, const struct sc_path *path) { LOG_FUNC_CALLED(p15card->card->ctx); return sc_pkcs15init_delete_by_path(profile, p15card, path); }
/* * @brief Import a private key. */ static int isoApplet_ctl_import_key(sc_card_t *card, sc_cardctl_isoApplet_import_key_t *args) { int r; sc_apdu_t apdu; u8 sbuf[SC_MAX_APDU_BUFFER_SIZE]; u8 *p; LOG_FUNC_CALLED(card->ctx); /* * Private keys are not stored in the filesystem. * ISO 7816-8 - section C.2 describes: * "Usage of the PUT DATA command for private key import" * The applet uses this PUT DATA to import private keys, if private key import is allowed. * * The first step is to perform a MANAGE SECURITY ENVIRONMENT as it would be done * with on-card key generation. The second step is PUT DATA (instead of * GENERATE ASYMMETRIC KEYPAIR). */ /* MANAGE SECURITY ENVIRONMENT (SET). Set the algorithm and key references. */ sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0x00); p = sbuf; *p++ = 0x80; /* algorithm reference */ *p++ = 0x01; *p++ = args->algorithm_ref; *p++ = 0x84; /* Private key reference */ *p++ = 0x01; *p++ = args->priv_key_ref; r = p - sbuf; p = NULL; apdu.lc = r; apdu.datalen = r; apdu.data = sbuf; r = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, r, "%s: APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(card->ctx, r, "Card returned error"); /* PUT DATA */ switch(args->algorithm_ref) { case SC_ISOAPPLET_ALG_REF_RSA_GEN_2048: r = isoApplet_put_data_prkey_rsa(card, args); LOG_TEST_RET(card->ctx, r, "Error in PUT DATA."); break; case SC_ISOAPPLET_ALG_REF_EC_GEN: r = isoApplet_put_data_prkey_ec(card, args); LOG_TEST_RET(card->ctx, r, "Error in PUT DATA."); break; default: LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Uknown algorithm refernce."); } LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); }
static int sc_pkcs15emu_pteid_init(sc_pkcs15_card_t * p15card) { u8 buf[1024]; sc_pkcs15_df_t *df; sc_pkcs15_object_t *p15_obj; sc_path_t path; struct sc_file *file = NULL; size_t len; int rv; int i; sc_context_t *ctx = p15card->card->ctx; LOG_FUNC_CALLED(ctx); /* Check for correct card atr */ if (pteid_detect_card(p15card->card) != SC_SUCCESS) return SC_ERROR_WRONG_CARD; sc_log(p15card->card->ctx, "Selecting application DF"); sc_format_path("4F00", &path); rv = sc_select_file(p15card->card, &path, &file); if (rv != SC_SUCCESS || !file) return SC_ERROR_INTERNAL; /* set the application DF */ if (p15card->file_app) free(p15card->file_app); p15card->file_app = file; /* Load TokenInfo */ len = sizeof(buf); rv = dump_ef(p15card->card, "4F005032", buf, &len); if (rv != SC_SUCCESS) { sc_log(ctx, "Reading of EF.TOKENINFO failed: %d", rv); LOG_FUNC_RETURN(ctx, rv); } memset(p15card->tokeninfo, 0, sizeof(*p15card->tokeninfo)); rv = sc_pkcs15_parse_tokeninfo(p15card->card->ctx, p15card->tokeninfo, buf, len); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of EF.TOKENINFO failed: %d", rv); LOG_FUNC_RETURN(ctx, rv); } p15card->tokeninfo->flags |= SC_PKCS15_TOKEN_PRN_GENERATION | SC_PKCS15_TOKEN_EID_COMPLIANT | SC_PKCS15_TOKEN_READONLY; /* Load ODF */ len = sizeof(buf); rv = dump_ef(p15card->card, "4F005031", buf, &len); if (rv != SC_SUCCESS) { sc_log(ctx, "Reading of ODF failed: %d", rv); LOG_FUNC_RETURN(ctx, rv); } rv = parse_odf(buf, len, p15card); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of ODF failed: %d", rv); LOG_FUNC_RETURN(ctx, rv); } /* Decode EF.PrKDF, EF.PuKDF, EF.CDF and EF.AODF */ for (df = p15card->df_list; df != NULL; df = df->next) { if (df->type == SC_PKCS15_PRKDF) { rv = sc_pkcs15_parse_df(p15card, df); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of EF.PrKDF (%s) failed: %d", sc_print_path(&df->path), rv); } } if (df->type == SC_PKCS15_PUKDF) { rv = sc_pkcs15_parse_df(p15card, df); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of EF.PuKDF (%s) failed: %d", sc_print_path(&df->path), rv); } } if (df->type == SC_PKCS15_CDF) { rv = sc_pkcs15_parse_df(p15card, df); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of EF.CDF (%s) failed: %d", sc_print_path(&df->path), rv); } } if (df->type == SC_PKCS15_AODF) { rv = sc_pkcs15_parse_df(p15card, df); if (rv != SC_SUCCESS) { sc_log(ctx, "Decoding of EF.AODF (%s) failed: %d", sc_print_path(&df->path), rv); } } } p15_obj = p15card->obj_list; while (p15_obj != NULL) { if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_PRKDF) ) { struct sc_pkcs15_prkey_info *prkey_info = (sc_pkcs15_prkey_info_t *) p15_obj->data; prkey_info->access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE | SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE | SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE | SC_PKCS15_PRKEY_ACCESS_LOCAL; p15_obj->flags = SC_PKCS15_CO_FLAG_PRIVATE; } if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_AODF) ) { static const char *pteid_pin_names[3] = { "Auth PIN", "Sign PIN", "Address PIN" }; struct sc_pin_cmd_data pin_cmd_data; struct sc_pkcs15_auth_info *pin_info = (sc_pkcs15_auth_info_t *) p15_obj->data; strlcpy(p15_obj->label, pteid_pin_names[pin_info->auth_id.value[0]-1], sizeof(p15_obj->label)); pin_info->attrs.pin.flags |= SC_PKCS15_PIN_FLAG_NEEDS_PADDING; pin_info->tries_left = -1; pin_info->max_tries = 3; pin_info->auth_method = SC_AC_CHV; memset(&pin_cmd_data, 0, sizeof(pin_cmd_data)); pin_cmd_data.cmd = SC_PIN_CMD_GET_INFO; pin_cmd_data.pin_type = pin_info->attrs.pin.type; pin_cmd_data.pin_reference = pin_info->attrs.pin.reference; rv = sc_pin_cmd(p15card->card, &pin_cmd_data, NULL); if (rv == SC_SUCCESS) { pin_info->tries_left = pin_cmd_data.pin1.tries_left; pin_info->logged_in = pin_cmd_data.pin1.logged_in; } } /* Remove found public keys as cannot be read_binary()'d */ if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_PUKDF) ) { sc_pkcs15_object_t *puk = p15_obj; p15_obj = p15_obj->next; sc_pkcs15_remove_object(p15card, puk); sc_pkcs15_free_object(puk); } else { p15_obj = p15_obj->next; } } /* Add data objects */ for (i = 0; i < 5; i++) { static const char *object_labels[5] = { "Trace", "Citizen Data", "Citizen Address Data", "SOd", "Citizen Notepad", }; static const char *object_authids[5] = {NULL, NULL, "3", NULL, NULL}; static const char *object_paths[5] = { "3f000003", "3f005f00ef02", "3f005f00ef05", "3f005f00ef06", "3f005f00ef07", }; static const int object_flags[5] = { 0, 0, SC_PKCS15_CO_FLAG_PRIVATE, 0, 0, }; struct sc_pkcs15_data_info obj_info; struct sc_pkcs15_object obj_obj; memset(&obj_info, 0, sizeof(obj_info)); memset(&obj_obj, 0, sizeof(obj_obj)); sc_format_path(object_paths[i], &obj_info.path); strlcpy(obj_info.app_label, object_labels[i], SC_PKCS15_MAX_LABEL_SIZE); if (object_authids[i] != NULL) sc_pkcs15_format_id(object_authids[i], &obj_obj.auth_id); strlcpy(obj_obj.label, object_labels[i], SC_PKCS15_MAX_LABEL_SIZE); obj_obj.flags = object_flags[i]; rv = sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_DATA_OBJECT, &obj_obj, &obj_info); if (rv != SC_SUCCESS){ sc_log(ctx, "Object add failed: %d", rv); break; } } LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
LIBOPENSC_API 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; 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 (ops[ii].mask == 0) LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED); sc_log(ctx, "OP:%i, mask:0x%X", op, ops[ii].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); }
static int sc_get_response(struct sc_card *card, struct sc_apdu *apdu, size_t olen) { struct sc_context *ctx = card->ctx; size_t le, minlen, buflen; unsigned char *buf; int rv; LOG_FUNC_CALLED(ctx); if (apdu->le == 0) { /* no data is requested => change return value to 0x9000 and ignore the remaining data */ apdu->sw1 = 0x90; apdu->sw2 = 0x00; return SC_SUCCESS; } /* this should _never_ happen */ if (!card->ops->get_response) LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "no GET RESPONSE command"); /* call GET RESPONSE until we have read all data requested or until the card retuns 0x9000, * whatever happens first. */ /* if there are already data in response append a new data to the end of the buffer */ buf = apdu->resp + apdu->resplen; /* read as much data as fits in apdu->resp (i.e. min(apdu->resplen, amount of data available)). */ buflen = olen - apdu->resplen; /* 0x6100 means at least 256 more bytes to read */ le = apdu->sw2 != 0 ? (size_t)apdu->sw2 : 256; /* we try to read at least as much as bytes as promised in the response bytes */ minlen = le; do { unsigned char resp[256]; size_t resp_len = le; /* call GET RESPONSE to get more date from the card; * note: GET RESPONSE returns the left amount of data (== SW2) */ memset(resp, 0, sizeof(resp)); rv = card->ops->get_response(card, &resp_len, resp); if (rv < 0) { #ifdef ENABLE_SM if (resp_len) { sc_log(ctx, "SM response data %s", sc_dump_hex(resp, resp_len)); sc_sm_update_apdu_response(card, resp, resp_len, rv, apdu); } #endif LOG_TEST_RET(ctx, rv, "GET RESPONSE error"); } le = resp_len; /* copy as much as will fit in requested buffer */ if (buflen < le) le = buflen; memcpy(buf, resp, le); buf += le; buflen -= le; /* we have all the data the caller requested even if the card has more data */ if (buflen == 0) break; minlen -= le; if (rv != 0) le = minlen = (size_t)rv; else /* if the card has returned 0x9000 but we still expect data ask for more * until we have read enough bytes */ le = minlen; } while (rv != 0 || minlen != 0); /* we've read all data, let's return 0x9000 */ apdu->resplen = buf - apdu->resp; apdu->sw1 = 0x90; apdu->sw2 = 0x00; LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
int sm_gp_external_authentication(struct sc_context *ctx, struct sm_info *sm_info, unsigned char *init_data, size_t init_len, struct sc_remote_data *rdata, int (*diversify_keyset)(struct sc_context *ctx, struct sm_info *sm_info, unsigned char *idata, size_t idata_len)) { struct sc_remote_apdu *new_rapdu = NULL; struct sc_apdu *apdu = NULL; unsigned char host_cryptogram[8], raw_apdu[SC_MAX_APDU_BUFFER_SIZE]; struct sm_gp_session *gp_session = &sm_info->session.gp; DES_cblock mac; int rv, offs = 0; LOG_FUNC_CALLED(ctx); if (!sm_info || !init_data || !rdata || !rdata->alloc) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); if (init_len != 0x1C) LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "SM GP authentication: invalid auth data length"); rv = sm_gp_parse_init_data(ctx, gp_session, init_data, init_len); LOG_TEST_RET(ctx, rv, "SM GP authentication: 'INIT DATA' parse error"); if (diversify_keyset) { rv = (*diversify_keyset)(ctx, sm_info, init_data, init_len); LOG_TEST_RET(ctx, rv, "SM GP authentication: keyset diversification error"); } rv = sm_gp_init_session(ctx, gp_session, init_data + 20, 8); LOG_TEST_RET(ctx, rv, "SM GP authentication: init session error"); rv = sm_gp_get_cryptogram(gp_session->session_enc, gp_session->card_challenge, gp_session->host_challenge, host_cryptogram, sizeof(host_cryptogram)); LOG_TEST_RET(ctx, rv, "SM GP authentication: get host cryptogram error"); sc_log(ctx, "SM GP authentication: host_cryptogram:%s", sc_dump_hex(host_cryptogram, 8)); rv = rdata->alloc(rdata, &new_rapdu); LOG_TEST_RET(ctx, rv, "SM GP authentication: cannot allocate remote APDU"); apdu = &new_rapdu->apdu; offs = 0; apdu->cse = SC_APDU_CASE_3_SHORT; apdu->cla = raw_apdu[offs++] = 0x84; apdu->ins = raw_apdu[offs++] = 0x82; apdu->p1 = raw_apdu[offs++] = gp_session->params.level; apdu->p2 = raw_apdu[offs++] = 0; apdu->lc = raw_apdu[offs++] = 0x10; apdu->datalen = 0x10; memcpy(raw_apdu + offs, host_cryptogram, 8); offs += 8; rv = sm_gp_get_mac(gp_session->session_mac, &gp_session->mac_icv, raw_apdu, offs, &mac); LOG_TEST_RET(ctx, rv, "SM GP authentication: get MAC error"); memcpy(new_rapdu->sbuf, host_cryptogram, 8); memcpy(new_rapdu->sbuf + 8, mac, 8); memcpy(gp_session->mac_icv, mac, 8); LOG_FUNC_RETURN(ctx, 1); }
int iasecc_sm_external_authentication(struct sc_card *card, unsigned skey_ref, int *tries_left) { struct sc_context *ctx = card->ctx; #ifdef ENABLE_SM struct sm_info *sm_info = &card->sm_ctx.info; struct sm_cwa_session *cwa_session = &sm_info->session.cwa; struct sc_remote_data rdata; struct sc_apdu apdu; unsigned char sbuf[0x100]; int rv, offs; LOG_FUNC_CALLED(ctx); sc_log(ctx, "iasecc_sm_external_authentication(): SKey ref %i", skey_ref); if (card->sm_ctx.sm_mode == SM_MODE_NONE) LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Cannot do 'External Authentication' without SM activated "); strlcpy(sm_info->config_section, card->sm_ctx.config_section, sizeof(sm_info->config_section)); sm_info->cmd = SM_CMD_EXTERNAL_AUTH; sm_info->serialnr = card->serialnr; sm_info->card_type = card->type; sm_info->sm_type = SM_TYPE_CWA14890; cwa_session->params.crt_at.usage = IASECC_UQB_AT_EXTERNAL_AUTHENTICATION; cwa_session->params.crt_at.algo = IASECC_ALGORITHM_ROLE_AUTH; cwa_session->params.crt_at.refs[0] = skey_ref; offs = 0; sbuf[offs++] = IASECC_CRT_TAG_ALGO; sbuf[offs++] = 0x01; sbuf[offs++] = IASECC_ALGORITHM_ROLE_AUTH; sbuf[offs++] = IASECC_CRT_TAG_REFERENCE; sbuf[offs++] = 0x01; sbuf[offs++] = skey_ref; sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x81, 0xA4); apdu.data = sbuf; apdu.datalen = offs; apdu.lc = offs; rv = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(ctx, rv, "iasecc_sm_external_authentication(): APDU transmit failed"); rv = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(ctx, rv, "iasecc_sm_external_authentication(): set SE error"); rv = sc_get_challenge(card, cwa_session->card_challenge, sizeof(cwa_session->card_challenge)); LOG_TEST_RET(ctx, rv, "iasecc_sm_external_authentication(): set SE error"); sc_remote_data_init(&rdata); if (!card->sm_ctx.module.ops.initialize) LOG_TEST_RET(ctx, SC_ERROR_SM_NOT_INITIALIZED, "No SM module"); rv = card->sm_ctx.module.ops.initialize(ctx, sm_info, &rdata); LOG_TEST_RET(ctx, rv, "SM: INITIALIZE failed"); sc_log(ctx, "sm_iasecc_external_authentication(): rdata length %i\n", rdata.length); rv = iasecc_sm_transmit_apdus (card, &rdata, NULL, 0); if (rv == SC_ERROR_PIN_CODE_INCORRECT && tries_left) *tries_left = (rdata.data + rdata.length - 1)->apdu.sw2 & 0x0F; LOG_TEST_RET(ctx, rv, "sm_iasecc_external_authentication(): execute failed"); LOG_FUNC_RETURN(ctx, rv); #else LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of SM and External Authentication"); return SC_ERROR_NOT_SUPPORTED; #endif }
int sm_gp_securize_apdu(struct sc_context *ctx, struct sm_info *sm_info, char *init_data, struct sc_apdu *apdu) { unsigned char buff[SC_MAX_APDU_BUFFER_SIZE + 24]; unsigned char *apdu_data = NULL; struct sm_gp_session *gp_session = &sm_info->session.gp; unsigned gp_level = sm_info->session.gp.params.level; unsigned gp_index = sm_info->session.gp.params.index; DES_cblock mac; unsigned char *encrypted = NULL; size_t encrypted_len = 0; int rv; LOG_FUNC_CALLED(ctx); apdu_data = (unsigned char *)apdu->data; sc_log(ctx, "SM GP securize APDU(cse:%X,cla:%X,ins:%X,data(len:%i,%p),lc:%i,GP level:%X,GP index:%X", apdu->cse, apdu->cla, apdu->ins, apdu->datalen, apdu->data, apdu->lc, gp_level, gp_index); if (gp_level == 0 || (apdu->cla & 0x04)) return 0; if (gp_level == SM_GP_SECURITY_MAC) { if (apdu->datalen + 8 > SC_MAX_APDU_BUFFER_SIZE) LOG_TEST_RET(ctx, SC_ERROR_WRONG_LENGTH, "SM GP securize APDU: too much data"); } else if (gp_level == SM_GP_SECURITY_ENC) { if (!gp_session->session_enc) LOG_TEST_RET(ctx, SC_ERROR_SM_INVALID_SESSION_KEY, "SM GP securize APDU: no ENC session key found"); if (sm_gp_encrypt_command_data(ctx, gp_session->session_enc, apdu->data, apdu->datalen, &encrypted, &encrypted_len)) LOG_TEST_RET(ctx, SC_ERROR_SM_ENCRYPT_FAILED, "SM GP securize APDU: data encryption error"); if (encrypted_len + 8 > SC_MAX_APDU_BUFFER_SIZE) LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "SM GP securize APDU: not enough place for encrypted data"); sc_log(ctx, "SM GP securize APDU: encrypted length %i", encrypted_len); } else { LOG_TEST_RET(ctx, SC_ERROR_SM_INVALID_LEVEL, "SM GP securize APDU: invalid SM level"); } buff[0] = apdu->cla | 0x04; buff[1] = apdu->ins; buff[2] = apdu->p1; buff[3] = apdu->p2; buff[4] = apdu->lc + 8; memcpy(buff + 5, apdu_data, apdu->datalen); rv = sm_gp_get_mac(gp_session->session_mac, &gp_session->mac_icv, buff, 5 + apdu->datalen, &mac); LOG_TEST_RET(ctx, rv, "SM GP securize APDU: get MAC error"); if (gp_level == SM_GP_SECURITY_MAC) { memcpy(apdu_data + apdu->datalen, mac, 8); apdu->cla |= 0x04; apdu->datalen += 8; apdu->lc = apdu->datalen; if (apdu->cse==SC_APDU_CASE_2_SHORT) apdu->cse = SC_APDU_CASE_4_SHORT; } else if (gp_level == SM_GP_SECURITY_ENC) { memcpy(apdu_data + encrypted_len, mac, 8); if (encrypted_len) memcpy(apdu_data, encrypted, encrypted_len); apdu->cla |= 0x04; apdu->datalen = encrypted_len + 8; apdu->lc = encrypted_len + 8; if (apdu->cse == SC_APDU_CASE_2_SHORT) apdu->cse = SC_APDU_CASE_4_SHORT; if (apdu->cse == SC_APDU_CASE_1) apdu->cse = SC_APDU_CASE_3_SHORT; free(encrypted); } memcpy(sm_info->session.gp.mac_icv, mac, 8); LOG_FUNC_RETURN(ctx, rv); }
/* * Initialize PKCS#15 emulation with user PIN, private keys, certificate and data objects * */ static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card) { sc_card_t *card = p15card->card; sc_file_t *file = NULL; sc_path_t path; u8 filelist[MAX_EXT_APDU_LENGTH]; int filelistlength; int r, i; sc_cvc_t devcert; struct sc_app_info *appinfo; struct sc_pkcs15_auth_info pin_info; struct sc_pkcs15_object pin_obj; u8 efbin[512]; u8 *ptr; size_t len; LOG_FUNC_CALLED(card->ctx); appinfo = calloc(1, sizeof(struct sc_app_info)); if (appinfo == NULL) { LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); } appinfo->aid = sc_hsm_aid; appinfo->ddo.aid = sc_hsm_aid; p15card->app = appinfo; sc_path_set(&path, SC_PATH_TYPE_DF_NAME, sc_hsm_aid.value, sc_hsm_aid.len, 0, 0); r = sc_select_file(card, &path, &file); LOG_TEST_RET(card->ctx, r, "Could not select SmartCard-HSM application"); p15card->card->version.hw_major = 24; /* JCOP 2.4.1r3 */ p15card->card->version.hw_minor = 13; p15card->card->version.fw_major = file->prop_attr[file->prop_attr_len - 2]; p15card->card->version.fw_minor = file->prop_attr[file->prop_attr_len - 1]; sc_file_free(file); /* Read device certificate to determine serial number */ sc_path_set(&path, SC_PATH_TYPE_FILE_ID, (u8 *) "\x2F\x02", 2, 0, 0); r = sc_select_file(card, &path, &file); LOG_TEST_RET(card->ctx, r, "Could not select EF.C_DevAut"); sc_file_free(file); r = sc_read_binary(p15card->card, 0, efbin, sizeof(efbin), 0); LOG_TEST_RET(card->ctx, r, "Could not read EF.C_DevAut"); ptr = efbin; len = r; memset(&devcert, 0 ,sizeof(devcert)); r = sc_pkcs15emu_sc_hsm_decode_cvc(p15card, (const u8 **)&ptr, &len, &devcert); LOG_TEST_RET(card->ctx, r, "Could not decode EF.C_DevAut"); sc_pkcs15emu_sc_hsm_read_tokeninfo(p15card); if (p15card->tokeninfo->label == NULL) { p15card->tokeninfo->label = strdup("SmartCard-HSM"); if (p15card->tokeninfo->label == NULL) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); } if ((p15card->tokeninfo->manufacturer_id != NULL) && !strcmp("(unknown)", p15card->tokeninfo->manufacturer_id)) { free(p15card->tokeninfo->manufacturer_id); p15card->tokeninfo->manufacturer_id = NULL; } if (p15card->tokeninfo->manufacturer_id == NULL) { p15card->tokeninfo->manufacturer_id = strdup("www.CardContact.de"); if (p15card->tokeninfo->manufacturer_id == NULL) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); } appinfo->label = strdup(p15card->tokeninfo->label); if (appinfo->label == NULL) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); len = strlen(devcert.chr); /* Strip last 5 digit sequence number from CHR */ assert(len >= 8); len -= 5; p15card->tokeninfo->serial_number = calloc(len + 1, 1); if (p15card->tokeninfo->serial_number == NULL) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); memcpy(p15card->tokeninfo->serial_number, devcert.chr, len); *(p15card->tokeninfo->serial_number + len) = 0; sc_hsm_set_serialnr(card, p15card->tokeninfo->serial_number); sc_pkcs15emu_sc_hsm_free_cvc(&devcert); memset(&pin_info, 0, sizeof(pin_info)); memset(&pin_obj, 0, sizeof(pin_obj)); pin_info.auth_id.len = 1; pin_info.auth_id.value[0] = 1; pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; pin_info.attrs.pin.reference = 0x81; pin_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_LOCAL|SC_PKCS15_PIN_FLAG_INITIALIZED|SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED|SC_PKCS15_PIN_FLAG_EXCHANGE_REF_DATA; pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC; pin_info.attrs.pin.min_length = 6; pin_info.attrs.pin.stored_length = 0; pin_info.attrs.pin.max_length = 15; pin_info.attrs.pin.pad_char = '\0'; pin_info.tries_left = 3; pin_info.max_tries = 3; strlcpy(pin_obj.label, "UserPIN", sizeof(pin_obj.label)); pin_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE|SC_PKCS15_CO_FLAG_MODIFIABLE; r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); if (r < 0) LOG_FUNC_RETURN(card->ctx, r); memset(&pin_info, 0, sizeof(pin_info)); memset(&pin_obj, 0, sizeof(pin_obj)); pin_info.auth_id.len = 1; pin_info.auth_id.value[0] = 2; pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; pin_info.attrs.pin.reference = 0x88; pin_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_LOCAL|SC_PKCS15_PIN_FLAG_CHANGE_DISABLED|SC_PKCS15_PIN_FLAG_INITIALIZED|SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED|SC_PKCS15_PIN_FLAG_SO_PIN; pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_BCD; pin_info.attrs.pin.min_length = 16; pin_info.attrs.pin.stored_length = 0; pin_info.attrs.pin.max_length = 16; pin_info.attrs.pin.pad_char = '\0'; pin_info.tries_left = 3; pin_info.max_tries = 3; strlcpy(pin_obj.label, "SOPIN", sizeof(pin_obj.label)); pin_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); if (r < 0) LOG_FUNC_RETURN(card->ctx, r); filelistlength = sc_list_files(card, filelist, sizeof(filelist)); LOG_TEST_RET(card->ctx, filelistlength, "Could not enumerate file and key identifier"); for (i = 0; i < filelistlength; i += 2) { switch(filelist[i]) { case KEY_PREFIX: r = sc_pkcs15emu_sc_hsm_add_prkd(p15card, filelist[i + 1]); break; case DCOD_PREFIX: r = sc_pkcs15emu_sc_hsm_add_dcod(p15card, filelist[i + 1]); break; case CD_PREFIX: r = sc_pkcs15emu_sc_hsm_add_cd(p15card, filelist[i + 1]); break; } if (r != SC_SUCCESS) { sc_log(card->ctx, "Error %d adding elements to framework", r); } } LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); }
int sm_gp_decode_card_answer(struct sc_context *ctx, struct sc_remote_data *rdata, unsigned char *out, size_t out_len) { #if 0 struct sc_asn1_entry asn1_authentic_card_response[4], asn1_card_response[2]; struct sc_hash *hash = NULL; unsigned char *hex = NULL; size_t hex_len; int rv, offs; unsigned char card_data[SC_MAX_APDU_BUFFER_SIZE]; size_t card_data_len = sizeof(card_data), len_left = 0; LOG_FUNC_CALLED(ctx); if (!out || !out_len) LOG_FUNC_RETURN(ctx, 0); if (strstr(str_data, "DATA=")) { rv = sc_hash_parse(ctx, str_data, strlen(str_data), &hash); LOG_TEST_RET(ctx, rv, "SM GP decode card answer: parse input data error"); str_data = sc_hash_get(hash, "DATA"); } if (!strlen(str_data)) LOG_FUNC_RETURN(ctx, 0); hex_len = strlen(str_data) / 2; hex = calloc(1, hex_len); if (!hex) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "SM GP decode card answer: hex allocate error"); sc_log(ctx, "SM GP decode card answer: hex length %i", hex_len); rv = sc_hex_to_bin(str_data, hex, &hex_len); LOG_TEST_RET(ctx, rv, "SM GP decode card answer: data 'HEX to BIN' conversion error"); sc_log(ctx, "SM GP decode card answer: hex length %i", hex_len); if (hash) sc_hash_free(hash); for (offs = 0, len_left = hex_len; len_left; ) { int num, status; sc_copy_asn1_entry(c_asn1_authentic_card_response, asn1_authentic_card_response); sc_copy_asn1_entry(c_asn1_card_response, asn1_card_response); sc_format_asn1_entry(asn1_authentic_card_response + 0, &num, NULL, 0); sc_format_asn1_entry(asn1_authentic_card_response + 1, &status, NULL, 0); card_data_len = sizeof(card_data); sc_format_asn1_entry(asn1_authentic_card_response + 2, &card_data, &card_data_len, 0); sc_format_asn1_entry(asn1_card_response + 0, asn1_authentic_card_response, NULL, 0); rv = sc_asn1_decode(ctx, asn1_card_response, hex + hex_len - len_left, len_left, NULL, &len_left); if (rv) { sc_log(ctx, "SM GP decode card answer: ASN.1 parse error: %s", sc_strerror(rv)); return rv; } if (status != 0x9000) continue; if (asn1_authentic_card_response[2].flags & SC_ASN1_PRESENT) { sc_log(ctx, "SM GP decode card answer: card_data_len %i", card_data_len); if (out_len < offs + card_data_len) LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "SM GP decode card answer: buffer too small"); memcpy(out + offs, card_data, card_data_len); offs += card_data_len; } sc_log(ctx, "SM GP decode card answer: offs:%i,left:%i", offs, len_left); } free(hex); LOG_FUNC_RETURN(ctx, offs); #else LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); #endif }
int sc_enum_apps(sc_card_t *card) { struct sc_context *ctx = card->ctx; sc_path_t path; int ef_structure; size_t file_size, jj; int r, ii, idx; LOG_FUNC_CALLED(ctx); if (card->app_count < 0) card->app_count = 0; sc_format_path("3F002F00", &path); sc_file_free(card->ef_dir); card->ef_dir = NULL; r = sc_select_file(card, &path, &card->ef_dir); LOG_TEST_RET(ctx, r, "Cannot select EF.DIR file"); if (card->ef_dir->type != SC_FILE_TYPE_WORKING_EF) { sc_file_free(card->ef_dir); card->ef_dir = NULL; LOG_TEST_RET(ctx, SC_ERROR_INVALID_CARD, "EF(DIR) is not a working EF."); } ef_structure = card->ef_dir->ef_structure; if (ef_structure == SC_FILE_EF_TRANSPARENT) { u8 *buf = NULL, *p; size_t bufsize; file_size = card->ef_dir->size; if (file_size == 0) LOG_FUNC_RETURN(ctx, 0); buf = malloc(file_size); if (buf == NULL) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); p = buf; r = sc_read_binary(card, 0, buf, file_size, 0); if (r < 0) { free(buf); LOG_TEST_RET(ctx, r, "sc_read_binary() failed"); } bufsize = r; while (bufsize > 0) { if (card->app_count == SC_MAX_CARD_APPS) { sc_log(ctx, "Too many applications on card"); break; } r = parse_dir_record(card, &p, &bufsize, -1); if (r) break; } if (buf) free(buf); } else { /* record structure */ unsigned char buf[256], *p; unsigned int rec_nr; size_t rec_size; /* Arbitrary set '16' as maximal number of records to check out: * to avoid endless loop because of some incomplete cards/drivers */ for (rec_nr = 1; rec_nr < 16; rec_nr++) { r = sc_read_record(card, rec_nr, buf, sizeof(buf), SC_RECORD_BY_REC_NR); if (r == SC_ERROR_RECORD_NOT_FOUND) break; LOG_TEST_RET(ctx, r, "read_record() failed"); if (card->app_count == SC_MAX_CARD_APPS) { sc_log(ctx, "Too many applications on card"); break; } rec_size = r; p = buf; parse_dir_record(card, &p, &rec_size, (int)rec_nr); } } /* Move known PKCS#15 applications to the head of the list */ for (ii=0, idx=0; ii<card->app_count; ii++) { for (jj=0; jj < sizeof(apps)/sizeof(apps[0]); jj++) { if (apps[jj].aid_len != card->app[ii]->aid.len) continue; if (memcmp(apps[jj].aid, card->app[ii]->aid.value, apps[jj].aid_len)) continue; break; } if (ii != idx && jj < sizeof(apps)/sizeof(apps[0])) { struct sc_app_info *tmp = card->app[idx]; card->app[idx] = card->app[ii]; card->app[ii] = tmp; idx++; } } LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
/** * Select a file from card, process fci and read data. * * This is done by mean of iso_select_file() and iso_read_binary() * * @param card pointer to sc_card data * @param path pathfile * @param file pointer to resulting file descriptor * @param buffer pointer to buffer where to store file contents * @param length length of buffer data * @return SC_SUCCESS if ok; else error code */ int dnie_read_file(sc_card_t * card, const sc_path_t * path, sc_file_t ** file, u8 ** buffer, size_t * length) { u8 *data = NULL; char *msg = NULL; int res = SC_SUCCESS; size_t fsize = 0; /* file size */ sc_context_t *ctx = NULL; if (!card || !card->ctx) return SC_ERROR_INVALID_ARGUMENTS; ctx = card->ctx; LOG_FUNC_CALLED(card->ctx); if (!buffer || !length || !path) /* check received arguments */ LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); /* select file by mean of iso7816 ops */ res = card->ops->select_file(card, path, file); if (res != SC_SUCCESS || !file || !(*file)) { msg = "select_file failed"; goto dnie_read_file_err; } /* iso's select file calls if needed process_fci, so arriving here * we have file structure filled. */ if ((*file)->type == SC_FILE_TYPE_DF) { /* just a DF, no need to read_binary() */ *buffer = NULL; *length = 0; res = SC_SUCCESS; msg = "File is a DF: no need to read_binary()"; goto dnie_read_file_end; } fsize = (*file)->size; /* reserve enought space to read data from card */ if (fsize <= 0) { res = SC_ERROR_FILE_TOO_SMALL; msg = "provided buffer size is too small"; goto dnie_read_file_err; } data = calloc(fsize, sizeof(u8)); if (data == NULL) { res = SC_ERROR_OUT_OF_MEMORY; msg = "cannot reserve requested buffer size"; goto dnie_read_file_err; } /* call sc_read_binary() to retrieve data */ sc_log(ctx, "read_binary(): expected '%d' bytes", fsize); res = sc_read_binary(card, 0, data, fsize, 0L); if (res < 0) { /* read_binary returns number of bytes readed */ res = SC_ERROR_CARD_CMD_FAILED; msg = "read_binary() failed"; goto dnie_read_file_err; } *buffer = data; *length = res; /* arriving here means success */ res = SC_SUCCESS; goto dnie_read_file_end; dnie_read_file_err: if (data) free(data); if (file && *file) { sc_file_free(*file); *file = NULL; } dnie_read_file_end: if (msg) sc_log(ctx, msg); LOG_FUNC_RETURN(ctx, res); }
static void sc_awp_clear(struct sc_pkcs15_card *p15card) { LOG_FUNC_CALLED(p15card->card->ctx); }
/** * Retrieve SN.IFD (8 bytes left padded with zeroes if required) * for the PIN channel DNIe 3.0. * * In DNIe local SM procedure, just read it from static data and * return SC_SUCCESS * * @param card pointer to card structure * @param buf where to store result (8 bytes) * @return SC_SUCCESS if ok; else error */ static int dnie_get_sn_ifd_pin(sc_card_t * card, u8 ** buf) { LOG_FUNC_CALLED(card->ctx); *buf = sn_ifd_pin; return SC_SUCCESS; }
static int sc_oberthur_parse_privateinfo (struct sc_pkcs15_card *p15card, unsigned char *buff, size_t len, int postpone_allowed) { struct sc_context *ctx = p15card->card->ctx; size_t ii; int rv; int no_more_private_keys = 0, no_more_private_data = 0; LOG_FUNC_CALLED(ctx); for (ii=0; ii<len; ii+=5) { unsigned int file_id, size; if(*(buff+ii) != 0xFF) continue; file_id = 0x100 * *(buff+ii + 1) + *(buff+ii + 2); size = 0x100 * *(buff+ii + 3) + *(buff+ii + 4); sc_log(ctx, "add private object (file-id:%04X, size:%X)", file_id, size); switch (*(buff+ii + 1)) { case BASE_ID_PRV_RSA : if (no_more_private_keys) break; rv = sc_pkcs15emu_oberthur_add_prvkey(p15card, file_id, size); if (rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED && postpone_allowed) { struct sc_path path; sc_log(ctx, "postpone adding of the private keys"); sc_format_path("5011A5A5", &path); rv = sc_pkcs15_add_df(p15card, SC_PKCS15_PRKDF, &path); LOG_TEST_RET(ctx, rv, "Add PrkDF error"); no_more_private_keys = 1; } LOG_TEST_RET(ctx, rv, "Cannot parse private key info"); break; case BASE_ID_PRV_DES : break; case BASE_ID_PRV_DATA : sc_log(ctx, "*(buff+ii + 1):%X", *(buff+ii + 1)); if (no_more_private_data) break; rv = sc_pkcs15emu_oberthur_add_data(p15card, file_id, size, 1); if (rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED && postpone_allowed) { struct sc_path path; sc_log(ctx, "postpone adding of the private data"); sc_format_path("5011A6A6", &path); rv = sc_pkcs15_add_df(p15card, SC_PKCS15_DODF, &path); LOG_TEST_RET(ctx, rv, "Add DODF error"); no_more_private_data = 1; } LOG_TEST_RET(ctx, rv, "Cannot parse private data info"); break; default: LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Private object parse error"); } } LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
/* Private key info: * flags:2, * CN(len:2,value:), * ID(len:2,value:(SHA1 value)), * StartDate(Ascii:8) * EndDate(Ascii:8) * Subject in ASN.1(len:2,value:) * modulus(value:) * exponent(length:1, value:3) */ static int sc_pkcs15emu_oberthur_add_prvkey(struct sc_pkcs15_card *p15card, unsigned int file_id, unsigned int size) { struct sc_context *ctx = p15card->card->ctx; struct sc_pkcs15_prkey_info kinfo; struct sc_pkcs15_object kobj; struct crypto_container ccont; unsigned char *info_blob = NULL; size_t info_len = 0; unsigned flags; size_t offs, len; char ch_tmp[0x100]; int rv; LOG_FUNC_CALLED(ctx); sc_log(ctx, "add private key(file-id:%04X,size:%04X)", file_id, size); memset(&kinfo, 0, sizeof(kinfo)); memset(&kobj, 0, sizeof(kobj)); memset(&ccont, 0, sizeof(ccont)); rv = sc_oberthur_get_friends (file_id, &ccont); LOG_TEST_RET(ctx, rv, "Failed to add private key: get friends error"); if (ccont.id_cert) { struct sc_pkcs15_object *objs[32]; int ii; sc_log(ctx, "friend certificate %04X", ccont.id_cert); rv = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_CERT_X509, objs, 32); LOG_TEST_RET(ctx, rv, "Failed to add private key: get certificates error"); for (ii=0; ii<rv; ii++) { struct sc_pkcs15_cert_info *cert = (struct sc_pkcs15_cert_info *)objs[ii]->data; struct sc_path path = cert->path; unsigned int id = path.value[path.len - 2] * 0x100 + path.value[path.len - 1]; if (id == ccont.id_cert) { strlcpy(kobj.label, objs[ii]->label, sizeof(kobj.label)); break; } } if (ii == rv) LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "Failed to add private key: friend not found"); } snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PRV, file_id | 0x100); rv = sc_oberthur_read_file(p15card, ch_tmp, &info_blob, &info_len, 1); LOG_TEST_RET(ctx, rv, "Failed to add private key: read oberthur file error"); if (info_len < 2) LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add private key: no 'tag'"); flags = *(info_blob + 0) * 0x100 + *(info_blob + 1); offs = 2; /* CN */ if (offs > info_len) LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add private key: no 'CN'"); len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; if (len && !strlen(kobj.label)) { if (len > sizeof(kobj.label) - 1) len = sizeof(kobj.label) - 1; strncpy(kobj.label, (char *)(info_blob + offs + 2), len); } offs += 2 + len; /* ID */ if (offs > info_len) LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add private key: no 'ID'"); len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; if (!len) LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add private key: zero length ID"); else if (len > sizeof(kinfo.id.value)) LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Failed to add private key: invalid ID length"); memcpy(kinfo.id.value, info_blob + offs + 2, len); kinfo.id.len = len; offs += 2 + len; /* Ignore Start/End dates */ offs += 16; /* Subject encoded in ASN1 */ if (offs > info_len) return SC_ERROR_UNKNOWN_DATA_RECEIVED; len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; if (len) { kinfo.subject.value = malloc(len); if (!kinfo.subject.value) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Failed to add private key: memory allocation error"); kinfo.subject.len = len; memcpy(kinfo.subject.value, info_blob + offs + 2, len); } /* Modulus and exponent are ignored */ snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PRV, file_id); sc_format_path(ch_tmp, &kinfo.path); sc_log(ctx, "Private key info path %s", ch_tmp); kinfo.modulus_length = size; kinfo.native = 1; kinfo.key_reference = file_id & 0xFF; kinfo.usage = sc_oberthur_decode_usage(flags); kobj.flags = SC_PKCS15_CO_FLAG_PRIVATE; if (flags & OBERTHUR_ATTR_MODIFIABLE) kobj.flags |= SC_PKCS15_CO_FLAG_MODIFIABLE; kobj.auth_id.len = sizeof(PinDomainID) > sizeof(kobj.auth_id.value) ? sizeof(kobj.auth_id.value) : sizeof(PinDomainID); memcpy(kobj.auth_id.value, PinDomainID, kobj.auth_id.len); sc_log(ctx, "Parsed private key(reference:%i,usage:%X,flags:%X)", kinfo.key_reference, kinfo.usage, kobj.flags); rv = sc_pkcs15emu_add_rsa_prkey(p15card, &kobj, &kinfo); LOG_FUNC_RETURN(ctx, rv); }
/* Certificate info: * flags:2, * Label(len:2,value:), * ID(len:2,value:(SHA1 value)), * Subject in ASN.1(len:2,value:) * Issuer in ASN.1(len:2,value:) * Serial encoded in LV or ASN.1 FIXME */ static int sc_pkcs15emu_oberthur_add_cert(struct sc_pkcs15_card *p15card, unsigned int file_id) { struct sc_context *ctx = p15card->card->ctx; struct sc_pkcs15_cert_info cinfo; struct sc_pkcs15_object cobj; unsigned char *info_blob, *cert_blob; size_t info_len, cert_len, len, offs; unsigned flags; int rv; char ch_tmp[0x20]; LOG_FUNC_CALLED(ctx); sc_log(ctx, "add certificate(file-id:%04X)", file_id); memset(&cinfo, 0, sizeof(cinfo)); memset(&cobj, 0, sizeof(cobj)); snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PUB, file_id | 0x100); rv = sc_oberthur_read_file(p15card, ch_tmp, &info_blob, &info_len, 1); LOG_TEST_RET(ctx, rv, "Failed to add certificate: read oberthur file error"); if (info_len < 2) LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add certificate: no 'tag'"); flags = *(info_blob + 0) * 0x100 + *(info_blob + 1); offs = 2; /* Label */ if (offs + 2 > info_len) LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add certificate: no 'CN'"); len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; if (len) { if (len > sizeof(cobj.label) - 1) len = sizeof(cobj.label) - 1; memcpy(cobj.label, info_blob + offs + 2, len); } offs += 2 + len; /* ID */ if (offs > info_len) LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add certificate: no 'ID'"); len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100; if (len > sizeof(cinfo.id.value)) LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Failed to add certificate: invalie 'ID' length"); memcpy(cinfo.id.value, info_blob + offs + 2, len); cinfo.id.len = len; /* Ignore subject, issuer and serial */ snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PUB, file_id); sc_format_path(ch_tmp, &cinfo.path); rv = sc_oberthur_read_file(p15card, ch_tmp, &cert_blob, &cert_len, 1); LOG_TEST_RET(ctx, rv, "Failed to add certificate: read certificate error"); cinfo.value.value = cert_blob; cinfo.value.len = cert_len; rv = sc_oberthur_get_certificate_authority(&cinfo.value, &cinfo.authority); LOG_TEST_RET(ctx, rv, "Failed to add certificate: get certificate attributes error"); if (flags & OBERTHUR_ATTR_MODIFIABLE) cobj.flags |= SC_PKCS15_CO_FLAG_MODIFIABLE; rv = sc_pkcs15emu_add_x509_cert(p15card, &cobj, &cinfo); SC_FUNC_RETURN(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, rv); }
/* * @brief Use PUT DATA to import a private RSA key. * * For simplicity, command chaining has to be used. One chunk (apdu) must contain * one RSA field (P, Q, etc.). The first apdu must contain the outer tag (7F48). * * @param card * @param rsa The RSA private key to import. * * @return SC_ERROR_INVALID_ARGUMENTS: The RSA key does not contain CRT fields. * other errors: Transmit errors / errors returned by card. */ static int isoApplet_put_data_prkey_rsa(sc_card_t *card, sc_cardctl_isoApplet_import_key_t *args) { sc_apdu_t apdu; u8 sbuf[SC_MAX_EXT_APDU_BUFFER_SIZE]; u8 *p = NULL; int r; size_t tags_len; LOG_FUNC_CALLED(card->ctx); if(!args->privkey.rsa.p.value || !args->privkey.rsa.q.value || !args->privkey.rsa.iqmp.value || !args->privkey.rsa.dmp1.value || !args->privkey.rsa.dmq1.value) { LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "RSA key is missing information."); } /* Note: The format is according to ISO 2-byte tag 7F48 * "T-L pair to indicate a private key data object" */ /* Calculate the length of all inner tag-length-value entries, but do not write anything yet. */ tags_len = 0; r = sc_asn1_put_tag(0x92, NULL, args->privkey.rsa.p.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x93, NULL, args->privkey.rsa.q.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x94, NULL, args->privkey.rsa.iqmp.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x95, NULL, args->privkey.rsa.dmp1.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; r = sc_asn1_put_tag(0x96, NULL, args->privkey.rsa.dmq1.len, NULL, 0, NULL); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); tags_len += r; /* Write the outer tag and length information. */ p = sbuf; r = sc_asn1_put_tag(0x7F48, NULL, tags_len, p, sizeof(sbuf), &p); LOG_TEST_RET(card->ctx, r, "Error handling TLV."); /* Write inner tags. */ /* p */ r = sc_asn1_put_tag(0x92, args->privkey.rsa.p.value, args->privkey.rsa.p.len, p, sizeof(sbuf) - (p - sbuf), &p); if(r < 0) goto out; /* q */ r = sc_asn1_put_tag(0x93, args->privkey.rsa.q.value, args->privkey.rsa.q.len, p, sizeof(sbuf) - (p - sbuf), &p); if(r < 0) goto out; /* 1/q mod p */ r = sc_asn1_put_tag(0x94, args->privkey.rsa.iqmp.value, args->privkey.rsa.iqmp.len, p, sizeof(sbuf) - (p - sbuf), &p); if(r < 0) goto out; /* d mod (p-1) */ r = sc_asn1_put_tag(0x95, args->privkey.rsa.dmp1.value, args->privkey.rsa.dmp1.len, p, sizeof(sbuf) - (p - sbuf), &p); if(r < 0) goto out; /* d mod (q-1) */ r = sc_asn1_put_tag(0x96, args->privkey.rsa.dmq1.value, args->privkey.rsa.dmq1.len, p, sizeof(sbuf) - (p - sbuf), &p); if(r < 0) goto out; /* Send to card, using chaining or extended APDUs. */ sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xDB, 0x3F, 0xFF); apdu.data = sbuf; apdu.datalen = p - sbuf; apdu.lc = p - sbuf; if ((card->caps & SC_CARD_CAP_APDU_EXT) == 0) { /* The lower layers will automatically do chaining */ apdu.flags |= SC_APDU_FLAGS_CHAINING; } r = sc_transmit_apdu(card, &apdu); if(r < 0) goto out; r = sc_check_sw(card, apdu.sw1, apdu.sw2); if(apdu.sw1 == 0x6A && apdu.sw2 == 0x81) { sc_log(card->ctx, "Key import not supported by the card with that particular key type. " "Your card may not support the specified algorithm used by the applet / specified by you. " "In most cases, this happens when trying to import EC keys not supported by your java card. " "In this case, look for supported field lengths and whether FP and/or F2M are supported. " "If you tried to import a private RSA key, check the key length."); } if(apdu.sw1 == 0x69 && apdu.sw2 == 0x00) { sc_log(card->ctx, "Key import not allowed by the applet's security policy. " "If you want to allow key import, set DEF_PRIVATE_KEY_IMPORT_ALLOWED in the IsoApplet," " rebuild and reinstall the applet."); } if(r < 0) goto out; r = SC_SUCCESS; out: sc_mem_clear(sbuf, sizeof(sbuf)); LOG_FUNC_RETURN(card->ctx, r); }