/* * Create an empty key object */ static int rtecp_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj) { sc_context_t *ctx; /* RSA_PRkey/ Adds Miller- * RSA_PUBkey Rabin tests Attempts Reserve */ const unsigned char prkey_prop[] = { 0x23, 0, 0, 0xAA, 0, 0 }; const unsigned char pbkey_prop[] = { 0x33, 0, 0, 0xAA, 0, 0 }; /* GOSTR3410_PRkey/ * GOSTR3410_PUBkey paramset Attempts Reserve */ unsigned char prgkey_prop[] = { 0x03, '?', 0, 0xAA, 0, 0 }; unsigned char pbgkey_prop[] = { 0x13, '?', 0, 0xAA, 0, 0 }; /* AccessMode - Update Use - - - Delete */ unsigned char prkey_sec[15] = { 0x46, 0, '?', '?', 0, 0, 0, '?' }; unsigned char pbkey_sec[15] = { 0x46, 0, '?', 0, 0, 0, 0, '?' }; unsigned char auth_id, paramset; sc_pkcs15_prkey_info_t *key_info; sc_file_t *file; int r; if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !obj || !obj->data) return SC_ERROR_INVALID_ARGUMENTS; ctx = p15card->card->ctx; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA && obj->type != SC_PKCS15_TYPE_PRKEY_GOSTR3410) return SC_ERROR_NOT_SUPPORTED; if (obj->auth_id.len != 1) return SC_ERROR_INVALID_ARGUMENTS; auth_id = obj->auth_id.value[0]; key_info = (sc_pkcs15_prkey_info_t *)obj->data; assert(key_info); if ((obj->type == SC_PKCS15_TYPE_PRKEY_RSA && key_info->modulus_length % 128 != 0) || (obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410 && key_info->modulus_length != SC_PKCS15_GOSTR3410_KEYSIZE)) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Unsupported key size %u\n", key_info->modulus_length); return SC_ERROR_INVALID_ARGUMENTS; } if (obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410) { if (key_info->params.len < sizeof(int)) return SC_ERROR_INVALID_ARGUMENTS; if (((int*)key_info->params.data)[0] < 1 || ((int*)key_info->params.data)[0] > 3) return SC_ERROR_INVALID_ARGUMENTS; paramset = ((unsigned int*)key_info->params.data)[0] & 0x03; assert(sizeof(prgkey_prop)/sizeof(prgkey_prop[0]) > 1); assert(sizeof(pbgkey_prop)/sizeof(pbgkey_prop[0]) > 1); prgkey_prop[1] = 0x10 + (paramset << 4); pbgkey_prop[1] = prgkey_prop[1]; } r = sc_profile_get_file(profile, "PKCS15-AppDF", &file); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Get PKCS15-AppDF info failed"); r = sc_file_add_acl_entry(file, SC_AC_OP_CREATE, SC_AC_CHV, auth_id); if (r == SC_SUCCESS) r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_CREATE); assert(file); sc_file_free(file); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Authenticate failed"); file = sc_file_new(); if (!file) SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); file->id = key_info->key_reference; r = sc_file_set_type_attr(file, (const u8*)"\x10\x00", 2); /* private key file */ if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA) file->size = key_info->modulus_length / 8 / 2 * 5 + 8; else file->size = key_info->modulus_length / 8; if (r == SC_SUCCESS) { assert(sizeof(prkey_sec)/sizeof(prkey_sec[0]) > 7); prkey_sec[2] = auth_id; prkey_sec[3] = auth_id; prkey_sec[7] = auth_id; r = sc_file_set_sec_attr(file, prkey_sec, sizeof(prkey_sec)); } if (r == SC_SUCCESS) { if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA) r = sc_file_set_prop_attr(file, prkey_prop, sizeof(prkey_prop)); else r = sc_file_set_prop_attr(file, prgkey_prop,sizeof(prgkey_prop)); } if (r == SC_SUCCESS) { sc_log(ctx, "create private key file id:%04i", file->id); r = sc_create_file(p15card->card, file); } /* public key file */ if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA) file->size = key_info->modulus_length / 8 / 2 * 3; else file->size = key_info->modulus_length / 8 * 2; if (r == SC_SUCCESS) { assert(sizeof(pbkey_sec)/sizeof(pbkey_sec[0]) > 7); pbkey_sec[2] = auth_id; pbkey_sec[7] = auth_id; r = sc_file_set_sec_attr(file, pbkey_sec, sizeof(pbkey_sec)); } if (r == SC_SUCCESS) { if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA) r = sc_file_set_prop_attr(file, pbkey_prop, sizeof(pbkey_prop)); else r = sc_file_set_prop_attr(file, pbgkey_prop,sizeof(pbgkey_prop)); } if (r == SC_SUCCESS) { sc_log(ctx, "create public key file id:%04i", file->id); r = sc_create_file(p15card->card, file); } assert(file); sc_file_free(file); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, r); }
/* * 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); }
static int iso7816_process_fci(struct sc_card *card, struct sc_file *file, const unsigned char *buf, size_t buflen) { struct sc_context *ctx = card->ctx; const unsigned char *p, *end; unsigned int cla = 0, tag = 0; size_t length; int size; for (p = buf, length = buflen, end = buf + buflen; p < end; p += length, length = end - p) { if (SC_SUCCESS != sc_asn1_read_tag(&p, length, &cla, &tag, &length) || p == NULL) { break; } switch (cla | tag) { case 0x81: if (file->size != 0) { /* don't overwrite existing file size excluding structural information */ break; } /* fall through */ case 0x80: /* determine the file size */ if (sc_asn1_decode_integer(p, length, &size) == 0 && size >= 0) { file->size = size; sc_log(ctx, " bytes in file: %"SC_FORMAT_LEN_SIZE_T"u", file->size); } break; case 0x82: if (length > 0) { unsigned char byte = p[0]; const char *type; file->shareable = byte & 0x40 ? 1 : 0; sc_log(ctx, " shareable: %s", (byte & 0x40) ? "yes" : "no"); file->ef_structure = byte & 0x07; switch ((byte >> 3) & 7) { case 0: type = "working EF"; file->type = SC_FILE_TYPE_WORKING_EF; break; case 1: type = "internal EF"; file->type = SC_FILE_TYPE_INTERNAL_EF; break; case 7: type = "DF"; file->type = SC_FILE_TYPE_DF; break; default: type = "unknown"; break; } sc_log(ctx, " type: %s", type); sc_log(ctx, " EF structure: %d", byte & 0x07); sc_log(ctx, " tag 0x82: 0x%02x", byte); if (SC_SUCCESS != sc_file_set_type_attr(file, &byte, 1)) sc_log(ctx, "Warning: Could not set file attributes"); } break; case 0x83: if (length == 2) { file->id = (p[0] << 8) | p[1]; sc_log(ctx, " file identifier: 0x%02X%02X", p[0], p[1]); } break; case 0x84: if (length > 0 && length <= 16) { memcpy(file->name, p, length); file->namelen = length; sc_log_hex(ctx, " File name:", file->name, file->namelen); if (!file->type) file->type = SC_FILE_TYPE_DF; } break; case 0x85: case 0xA5: if (SC_SUCCESS != sc_file_set_prop_attr(file, p, length)) { sc_log(ctx, "Warning: Could not set proprietary file properties"); } break; case 0x86: if (SC_SUCCESS != sc_file_set_sec_attr(file, p, length)) { sc_log(ctx, "Warning: Could not set file security properties"); } break; case 0x88: if (length == 1) { file->sid = *p; sc_log(ctx, " short file identifier: 0x%02X", *p); } break; case 0x8A: if (length == 1) { if (p[0] == 0x01) file->status = SC_FILE_STATUS_CREATION; else if (p[0] == 0x07 || p[0] == 0x05) file->status = SC_FILE_STATUS_ACTIVATED; else if (p[0] == 0x06 || p[0] == 0x04) file->status = SC_FILE_STATUS_INVALIDATED; } break; case 0x62: case 0x64: case 0x6F: /* allow nested FCP/FMD/FCI templates */ iso7816_process_fci(card, file, p, length); } }
/* * 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); }
/* * 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_pin_info_t *pin_info; sc_file_t *file; /* 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 }; int r; (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; } pin_info = (sc_pkcs15_pin_info_t *)pin_obj->data; if (pin_info->reference != RTECP_SO_PIN_REF && pin_info->reference != RTECP_USER_PIN_REF) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "PIN reference %i not found in standard" " (Rutoken ECP) PINs\n", pin_info->reference); return SC_ERROR_NOT_SUPPORTED; } file = sc_file_new(); if (!file) SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); file->id = pin_info->reference; file->size = pin_len; assert(sizeof(sec)/sizeof(sec[0]) > 2); sec[1] = (pin_info->reference == RTECP_SO_PIN_REF) ? 0xFF : RTECP_SO_PIN_REF; sec[2] = (unsigned char)pin_info->reference; 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)pin_info->min_length; prop[3] = 0x11 * (unsigned char)(pin_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, pin_info->reference, NULL, 0, pin, pin_len, NULL); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, r); }