/* * On-board key generation. */ static int gpk_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey) { struct sc_cardctl_gpk_genkey args; sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data; unsigned int keybits; sc_file_t *keyfile; int r, n; sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "path=%s, %d bits\n", sc_print_path(&key_info->path), key_info->modulus_length); if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) { sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "GPK supports generating 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; keybits = key_info->modulus_length; if ((r = sc_select_file(p15card->card, &key_info->path, &keyfile)) < 0) return r; #ifndef PK_INIT_IMMEDIATELY r = gpk_pkfile_init_public(profile, p15card, keyfile, SC_ALGORITHM_RSA, keybits, key_info->usage); if (r < 0) { sc_file_free(keyfile); return r; } if ((r = gpk_pkfile_init_private(p15card->card, keyfile, 5 * ((3 + keybits / 16 + 7) & ~7UL))) < 0) { sc_file_free(keyfile); return r; } #endif sc_file_free(keyfile); memset(&args, 0, sizeof(args)); /*args.exponent = 0x10001;*/ n = key_info->path.len; args.fid = (key_info->path.value[n-2] << 8) | key_info->path.value[n-1]; args.privlen = keybits; r = sc_card_ctl(p15card->card, SC_CARDCTL_GPK_GENERATE_KEY, &args); if (r < 0) return r; /* This is fairly weird. The GENERATE RSA KEY command returns * immediately, but obviously it needs more time to complete. * This is why we sleep here. */ sleep(20); pubkey->algorithm = SC_ALGORITHM_RSA; return gpk_read_rsa_key(p15card->card, &pubkey->u.rsa); }
static int gpk_store_pk(struct sc_profile *profile, sc_card_t *card, sc_file_t *file, struct pkdata *p) { size_t fsize; int r; /* Compute length of private/public key parts */ gpk_compute_publen(&p->_public); gpk_compute_privlen(&p->_private); if (card->ctx->debug) sc_debug(card->ctx, "Storing pk: %u bits, pub %u bytes, priv %u bytes\n", p->bits, p->_public.size, p->_private.size); fsize = p->_public.size + p->_private.size; if (fsize > file->size) return SC_ERROR_FILE_TOO_SMALL; /* Put the system record */ #ifndef PK_INIT_IMMEDIATELY r = gpk_pkfile_init_public(profile, card, file, p->algo, p->bits, p->usage); if (r < 0) return r; #endif /* Put the public key elements */ r = gpk_pkfile_update_public(profile, card, &p->_public); if (r < 0) return r; /* Create the private key part */ #ifndef PK_INIT_IMMEDIATELY r = gpk_pkfile_init_private(card, file, p->_private.size); if (r < 0) return r; #endif /* Now store the private key elements */ r = gpk_pkfile_update_private(profile, card, file, &p->_private); 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; }