int sc_pkcs15_decode_pubkey_with_param(sc_context_t *ctx, struct sc_pkcs15_pubkey *key, const u8 *buf, size_t len) { /* We assume all algrothims allow SPKI which starts with a sequence*/ if (*buf == 0x30) /* Decode Public Key from SPKI */ return sc_pkcs15_copy_pubkey_from_spki_object(ctx, buf, len, key); key->data.value = (u8 *)buf; key->data.len = len; return sc_pkcs15_decode_pubkey(ctx, key, buf, len); }
/* * 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 }
/* * can be used as an SC_ASN1_CALLBACK while parsing a certificate, * or can be called from the sc_pkcs15_pubkey_from_spki_filename */ int sc_pkcs15_pubkey_from_spki(sc_context_t *ctx, sc_pkcs15_pubkey_t ** outpubkey, u8 *buf, size_t buflen, int depth) { int r; sc_pkcs15_pubkey_t * pubkey = NULL; sc_pkcs15_der_t pk = { NULL, 0 }; struct sc_algorithm_id pk_alg; struct sc_asn1_entry asn1_pkinfo[C_ASN1_PKINFO_ATTR_SIZE]; struct sc_asn1_entry asn1_ec_pointQ[2]; sc_log(ctx, "sc_pkcs15_pubkey_from_spki %p:%d", buf, buflen); memset(&pk_alg, 0, sizeof(pk_alg)); pubkey = calloc(1, sizeof(sc_pkcs15_pubkey_t)); if (pubkey == NULL) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } sc_copy_asn1_entry(c_asn1_pkinfo, asn1_pkinfo); sc_format_asn1_entry(asn1_pkinfo + 0, &pk_alg, NULL, 0); sc_format_asn1_entry(asn1_pkinfo + 1, &pk.value, &pk.len, 0); r = sc_asn1_decode(ctx, asn1_pkinfo, buf, buflen, NULL, NULL); if (r < 0) goto err; pubkey->alg_id = calloc(1, sizeof(struct sc_algorithm_id)); if (pubkey->alg_id == NULL) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } memcpy(pubkey->alg_id, &pk_alg, sizeof(struct sc_algorithm_id)); pubkey->algorithm = pk_alg.algorithm; pk_alg.params = NULL; sc_log(ctx, "DEE pk_alg.algorithm=%d", pk_alg.algorithm); /* pk.len is in bits at this point */ switch (pk_alg.algorithm) { case SC_ALGORITHM_EC: /* * TODO we really should only have params in one place! * The alg_id may have the sc_ec_params, * we want to get the curve OID into the * u.ec.params and get the field length too. */ if (pubkey->alg_id->params) { struct sc_ec_params * ecp = (struct sc_ec_params *)pubkey->alg_id->params; pubkey->u.ec.params.der.value = malloc(ecp->der_len); if (pubkey->u.ec.params.der.value) { memcpy(pubkey->u.ec.params.der.value, ecp->der, ecp->der_len); pubkey->u.ec.params.der.len = ecp->der_len; sc_pkcs15_fix_ec_parameters(ctx,&pubkey->u.ec.params); } } /* * For most keys, the above ASN.1 parsing of a key works, but for EC keys, * the ec_pointQ in a certificate is stored in the bitstring, in its raw format. * RSA for example is stored in the bitstring, as a ASN1 DER * So we encoded the raw ecpointQ into ASN1 DER as the pubkey->data * and let the sc_pkcs15_decode_pubkey below get the ecpointQ out later. */ pk.len >>= 3; /* Assume it is multiple of 8 */ if (pubkey->u.ec.params.field_length == 0) pubkey->u.ec.params.field_length = (pk.len - 1)/2 * 8; sc_copy_asn1_entry(c_asn1_ec_pointQ, asn1_ec_pointQ); sc_format_asn1_entry(&asn1_ec_pointQ[0], pk.value, &pk.len, 1); r = sc_asn1_encode(ctx, asn1_ec_pointQ, &pubkey->data.value, &pubkey->data.len); pk.value = NULL; sc_log(ctx, "DEE r=%d data=%p:%d", r, pubkey->data.value, pubkey->data.len); break; default: pk.len >>= 3; /* convert number of bits to bytes */ pubkey->data = pk; /* save in publey */ pk.value = NULL; break; } /* Now decode what every is in pk as it depends on the key algorthim */ r = sc_pkcs15_decode_pubkey(ctx, pubkey, pubkey->data.value, pubkey->data.len); if (r < 0) goto err; *outpubkey = pubkey; pubkey = NULL; return 0; err: if (pubkey) free(pubkey); if (pk.value) free(pk.value); LOG_TEST_RET(ctx, r, "ASN.1 parsing of subjectPubkeyInfo failed"); LOG_FUNC_RETURN(ctx, r); }
/* * Read public key. */ int sc_pkcs15_read_pubkey(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_object *obj, struct sc_pkcs15_pubkey **out) { struct sc_context *ctx = p15card->card->ctx; const struct sc_pkcs15_pubkey_info *info = NULL; struct sc_pkcs15_pubkey *pubkey = NULL; unsigned char *data = NULL; size_t len; int algorithm, r; assert(p15card != NULL && obj != NULL && out != NULL); LOG_FUNC_CALLED(ctx); switch (obj->type) { case SC_PKCS15_TYPE_PUBKEY_RSA: algorithm = SC_ALGORITHM_RSA; break; case SC_PKCS15_TYPE_PUBKEY_DSA: algorithm = SC_ALGORITHM_DSA; break; case SC_PKCS15_TYPE_PUBKEY_GOSTR3410: algorithm = SC_ALGORITHM_GOSTR3410; break; case SC_PKCS15_TYPE_PUBKEY_EC: algorithm = SC_ALGORITHM_EC; break; default: LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported public key type."); } info = (const struct sc_pkcs15_pubkey_info *) obj->data; sc_log(ctx, "Content (%p, %i)", obj->content.value, obj->content.len); if (obj->content.value && obj->content.len) { /* public key data is present as 'direct' value of pkcs#15 object */ data = calloc(1, obj->content.len); if (!data) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); memcpy(data, obj->content.value, obj->content.len); len = obj->content.len; } else if (p15card->card->ops->read_public_key) { r = p15card->card->ops->read_public_key(p15card->card, algorithm, &info->path, info->key_reference, info->modulus_length, &data, &len); LOG_TEST_RET(ctx, r, "Card specific 'read-public' procedure failed."); } else if (info->path.len) { r = sc_pkcs15_read_file(p15card, &info->path, &data, &len); LOG_TEST_RET(ctx, r, "Failed to read public key file."); } else { LOG_TEST_RET(ctx, SC_ERROR_NOT_IMPLEMENTED, "No way to get public key"); } if (!data || !len) LOG_FUNC_RETURN(ctx, SC_ERROR_OBJECT_NOT_VALID); pubkey = calloc(1, sizeof(struct sc_pkcs15_pubkey)); if (pubkey == NULL) { free(data); LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); } pubkey->algorithm = algorithm; pubkey->data.value = data; pubkey->data.len = len; if (sc_pkcs15_decode_pubkey(ctx, pubkey, data, len)) { free(data); free(pubkey); LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ASN1_OBJECT); } *out = pubkey; LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
/* * can be used as an SC_ASN1_CALLBACK while parsing a certificate, * or can be called from the sc_pkcs15_pubkey_from_spki_filename */ int sc_pkcs15_pubkey_from_spki(sc_context_t *ctx, sc_pkcs15_pubkey_t ** outpubkey, u8 *buf, size_t buflen, int depth) { int r; sc_pkcs15_pubkey_t * pubkey = NULL; sc_pkcs15_der_t pk = { NULL, 0 }; struct sc_algorithm_id pk_alg; struct sc_asn1_entry asn1_pkinfo[3]; struct sc_asn1_entry asn1_ec_pointQ[2]; sc_debug(ctx,SC_LOG_DEBUG_NORMAL,"sc_pkcs15_pubkey_from_spki %p:%d", buf, buflen); memset(&pk_alg, 0, sizeof(pk_alg)); pubkey = calloc(1, sizeof(sc_pkcs15_pubkey_t)); if (pubkey == NULL) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } sc_copy_asn1_entry(c_asn1_pkinfo, asn1_pkinfo); sc_format_asn1_entry(asn1_pkinfo + 0, &pk_alg, NULL, 0); sc_format_asn1_entry(asn1_pkinfo + 1, &pk.value, &pk.len, 0); r = sc_asn1_decode(ctx, asn1_pkinfo, buf, buflen, NULL, NULL); if (r < 0) goto err; pubkey->alg_id = calloc(1, sizeof(struct sc_algorithm_id)); if (pubkey->alg_id == NULL) { r = SC_ERROR_OUT_OF_MEMORY; goto err; } memcpy(pubkey->alg_id, &pk_alg, sizeof(struct sc_algorithm_id)); pubkey->algorithm = pk_alg.algorithm; sc_debug(ctx,SC_LOG_DEBUG_NORMAL,"DEE pk_alg.algorithm=%d",pk_alg.algorithm); /* pk.len is in bits at this point */ switch (pk_alg.algorithm) { case SC_ALGORITHM_EC: /* * For most keys, the above ASN.1 parsing of a key works, but for EC keys, * the ec_pointQ in a certificate is stored in a bitstring, but * in PKCS#11 it is an octet string and we just decoded its * contents from the bitstring in the certificate. So we need to encode it * back to an octet string so we can store it as an octet string. */ pk.len >>= 3; /* Assume it is multiple of 8 */ // pubkey->u.ec.field_length = (pk.len - 1)/2 * 8; sc_copy_asn1_entry(c_asn1_ec_pointQ, asn1_ec_pointQ); sc_format_asn1_entry(&asn1_ec_pointQ[0], pk.value, &pk.len, 1); r = sc_asn1_encode(ctx, asn1_ec_pointQ, &pubkey->data.value, &pubkey->data.len); sc_debug(ctx,SC_LOG_DEBUG_NORMAL,"DEE r=%d data=%p:%d", r,pubkey->data.value, pubkey->data.len); break; default: pk.len >>= 3; /* convert number of bits to bytes */ pubkey->data = pk; /* save in publey */ pk.value = NULL; break; } /* Now decode what every is in pk as it depends on the key algorthim */ r = sc_pkcs15_decode_pubkey(ctx, pubkey, pubkey->data.value, pubkey->data.len); if (r < 0) goto err; *outpubkey = pubkey; pubkey = NULL; return 0; err: if (pubkey) free(pubkey); if (pk.value) free(pk.value); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "ASN.1 parsing of subjectPubkeyInfo failed"); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, r); }
/* * Read public key. */ int sc_pkcs15_read_pubkey(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_object *obj, struct sc_pkcs15_pubkey **out) { struct sc_context *ctx = p15card->card->ctx; const struct sc_pkcs15_pubkey_info *info; struct sc_pkcs15_pubkey *pubkey; u8 *data; size_t len; int algorithm, r; assert(p15card != NULL && obj != NULL && out != NULL); SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); switch (obj->type) { case SC_PKCS15_TYPE_PUBKEY_RSA: algorithm = SC_ALGORITHM_RSA; break; case SC_PKCS15_TYPE_PUBKEY_DSA: algorithm = SC_ALGORITHM_DSA; break; case SC_PKCS15_TYPE_PUBKEY_GOSTR3410: algorithm = SC_ALGORITHM_GOSTR3410; break; case SC_PKCS15_TYPE_PUBKEY_EC: algorithm = SC_ALGORITHM_EC; break; default: SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_NOT_SUPPORTED, "Unsupported public key type."); } info = (const struct sc_pkcs15_pubkey_info *) obj->data; if (obj->content.value && obj->content.len) { /* public key data is present as 'direct' value of pkcs#15 object */ data = calloc(1, obj->content.len); if (!data) SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); memcpy(data, obj->content.value, obj->content.len); len = obj->content.len; } else { r = sc_pkcs15_read_file(p15card, &info->path, &data, &len); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Failed to read public key file."); } pubkey = calloc(1, sizeof(struct sc_pkcs15_pubkey)); if (pubkey == NULL) { free(data); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); } pubkey->algorithm = algorithm; pubkey->data.value = data; pubkey->data.len = len; if (sc_pkcs15_decode_pubkey(ctx, pubkey, data, len)) { free(data); free(pubkey); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ASN1_OBJECT); } *out = pubkey; SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS); }