static int cardos_acl_to_bytes(sc_card_t *card, const sc_file_t *file, u8 *buf, size_t *outlen) { int i, byte; const int *idx; if (buf == NULL || *outlen < 9) return SC_ERROR_INVALID_ARGUMENTS; idx = (file->type == SC_FILE_TYPE_DF) ? df_acl : ef_acl; for (i = 0; i < 9; i++) { if (idx[i] < 0) byte = 0x00; else byte = acl_to_byte(sc_file_get_acl_entry(file, idx[i])); if (byte < 0) { sc_error(card->ctx, "Invalid ACL\n"); return SC_ERROR_INVALID_ARGUMENTS; } buf[i] = byte; } *outlen = 9; return SC_SUCCESS; }
static u8 process_acl_entry(sc_file_t *in, unsigned int method, unsigned int in_def) { u8 def = (u8)in_def; const sc_acl_entry_t *entry = sc_file_get_acl_entry(in, method); if (!entry) { return def; } else if (entry->method & SC_AC_CHV) { unsigned int key_ref = entry->key_ref; if (key_ref == SC_AC_KEY_REF_NONE) return def; else return ENTERSAFE_AC_ALWAYS&0x04; } else if (entry->method & SC_AC_NEVER) { return ENTERSAFE_AC_NEVER; } else { return def; } }
static void check_ret(int r, int op, const char *err, const sc_file_t *file) { fprintf(stderr, "%s: %s\n", err, sc_strerror(r)); if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) fprintf(stderr, "ACL for operation: %s\n", util_acl_to_str(sc_file_get_acl_entry(file, op))); }
static int entersafe_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj, sc_pkcs15_prkey_t *key) { sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data; sc_card_t *card = p15card->card; sc_entersafe_wkey_data data; sc_file_t *tfile; const sc_acl_entry_t *acl_entry; int r; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); if (key->algorithm != SC_ALGORITHM_RSA) /* ignore DSA keys */ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_INVALID_ARGUMENTS); r = sc_profile_get_file(profile, "PKCS15-AODF", &tfile); if (r < 0) return r; acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_UPDATE); if (acl_entry->method != SC_AC_NONE) { r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_UPDATE); if(r<0) r = SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; } sc_file_free(tfile); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "cant verify pin"); data.key_id = (u8) kinfo->key_reference; data.usage=0x22; data.key_data.rsa=&key->u.rsa; return sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_WRITE_KEY, &data); }
/** starcos_process_acl * \param card pointer to the sc_card object * \param file pointer to the sc_file object * \param data pointer to a sc_starcos_create_data structure * \return SC_SUCCESS if no error occured otherwise error code * * This function tries to create a somewhat useable Starcos spk 2.3 acl * from the OpenSC internal acl (storing the result in the supplied * sc_starcos_create_data structure). */ static int starcos_process_acl(sc_card_t *card, sc_file_t *file, sc_starcos_create_data *data) { u8 tmp, *p; static const u8 def_key[] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}; if (file->type == SC_FILE_TYPE_DF && file->id == 0x3f00) { p = data->data.mf.header; memcpy(p, def_key, 8); p += 8; *p++ = (file->size >> 8) & 0xff; *p++ = file->size & 0xff; /* guess isf size (mf_size / 4) */ *p++ = (file->size >> 10) & 0xff; *p++ = (file->size >> 2) & 0xff; /* ac create ef */ *p++ = process_acl_entry(file,SC_AC_OP_CREATE,STARCOS_AC_ALWAYS); /* ac create key */ *p++ = process_acl_entry(file,SC_AC_OP_CREATE,STARCOS_AC_ALWAYS); /* ac create df */ *p++ = process_acl_entry(file,SC_AC_OP_CREATE,STARCOS_AC_ALWAYS); /* use the same ac for register df and create df */ *p++ = data->data.mf.header[14]; /* if sm is required use combined mode */ if (file->acl[SC_AC_OP_CREATE] && (sc_file_get_acl_entry(file, SC_AC_OP_CREATE))->method & SC_AC_PRO) tmp = 0x03; /* combinde mode */ else tmp = 0x00; /* no sm */ *p++ = tmp; /* use the same sm mode for all ops */ *p++ = tmp; *p = tmp; data->type = SC_STARCOS_MF_DATA; return SC_SUCCESS; } else if (file->type == SC_FILE_TYPE_DF) {
static int entersafe_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey) { int r; sc_entersafe_gen_key_data gendat; sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data; sc_card_t *card = p15card->card; sc_file_t *tfile; const sc_acl_entry_t *acl_entry; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) return SC_ERROR_NOT_SUPPORTED; r = sc_profile_get_file(profile, "PKCS15-AODF", &tfile); if (r < 0) return r; acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_UPDATE); if (acl_entry->method != SC_AC_NONE) { r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_UPDATE); if(r<0) r = SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; } sc_file_free(tfile); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "cant verify pin"); /* generate key pair */ gendat.key_id = (u8) kinfo->key_reference; gendat.key_length = (size_t) kinfo->modulus_length; gendat.modulus = NULL; r = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_GENERATE_KEY, &gendat); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "EnterSafe generate RSA key pair failed"); /* get the modulus via READ PUBLIC KEY */ if (pubkey) { u8 *buf; struct sc_pkcs15_pubkey_rsa *rsa = &pubkey->u.rsa; /* set the modulus */ rsa->modulus.data = gendat.modulus; rsa->modulus.len = kinfo->modulus_length >> 3; /* set the exponent (always 0x10001) */ buf = malloc(3); if (!buf) return SC_ERROR_OUT_OF_MEMORY; buf[0] = 0x01; buf[1] = 0x00; buf[2] = 0x01; rsa->exponent.data = buf; rsa->exponent.len = 3; pubkey->algorithm = SC_ALGORITHM_RSA; } else
/* encodes the opensc file attributes into the card specific format */ static int asepcos_set_security_attributes(sc_card_t *card, sc_file_t *file) { size_t i; const amode_entry_t *table; u8 buf[64], *p; int r = SC_SUCCESS; /* first check wether the security attributes in encoded form * are already set. If present use these */ if (file->sec_attr != NULL && file->sec_attr_len != 0) return asepcos_set_sec_attributes(card, file->sec_attr, file->sec_attr_len, file->type == SC_FILE_TYPE_DF ? 0:1); /* otherwise construct the ACL from the opensc ACLs */ if (file->type == SC_FILE_TYPE_DF) table = df_amode_table; else if (file->type == SC_FILE_TYPE_WORKING_EF) table = wef_amode_table; else if (file->type == SC_FILE_TYPE_INTERNAL_EF) table = ief_amode_table; else return SC_ERROR_INVALID_ARGUMENTS; p = buf; for (i = 0; table[i].am != 0; i++) { const struct sc_acl_entry *ent = sc_file_get_acl_entry(file, table[i].sc); if (ent == NULL) continue; *p++ = 0x80; *p++ = 0x01; *p++ = table[i].am & 0xff; if (ent->method == SC_AC_NONE) { *p++ = 0x90; *p++ = 0x00; } else if (ent->method == SC_AC_NEVER) { *p++ = 0x97; *p++ = 0x00; } else if (ent->method == SC_AC_CHV) { sc_cardctl_asepcos_akn2fileid_t st; st.akn = ent->key_ref; r = asepcos_akn_to_fileid(card, &st); if (r != SC_SUCCESS) return r; *p++ = 0xa0; *p++ = 0x05; *p++ = 0x89; *p++ = 0x03; *p++ = (st.fileid >> 16) & 0xff; *p++ = (st.fileid >> 8 ) & 0xff; *p++ = st.fileid & 0xff; } else {
static int entersafe_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj, sc_pkcs15_prkey_t *key) { sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data; sc_card_t *card = p15card->card; sc_entersafe_wkey_data data; sc_file_t *tfile; const sc_acl_entry_t *acl_entry; int r; struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)obj->data; size_t keybits = key_info->modulus_length; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); if ( key->algorithm != SC_ALGORITHM_RSA ) { /* ignore DSA keys */ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_INVALID_ARGUMENTS); } /* Disable RSA:512bits */ if ( ( keybits < 1024 ) || ( keybits > 2048 ) || ( keybits % 0x20 ) ) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unsupported key size %"SC_FORMAT_LEN_SIZE_T"u\n", keybits); return SC_ERROR_INVALID_ARGUMENTS; } r = sc_profile_get_file(profile, "PKCS15-AODF", &tfile); if (r < 0) return r; acl_entry = sc_file_get_acl_entry(tfile, SC_AC_OP_UPDATE); if (acl_entry->method != SC_AC_NONE) { r = sc_pkcs15init_authenticate(profile, p15card, tfile, SC_AC_OP_UPDATE); if(r<0) r = SC_ERROR_SECURITY_STATUS_NOT_SATISFIED; } sc_file_free(tfile); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "cant verify pin"); data.key_id = (u8) kinfo->key_reference; data.usage=0x22; data.key_data.rsa=&key->u.rsa; return sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_WRITE_KEY, &data); }
/* * Parse ACL list. * The way we do this is we first split things like CHV1 * into a method (SC_AC_CHV) and a reference (1). * When we're finished parsing the profile, the fake references * are replaced by the real references given in KEY or PIN * commands */ static int do_acl(struct state *cur, int argc, char **argv) { struct sc_file *file = cur->file->file; char oper[64], *what = NULL; memset(oper, 0, sizeof(oper)); while (argc--) { unsigned int op, method, id; strlcpy(oper, *argv++, sizeof(oper)); if ((what = strchr(oper, '=')) == NULL) goto bad; *what++ = '\0'; if (*what == '$') { method = SC_AC_SYMBOLIC; if (map_str2int(cur, what+1, &id, pinIdNames)) return 1; } else if (get_authid(cur, what, &method, &id)) goto bad; if (!strcmp(oper, "*")) { for (op = 0; op < SC_MAX_AC_OPS; op++) { sc_file_clear_acl_entries(file, op); sc_file_add_acl_entry(file, op, method, id); } } else { const sc_acl_entry_t *acl; if (map_str2int(cur, oper, &op, fileOpNames)) goto bad; acl = sc_file_get_acl_entry(file, op); if (acl->method == SC_AC_NEVER || acl->method == SC_AC_NONE || acl->method == SC_AC_UNKNOWN) sc_file_clear_acl_entries(file, op); sc_file_add_acl_entry(file, op, method, id); } } return 0; bad: parse_error(cur, "Invalid ACL \"%s%s%s\"\n", oper, what? "=" : "", what? what : ""); return 1; }
static u8 process_acl_entry(sc_file_t *in, unsigned int method, unsigned int in_def) { u8 def = (u8)in_def; const sc_acl_entry_t *entry = sc_file_get_acl_entry(in, method); if (!entry) return def; else if (entry->method & SC_AC_CHV) { unsigned int key_ref = entry->key_ref; if (key_ref == SC_AC_KEY_REF_NONE) return def; else if ((key_ref & 0x0f) == 1) /* SOPIN */ return (key_ref & 0x80 ? 0x10 : 0x00) | 0x01; else return (key_ref & 0x80 ? 0x10 : 0x00) | STARCOS_PINID2STATE(key_ref); } else if (entry->method & SC_AC_NEVER) return STARCOS_AC_NEVER; else return def; }
static int do_info(int argc, char **argv) { sc_file_t *file; sc_path_t path; size_t i; const char *st; int r, not_current = 1; const id2str_t *ac_ops = NULL; if (!argc) { path = current_path; file = current_file; not_current = 0; } else if (argc == 1) { if (arg_to_path(argv[0], &path, 0) != 0) return usage(do_info); r = sc_select_file(card, &path, &file); if (r) { printf("unable to select file: %s\n", sc_strerror(r)); return -1; } } else return usage(do_info); switch (file->type) { case SC_FILE_TYPE_WORKING_EF: case SC_FILE_TYPE_INTERNAL_EF: st = "Elementary File"; break; case SC_FILE_TYPE_DF: st = "Dedicated File"; break; default: st = "Unknown File"; break; } printf("\n%s ID %04X\n\n", st, file->id); printf("%-15s%s\n", "File path:", path_to_filename(&path, '/')); printf("%-15s%lu bytes\n", "File size:", (unsigned long) file->size); if (file->type == SC_FILE_TYPE_DF) { static const id2str_t ac_ops_df[] = { { SC_AC_OP_SELECT, "SELECT" }, { SC_AC_OP_LOCK, "LOCK" }, { SC_AC_OP_DELETE, "DELETE" }, { SC_AC_OP_CREATE, "CREATE" }, { SC_AC_OP_REHABILITATE, "REHABILITATE" }, { SC_AC_OP_INVALIDATE, "INVALIDATE" }, { SC_AC_OP_LIST_FILES, "LIST FILES" }, { SC_AC_OP_CRYPTO, "CRYPTO" }, { SC_AC_OP_DELETE_SELF, "DELETE SELF" }, { 0, NULL } }; if (file->namelen) { printf("%-15s", "DF name:"); util_print_binary(stdout, file->name, file->namelen); printf("\n"); } ac_ops = ac_ops_df; } else { static const id2str_t ac_ops_ef[] = { { SC_AC_OP_READ, "READ" }, { SC_AC_OP_UPDATE, "UPDATE" }, { SC_AC_OP_DELETE, "DELETE" }, { SC_AC_OP_WRITE, "WRITE" }, { SC_AC_OP_REHABILITATE, "REHABILITATE" }, { SC_AC_OP_INVALIDATE, "INVALIDATE" }, { SC_AC_OP_LIST_FILES, "LIST FILES" }, { SC_AC_OP_CRYPTO, "CRYPTO" }, { 0, NULL } }; const id2str_t ef_type_name[] = { { SC_FILE_EF_TRANSPARENT, "Transparent" }, { SC_FILE_EF_LINEAR_FIXED, "Linear fixed" }, { SC_FILE_EF_LINEAR_FIXED_TLV, "Linear fixed, SIMPLE-TLV" }, { SC_FILE_EF_LINEAR_VARIABLE, "Linear variable" }, { SC_FILE_EF_LINEAR_VARIABLE_TLV, "Linear variable, SIMPLE-TLV" }, { SC_FILE_EF_CYCLIC, "Cyclic" }, { SC_FILE_EF_CYCLIC_TLV, "Cyclic, SIMPLE-TLV" }, { 0, NULL } }; const char *ef_type = "Unknown"; for (i = 0; ef_type_name[i].str != NULL; i++) if (file->ef_structure == ef_type_name[i].id) ef_type = ef_type_name[i].str; printf("%-15s%s\n", "EF structure:", ef_type); ac_ops = ac_ops_ef; } for (i = 0; ac_ops != NULL && ac_ops[i].str != NULL; i++) { int len = strlen(ac_ops[i].str); printf("ACL for %s:%*s %s\n", ac_ops[i].str, (12 > len) ? (12 - len) : 0, "", util_acl_to_str(sc_file_get_acl_entry(file, ac_ops[i].id))); } if (file->prop_attr_len) { printf("%-25s", "Proprietary attributes:"); util_hex_dump(stdout, file->prop_attr, file->prop_attr_len, " "); printf("\n"); } if (file->sec_attr_len) { printf("%-25s", "Security attributes:"); util_hex_dump(stdout, file->sec_attr, file->sec_attr_len, " "); printf("\n"); } printf("\n"); if (not_current) { sc_file_free(file); select_current_path_or_die(); } return 0; }
/* * Create a PIN object within the given DF */ static int rtecp_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df, sc_pkcs15_object_t *pin_obj, const unsigned char *pin, size_t pin_len, const unsigned char *puk, size_t puk_len) { sc_context_t *ctx; sc_pkcs15_auth_info_t *auth_info; sc_file_t *file = NULL; /* GCHV min-length Flags Attempts Reserve */ unsigned char prop[] = { 0x01, '?', 0x01, '?', 0, 0 }; /* AccessMode Unblock Change Delete */ unsigned char sec[15] = { 0x43, '?', '?', 0, 0, 0, 0, 0xFF }; char pin_sname[0x10]; int r, reset_by_sopin = 0; (void)puk; /* no warning */ if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !df || !pin_obj || !pin_obj->data || !pin || !pin_len) return SC_ERROR_INVALID_ARGUMENTS; ctx = p15card->card->ctx; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); if (puk_len != 0) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Do not enter User unblocking PIN (PUK): %s\n", sc_strerror(SC_ERROR_NOT_SUPPORTED)); return SC_ERROR_NOT_SUPPORTED; } auth_info = (sc_pkcs15_auth_info_t *)pin_obj->data; if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) return SC_ERROR_OBJECT_NOT_VALID; if (auth_info->attrs.pin.reference != RTECP_SO_PIN_REF && auth_info->attrs.pin.reference != RTECP_USER_PIN_REF) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "PIN reference %i not found in standard" " (Rutoken ECP) PINs\n", auth_info->attrs.pin.reference); return SC_ERROR_NOT_SUPPORTED; } snprintf(pin_sname, sizeof(pin_sname), "CHV%i", auth_info->attrs.pin.reference); if (auth_info->attrs.pin.reference == RTECP_USER_PIN_REF) { r = sc_profile_get_file(profile, pin_sname, &file); if (!r) { const struct sc_acl_entry *acl = NULL; r = sc_pkcs15init_fixup_file(profile, p15card, file); if (r < 0) sc_file_free(file); SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r, "Cannot fixup the ACLs of PIN file"); acl = sc_file_get_acl_entry(file, SC_AC_OP_PIN_RESET); if (acl && acl->method == SC_AC_CHV && acl->key_ref == RTECP_SO_PIN_REF) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Allow reset of User PIN with SoPIN\n"); reset_by_sopin = 1; } sc_file_free(file); } } file = sc_file_new(); if (!file) SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); file->id = auth_info->attrs.pin.reference; file->size = pin_len; assert(sizeof(sec)/sizeof(sec[0]) > 2); sec[1] = (auth_info->attrs.pin.reference == RTECP_SO_PIN_REF) ? 0xFF : RTECP_SO_PIN_REF; sec[2] = (unsigned char)auth_info->attrs.pin.reference | (reset_by_sopin ? RTECP_SO_PIN_REF : 0); r = sc_file_set_sec_attr(file, sec, sizeof(sec)); if (r == SC_SUCCESS) { assert(sizeof(prop)/sizeof(prop[0]) > 3); prop[1] = (unsigned char)auth_info->attrs.pin.min_length; prop[3] = 0x11 * (unsigned char)(auth_info->tries_left & 0x0F); r = sc_file_set_prop_attr(file, prop, sizeof(prop)); } if (r == SC_SUCCESS) r = sc_file_set_type_attr(file, (const u8*)"\x10\x00", 2); if (r == SC_SUCCESS) r = sc_create_file(p15card->card, file); sc_file_free(file); if (r == SC_SUCCESS) r = sc_change_reference_data(p15card->card, SC_AC_CHV, auth_info->attrs.pin.reference, NULL, 0, pin, pin_len, NULL); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, r); }
/* * 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); }
/* * If an access condition references e.g. CHV1, but we don't have * a CHV1 file yet, create an unprotected dummy file in the MF. */ static int cflex_create_dummy_chvs(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *file, int op, sc_file_t **dummies) { struct sc_context *ctx = p15card->card->ctx; const sc_acl_entry_t *acl; int r = 0, ndummies = 0; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); /* See if the DF is supposed to be PIN protected, and if * it is, whether that CHV file actually exists. If it doesn't, * create it. */ acl = sc_file_get_acl_entry(file, op); for (; acl; acl = acl->next) { sc_path_t parent, ef; if (acl->method != SC_AC_CHV) continue; parent = file->path; parent.len -= 2; r = SC_ERROR_FILE_NOT_FOUND; while (parent.len >= 2 && r == SC_ERROR_FILE_NOT_FOUND) { ef = parent; ef.value[ef.len++] = acl->key_ref - 1; ef.value[ef.len++] = 0; parent.len -= 2; if (ef.len == parent.len && !memcmp(ef.value, parent.value, ef.len)) continue; r = sc_select_file(p15card->card, &ef, NULL); } /* If a valid EF(CHVx) was found, we're fine */ if (r == 0) continue; if (r != SC_ERROR_FILE_NOT_FOUND) break; /* Create a CHV file in the MF */ parent = file->path; parent.len = 2; r = cflex_create_empty_pin_file(profile, p15card, &parent, acl->key_ref, &dummies[ndummies]); if (r < 0) break; ndummies++; } if (r < 0) { cflex_delete_dummy_chvs(profile, p15card, ndummies, dummies); return r; } SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, ndummies); }
/* * The reason for this function is that OpenSC doesn't set any * Security Attribute Tag in the FCI upon file creation if there * is no file->sec_attr. I set the file->sec_attr to a format * understood by the applet (ISO 7816-4 tables 16, 17 and 20). * The iso7816_create_file will then set this as Tag 86 - Sec. * Attr. Prop. Format. * The applet will then be able to set and enforce access rights * for any file created by OpenSC. Without this function, the * applet would not know where to enforce security rules and * when. * * Note: IsoApplet currently only supports a "onepin" option. * * Format of the sec_attr: 8 Bytes: * 7 - ISO 7816-4 table 16 or 17 * 6 to 0 - ISO 7816-4 table 20 */ static int isoApplet_create_file(sc_card_t *card, sc_file_t *file) { int r = 0; LOG_FUNC_CALLED(card->ctx); if(file->sec_attr_len == 0) { u8 access_buf[8]; int idx[8], i; if(file->type == SC_FILE_TYPE_DF) { const int df_idx[8] = /* These are the SC operations. */ { 0, /* Reserved. */ SC_AC_OP_DELETE_SELF, /* b6 */ SC_AC_OP_LOCK, /* b5 */ SC_AC_OP_ACTIVATE, /* b4 */ SC_AC_OP_DEACTIVATE, /* b3 */ SC_AC_OP_CREATE_DF, /* b2 */ SC_AC_OP_CREATE_EF, /* b1 */ SC_AC_OP_DELETE /* b0 */ }; for(i=0; i<8; i++) { idx[i] = df_idx[i]; } } else /* EF */ { const int ef_idx[8] = { 0, /* Reserved. */ SC_AC_OP_DELETE_SELF, /* b6 */ SC_AC_OP_LOCK, /* b5 */ SC_AC_OP_ACTIVATE, /* b4 */ SC_AC_OP_DEACTIVATE, /* b3 */ SC_AC_OP_WRITE, /* b2 */ SC_AC_OP_UPDATE, /* b1 */ SC_AC_OP_READ /* b0 */ }; for(i=0; i<8; i++) { idx[i] = ef_idx[i]; } } /* Now idx contains the operation identifiers. * We now search for the OPs. */ access_buf[0] = 0xFF; /* A security condition byte is present for every OP. (Table 19) */ for(i=1; i<8; i++) { const sc_acl_entry_t *entry; entry = sc_file_get_acl_entry(file, idx[i]); access_buf[i] = isoApplet_acl_to_security_condition_byte(entry); } r = sc_file_set_sec_attr(file, access_buf, 8); LOG_TEST_RET(card->ctx, r, "Error adding security attribute."); } r = iso_ops->create_file(card, file); LOG_FUNC_RETURN(card->ctx, r); }
/* * Initialize pin file */ static int gpk_init_pinfile(struct sc_profile *profile, sc_pkcs15_card_t *p15card, sc_file_t *file) { const sc_acl_entry_t *acl; unsigned char buffer[GPK_MAX_PINS * 8], *blk; struct sc_file *pinfile; unsigned int so_attempts[2], user_attempts[2]; unsigned int npins, i, j, cks; int r; SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE); /* Set defaults */ so_attempts[0] = sc_profile_get_pin_retries(profile, SC_PKCS15INIT_SO_PIN); so_attempts[1] = sc_profile_get_pin_retries(profile, SC_PKCS15INIT_SO_PUK); user_attempts[0] = sc_profile_get_pin_retries(profile, SC_PKCS15INIT_USER_PIN); user_attempts[1] = sc_profile_get_pin_retries(profile, SC_PKCS15INIT_USER_PUK); sc_file_dup(&pinfile, file); if (pinfile == NULL) return SC_ERROR_OUT_OF_MEMORY; /* Create the PIN file. */ acl = sc_file_get_acl_entry(pinfile, SC_AC_OP_WRITE); if (acl->method != SC_AC_NEVER) { sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "PIN file most be protected by WRITE=NEVER"); sc_file_free(pinfile); return SC_ERROR_INVALID_ARGUMENTS; } sc_file_add_acl_entry(pinfile, SC_AC_OP_WRITE, SC_AC_NONE, 0); if (pinfile->size == 0) pinfile->size = GPK_MAX_PINS * 8; sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "Now create file"); /* Now create the file */ if ((r = sc_pkcs15init_create_file(profile, p15card, pinfile)) < 0 || (r = sc_select_file(p15card->card, &pinfile->path, NULL)) < 0) { goto out; } /* Set up the PIN file contents. * We assume the file will contain pairs of PINs/PUKs */ npins = pinfile->size / 8; memset(buffer, 0, sizeof(buffer)); for (i = 0, blk = buffer; i < npins; blk += 8, i += 1) { /* Determine the number of PIN/PUK presentation * attempts. If the profile defines a SO PIN, * it will be stored in the first PIN/PUK pair. */ blk[0] = user_attempts[i & 1]; if (i < 2 && so_attempts[0]) blk[0] = so_attempts[i & 1]; if ((i & 1) == 0) { /* This is a PIN. If there's room in the file, * the next will be a PUK so take note of the * unlock code */ if (i + 1 < npins) blk[2] = GPK_PIN_SCOPE | (i + 1); } /* Compute the CKS */ for (j = 0, cks = 0; j < 8; j++) cks ^= blk[j]; blk[3] = ~cks; } r = sc_write_binary(p15card->card, 0, buffer, npins * 8, 0); if (r >= 0) r = gpk_lock_pinfile(profile, p15card, pinfile); out: sc_file_free(pinfile); SC_FUNC_RETURN(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r); }
/* * Set up the public key record for a signature only public key */ static int gpk_pkfile_init_public(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *file, unsigned int algo, unsigned int bits, unsigned int usage) { struct sc_context *ctx = p15card->card->ctx; const sc_acl_entry_t *acl; sc_file_t *tmp = NULL; u8 sysrec[7], buffer[256]; unsigned int n, npins; int r, card_type; /* Find out what sort of GPK we're using */ if ((r = sc_card_ctl(p15card->card, SC_CARDCTL_GPK_VARIANT, &card_type)) < 0) return r; /* Set up the system record */ memset(sysrec, 0, sizeof(sysrec)); /* Mapping keyUsage to sysrec[2]: * 0x00 sign & unwrap * 0x10 sign only * 0x20 unwrap only * 0x30 CA key * * We start with a value of 0x30. * If the key allows decryption, clear the sign only bit. * Likewise, if it allows signing, clear the unwrap only bit. */ sysrec[2] = 0x30; if (usage & (SC_PKCS15_PRKEY_USAGE_DECRYPT|SC_PKCS15_PRKEY_USAGE_UNWRAP)) sysrec[2] &= ~0x10; if (usage & (SC_PKCS15_PRKEY_USAGE_SIGN|SC_PKCS15_PRKEY_USAGE_NONREPUDIATION)) sysrec[2] &= ~0x20; if (sysrec[2] == 0x30) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Key usage should specify at least one of sign or decipher"); return SC_ERROR_INVALID_ARGUMENTS; } /* Set the key size and algorithm */ if ((r = gpk_pkfile_keybits(bits, &sysrec[1])) < 0 || (r = gpk_pkfile_keyalgo(algo, &sysrec[5])) < 0) return r; /* Set PIN protection if requested. * As the crypto ACLs are stored inside the file, * we have to get them from the profile here. */ r = sc_profile_get_file_by_path(profile, &file->path, &tmp); if (r < 0) return r; /* Fix up PIN references in file ACL */ if ((r = sc_pkcs15init_fixup_file(profile, p15card, tmp)) < 0) goto out; acl = sc_file_get_acl_entry(tmp, SC_AC_OP_CRYPTO); for (npins = 0; acl; acl = acl->next) { if (acl->method == SC_AC_NONE || acl->method == SC_AC_NEVER) continue; if (acl->method != SC_AC_CHV) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Authentication method not " "supported for private key files.\n"); r = SC_ERROR_NOT_SUPPORTED; goto out; } if (++npins >= 2) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Too many pins for PrKEY file!\n"); r = SC_ERROR_NOT_SUPPORTED; goto out; } sysrec[2] += 0x40; sysrec[3] >>= 4; sysrec[3] |= acl->key_ref << 4; } /* compute checksum - yet another slightly different * checksum algorithm courtesy of Gemplus */ if (card_type >= SC_CARD_TYPE_GPK_GPK8000) { /* This is according to the gpk reference manual */ sysrec[6] = 0xA5; } else { /* And this is what you have to use for the GPK4000 */ sysrec[6] = 0xFF; } for (n = 0; n < 6; n++) sysrec[6] ^= sysrec[n]; r = sc_read_record(p15card->card, 1, buffer, sizeof(buffer), SC_RECORD_BY_REC_NR); if (r >= 0) { if (r != 7 || buffer[0] != 0) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "first record of public key file is not Lsys0"); r = SC_ERROR_OBJECT_NOT_VALID; goto out; } r = sc_update_record(p15card->card, 1, sysrec, sizeof(sysrec), SC_RECORD_BY_REC_NR); } else { r = sc_append_record(p15card->card, sysrec, sizeof(sysrec), 0); } out: if (tmp) sc_file_free(tmp); return 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; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); if (!in_path || !out || !out_len) SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS, "Cannot read oberthur file"); sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "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); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, 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) SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_MEMORY_FAILURE, "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_debug(ctx, SC_LOG_DEBUG_NORMAL, "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); SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, 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_debug(ctx, SC_LOG_DEBUG_NORMAL, "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; SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, rv); }
static int print_file(sc_card_t *in_card, const sc_file_t *file, const sc_path_t *path, int depth) { int r; const char *tmps; const char *ac_ops_df[] = { "select", "lock", "delete", "create", "rehab", "inval", "list" }; const char *ac_ops_ef[] = { "read", "update", "write", "erase", "rehab", "inval" }; for (r = 0; r < depth; r++) printf(" "); printf("%s ", sc_print_path(path)); if (file->namelen) { printf("["); print_binary(stdout, file->name, file->namelen); printf("] "); } switch (file->type) { case SC_FILE_TYPE_WORKING_EF: tmps = "wEF"; break; case SC_FILE_TYPE_INTERNAL_EF: tmps = "iEF"; break; case SC_FILE_TYPE_DF: tmps = " DF"; break; default: tmps = "unknown"; break; } printf("type: %-3s, ", tmps); if (file->type != SC_FILE_TYPE_DF) { const char *structs[] = { "unknown", "transpnt", "linrfix", "linrfix(TLV)", "linvar", "linvar(TLV)", "lincyc", "lincyc(TLV)" }; int ef_type = file->ef_structure; if (ef_type < 0 || ef_type > 7) ef_type = 0; /* invalid or unknow ef type */ printf("ef structure: %s, ", structs[ef_type]); } printf("size: %lu\n", (unsigned long) file->size); for (r = 0; r < depth; r++) printf(" "); if (file->type == SC_FILE_TYPE_DF) for (r = 0; r < (int) (sizeof(ac_ops_df)/sizeof(ac_ops_df[0])); r++) printf("%s[%s] ", ac_ops_df[r], acl_to_str(sc_file_get_acl_entry(file, r))); else for (r = 0; r < (int) (sizeof(ac_ops_ef)/sizeof(ac_ops_ef[0])); r++) printf("%s[%s] ", ac_ops_ef[r], acl_to_str(sc_file_get_acl_entry(file, r))); if (file->sec_attr_len) { printf("sec: "); /* Octets are as follows: * DF: select, lock, delete, create, rehab, inval * EF: read, update, write, erase, rehab, inval * 4 MSB's of the octet mean: * 0 = ALW, 1 = PIN1, 2 = PIN2, 4 = SYS, * 15 = NEV */ hex_dump(stdout, file->sec_attr, file->sec_attr_len, ":"); } if (file->prop_attr_len) { printf("\n"); for (r = 0; r < depth; r++) printf(" "); printf("prop: "); hex_dump(stdout, file->prop_attr, file->prop_attr_len, ":"); } printf("\n\n"); if (file->type == SC_FILE_TYPE_DF) return 0; if (file->ef_structure == SC_FILE_EF_TRANSPARENT) { unsigned char *buf; if (!(buf = (unsigned char *) malloc(file->size))) { fprintf(stderr, "out of memory"); return 1; } r = sc_read_binary(in_card, 0, buf, file->size, 0); if (r > 0) hex_dump_asc(stdout, buf, r, 0); free(buf); } else { unsigned char buf[256]; int i; for (i=0; i < file->record_count; i++) { printf("Record %d\n", i); r = sc_read_record(in_card, i, buf, 256, 0); if (r > 0) hex_dump_asc(stdout, buf, r, 0); } } return 0; }
static int do_info(int argc, char **argv) { sc_file_t *file; sc_path_t path; size_t i; const char *st; int r, not_current = 1; if (!argc) { path = current_path; file = current_file; not_current = 0; } else if (argc == 1) { if (arg_to_path(argv[0], &path, 0) != 0) goto usage; r = sc_select_file(card, &path, &file); if (r) { printf("unable to select file: %s\n", sc_strerror(r)); return -1; } } else goto usage; switch (file->type) { case SC_FILE_TYPE_WORKING_EF: case SC_FILE_TYPE_INTERNAL_EF: st = "Elementary File"; break; case SC_FILE_TYPE_DF: st = "Dedicated File"; break; default: st = "Unknown File"; break; } printf("\n%s ID %04X\n\n", st, file->id); printf("%-15s", "File path:"); for (i = 0; i < path.len; i++) { for (i = 0; i < path.len; i++) { if ((i & 1) == 0 && i) printf("/"); printf("%02X", path.value[i]); } } printf("\n%-15s%lu bytes\n", "File size:", (unsigned long) file->size); if (file->type == SC_FILE_TYPE_DF) { const char *ops[] = { "SELECT", "LOCK", "DELETE", "CREATE", "REHABILITATE", "INVALIDATE", "LIST FILES", "CRYPTO", "DELETE SELF" }; if (file->namelen) { printf("%-15s", "DF name:"); util_print_binary(stdout, file->name, file->namelen); printf("\n"); } for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) { char buf[80]; sprintf(buf, "ACL for %s:", ops[i]); printf("%-25s%s\n", buf, util_acl_to_str(sc_file_get_acl_entry(file, i))); } } else { const char *structs[] = { "Unknown", "Transparent", "Linear fixed", "Linear fixed, SIMPLE-TLV", "Linear variable", "Linear variable TLV", "Cyclic, SIMPLE-TLV", }; const struct { const char * label; int op; } ops[] = { { "READ", SC_AC_OP_READ }, { "UPDATE", SC_AC_OP_UPDATE }, { "DELETE", SC_AC_OP_DELETE }, { "WRITE", SC_AC_OP_WRITE }, { "REHABILITATE", SC_AC_OP_REHABILITATE }, { "INVALIDATE", SC_AC_OP_INVALIDATE }, { "LIST_FILES", SC_AC_OP_LIST_FILES }, { "CRYPTO", SC_AC_OP_CRYPTO }, }; printf("%-15s%s\n", "EF structure:", structs[file->ef_structure]); for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) { char buf[80]; sprintf(buf, "ACL for %s:", ops[i].label); printf("%-25s%s\n", buf, util_acl_to_str(sc_file_get_acl_entry(file, ops[i].op))); } } if (file->prop_attr_len) { printf("%-25s", "Proprietary attributes:"); for (i = 0; i < file->prop_attr_len; i++) printf("%02X ", file->prop_attr[i]); printf("\n"); } if (file->sec_attr_len) { printf("%-25s", "Security attributes:"); for (i = 0; i < file->sec_attr_len; i++) printf("%02X ", file->sec_attr[i]); printf("\n"); } printf("\n"); if (not_current) { sc_file_free(file); select_current_path_or_die(); } return 0; usage: puts("Usage: info [file_id]"); return -1; }