Exemplo n.º 1
0
static CK_RV
add_pubkey_info(hx509_context hxctx, struct st_object *o,
		CK_KEY_TYPE key_type, hx509_cert cert)
{
    BIGNUM *num;
    CK_BYTE *modulus = NULL;
    size_t modulus_len = 0;
    CK_ULONG modulus_bits = 0;
    CK_BYTE *exponent = NULL;
    size_t exponent_len = 0;

    if (key_type != CKK_RSA)
	return CKR_OK;
    if (_hx509_cert_private_key(cert) == NULL)
	return CKR_OK;

    num = _hx509_private_key_get_internal(context,
					  _hx509_cert_private_key(cert),
					  "rsa-modulus");
    if (num == NULL)
	return CKR_GENERAL_ERROR;
    modulus_bits = BN_num_bits(num);

    modulus_len = BN_num_bytes(num);
    modulus = malloc(modulus_len);
    BN_bn2bin(num, modulus);
    BN_free(num);

    add_object_attribute(o, 0, CKA_MODULUS, modulus, modulus_len);
    add_object_attribute(o, 0, CKA_MODULUS_BITS,
			 &modulus_bits, sizeof(modulus_bits));

    free(modulus);

    num = _hx509_private_key_get_internal(context,
					  _hx509_cert_private_key(cert),
					  "rsa-exponent");
    if (num == NULL)
	return CKR_GENERAL_ERROR;

    exponent_len = BN_num_bytes(num);
    exponent = malloc(exponent_len);
    BN_bn2bin(num, exponent);
    BN_free(num);

    add_object_attribute(o, 0, CKA_PUBLIC_EXPONENT,
			 exponent, exponent_len);

    free(exponent);

    return CKR_OK;
}
Exemplo n.º 2
0
static CK_RV
add_pubkey_info(struct gpkcs11_st_object *o, CK_KEY_TYPE key_type, EVP_PKEY *key)
{
    switch (key_type) {
    case CKK_RSA: {
	CK_BYTE *modulus = NULL;
	size_t modulus_len = 0;
	CK_ULONG modulus_bits = 0;
	CK_BYTE *exponent = NULL;
	size_t exponent_len = 0;

	modulus_bits = BN_num_bits(key->pkey.rsa->n);

	modulus_len = BN_num_bytes(key->pkey.rsa->n);
	modulus = malloc(modulus_len);
	BN_bn2bin(key->pkey.rsa->n, modulus);
	
	exponent_len = BN_num_bytes(key->pkey.rsa->e);
	exponent = malloc(exponent_len);
	BN_bn2bin(key->pkey.rsa->e, exponent);
	
	add_object_attribute(o, 0, CKA_MODULUS, modulus, modulus_len);
	add_object_attribute(o, 0, CKA_MODULUS_BITS,
			     &modulus_bits, sizeof(modulus_bits));
	add_object_attribute(o, 0, CKA_PUBLIC_EXPONENT,
			     exponent, exponent_len);

	RSA_set_method(key->pkey.rsa, RSA_PKCS1_SSLeay());

	free(modulus);
	free(exponent);
    }
    default:
	/* XXX */
	break;
    }
    return CKR_OK;
}
Exemplo n.º 3
0
static int HX509_LIB_CALL
add_cert(hx509_context hxctx, void *ctx, hx509_cert cert)
{
    static char empty[] = "";
    struct foo *foo = (struct foo *)ctx;
    struct st_object *o = NULL;
    CK_OBJECT_CLASS type;
    CK_BBOOL bool_true = CK_TRUE;
    CK_BBOOL bool_false = CK_FALSE;
    CK_CERTIFICATE_TYPE cert_type = CKC_X_509;
    CK_KEY_TYPE key_type;
    CK_MECHANISM_TYPE mech_type;
    CK_RV ret = CKR_GENERAL_ERROR;
    int hret;
    heim_octet_string cert_data, subject_data, issuer_data, serial_data;

    st_logf("adding certificate\n");

    serial_data.data = NULL;
    serial_data.length = 0;
    cert_data = subject_data = issuer_data = serial_data;

    hret = hx509_cert_binary(hxctx, cert, &cert_data);
    if (hret)
	goto out;

    {
	    hx509_name name;

	    hret = hx509_cert_get_issuer(cert, &name);
	    if (hret)
		goto out;
	    hret = hx509_name_binary(name, &issuer_data);
	    hx509_name_free(&name);
	    if (hret)
		goto out;

	    hret = hx509_cert_get_subject(cert, &name);
	    if (hret)
		goto out;
	    hret = hx509_name_binary(name, &subject_data);
	    hx509_name_free(&name);
	    if (hret)
		goto out;
    }

    {
	AlgorithmIdentifier alg;

	hret = hx509_cert_get_SPKI_AlgorithmIdentifier(context, cert, &alg);
	if (hret) {
	    ret = CKR_DEVICE_MEMORY;
	    goto out;
	}

	key_type = CKK_RSA; /* XXX */

	free_AlgorithmIdentifier(&alg);
    }


    type = CKO_CERTIFICATE;
    o = add_st_object();
    if (o == NULL) {
	ret = CKR_DEVICE_MEMORY;
	goto out;
    }

    o->cert = hx509_cert_ref(cert);

    add_object_attribute(o, 0, CKA_CLASS, &type, sizeof(type));
    add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
    add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false));
    add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
    add_object_attribute(o, 0, CKA_LABEL, foo->label, strlen(foo->label));

    add_object_attribute(o, 0, CKA_CERTIFICATE_TYPE, &cert_type, sizeof(cert_type));
    add_object_attribute(o, 0, CKA_ID, foo->id, strlen(foo->id));

    add_object_attribute(o, 0, CKA_SUBJECT, subject_data.data, subject_data.length);
    add_object_attribute(o, 0, CKA_ISSUER, issuer_data.data, issuer_data.length);
    add_object_attribute(o, 0, CKA_SERIAL_NUMBER, serial_data.data, serial_data.length);
    add_object_attribute(o, 0, CKA_VALUE, cert_data.data, cert_data.length);
    add_object_attribute(o, 0, CKA_TRUSTED, &bool_false, sizeof(bool_false));

    st_logf("add cert ok: %lx\n", (unsigned long)OBJECT_ID(o));

    type = CKO_PUBLIC_KEY;
    o = add_st_object();
    if (o == NULL) {
	ret = CKR_DEVICE_MEMORY;
	goto out;
    }
    o->cert = hx509_cert_ref(cert);

    add_object_attribute(o, 0, CKA_CLASS, &type, sizeof(type));
    add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
    add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false));
    add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
    add_object_attribute(o, 0, CKA_LABEL, foo->label, strlen(foo->label));

    add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type));
    add_object_attribute(o, 0, CKA_ID, foo->id, strlen(foo->id));
    add_object_attribute(o, 0, CKA_START_DATE, empty, 1); /* XXX */
    add_object_attribute(o, 0, CKA_END_DATE, empty, 1); /* XXX */
    add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false));
    add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false));
    mech_type = CKM_RSA_X_509;
    add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type));

    add_object_attribute(o, 0, CKA_SUBJECT, subject_data.data, subject_data.length);
    add_object_attribute(o, 0, CKA_ENCRYPT, &bool_true, sizeof(bool_true));
    add_object_attribute(o, 0, CKA_VERIFY, &bool_true, sizeof(bool_true));
    add_object_attribute(o, 0, CKA_VERIFY_RECOVER, &bool_false, sizeof(bool_false));
    add_object_attribute(o, 0, CKA_WRAP, &bool_true, sizeof(bool_true));
    add_object_attribute(o, 0, CKA_TRUSTED, &bool_true, sizeof(bool_true));

    add_pubkey_info(hxctx, o, key_type, cert);

    st_logf("add key ok: %lx\n", (unsigned long)OBJECT_ID(o));

    if (hx509_cert_have_private_key(cert)) {
	CK_FLAGS flags;

	type = CKO_PRIVATE_KEY;

        /* Note to static analyzers: `o' is still referred to via globals */
	o = add_st_object();
	if (o == NULL) {
	    ret = CKR_DEVICE_MEMORY;
	    goto out;
	}
	o->cert = hx509_cert_ref(cert);

	add_object_attribute(o, 0, CKA_CLASS, &type, sizeof(type));
	add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
	add_object_attribute(o, 0, CKA_PRIVATE, &bool_true, sizeof(bool_false));
	add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
	add_object_attribute(o, 0, CKA_LABEL, foo->label, strlen(foo->label));

	add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type));
	add_object_attribute(o, 0, CKA_ID, foo->id, strlen(foo->id));
	add_object_attribute(o, 0, CKA_START_DATE, empty, 1); /* XXX */
	add_object_attribute(o, 0, CKA_END_DATE, empty, 1); /* XXX */
	add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false));
	add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false));
	mech_type = CKM_RSA_X_509;
	add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type));

	add_object_attribute(o, 0, CKA_SUBJECT, subject_data.data, subject_data.length);
	add_object_attribute(o, 0, CKA_SENSITIVE, &bool_true, sizeof(bool_true));
	add_object_attribute(o, 0, CKA_SECONDARY_AUTH, &bool_false, sizeof(bool_true));
	flags = 0;
	add_object_attribute(o, 0, CKA_AUTH_PIN_FLAGS, &flags, sizeof(flags));

	add_object_attribute(o, 0, CKA_DECRYPT, &bool_true, sizeof(bool_true));
	add_object_attribute(o, 0, CKA_SIGN, &bool_true, sizeof(bool_true));
	add_object_attribute(o, 0, CKA_SIGN_RECOVER, &bool_false, sizeof(bool_false));
	add_object_attribute(o, 0, CKA_UNWRAP, &bool_true, sizeof(bool_true));
	add_object_attribute(o, 0, CKA_EXTRACTABLE, &bool_true, sizeof(bool_true));
	add_object_attribute(o, 0, CKA_NEVER_EXTRACTABLE, &bool_false, sizeof(bool_false));

	add_pubkey_info(hxctx, o, key_type, cert);
    }

    ret = CKR_OK;
 out:
    if (ret != CKR_OK) {
	st_logf("something went wrong when adding cert!\n");

	/* XXX wack o */;
    }
    hx509_xfree(cert_data.data);
    hx509_xfree(serial_data.data);
    hx509_xfree(issuer_data.data);
    hx509_xfree(subject_data.data);

    /* Note to static analyzers: `o' is still referred to via globals */
    return 0;
}
Exemplo n.º 4
0
CK_RV
gpkcs11_add_credentials(char *label,
			const char *cert_file,
			const char *private_key_file,
			char *id,
			int anchor)
{
    struct gpkcs11_st_object *o = NULL;
    CK_BBOOL bool_true = CK_TRUE;
    CK_BBOOL bool_false = CK_FALSE;
    CK_OBJECT_CLASS c;
    CK_CERTIFICATE_TYPE cert_type = CKC_X_509;
    CK_KEY_TYPE key_type;
    CK_MECHANISM_TYPE mech_type;
    CK_RV ret = CKR_GENERAL_ERROR;
    void *subject_data = NULL;
    size_t subject_length;
    X509 *cert, *proxy_cert = NULL;
    EVP_PKEY *public_key;
    FILE *f = NULL;
    size_t id_len = strlen(id);

    f = fopen(cert_file, "r");
    if (f == NULL) {
	gpkcs11_log("failed to open file %s\n", cert_file);
	return CKR_GENERAL_ERROR;
    }

    while (1) {
	cert = PEM_read_X509(f, NULL, NULL, NULL);
	if (cert == NULL) {
	    if (ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE)
		break;
	    ret = CKR_GENERAL_ERROR;
	    goto out;
	}
	if (proxy_cert == NULL)
	    proxy_cert = cert;
	ret = gpkcs11_add_certificate(label, cert, id, anchor);
	if (ret)
	    goto out;
    }

    public_key = X509_get_pubkey(proxy_cert);
    switch (EVP_PKEY_type(public_key->type)) {
    case EVP_PKEY_RSA:
	key_type = CKK_RSA;
	break;
    case EVP_PKEY_DSA:
	key_type = CKK_DSA;
	break;
    default:
	/* XXX */
	break;
    }

    OPENSSL_ASN1_MALLOC_ENCODE(X509_NAME, subject_data, subject_length, 
			       X509_get_subject_name(proxy_cert), ret);
    if (ret)
	goto out;


    if (private_key_file) {
	CK_FLAGS flags;
	FILE *f;

	o = add_st_object();
	if (o == NULL) {
	    ret = CKR_DEVICE_MEMORY;
	    goto out;
	}
	o->type = STO_T_PRIVATE_KEY;
	o->u.private_key.file = strdup(private_key_file);
	o->u.private_key.key = NULL;

	o->u.private_key.cert = proxy_cert;

	c = CKO_PRIVATE_KEY;
	add_object_attribute(o, 0, CKA_CLASS, &c, sizeof(c));
	add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
	add_object_attribute(o, 0, CKA_PRIVATE, &bool_true, sizeof(bool_false));
	add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
	add_object_attribute(o, 0, CKA_LABEL, label, strlen(label));

	add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type));
	add_object_attribute(o, 0, CKA_ID, id, id_len);
	add_object_attribute(o, 0, CKA_START_DATE, "", 1); /* XXX */
	add_object_attribute(o, 0, CKA_END_DATE, "", 1); /* XXX */
	add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false));
	add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false));
	mech_type = CKM_RSA_X_509;
	add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type));

	add_object_attribute(o, 0, CKA_SUBJECT, subject_data, subject_length);
	add_object_attribute(o, 0, CKA_SENSITIVE, &bool_true, sizeof(bool_true));
	add_object_attribute(o, 0, CKA_SECONDARY_AUTH, &bool_false, sizeof(bool_true));
	flags = 0;
	add_object_attribute(o, 0, CKA_AUTH_PIN_FLAGS, &flags, sizeof(flags));

	add_object_attribute(o, 0, CKA_DECRYPT, &bool_true, sizeof(bool_true));
	add_object_attribute(o, 0, CKA_SIGN, &bool_true, sizeof(bool_true));
	add_object_attribute(o, 0, CKA_SIGN_RECOVER, &bool_false, sizeof(bool_false));
	add_object_attribute(o, 0, CKA_UNWRAP, &bool_true, sizeof(bool_true));
	add_object_attribute(o, 0, CKA_EXTRACTABLE, &bool_true, sizeof(bool_true));
	add_object_attribute(o, 0, CKA_NEVER_EXTRACTABLE, &bool_false, sizeof(bool_false));

	add_pubkey_info(o, key_type, public_key);

	f = fopen(private_key_file, "r");
	if (f == NULL) {
	    gpkcs11_log("failed to open private key\n");
	    return CKR_GENERAL_ERROR;
	}

	o->u.private_key.key = PEM_read_PrivateKey(f, NULL, pem_callback, NULL);
	fclose(f);
	if (o->u.private_key.key == NULL) {
	    gpkcs11_log("failed to read private key a startup\n");
	    /* don't bother with this failure for now, 
	       fix it at C_Login time */;
	} else {
	    /* XXX verify keytype */

	    if (key_type == CKK_RSA)
		RSA_set_method(o->u.private_key.key->pkey.rsa, 
			       RSA_PKCS1_SSLeay());

	    if (X509_check_private_key(proxy_cert, o->u.private_key.key) != 1) {
		EVP_PKEY_free(o->u.private_key.key);	    
		o->u.private_key.key = NULL;
		gpkcs11_log("private key doesn't verify\n");
	    } else {
		gpkcs11_log("private key usable\n");
		gpkcs11_soft_token.flags.login_done = 1;
	    }
	}
    }

    ret = CKR_OK;
 out:
    if (ret != CKR_OK) {
	gpkcs11_log("something went wrong when adding cert!\n");

	/* XXX wack o */;
    }

    if (f)
	fclose(f);

    return ret;
}
Exemplo n.º 5
0
CK_RV
gpkcs11_add_certificate(char *label,
			X509 *cert,
			char *id,
			int anchor)
{
    struct gpkcs11_st_object *o = NULL;
    void *cert_data = NULL;
    size_t cert_length;
    void *subject_data = NULL;
    size_t subject_length;
    void *issuer_data = NULL;
    size_t issuer_length;
    void *serial_data = NULL;
    size_t serial_length;
    EVP_PKEY *public_key;
    unsigned char sha1[SHA_DIGEST_LENGTH];
    CK_TRUST trust_ca = CKT_NSS_TRUSTED_DELEGATOR;
    int ret;
    CK_BBOOL bool_true = CK_TRUE;
    CK_BBOOL bool_false = CK_FALSE;
    CK_OBJECT_CLASS c;
    CK_CERTIFICATE_TYPE cert_type = CKC_X_509;
    CK_KEY_TYPE key_type;
    CK_MECHANISM_TYPE mech_type;
    size_t id_len = strlen(id);

    OPENSSL_ASN1_MALLOC_ENCODE(X509, cert_data, cert_length, cert, ret);
    if (ret)
	goto out;

    OPENSSL_ASN1_MALLOC_ENCODE(X509_NAME, issuer_data, issuer_length, 
			       X509_get_issuer_name(cert), ret);
    if (ret)
	goto out;

    OPENSSL_ASN1_MALLOC_ENCODE(X509_NAME, subject_data, subject_length, 
			       X509_get_subject_name(cert), ret);
    if (ret)
	goto out;

    OPENSSL_ASN1_MALLOC_ENCODE(ASN1_INTEGER, serial_data, serial_length, 
			       X509_get_serialNumber(cert), ret);
    if (ret)
	goto out;

    gpkcs11_log("done parsing, adding to internal structure\n");

    o = add_st_object();
    if (o == NULL) {
	ret = CKR_DEVICE_MEMORY;
	goto out;
    }
    o->type = STO_T_CERTIFICATE;
    o->u.cert = cert;
    public_key = X509_get_pubkey(o->u.cert);

    switch (EVP_PKEY_type(public_key->type)) {
    case EVP_PKEY_RSA:
	key_type = CKK_RSA;
	break;
    case EVP_PKEY_DSA:
	key_type = CKK_DSA;
	break;
    default:
	/* XXX */
	break;
    }

    c = CKO_CERTIFICATE;
    add_object_attribute(o, 0, CKA_CLASS, &c, sizeof(c));
    add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
    add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false));
    add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
    add_object_attribute(o, 0, CKA_LABEL, label, strlen(label));

    add_object_attribute(o, 0, CKA_CERTIFICATE_TYPE, &cert_type, sizeof(cert_type));
    add_object_attribute(o, 0, CKA_ID, id, id_len);

    add_object_attribute(o, 0, CKA_SUBJECT, subject_data, subject_length);
    add_object_attribute(o, 0, CKA_ISSUER, issuer_data, issuer_length);
    add_object_attribute(o, 0, CKA_SERIAL_NUMBER, serial_data, serial_length);
    add_object_attribute(o, 0, CKA_VALUE, cert_data, cert_length);
    if (anchor)
	add_object_attribute(o, 0, CKA_TRUSTED, &bool_true, sizeof(bool_true));
    else
	add_object_attribute(o, 0, CKA_TRUSTED, &bool_false, sizeof(bool_false));

    gpkcs11_log("add cert ok: %lx\n", (unsigned long)OBJECT_ID(o));

    if (anchor) {
	o = add_st_object();
	if (o == NULL) {
	    ret = CKR_DEVICE_MEMORY;
	    goto out;
	}

	o->type = STO_T_NETSCAPE_TRUST;

	c = CKO_NETSCAPE_TRUST;
	add_object_attribute(o, 0, CKA_CLASS, &c, sizeof(c));
	add_object_attribute(o, 0, CKA_LABEL, "IGTF CA Trust", 13);
	add_object_attribute(o, 0, CKA_ID, id, id_len);
	add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
	add_object_attribute(o, 0, CKA_ISSUER, issuer_data, issuer_length);
	add_object_attribute(o, 0, CKA_SUBJECT, subject_data, subject_length);
	add_object_attribute(o, 0, CKA_SERIAL_NUMBER, serial_data, serial_length);
	EVP_Digest(cert_data, cert_length, sha1, NULL, EVP_sha1(), NULL);
	add_object_attribute(o, 0, CKA_CERT_SHA1_HASH, sha1, sizeof(sha1));
	add_object_attribute(o, 0, CKA_TRUST_SERVER_AUTH, &trust_ca, sizeof(trust_ca));
	add_object_attribute(o, 0, CKA_TRUST_CLIENT_AUTH, &trust_ca, sizeof(trust_ca));
	add_object_attribute(o, 0, CKA_TRUST_CODE_SIGNING, &trust_ca, sizeof(trust_ca));
	add_object_attribute(o, 0, CKA_TRUST_EMAIL_PROTECTION, &trust_ca, sizeof(trust_ca));
	gpkcs11_log("add Netscape trust object: %lx\n", (unsigned long)OBJECT_ID(o));
    }

    o = add_st_object();
    if (o == NULL) {
	ret = CKR_DEVICE_MEMORY;
	goto out;
    }
    o->type = STO_T_PUBLIC_KEY;
    o->u.public_key = public_key;

    c = CKO_PUBLIC_KEY;
    add_object_attribute(o, 0, CKA_CLASS, &c, sizeof(c));
    add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
    add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false));
    add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
    add_object_attribute(o, 0, CKA_LABEL, label, strlen(label));

    add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type));
    add_object_attribute(o, 0, CKA_ID, id, id_len);
    add_object_attribute(o, 0, CKA_START_DATE, "", 1); /* XXX */
    add_object_attribute(o, 0, CKA_END_DATE, "", 1); /* XXX */
    add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false));
    add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false));
    mech_type = CKM_RSA_X_509;
    add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type));

    add_object_attribute(o, 0, CKA_SUBJECT, subject_data, subject_length);
    add_object_attribute(o, 0, CKA_ENCRYPT, &bool_true, sizeof(bool_true));
    add_object_attribute(o, 0, CKA_VERIFY, &bool_true, sizeof(bool_true));
    add_object_attribute(o, 0, CKA_VERIFY_RECOVER, &bool_false, sizeof(bool_false));
    add_object_attribute(o, 0, CKA_WRAP, &bool_true, sizeof(bool_true));
    add_object_attribute(o, 0, CKA_TRUSTED, &bool_true, sizeof(bool_true));

    add_pubkey_info(o, key_type, public_key);

    gpkcs11_log("add key ok: %lx\n", (unsigned long)OBJECT_ID(o));

    ret = CKR_OK;

out:
    free(cert_data);
    free(serial_data);
    free(issuer_data);
    free(subject_data);

    return ret;
}