/* * 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; }
/* * Store a private key * Private key file formats: (transparent file) * Non-CRT: * byte 0 0x05 * byte 1 Modulus length (in byte/4) * byte 2 Modulus (n) * byte 2+x private exponent (d) * * CRT: * byte 0 0x06 * byte 1 component length (in byte/2; component length is half * of modulus length * byte 2 Prime (p) * byte 2+x Prime (q) * byte 2+2*x Exponent 1 (d mod (p-1)) * byte 2+3*x Exponent 2 (d mod (q-1)) * byte 2+4*x Coefficient ((p ^ -1) mod q * * We use the CRT format, since that's what key generation does. * * Numbers are stored big endian. */ static int jcop_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 *key_info = (sc_pkcs15_prkey_info_t *) obj->data; sc_file_t *keyfile; unsigned char keybuf[1024]; size_t size,base; int r; 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_by_path(profile, &key_info->path, &keyfile); if (r < 0) return r; base=key_info->modulus_length / 16; size=2+5*base; keybuf[0]=6; keybuf[1]=base/4; jcop_bn2bin(&keybuf[2 + 0 * base], &key->u.rsa.p, base); jcop_bn2bin(&keybuf[2 + 1 * base], &key->u.rsa.q, base); jcop_bn2bin(&keybuf[2 + 2 * base], &key->u.rsa.dmp1, base); jcop_bn2bin(&keybuf[2 + 3 * base], &key->u.rsa.dmq1, base); jcop_bn2bin(&keybuf[2 + 4 * base], &key->u.rsa.iqmp, base); r = sc_pkcs15init_update_file(profile, p15card, keyfile, keybuf, size); sc_file_free(keyfile); return r; }
/* * Create a new key file */ static int jcop_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj) { sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data; sc_file_t *keyfile = NULL; size_t bytes, mod_len, prv_len; int r; 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; } /* The caller is supposed to have chosen a key file path for us */ if (key_info->path.len == 0 || key_info->modulus_length == 0) return SC_ERROR_INVALID_ARGUMENTS; /* Get the file we're supposed to create */ r = sc_profile_get_file_by_path(profile, &key_info->path, &keyfile); if (r < 0) return r; mod_len = key_info->modulus_length / 8; bytes = mod_len / 2; prv_len = 2 + 5 * bytes; keyfile->size = prv_len; /* Fix up PIN references in file ACL */ r = sc_pkcs15init_fixup_file(profile, p15card, keyfile); if (r >= 0) r = sc_pkcs15init_create_file(profile, p15card, keyfile); sc_file_free(keyfile); return r; }
/* * Store a private key object. */ static int muscle_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj, sc_pkcs15_prkey_t *key) { struct sc_context *ctx = p15card->card->ctx; sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data; sc_file_t* prkf; struct sc_pkcs15_prkey_rsa *rsa; sc_cardctl_muscle_key_info_t info; int r; if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Muscle supports RSA keys only."); return SC_ERROR_NOT_SUPPORTED; } /* Verification stuff */ /* Used for verification AND for obtaining private key acls */ r = sc_profile_get_file_by_path(profile, &key_info->path, &prkf); if(!prkf) SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_NOT_SUPPORTED); r = sc_pkcs15init_authenticate(profile, p15card, prkf, SC_AC_OP_CRYPTO); if (r < 0) { sc_file_free(prkf); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_NOT_SUPPORTED); } sc_file_free(prkf); r = muscle_select_key_reference(profile, p15card, key_info); if (r < 0) { SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE,r); } rsa = &key->u.rsa; info.keySize = rsa->modulus.len << 3; info.keyType = 0x03; /* CRT type */ info.keyLocation = key_info->key_reference * 2; /* Mult by 2 to preserve even/odd keynumber structure */ info.pLength = rsa->p.len; info.pValue = rsa->p.data; info.qLength = rsa->q.len; info.qValue = rsa->q.data; info.pqLength = rsa->iqmp.len; info.pqValue = rsa->iqmp.data; info.dp1Length = rsa->dmp1.len; info.dp1Value = rsa->dmp1.data; info.dq1Length = rsa->dmq1.len; info.dq1Value = rsa->dmq1.data; r = sc_card_ctl(p15card->card, SC_CARDCTL_MUSCLE_IMPORT_KEY, &info); if (r < 0) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Unable to import key"); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE,r); } return 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; }
/* * Create a key file */ static int gpk_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj) { sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data; struct sc_file *keyfile = NULL; size_t bytes, mod_len, exp_len, prv_len, pub_len; int r, algo; /* The caller is supposed to have chosen a key file path for us */ if (key_info->path.len == 0 || key_info->modulus_length == 0) return SC_ERROR_INVALID_ARGUMENTS; /* Get the file we're supposed to create */ r = sc_profile_get_file_by_path(profile, &key_info->path, &keyfile); if (r < 0) return r; /* Compute the file size. * We assume private keys are stored as CRT elements. * - 512, 768 bit keys: all CRT elements fit into one record * - >= 1024: each CRT element into a record of its own * * We also assume the public exponent is 32bit max * * Rules * - private key records must have a length divisible by 8 */ mod_len = key_info->modulus_length / 8; exp_len = 4; bytes = mod_len / 2; pub_len = 8 + ((3 + mod_len + 3 + exp_len + 3) & ~3UL); if (5 * bytes < 256) { prv_len = 8 + ((3 + 5 * bytes + 7) & ~7UL); } else { prv_len = 8 + 5 * ((3 + bytes + 7) & ~7UL); } keyfile->size = pub_len + prv_len; switch (obj->type) { case SC_PKCS15_TYPE_PRKEY_RSA: algo = SC_ALGORITHM_RSA; break; case SC_PKCS15_TYPE_PRKEY_DSA: algo = SC_ALGORITHM_DSA; break; default: sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "Unsupported public key algorithm"); return SC_ERROR_NOT_SUPPORTED; } /* Fix up PIN references in file ACL and create the PK file */ if ((r = sc_pkcs15init_fixup_file(profile, p15card, keyfile)) < 0 || (r = gpk_pkfile_create(profile, p15card, keyfile)) < 0) goto done; #ifdef PK_INIT_IMMEDIATELY /* Initialize the public key header */ r = gpk_pkfile_init_public(profile, p15card, keyfile, algo, key_info->modulus_length, key_info->usage); if (r < 0) goto done; /* Create the private key portion */ r = gpk_pkfile_init_private(p15card->card, keyfile, prv_len); #endif done: sc_file_free(keyfile); return r; }
/* * Generate key */ static int westcos_pkcs15init_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey) { #ifndef ENABLE_OPENSSL return SC_ERROR_NOT_SUPPORTED; #else int r = SC_ERROR_UNKNOWN; long lg; u8 *p; sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data; RSA *rsa = NULL; BIGNUM *bn = NULL; BIO *mem = NULL; sc_file_t *prkf = NULL; if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) { return SC_ERROR_NOT_SUPPORTED; } #if OPENSSL_VERSION_NUMBER>=0x00908000L rsa = RSA_new(); bn = BN_new(); mem = BIO_new(BIO_s_mem()); if(rsa == NULL || bn == NULL || mem == NULL) { r = SC_ERROR_OUT_OF_MEMORY; goto out; } if(!BN_set_word(bn, RSA_F4) || !RSA_generate_key_ex(rsa, key_info->modulus_length, bn, NULL)) #else mem = BIO_new(BIO_s_mem()); if(mem == NULL) { r = SC_ERROR_OUT_OF_MEMORY; goto out; } rsa = RSA_generate_key(key_info->modulus_length, RSA_F4, NULL, NULL); if (!rsa) #endif { r = SC_ERROR_UNKNOWN; goto out; } rsa->meth = RSA_PKCS1_SSLeay(); if(pubkey != NULL) { if(!i2d_RSAPublicKey_bio(mem, rsa)) { r = SC_ERROR_UNKNOWN; goto out; } lg = BIO_get_mem_data(mem, &p); pubkey->algorithm = SC_ALGORITHM_RSA; r = sc_pkcs15_decode_pubkey(p15card->card->ctx, pubkey, p, lg); } (void) BIO_reset(mem); if(!i2d_RSAPrivateKey_bio(mem, rsa)) { r = SC_ERROR_UNKNOWN; goto out; } lg = BIO_get_mem_data(mem, &p); /* Get the private key file */ r = sc_profile_get_file_by_path(profile, &key_info->path, &prkf); if (r < 0) { char pbuf[SC_MAX_PATH_STRING_SIZE]; r = sc_path_print(pbuf, sizeof(pbuf), &key_info->path); if (r != SC_SUCCESS) pbuf[0] = '\0'; goto out; } prkf->size = lg; r = sc_pkcs15init_create_file(profile, p15card, prkf); if(r) goto out; r = sc_pkcs15init_update_file(profile, p15card, prkf, p, lg); if(r) goto out; out: if(mem) BIO_free(mem); if(bn) BN_free(bn); if(rsa) RSA_free(rsa); if(prkf) sc_file_free(prkf); return r; #endif }
static int muscle_generate_key(sc_profile_t *profile, sc_card_t *card, sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey) { sc_cardctl_muscle_gen_key_info_t args; sc_cardctl_muscle_key_info_t extArgs; sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data; sc_file_t* prkf; unsigned int keybits; int r; if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) { sc_error(card->ctx, "Muscle supports only RSA keys (for now)."); SC_FUNC_RETURN(card->ctx, 2,SC_ERROR_NOT_SUPPORTED); } keybits = key_info->modulus_length & ~7UL; if (keybits > 2048) { sc_error(card->ctx, "Unable to generate key, max size is %d", 2048); SC_FUNC_RETURN(card->ctx, 2,SC_ERROR_INVALID_ARGUMENTS); } /* Verification stuff */ /* Used for verification AND for obtaining private key acls */ r = sc_profile_get_file_by_path(profile, &key_info->path, &prkf); if(!prkf) SC_FUNC_RETURN(card->ctx, 2,SC_ERROR_NOT_SUPPORTED); r = sc_pkcs15init_authenticate(profile, card, prkf, SC_AC_OP_CRYPTO); if (r < 0) { sc_file_free(prkf); SC_FUNC_RETURN(card->ctx, 2,SC_ERROR_NOT_SUPPORTED); } sc_file_free(prkf); /* END VERIFICATION STUFF */ /* Public key acls... get_file_by_path as well? */ memset(&args, 0, sizeof(args)); args.keyType = 0x01; // RSA forced args.privateKeyLocation = key_info->key_reference * 2; args.publicKeyLocation = key_info->key_reference * 2 + 1; args.keySize = keybits; r = sc_card_ctl(card, SC_CARDCTL_MUSCLE_GENERATE_KEY, &args); if (r < 0) { sc_error(card->ctx, "Unable to generate key"); SC_FUNC_RETURN(card->ctx, 2,r); } memset(&extArgs, 0, sizeof(extArgs)); memset(pubkey, 0, sizeof(*pubkey)); extArgs.keyType = 0x01; extArgs.keyLocation = args.publicKeyLocation; r = sc_card_ctl(card, SC_CARDCTL_MUSCLE_EXTRACT_KEY, &extArgs); if (r < 0) { sc_error(card->ctx, "Unable to extract the public key"); SC_FUNC_RETURN(card->ctx, 2,r); } pubkey->algorithm = SC_ALGORITHM_RSA; pubkey->u.rsa.modulus.len = extArgs.modLength; pubkey->u.rsa.modulus.data = extArgs.modValue; pubkey->u.rsa.exponent.len = extArgs.expLength; pubkey->u.rsa.exponent.data = extArgs.expValue; if (r < 0) { if (pubkey->u.rsa.modulus.data) free (pubkey->u.rsa.modulus.data); if (pubkey->u.rsa.exponent.data) free (pubkey->u.rsa.exponent.data); } return r; }
static int cflex_create_pin_file(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_path_t *df_path, int ref, const u8 *pin, size_t pin_len, int pin_tries, const u8 *puk, size_t puk_len, int puk_tries, sc_file_t **file_ret, int unprotected) { struct sc_context *ctx = p15card->card->ctx; struct sc_pkcs15_object *pin_obj = NULL; unsigned char buffer[23]; sc_path_t path; sc_file_t *dummies[2], *file; int r, ndummies; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); if (file_ret) *file_ret = NULL; /* Build the CHV path */ path = *df_path; path.value[path.len++] = ref - 1; path.value[path.len++] = 0; /* See if the CHV already exists */ r = sc_select_file(p15card->card, &path, NULL); if (r >= 0) return SC_ERROR_FILE_ALREADY_EXISTS; /* Get the file definition from the profile */ if (sc_profile_get_file_by_path(profile, &path, &file) < 0 && sc_profile_get_file(profile, (ref == 1)? "CHV1" : "CHV2", &file) < 0 && sc_profile_get_file(profile, "CHV", &file) < 0) SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_FILE_NOT_FOUND, "profile does not define pin file ACLs"); file->path = path; file->size = 23; file->id = (ref == 1)? 0x0000 : 0x0100; if (unprotected) { sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_NONE, SC_AC_KEY_REF_NONE); } /* Build the contents of the file */ buffer[0] = buffer[1] = buffer[2] = 0xFF; put_pin(profile, buffer + 3, pin, pin_len, pin_tries); put_pin(profile, buffer + 13, puk, puk_len, puk_tries); /* For updating the file, create a dummy CHV files if * necessary */ ndummies = cflex_create_dummy_chvs(profile, p15card, file, SC_AC_OP_UPDATE, dummies); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, ndummies, "Unable to create dummy CHV file"); if (!unprotected) { struct sc_pin_cmd_data pin_cmd; memset(&pin_cmd, 0, sizeof(pin_cmd)); pin_cmd.cmd = SC_PIN_CMD_VERIFY; pin_cmd.pin_type = SC_AC_CHV; pin_cmd.pin_reference = ref; pin_cmd.pin1.data = dummy_pin_value; pin_cmd.pin1.len = sizeof(dummy_pin_value); r = sc_pin_cmd(p15card->card, &pin_cmd, NULL); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Cannot verify dummy PIN"); }; if (ref == 2) { /* Cache dummy SOPIN value */ r = sc_pkcs15_find_pin_by_type_and_reference(p15card, NULL, SC_AC_CHV, ref, &pin_obj); if (!r && pin_obj) sc_pkcs15_pincache_add(p15card, pin_obj, dummy_pin_value, sizeof(dummy_pin_value)); } r = sc_pkcs15init_create_file(profile, p15card, file); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Failed to create PIN file"); r = sc_update_binary(p15card->card, 0, buffer, 23, 0); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Failed to update PIN file"); if (r < 0 || file_ret == NULL) sc_file_free(file); else *file_ret = file; /* Delete the dummy CHV files */ cflex_delete_dummy_chvs(profile, p15card, ndummies, dummies); if (pin_obj) { /* Cache new SOPIN value */ sc_pkcs15_pincache_add(p15card, pin_obj, pin, pin_len); } SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r); }