/* * Load the shared library, and initialize it. */ int PKCS11_CTX_load(PKCS11_CTX * ctx, const char *name) { PKCS11_CTX_private *priv = PRIVCTX(ctx); CK_C_INITIALIZE_ARGS args; CK_INFO ck_info; int rv; if (priv->libinfo != NULL) { PKCS11err(PKCS11_F_PKCS11_CTX_LOAD, PKCS11_MODULE_LOADED_ERROR); return -1; } handle = C_LoadModule(name, &priv->method); if (!handle) { PKCS11err(PKCS11_F_PKCS11_CTX_LOAD, PKCS11_LOAD_MODULE_ERROR); return -1; } /* Tell the PKCS11 to initialize itself */ memset(&args, 0, sizeof(args)); args.pReserved = priv->init_args; rv = priv->method->C_Initialize(&args); if (rv && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { PKCS11err(PKCS11_F_PKCS11_CTX_LOAD, rv); return -1; } /* Get info on the library */ rv = priv->method->C_GetInfo(&ck_info); CRYPTOKI_checkerr(PKCS11_F_PKCS11_CTX_LOAD, rv); ctx->manufacturer = PKCS11_DUP(ck_info.manufacturerID); ctx->description = PKCS11_DUP(ck_info.libraryDescription); return 0; }
/* * Generate and store a private key on the token * FIXME: We should check first whether the token supports * on-board key generation, and if it does, use its own algorithm */ int pkcs11_generate_key(PKCS11_TOKEN *token, int algorithm, unsigned int bits, char *label, unsigned char* id, size_t id_len) { PKCS11_KEY *key_obj; EVP_PKEY *pk; RSA *rsa; BIO *err; #if OPENSSL_VERSION_NUMBER >= 0x10100000L BIGNUM *exp = NULL; BN_GENCB *gencb = NULL; #endif int rc; if (algorithm != EVP_PKEY_RSA) { PKCS11err(PKCS11_F_PKCS11_GENERATE_KEY, PKCS11_NOT_SUPPORTED); return -1; } err = BIO_new_fp(stderr, BIO_NOCLOSE); #if OPENSSL_VERSION_NUMBER >= 0x10100000L exp = BN_new(); rsa = RSA_new(); gencb = BN_GENCB_new(); if (gencb) BN_GENCB_set(gencb, NULL, err); if ( rsa == NULL || exp == NULL || gencb == NULL || !BN_set_word(exp, RSA_F4) || !RSA_generate_key_ex(rsa, bits, exp, gencb)) { RSA_free(rsa); } BN_GENCB_free(gencb); BN_free(exp); #else rsa = RSA_generate_key(bits, RSA_F4, NULL, err); #endif BIO_free(err); if (rsa == NULL) { PKCS11err(PKCS11_F_PKCS11_GENERATE_KEY, PKCS11_KEYGEN_FAILED); return -1; } pk = EVP_PKEY_new(); EVP_PKEY_assign_RSA(pk, rsa); rc = pkcs11_store_key(token, pk, CKO_PRIVATE_KEY, label, id, id_len, &key_obj); if (rc == 0) { PKCS11_KEY_private *kpriv; kpriv = PRIVKEY(key_obj); rc = pkcs11_store_key(token, pk, CKO_PUBLIC_KEY, label, kpriv->id, kpriv->id_len, NULL); } EVP_PKEY_free(pk); return rc; }
/* RSA private key decryption */ int pkcs11_private_decrypt(int flen, const unsigned char *from, unsigned char *to, PKCS11_KEY *key, int padding) { PKCS11_SLOT *slot = KEY2SLOT(key); PKCS11_CTX *ctx = KEY2CTX(key); PKCS11_KEY_private *kpriv = PRIVKEY(key); PKCS11_SLOT_private *spriv = PRIVSLOT(slot); CK_MECHANISM mechanism; CK_ULONG size = flen; CK_RV rv; if (pkcs11_mechanism(&mechanism, padding) < 0) return -1; CRYPTO_THREAD_write_lock(PRIVSLOT(slot)->rwlock); rv = CRYPTOKI_call(ctx, C_DecryptInit(spriv->session, &mechanism, kpriv->object)); if (rv == CKR_USER_NOT_LOGGED_IN) rv = pkcs11_authenticate(key); if (!rv) rv = CRYPTOKI_call(ctx, C_Decrypt(spriv->session, (CK_BYTE *)from, size, (CK_BYTE_PTR)to, &size)); CRYPTO_THREAD_unlock(PRIVSLOT(slot)->rwlock); if (rv) { PKCS11err(PKCS11_F_PKCS11_RSA_DECRYPT, pkcs11_map_err(rv)); return -1; } return size; }
/* No padding or other stuff needed. We can call PKCS11 from here */ static int pkcs11_ecdsa_sign(const unsigned char *msg, unsigned int msg_len, unsigned char *sigret, unsigned int *siglen, PKCS11_KEY *key) { int rv; PKCS11_SLOT *slot = KEY2SLOT(key); PKCS11_CTX *ctx = KEY2CTX(key); PKCS11_KEY_private *kpriv = PRIVKEY(key); PKCS11_SLOT_private *spriv = PRIVSLOT(slot); CK_MECHANISM mechanism; CK_ULONG ck_sigsize; ck_sigsize = *siglen; memset(&mechanism, 0, sizeof(mechanism)); mechanism.mechanism = CKM_ECDSA; CRYPTO_THREAD_write_lock(PRIVSLOT(slot)->rwlock); rv = CRYPTOKI_call(ctx, C_SignInit(spriv->session, &mechanism, kpriv->object)); if (!rv) rv = pkcs11_authenticate(key); if (!rv) rv = CRYPTOKI_call(ctx, C_Sign(spriv->session, (CK_BYTE *)msg, msg_len, sigret, &ck_sigsize)); CRYPTO_THREAD_unlock(PRIVSLOT(slot)->rwlock); if (rv) { PKCS11err(PKCS11_F_PKCS11_EC_KEY_SIGN, pkcs11_map_err(rv)); return -1; } *siglen = ck_sigsize; return ck_sigsize; }
/* * Reinitialize (e.g., after a fork). */ int pkcs11_CTX_reload(PKCS11_CTX * ctx) { PKCS11_CTX_private *cpriv = PRIVCTX(ctx); CK_C_INITIALIZE_ARGS _args; CK_C_INITIALIZE_ARGS *args = NULL; int rv; if (cpriv->method == NULL) /* Module not loaded */ return 0; /* Tell the PKCS11 to initialize itself */ if (cpriv->init_args != NULL) { memset(&_args, 0, sizeof(_args)); args = &_args; args->pReserved = cpriv->init_args; } rv = cpriv->method->C_Initialize(args); if (rv && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { PKCS11err(PKCS11_F_PKCS11_CTX_LOAD, rv); return -1; } /* Reinitialize the PKCS11 internal slot table */ return pkcs11_enumerate_slots(ctx, NULL, NULL); }
/** * ECDSA signing method (replaces ossl_ecdsa_sign_sig) * * @param dgst hash value to sign * @param dlen length of the hash value * @param kinv precomputed inverse k (from the sign_setup method) * @param rp precomputed rp (from the sign_setup method) * @param ec private EC signing key * @return pointer to a ECDSA_SIG structure or NULL if an error occurred */ static ECDSA_SIG *pkcs11_ecdsa_sign_sig(const unsigned char *dgst, int dlen, const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *ec) { unsigned char sigret[512]; /* HACK for now */ ECDSA_SIG *sig; PKCS11_KEY *key; unsigned int siglen; BIGNUM *r, *s, *order; (void)kinv; /* Precomputed values are not used for PKCS#11 */ (void)rp; /* Precomputed values are not used for PKCS#11 */ #if OPENSSL_VERSION_NUMBER >= 0x10100000L key = (PKCS11_KEY *)EC_KEY_get_ex_data(ec, ec_ex_index); #else key = (PKCS11_KEY *)ECDSA_get_ex_data(ec, ec_ex_index); #endif if (key == NULL) { PKCS11err(PKCS11_F_PKCS11_EC_KEY_SIGN, PKCS11_ALIEN_KEY); return NULL; } /* TODO: Add an atfork check */ /* Truncate digest if its byte size is longer than needed */ order = BN_new(); if (order) { const EC_GROUP *group = EC_KEY_get0_group(ec); if (group && EC_GROUP_get_order(group, order, NULL)) { int klen = BN_num_bits(order); if (klen < 8*dlen) dlen = (klen+7)/8; } BN_free(order); } siglen = sizeof sigret; if (pkcs11_ecdsa_sign(dgst, dlen, sigret, &siglen, key) <= 0) return NULL; sig = ECDSA_SIG_new(); if (sig == NULL) return NULL; #if OPENSSL_VERSION_NUMBER >= 0x10100000L ECDSA_SIG_get0(&r, &s, sig); #else r = sig->r; s = sig->s; #endif BN_bin2bn(sigret, siglen/2, r); BN_bin2bn(sigret + siglen/2, siglen/2, s); return sig; }
/* TODO: remove this function in libp11 0.5.0 */ int pkcs11_verify(int type, const unsigned char *m, unsigned int m_len, unsigned char *signature, unsigned int siglen, PKCS11_KEY *key) { (void)type; (void)m; (void)m_len; (void)signature; (void)siglen; (void)key; /* PKCS11 calls go here */ PKCS11err(PKCS11_F_PKCS11_RSA_VERIFY, PKCS11_NOT_SUPPORTED); return -1; }
/* * Load the shared library, and initialize it. */ int pkcs11_CTX_load(PKCS11_CTX * ctx, const char *name) { PKCS11_CTX_private *cpriv = PRIVCTX(ctx); CK_C_INITIALIZE_ARGS _args; CK_C_INITIALIZE_ARGS *args = NULL; CK_INFO ck_info; int rv; cpriv->handle = C_LoadModule(name, &cpriv->method); if (cpriv->handle == NULL) { PKCS11err(PKCS11_F_PKCS11_CTX_LOAD, PKCS11_LOAD_MODULE_ERROR); return -1; } /* Tell the PKCS11 to initialize itself */ if (cpriv->init_args != NULL) { memset(&_args, 0, sizeof(_args)); args = &_args; /* Unconditionally say using OS locking primitives is OK */ args->flags |= CKF_OS_LOCKING_OK; args->pReserved = cpriv->init_args; } rv = cpriv->method->C_Initialize(args); if (rv && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { PKCS11err(PKCS11_F_PKCS11_CTX_LOAD, rv); return -1; } /* Get info on the library */ rv = cpriv->method->C_GetInfo(&ck_info); CRYPTOKI_checkerr(PKCS11_F_PKCS11_CTX_LOAD, rv); ctx->manufacturer = PKCS11_DUP(ck_info.manufacturerID); ctx->description = PKCS11_DUP(ck_info.libraryDescription); return 0; }
int pkcs11_getattr_bn(PKCS11_TOKEN * token, CK_OBJECT_HANDLE object, unsigned int type, BIGNUM ** bn) { CK_BYTE binary[4196 / 8]; size_t size = sizeof(binary); if (pkcs11_getattr_var(token, object, type, binary, &size)) return -1; if (size == -1) { PKCS11err(PKCS11_F_PKCS11_GETATTR, pkcs11_map_err(CKR_ATTRIBUTE_TYPE_INVALID)); return -1; } *bn = BN_bin2bn(binary, size, *bn); return *bn ? 0 : -1; }
/* OpenSSL assumes that the output buffer is always big enough */ int pkcs11_private_encrypt(int flen, const unsigned char *from, unsigned char *to, PKCS11_KEY *key, int padding) { PKCS11_SLOT *slot = KEY2SLOT(key); PKCS11_CTX *ctx = KEY2CTX(key); PKCS11_KEY_private *kpriv = PRIVKEY(key); PKCS11_SLOT_private *spriv = PRIVSLOT(slot); CK_MECHANISM mechanism; CK_ULONG size; int rv; size = pkcs11_get_key_size(key); if (pkcs11_mechanism(&mechanism, padding) < 0) return -1; CRYPTO_THREAD_write_lock(PRIVSLOT(slot)->rwlock); /* Try signing first, as applications are more likely to use it */ rv = CRYPTOKI_call(ctx, C_SignInit(spriv->session, &mechanism, kpriv->object)); if (rv == CKR_USER_NOT_LOGGED_IN) rv = pkcs11_authenticate(key); if (!rv) rv = CRYPTOKI_call(ctx, C_Sign(spriv->session, (CK_BYTE *)from, flen, to, &size)); if (rv == CKR_KEY_FUNCTION_NOT_PERMITTED) { /* OpenSSL may use it for encryption rather than signing */ rv = CRYPTOKI_call(ctx, C_EncryptInit(spriv->session, &mechanism, kpriv->object)); if (rv == CKR_USER_NOT_LOGGED_IN) rv = pkcs11_authenticate(key); if (!rv) rv = CRYPTOKI_call(ctx, C_Encrypt(spriv->session, (CK_BYTE *)from, flen, to, &size)); } CRYPTO_THREAD_unlock(PRIVSLOT(slot)->rwlock); if (rv) { PKCS11err(PKCS11_F_PKCS11_RSA_ENCRYPT, pkcs11_map_err(rv)); return -1; } return size; }
int PKCS11_private_decrypt(int flen, const unsigned char *from, unsigned char *to, PKCS11_KEY * key, int padding) { CK_RV rv; PKCS11_KEY_private *priv; PKCS11_SLOT *slot; PKCS11_CTX *ctx; CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_ULONG size = flen; if (padding != RSA_PKCS1_PADDING) { printf("pkcs11 engine: only RSA_PKCS1_PADDING allowed so far\n"); return -1; } if (key == NULL) return -1; /* PKCS11 calls go here */ ctx = KEY2CTX(key); priv = PRIVKEY(key); slot = TOKEN2SLOT(priv->parent); CHECK_KEY_FORK(key); session = PRIVSLOT(slot)->session; memset(&mechanism, 0, sizeof(mechanism)); mechanism.mechanism = CKM_RSA_PKCS; pkcs11_w_lock(PRIVSLOT(slot)->lockid); rv = CRYPTOKI_call(ctx, C_DecryptInit(session, &mechanism, priv->object)) || CRYPTOKI_call(ctx, C_Decrypt(session, (CK_BYTE *) from, (CK_ULONG)flen, (CK_BYTE_PTR)to, &size)); pkcs11_w_unlock(PRIVSLOT(slot)->lockid); if (rv) { PKCS11err(PKCS11_F_PKCS11_RSA_DECRYPT, pkcs11_map_err(rv)); } return rv ? 0 : size; }
/* * Set the User PIN */ int PKCS11_init_pin(PKCS11_TOKEN * token, const char *pin) { PKCS11_SLOT_private *priv = PRIVSLOT(TOKEN2SLOT(token)); PKCS11_CTX *ctx = priv->parent; int len, rv; CHECK_FORK(ctx); if (!priv->haveSession) { PKCS11err(PKCS11_F_PKCS11_INIT_PIN, PKCS11_NO_SESSION); return -1; } len = pin ? strlen(pin) : 0; rv = CRYPTOKI_call(ctx, C_InitPIN(priv->session, (CK_UTF8CHAR *) pin, len)); CRYPTOKI_checkerr(PKCS11_F_PKCS11_INIT_PIN, rv); return pkcs11_check_token(ctx, TOKEN2SLOT(token)); }
/* * Generate random numbers */ int PKCS11_generate_random(PKCS11_SLOT *slot, unsigned char *r, unsigned int r_len) { PKCS11_SLOT_private *priv = PRIVSLOT(slot); PKCS11_CTX *ctx = priv->parent; int rv; CHECK_SLOT_FORK(slot); if (!priv->haveSession && PKCS11_open_session(slot, 0)) { PKCS11err(PKCS11_F_PKCS11_GENERATE_RANDOM, PKCS11_NO_SESSION); return -1; } rv = CRYPTOKI_call(ctx, C_GenerateRandom(priv->session, (CK_BYTE_PTR) r, r_len)); CRYPTOKI_checkerr(PKCS11_F_PKCS11_GENERATE_RANDOM, rv); return pkcs11_check_token(ctx, slot); }
/* * Seed the random number generator */ int PKCS11_seed_random(PKCS11_SLOT *slot, const unsigned char *s, unsigned int s_len) { PKCS11_SLOT_private *priv = PRIVSLOT(slot); PKCS11_CTX *ctx = priv->parent; int rv; CHECK_SLOT_FORK(slot); if (!priv->haveSession && PKCS11_open_session(slot, 0)) { PKCS11err(PKCS11_F_PKCS11_SEED_RANDOM, PKCS11_NO_SESSION); return -1; } rv = CRYPTOKI_call(ctx, C_SeedRandom(priv->session, (CK_BYTE_PTR) s, s_len)); CRYPTOKI_checkerr(PKCS11_F_PKCS11_SEED_RANDOM, rv); return pkcs11_check_token(ctx, slot); }
int PKCS11_ecdsa_sign(const unsigned char *m, unsigned int m_len, unsigned char *sigret, unsigned int *siglen, PKCS11_KEY * key) { /* signature size is the issue, will assume caller has a big buffer ! */ /* No padding or other stuff needed, we can cal PKCS11 from here */ int rv; PKCS11_KEY_private *priv; PKCS11_SLOT *slot; PKCS11_CTX *ctx; CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_ULONG ck_sigsize; ctx = KEY2CTX(key); priv = PRIVKEY(key); slot = TOKEN2SLOT(priv->parent); CHECK_KEY_FORK(key); session = PRIVSLOT(slot)->session; ck_sigsize = *siglen; memset(&mechanism, 0, sizeof(mechanism)); mechanism.mechanism = CKM_ECDSA; pkcs11_w_lock(PRIVSLOT(slot)->lockid); rv = CRYPTOKI_call(ctx, C_SignInit(session, &mechanism, priv->object)) || CRYPTOKI_call(ctx, C_Sign(session, (CK_BYTE *) m, m_len, sigret, &ck_sigsize)); pkcs11_w_unlock(PRIVSLOT(slot)->lockid); if (rv) { PKCS11err(PKCS11_F_PKCS11_EC_KEY_SIGN, pkcs11_map_err(rv)); return -1; } *siglen = ck_sigsize; return ck_sigsize; }
/* * Change the User PIN */ int PKCS11_change_pin(PKCS11_SLOT * slot, const char *old_pin, const char *new_pin) { PKCS11_SLOT_private *priv = PRIVSLOT(slot); PKCS11_CTX *ctx = priv->parent; int old_len, new_len, rv; CHECK_SLOT_FORK(slot); if (!priv->haveSession) { PKCS11err(PKCS11_F_PKCS11_CHANGE_PIN, PKCS11_NO_SESSION); return -1; } old_len = old_pin ? strlen(old_pin) : 0; new_len = new_pin ? strlen(new_pin) : 0; rv = CRYPTOKI_call(ctx, C_SetPIN(priv->session, (CK_UTF8CHAR *) old_pin, old_len, (CK_UTF8CHAR *) new_pin, new_len)); CRYPTOKI_checkerr(PKCS11_F_PKCS11_CHANGE_PIN, rv); return pkcs11_check_token(ctx, slot); }
/* * Log out */ int PKCS11_logout(PKCS11_SLOT * slot) { PKCS11_SLOT_private *priv = PRIVSLOT(slot); PKCS11_CTX *ctx = priv->parent; int rv; CHECK_SLOT_FORK(slot); /* Calling PKCS11_logout invalidates all cached * keys we have */ if (slot->token) { pkcs11_destroy_keys(slot->token, CKO_PRIVATE_KEY); pkcs11_destroy_keys(slot->token, CKO_PUBLIC_KEY); } if (!priv->haveSession) { PKCS11err(PKCS11_F_PKCS11_LOGOUT, PKCS11_NO_SESSION); return -1; } rv = CRYPTOKI_call(ctx, C_Logout(priv->session)); CRYPTOKI_checkerr(PKCS11_F_PKCS11_LOGOUT, rv); priv->loggedIn = 0; return 0; }
/* initial code will only support what is needed for pkcs11_ec_ckey * i.e. CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE * and CK_EC_KDF_TYPE supported by token * The secret key object is deleted * * In future CKM_ECMQV_DERIVE with CK_ECMQV_DERIVE_PARAMS * could also be supported, and the secret key object could be returned. */ static int pkcs11_ecdh_derive(unsigned char **out, size_t *outlen, const unsigned long ecdh_mechanism, const void * ec_params, void *outnewkey, PKCS11_KEY * key) { PKCS11_SLOT *slot = KEY2SLOT(key); PKCS11_CTX *ctx = KEY2CTX(key); PKCS11_TOKEN *token = KEY2TOKEN(key); PKCS11_KEY_private *kpriv = PRIVKEY(key); PKCS11_SLOT_private *spriv = PRIVSLOT(slot); CK_MECHANISM mechanism; int rv; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_OBJECT_HANDLE newkey = CK_INVALID_HANDLE; CK_OBJECT_CLASS newkey_class= CKO_SECRET_KEY; CK_KEY_TYPE newkey_type = CKK_GENERIC_SECRET; CK_OBJECT_HANDLE * tmpnewkey = (CK_OBJECT_HANDLE *)outnewkey; CK_ATTRIBUTE newkey_template[] = { {CKA_TOKEN, &false, sizeof(false)}, /* session only object */ {CKA_CLASS, &newkey_class, sizeof(newkey_class)}, {CKA_KEY_TYPE, &newkey_type, sizeof(newkey_type)}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_DECRYPT, &true, sizeof(true)} }; memset(&mechanism, 0, sizeof(mechanism)); mechanism.mechanism = ecdh_mechanism; mechanism.pParameter = (void*)ec_params; switch (ecdh_mechanism) { case CKM_ECDH1_DERIVE: case CKM_ECDH1_COFACTOR_DERIVE: mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS); break; #if 0 /* TODO */ case CK_ECMQV_DERIVE_PARAMS: mechanism.ulParameterLen = sizeof(CK_ECMQV_DERIVE_PARAMS); break; #endif default: PKCS11err(PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, pkcs11_map_err(PKCS11_NOT_SUPPORTED)); return -1; } rv = CRYPTOKI_call(ctx, C_DeriveKey(spriv->session, &mechanism, kpriv->object, newkey_template, 5, &newkey)); CRYPTOKI_checkerr(PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, rv); /* Return the value of the secret key and/or the object handle of the secret key */ if (out && outlen) { /* pkcs11_ec_ckey only asks for the value */ if (pkcs11_getattr_alloc(token, newkey, CKA_VALUE, out, outlen)) { PKCS11err(PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, pkcs11_map_err(CKR_ATTRIBUTE_VALUE_INVALID)); CRYPTOKI_call(ctx, C_DestroyObject(spriv->session, newkey)); return -1; } } if (tmpnewkey) /* For future use (not used by pkcs11_ec_ckey) */ *tmpnewkey = newkey; else /* Destroy the temporary key */ CRYPTOKI_call(ctx, C_DestroyObject(spriv->session, newkey)); return 0; }
/* initial code will only support what is needed for pkcs11_ec_ckey * i.e. CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE * and CK_EC_KDF_TYPE supported by token * The secret key object is deleted * * In future CKM_ECMQV_DERIVE with CK_ECMQV_DERIVE_PARAMS * could also be supported, and the secret key object could be returned. */ int pkcs11_ecdh_derive_internal(unsigned char **out, size_t *outlen, const unsigned long ecdh_mechanism, const void * ec_params, void *outnewkey, PKCS11_KEY * key) { int rv; int ret = -1; unsigned char * buf = NULL; size_t buflen; PKCS11_KEY_private *priv; PKCS11_SLOT *slot; PKCS11_CTX *ctx; PKCS11_TOKEN *token; CK_SESSION_HANDLE session; CK_MECHANISM mechanism; CK_BBOOL true = TRUE; CK_BBOOL false = FALSE; CK_OBJECT_HANDLE newkey = CK_INVALID_HANDLE; CK_OBJECT_CLASS newkey_class= CKO_SECRET_KEY; CK_KEY_TYPE newkey_type = CKK_GENERIC_SECRET; CK_OBJECT_HANDLE * tmpnewkey = (CK_OBJECT_HANDLE *)outnewkey; CK_ATTRIBUTE newkey_template[] = { {CKA_TOKEN, &false, sizeof(false)}, /* session only object */ {CKA_CLASS, &newkey_class, sizeof(newkey_class)}, {CKA_KEY_TYPE, &newkey_type, sizeof(newkey_type)}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_DECRYPT, &true, sizeof(true)} }; ctx = KEY2CTX(key); priv = PRIVKEY(key); token = KEY2TOKEN(key); slot = KEY2SLOT(key); CHECK_KEY_FORK(key); session = PRIVSLOT(slot)->session; memset(&mechanism, 0, sizeof(mechanism)); mechanism.mechanism = ecdh_mechanism; mechanism.pParameter = (void*)ec_params; switch (ecdh_mechanism) { case CKM_ECDH1_DERIVE: case CKM_ECDH1_COFACTOR_DERIVE: mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS); break; // case CK_ECMQV_DERIVE_PARAMS: // mechanism.ulParameterLen = sizeof(CK_ECMQV_DERIVE_PARAMS); // break; default: PKCS11err(PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, PKCS11_NOT_SUPPORTED); goto err; } CRYPTO_w_lock(PRIVSLOT(slot)->lockid); rv = CRYPTOKI_call(ctx, C_DeriveKey(session, &mechanism, priv->object, newkey_template, 5, &newkey)); if (rv) { PKCS11err(PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, pkcs11_map_err(rv)); goto err; } /* Return the value of the secret key and/or the object handle of the secret key */ /* pkcs11_ec_ckey only asks for the value */ if (out && outlen) { /* get size of secret key value */ if (!pkcs11_getattr_var(token, newkey, CKA_VALUE, NULL, &buflen) && buflen > 0) { buf = OPENSSL_malloc(buflen); if (buf == NULL) { PKCS11err(PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, pkcs11_map_err(CKR_HOST_MEMORY)); goto err; } } else { PKCS11err(PKCS11_F_PKCS11_EC_KEY_COMPUTE_KEY, pkcs11_map_err(CKR_ATTRIBUTE_VALUE_INVALID)); goto err; } pkcs11_getattr_var(token, newkey, CKA_VALUE, buf, &buflen); *out = buf; *outlen = buflen; buf = NULL; } /* not used by pkcs11_ec_ckey for future use */ if (tmpnewkey) { *tmpnewkey = newkey; newkey = CK_INVALID_HANDLE; } ret = 1; err: if (buf) OPENSSL_free(buf); if (newkey != CK_INVALID_HANDLE && session != CK_INVALID_HANDLE) CRYPTOKI_call(ctx, C_DestroyObject(session, newkey)); return ret; }
int PKCS11_private_encrypt(int flen, const unsigned char *from, unsigned char *to, PKCS11_KEY * key, int padding) { PKCS11_KEY_private *priv; PKCS11_SLOT *slot; PKCS11_CTX *ctx; CK_SESSION_HANDLE session; CK_MECHANISM mechanism; int rv; int sigsize; CK_ULONG ck_sigsize; if (key == NULL) return -1; sigsize=PKCS11_get_key_size(key); ck_sigsize=sigsize; memset(&mechanism, 0, sizeof(mechanism)); switch (padding) { case RSA_NO_PADDING: mechanism.mechanism = CKM_RSA_X_509; break; case RSA_PKCS1_PADDING: if ((flen + RSA_PKCS1_PADDING_SIZE) > sigsize) { return -1; /* the size is wrong */ } mechanism.mechanism = CKM_RSA_PKCS; break; default: printf("pkcs11 engine: only RSA_NO_PADDING or RSA_PKCS1_PADDING allowed so far\n"); return -1; } ctx = KEY2CTX(key); priv = PRIVKEY(key); slot = TOKEN2SLOT(priv->parent); CHECK_KEY_FORK(key); session = PRIVSLOT(slot)->session; pkcs11_w_lock(PRIVSLOT(slot)->lockid); /* API is somewhat fishy here. *siglen is 0 on entry (cleared * by OpenSSL). The library assumes that the memory passed * by the caller is always big enough */ rv = CRYPTOKI_call(ctx, C_SignInit(session, &mechanism, priv->object)) || CRYPTOKI_call(ctx, C_Sign(session, (CK_BYTE *) from, flen, to, &ck_sigsize)); pkcs11_w_unlock(PRIVSLOT(slot)->lockid); if (rv) { PKCS11err(PKCS11_F_PKCS11_RSA_SIGN, pkcs11_map_err(rv)); return -1; } if ((unsigned)sigsize != ck_sigsize) return -1; return sigsize; }
/* * Store private key */ static int pkcs11_store_key(PKCS11_TOKEN *token, EVP_PKEY *pk, unsigned int type, char *label, unsigned char *id, size_t id_len, PKCS11_KEY ** ret_key) { PKCS11_SLOT *slot = TOKEN2SLOT(token); PKCS11_CTX *ctx = TOKEN2CTX(token); PKCS11_SLOT_private *spriv = PRIVSLOT(slot); CK_OBJECT_HANDLE object; CK_ATTRIBUTE attrs[32]; unsigned int n = 0; int rv; const BIGNUM *rsa_n, *rsa_e, *rsa_d, *rsa_p, *rsa_q; /* First, make sure we have a session */ if (!spriv->haveSession && PKCS11_open_session(slot, 1)) return -1; /* Now build the key attrs */ pkcs11_addattr_int(attrs + n++, CKA_CLASS, type); if (label) pkcs11_addattr_s(attrs + n++, CKA_LABEL, label); if (id && id_len) pkcs11_addattr(attrs + n++, CKA_ID, id, id_len); pkcs11_addattr_bool(attrs + n++, CKA_TOKEN, TRUE); if (type == CKO_PRIVATE_KEY) { pkcs11_addattr_bool(attrs + n++, CKA_PRIVATE, TRUE); pkcs11_addattr_bool(attrs + n++, CKA_SENSITIVE, TRUE); pkcs11_addattr_bool(attrs + n++, CKA_DECRYPT, TRUE); pkcs11_addattr_bool(attrs + n++, CKA_SIGN, TRUE); pkcs11_addattr_bool(attrs + n++, CKA_UNWRAP, TRUE); } else { /* CKO_PUBLIC_KEY */ pkcs11_addattr_bool(attrs + n++, CKA_ENCRYPT, TRUE); pkcs11_addattr_bool(attrs + n++, CKA_VERIFY, TRUE); pkcs11_addattr_bool(attrs + n++, CKA_WRAP, TRUE); } #if OPENSSL_VERSION_NUMBER >= 0x10100003L if (EVP_PKEY_base_id(pk) == EVP_PKEY_RSA) { RSA *rsa = EVP_PKEY_get1_RSA(pk); #else if (pk->type == EVP_PKEY_RSA) { RSA *rsa = pk->pkey.rsa; #endif pkcs11_addattr_int(attrs + n++, CKA_KEY_TYPE, CKK_RSA); #if OPENSSL_VERSION_NUMBER >= 0x10100005L RSA_get0_key(rsa, &rsa_n, &rsa_e, &rsa_d); RSA_get0_factors(rsa, &rsa_p, &rsa_q); #else rsa_n=rsa->n; rsa_e=rsa->e; rsa_d=rsa->d; rsa_p=rsa->p; rsa_q=rsa->q; #endif pkcs11_addattr_bn(attrs + n++, CKA_MODULUS, rsa_n); pkcs11_addattr_bn(attrs + n++, CKA_PUBLIC_EXPONENT, rsa_e); if (type == CKO_PRIVATE_KEY) { pkcs11_addattr_bn(attrs + n++, CKA_PRIVATE_EXPONENT, rsa_d); pkcs11_addattr_bn(attrs + n++, CKA_PRIME_1, rsa_p); pkcs11_addattr_bn(attrs + n++, CKA_PRIME_2, rsa_q); } } else { pkcs11_zap_attrs(attrs, n); PKCS11err(type == CKO_PRIVATE_KEY ? PKCS11_F_PKCS11_STORE_PRIVATE_KEY : PKCS11_F_PKCS11_STORE_PUBLIC_KEY, PKCS11_NOT_SUPPORTED); return -1; } /* Now call the pkcs11 module to create the object */ rv = CRYPTOKI_call(ctx, C_CreateObject(spriv->session, attrs, n, &object)); /* Zap all memory allocated when building the template */ pkcs11_zap_attrs(attrs, n); CRYPTOKI_checkerr(PKCS11_F_PKCS11_STORE_PRIVATE_KEY, rv); /* Gobble the key object */ return pkcs11_init_key(ctx, token, spriv->session, object, type, ret_key); } /* * Get the key type */ int pkcs11_get_key_type(PKCS11_KEY *key) { PKCS11_KEY_private *kpriv = PRIVKEY(key); return kpriv->ops->type; }