/* * Get private and public key file */ static int cflex_get_keyfiles(sc_profile_t *profile, sc_card_t *card, const sc_path_t *df_path, sc_file_t **prkf, sc_file_t **pukf) { sc_path_t path = *df_path; int r; /* Get the private key file */ r = sc_profile_get_file_by_path(profile, &path, prkf); if (r < 0) { char pbuf[SC_MAX_PATH_STRING_SIZE]; r = sc_path_print(pbuf, sizeof(pbuf), &path); if (r != SC_SUCCESS) pbuf[0] = '\0'; sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Cannot find private key file info " "in profile (path=%s).", pbuf); return r; } /* Get the public key file */ path.len -= 2; sc_append_file_id(&path, 0x1012); r = sc_profile_get_file_by_path(profile, &path, pukf); if (r < 0) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Cannot find public key file info in profile."); sc_file_free(*prkf); return r; } return 0; }
static file_info * sc_profile_instantiate_file(sc_profile_t *profile, file_info *ft, file_info *parent, unsigned int skew) { struct file_info *fi; sc_card_t *card = profile->card; fi = (file_info *) calloc(1, sizeof(*fi)); if (fi == NULL) return NULL; fi->instance = fi; fi->parent = parent; fi->ident = strdup(ft->ident); if (fi->ident == NULL) { free(fi); return NULL; } sc_file_dup(&fi->file, ft->file); if (fi->file == NULL) { free(fi->ident); free(fi); return NULL; } fi->file->path = parent->file->path; fi->file->id += skew; sc_append_file_id(&fi->file->path, fi->file->id); append_file(profile, fi); ft->instance = fi; if (card->ctx->debug >= 2) { char pbuf[SC_MAX_PATH_STRING_SIZE]; int r = sc_path_print(pbuf, sizeof(pbuf), &fi->file->path); if (r != SC_SUCCESS) pbuf[0] = '\0'; sc_debug(card->ctx, "Instantiated %s at %s", ft->ident, pbuf); r = sc_path_print(pbuf, sizeof(pbuf), &parent->file->path); if (r != SC_SUCCESS) pbuf[0] = '\0'; sc_debug(card->ctx, " parent=%s@%s", parent->ident, pbuf); } return fi; }
/* * Create a new DF * This will usually be the application DF */ static int gpk_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df) { struct sc_file *pinfile; int r, locked; SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE); if (sc_card_ctl(p15card->card, SC_CARDCTL_GPK_IS_LOCKED, &locked) == 0 && locked) { sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "This card is already personalized, unable to " "create PKCS#15 structure."); return SC_ERROR_NOT_SUPPORTED; } /* Create the DF. */ r = sc_pkcs15init_create_file(profile, p15card, df); if (r < 0) return r; /* See if there's a file called "pinfile" that resides within * this DF. If so, create it */ if (sc_profile_get_file(profile, "pinfile", &pinfile) >= 0) { /* Build the pin file's path from the DF path + its * file ID */ pinfile->path = df->path; sc_append_file_id(&pinfile->path, pinfile->id); r = gpk_init_pinfile(profile, p15card, pinfile); sc_file_free(pinfile); if (r < 0) return r; /* TODO: What for it was used ? for (i = 0; i < GPK_MAX_PINS; i++) * sc_keycache_put_pin(&df->path, GPK_PIN_SCOPE|i, (const u8 *) " "); */ } SC_FUNC_RETURN(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r); }
/* * Select a reference for a private key object */ static int rtecp_select_key_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_prkey_info_t *key_info) { sc_file_t *df; int r; if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !key_info) return SC_ERROR_INVALID_ARGUMENTS; if (key_info->key_reference <= 0) key_info->key_reference = 1; else if (key_info->key_reference > 0xFF) return SC_ERROR_TOO_MANY_OBJECTS; r = sc_profile_get_file(profile, "PrKey-DF", &df); SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r, "Get PrKey-DF info failed"); assert(df); key_info->path = df->path; sc_file_free(df); r = sc_append_file_id(&key_info->path, key_info->key_reference); return r; }
/* * Create a new DF * This will usually be the application DF */ static int gpk_create_dir(sc_profile_t *profile, sc_card_t *card, sc_file_t *df) { struct sc_file *pinfile; int r, locked, i; if (sc_card_ctl(card, SC_CARDCTL_GPK_IS_LOCKED, &locked) == 0 && locked) { sc_error(card->ctx, "This card is already personalized, unable to " "create PKCS#15 structure."); return SC_ERROR_NOT_SUPPORTED; } /* Create the DF. */ r = sc_pkcs15init_create_file(profile, card, df); if (r < 0) return r; /* See if there's a file called "pinfile" that resides within * this DF. If so, create it */ if (sc_profile_get_file(profile, "pinfile", &pinfile) >= 0) { /* Build the pin file's path from the DF path + its * file ID */ pinfile->path = df->path; sc_append_file_id(&pinfile->path, pinfile->id); r = gpk_init_pinfile(profile, card, pinfile); sc_file_free(pinfile); if (r < 0) return r; for (i = 0; i < GPK_MAX_PINS; i++) sc_keycache_put_pin(&df->path, GPK_PIN_SCOPE|i, (const u8 *) " "); } return r; }
/* * Delete object * * Applied to private key: used to delete public part internal file */ static int rtecp_delete_object(struct sc_profile *profile, struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *obj, const struct sc_path *path) { sc_context_t *ctx; sc_file_t *df; sc_path_t pubkey_path; int key_ref; int r; if (!profile || !p15card || !p15card->card || !p15card->card->ctx) return SC_ERROR_INVALID_ARGUMENTS; ctx = p15card->card->ctx; LOG_FUNC_CALLED(ctx); sc_log(ctx, "delete object: type %X, path %s", obj->type, sc_print_path(path)); if ((obj->type & SC_PKCS15_TYPE_CLASS_MASK) != SC_PKCS15_TYPE_PRKEY) LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); key_ref = ((struct sc_pkcs15_prkey_info *)obj->data)->key_reference; sc_log(ctx, "key reference %04i", key_ref); r = sc_profile_get_file(profile, "PuKey-DF", &df); LOG_TEST_RET(ctx, r, "Get PuKey-DF info failed"); pubkey_path = df->path; sc_file_free(df); r = sc_append_file_id(&pubkey_path, key_ref); LOG_TEST_RET(ctx, r, "Append ID to file failed"); sc_log(ctx, "delete pubkey file %s", sc_print_path(&pubkey_path)); r = sc_pkcs15init_delete_by_path(profile, p15card, &pubkey_path); if (r && r != SC_ERROR_FILE_NOT_FOUND) LOG_FUNC_RETURN(ctx, r); LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); }
/* * Store a key on the card */ static int rtecp_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj, sc_pkcs15_prkey_t *key) { sc_card_t *card; sc_pkcs15_prkey_info_t *key_info; sc_file_t *pukey_df; sc_path_t path; unsigned char *buf; size_t buf_len, key_len, len, i; int r; if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !obj || !obj->data || !key) return SC_ERROR_INVALID_ARGUMENTS; card = p15card->card; SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); if ((obj->type != SC_PKCS15_TYPE_PRKEY_RSA || key->algorithm != SC_ALGORITHM_RSA) && (obj->type != SC_PKCS15_TYPE_PRKEY_GOSTR3410 || key->algorithm != SC_ALGORITHM_GOSTR3410)) return SC_ERROR_NOT_SUPPORTED; key_info = (sc_pkcs15_prkey_info_t *)obj->data; assert(key_info); if (key->algorithm == SC_ALGORITHM_RSA) { assert(key_info->modulus_length % 128 == 0); len = key_info->modulus_length / 8 / 2; key_len = len * 5 + 8; buf_len = key_len; } else { assert(key_info->modulus_length == SC_PKCS15_GOSTR3410_KEYSIZE); len = key_info->modulus_length / 8; key_len = len; buf_len = len; } if (key->algorithm == SC_ALGORITHM_RSA && (!key->u.rsa.p.data || !key->u.rsa.q.data || !key->u.rsa.iqmp.data || !key->u.rsa.dmp1.data || !key->u.rsa.dmq1.data || !key->u.rsa.modulus.data || !key->u.rsa.exponent.data || key->u.rsa.p.len != len || key->u.rsa.q.len != len || key->u.rsa.iqmp.len != len || key->u.rsa.dmp1.len != len || key->u.rsa.dmq1.len != len || key->u.rsa.modulus.len != 2*len || key->u.rsa.exponent.len > len || key->u.rsa.exponent.len == 0)) return SC_ERROR_INVALID_ARGUMENTS; if (key->algorithm == SC_ALGORITHM_GOSTR3410 && (!key->u.gostr3410.d.data || key->u.gostr3410.d.len != len)) return SC_ERROR_INVALID_ARGUMENTS; buf = calloc(1, buf_len); if (!buf) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); assert(key_len <= buf_len); if (key->algorithm == SC_ALGORITHM_RSA) { /* p */ for (i = 0; i < len; ++i) buf[i] = key->u.rsa.p.data[len - 1 - i]; /* q */ for (i = 0; i < len; ++i) buf[len + 4 + i] = key->u.rsa.q.data[len - 1 - i]; /* iqmp */ for (i = 0; i < len; ++i) buf[len + 4 + len + 4 + i] = key->u.rsa.iqmp.data[len - 1 - i]; /* dmp1 */ for (i = 0; i < len; ++i) buf[len + 4 + len + 4 + len + i] = key->u.rsa.dmp1.data[len - 1 - i]; /* dmq1 */ for (i = 0; i < len; ++i) buf[len * 4 + 8 + i] = key->u.rsa.dmq1.data[len - 1 - i]; } else { /* d */ for (i = 0; i < len; ++i) buf[i] = key->u.gostr3410.d.data[len - 1 - i]; } path = key_info->path; r = sc_select_file(card, &path, NULL); if (r == SC_SUCCESS) r = sc_change_reference_data(card, 0, 0, NULL, 0, buf, key_len, NULL); assert(buf); sc_mem_clear(buf, key_len); /* store public key */ if (key->algorithm == SC_ALGORITHM_RSA) key_len = len * 3; else goto end; assert(key_len <= buf_len); if (key->algorithm == SC_ALGORITHM_RSA) { /* modulus */ for (i = 0; i < 2*len; ++i) buf[i] = key->u.rsa.modulus.data[2*len - 1 - i]; /* exponent */ for (i = 0; i < key->u.rsa.exponent.len && i < len; ++i) buf[2 * len + i] = key->u.rsa.exponent.data[ key->u.rsa.exponent.len - 1 - i]; } if (r == SC_SUCCESS) { r = sc_profile_get_file(profile, "PuKey-DF", &pukey_df); if (r == SC_SUCCESS) { assert(pukey_df); path = pukey_df->path; r = sc_append_file_id(&path, key_info->key_reference); sc_file_free(pukey_df); } else if (card->ctx->debug >= 2) sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "%s\n", "Get PuKey-DF info failed"); } if (r == SC_SUCCESS) { r = sc_select_file(card, &path, NULL); if (r == SC_SUCCESS) r = sc_change_reference_data(card, 0, 0, NULL, 0, buf, key_len, NULL); if (r && card->ctx->debug >= 2) sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "%s\n", "Store public key failed"); } end: assert(buf); free(buf); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); }
/* * Generate a keypair */ static int jcop_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey) { sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data; struct sc_cardctl_jcop_genkey args; sc_file_t *temppubfile=NULL, *keyfile=NULL; unsigned char *keybuf=NULL; size_t mod_len, exp_len, pub_len, keybits; int r,delete_ok=0; if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) { sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "JCOP supports only RSA keys."); return SC_ERROR_NOT_SUPPORTED; } r=sc_profile_get_file(profile, "temp-pubkey", &temppubfile); if (r < 0) goto out; r = sc_select_file(p15card->card, &key_info->path, &keyfile); if (r < 0) goto out; mod_len = key_info->modulus_length / 8; exp_len = 4; pub_len = 2 + mod_len + exp_len; temppubfile->size = pub_len; r = sc_pkcs15init_fixup_file(profile, p15card, temppubfile); if (r < 0) goto out; r = sc_pkcs15init_create_file(profile, p15card, temppubfile); if (r < 0) goto out; delete_ok=1; r = sc_pkcs15init_authenticate(profile, p15card, temppubfile, SC_AC_OP_UPDATE); if (r < 0) goto out; r = sc_pkcs15init_authenticate(profile, p15card, keyfile, SC_AC_OP_UPDATE); if (r < 0) goto out; keybits = key_info->modulus_length; /* generate key */ /* keysize is _not_ passed to the card at any point. it appears to infer it from the file size */ memset(&args, 0, sizeof(args)); args.exponent = 0x10001; sc_append_file_id(&args.pub_file_ref, temppubfile->id); sc_append_file_id(&args.pri_file_ref, keyfile->id); keybuf = malloc(keybits / 8); if (!keybuf) { r=SC_ERROR_OUT_OF_MEMORY; goto out; } args.pubkey = keybuf; args.pubkey_len = keybits / 8; r = sc_card_ctl(p15card->card, SC_CARDCTL_JCOP_GENERATE_KEY, (void *)&args); if (r < 0) goto out; /* extract public key */ pubkey->algorithm = SC_ALGORITHM_RSA; pubkey->u.rsa.modulus.len = keybits / 8; pubkey->u.rsa.modulus.data = keybuf; pubkey->u.rsa.exponent.len = 3; pubkey->u.rsa.exponent.data = malloc(3); if (!pubkey->u.rsa.exponent.data) { pubkey->u.rsa.modulus.data = NULL; r=SC_ERROR_OUT_OF_MEMORY; goto out; } memcpy(pubkey->u.rsa.exponent.data, "\x01\x00\x01", 3); out: if (r < 0 && keybuf) free(keybuf); if (delete_ok) sc_pkcs15init_rmdir(p15card, profile, temppubfile); if (keyfile) sc_file_free(keyfile); if (temppubfile) sc_file_free(temppubfile); return r; }
static int insert_key( sc_pkcs15_card_t *p15card, const char *path, unsigned char id, unsigned char key_reference, int key_length, unsigned char auth_id, const char *label ){ sc_card_t *card=p15card->card; sc_context_t *ctx=p15card->card->ctx; sc_file_t *f; struct sc_pkcs15_prkey_info prkey_info; struct sc_pkcs15_object prkey_obj; int r, can_sign, can_crypt; memset(&prkey_info, 0, sizeof(prkey_info)); prkey_info.id.len = 1; prkey_info.id.value[0] = id; prkey_info.native = 1; prkey_info.key_reference = key_reference; prkey_info.modulus_length = key_length; sc_format_path(path, &prkey_info.path); memset(&prkey_obj, 0, sizeof(prkey_obj)); strlcpy(prkey_obj.label, label, sizeof(prkey_obj.label)); prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; prkey_obj.auth_id.len = 1; prkey_obj.auth_id.value[0] = auth_id; can_sign=can_crypt=0; if(card->type==SC_CARD_TYPE_TCOS_V3){ unsigned char buf[256]; int i, rec_no=0; if(prkey_info.path.len>=2) prkey_info.path.len-=2; sc_append_file_id(&prkey_info.path, 0x5349); if(sc_select_file(card, &prkey_info.path, NULL)!=SC_SUCCESS){ sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Select(%s) failed\n", sc_print_path(&prkey_info.path)); return 1; } sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Searching for Key-Ref %02X\n", key_reference); while((r=sc_read_record(card, ++rec_no, buf, sizeof(buf), SC_RECORD_BY_REC_NR))>0){ int found=0; if(buf[0]!=0xA0) continue; for(i=2;i<buf[1]+2;i+=2+buf[i+1]){ if(buf[i]==0x83 && buf[i+1]==1 && buf[i+2]==key_reference) ++found; } if(found) break; } if(r<=0){ sc_debug(ctx, SC_LOG_DEBUG_NORMAL,"No EF_KEYD-Record found\n"); return 1; } for(i=0;i<r;i+=2+buf[i+1]){ if(buf[i]==0xB6) can_sign++; if(buf[i]==0xB8) can_crypt++; } } else { if(sc_select_file(card, &prkey_info.path, &f)!=SC_SUCCESS){ sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Select(%s) failed\n", sc_print_path(&prkey_info.path)); return 1; } if (f->prop_attr[1] & 0x04) can_crypt=1; if (f->prop_attr[1] & 0x08) can_sign=1; sc_file_free(f); } prkey_info.usage= SC_PKCS15_PRKEY_USAGE_SIGN; if(can_crypt) prkey_info.usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT|SC_PKCS15_PRKEY_USAGE_DECRYPT; if(can_sign) prkey_info.usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION; r=sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info); if(r!=SC_SUCCESS){ sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "sc_pkcs15emu_add_rsa_prkey(%s) failed\n", path); return 4; } sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "%s: OK%s%s\n", path, can_sign ? ", Sign" : "", can_crypt ? ", Crypt" : ""); return 0; }
static int insert_pin( sc_pkcs15_card_t *p15card, const char *path, unsigned char id, unsigned char auth_id, unsigned char pin_reference, int min_length, const char *label, int pin_flags ){ sc_card_t *card=p15card->card; sc_context_t *ctx=p15card->card->ctx; sc_file_t *f; struct sc_pkcs15_auth_info pin_info; struct sc_pkcs15_object pin_obj; int r; memset(&pin_info, 0, sizeof(pin_info)); pin_info.auth_id.len = 1; pin_info.auth_id.value[0] = id; pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; pin_info.attrs.pin.reference = pin_reference; pin_info.attrs.pin.flags = pin_flags; pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC; pin_info.attrs.pin.min_length = min_length; pin_info.attrs.pin.stored_length = 16; pin_info.attrs.pin.max_length = 16; pin_info.attrs.pin.pad_char = '\0'; sc_format_path(path, &pin_info.path); memset(&pin_obj, 0, sizeof(pin_obj)); strlcpy(pin_obj.label, label, sizeof(pin_obj.label)); pin_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE; pin_obj.auth_id.len = auth_id ? 0 : 1; pin_obj.auth_id.value[0] = auth_id; if(card->type==SC_CARD_TYPE_TCOS_V3){ unsigned char buf[256]; int i, rec_no=0; if(pin_info.path.len>=2) pin_info.path.len-=2; sc_append_file_id(&pin_info.path, 0x5049); if(sc_select_file(card, &pin_info.path, NULL)!=SC_SUCCESS){ sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Select(%s) failed\n", sc_print_path(&pin_info.path)); return 1; } sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Searching for PIN-Ref %02X\n", pin_reference); while((r=sc_read_record(card, ++rec_no, buf, sizeof(buf), SC_RECORD_BY_REC_NR))>0){ int found=0, fbz=-1; if(buf[0]!=0xA0) continue; for(i=2;i<buf[1]+2;i+=2+buf[i+1]){ if(buf[i]==0x83 && buf[i+1]==1 && buf[i+2]==pin_reference) ++found; if(buf[i]==0x90) fbz=buf[i+1+buf[i+1]]; } if(found) pin_info.tries_left=fbz; if(found) break; } if(r<=0){ sc_debug(ctx, SC_LOG_DEBUG_NORMAL,"No EF_PWDD-Record found\n"); return 1; } } else { if(sc_select_file(card, &pin_info.path, &f)!=SC_SUCCESS){ sc_debug(ctx, SC_LOG_DEBUG_NORMAL,"Select(%s) failed\n", path); return 1; } pin_info.tries_left=f->prop_attr[3]; sc_file_free(f); } r=sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); if(r!=SC_SUCCESS){ sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "sc_pkcs15emu_add_pin_obj(%s) failed\n", path); return 4; } sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "%s: OK, FBZ=%d\n", path, pin_info.tries_left); return 0; }