/* 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; }
/* 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; }
/* * Find all certs of a given type (public or private) */ static int pkcs11_find_certs(PKCS11_TOKEN * token) { PKCS11_SLOT *slot = TOKEN2SLOT(token); PKCS11_CTX *ctx = TOKEN2CTX(token); CK_SESSION_HANDLE session; int rv, res = -1; /* Make sure we have a session */ if (!PRIVSLOT(slot)->haveSession && PKCS11_open_session(slot, 0)) return -1; session = PRIVSLOT(slot)->session; /* Tell the PKCS11 lib to enumerate all matching objects */ cert_search_class = CKO_CERTIFICATE; rv = CRYPTOKI_call(ctx, C_FindObjectsInit(session, cert_search_attrs, numof(cert_search_attrs))); CRYPTOKI_checkerr(PKCS11_F_PKCS11_ENUM_CERTS, rv); do { res = pkcs11_next_cert(ctx, token, session); } while (res == 0); CRYPTOKI_call(ctx, C_FindObjectsFinal(session)); return (res < 0) ? -1 : 0; }
/* * Initialize the token */ int PKCS11_init_token(PKCS11_TOKEN * token, const char *pin, const char *label) { PKCS11_SLOT_private *priv = PRIVSLOT(TOKEN2SLOT(token)); PKCS11_CTX *ctx = priv->parent; int rv; CHECK_FORK(ctx); if (label == NULL) label = "PKCS#11 Token"; rv = CRYPTOKI_call(ctx, C_InitToken(priv->id, (CK_UTF8CHAR *) pin, strlen(pin), (CK_UTF8CHAR *) label)); CRYPTOKI_checkerr(PKCS11_F_PKCS11_INIT_TOKEN, rv); /* FIXME: how to update the token? * PKCS11_CTX_private *cpriv; * int n; * cpriv = PRIVCTX(ctx); * for (n = 0; n < cpriv->nslots; n++) { * if (pkcs11_check_token(ctx, cpriv->slots + n) < 0) * return -1; * } */ return 0; }
/* * Get slotid from private */ unsigned long PKCS11_get_slotid_from_slot(PKCS11_SLOT *slot) { PKCS11_SLOT_private *priv = PRIVSLOT(slot); return priv->id; }
/* * Return keys of a given type (public or private) * Use the cached values if available */ int pkcs11_enumerate_keys(PKCS11_TOKEN *token, unsigned int type, PKCS11_KEY ** keyp, unsigned int *countp) { PKCS11_SLOT *slot = TOKEN2SLOT(token); PKCS11_CTX *ctx = TOKEN2CTX(token); PKCS11_TOKEN_private *tpriv = PRIVTOKEN(token); PKCS11_SLOT_private *spriv = PRIVSLOT(slot); PKCS11_CTX_private *cpriv = PRIVCTX(ctx); PKCS11_keys *keys = (type == CKO_PRIVATE_KEY) ? &tpriv->prv : &tpriv->pub; int rv; if (keys->num < 0) { /* No cache was built for the specified type */ /* Make sure we have a session */ if (!spriv->haveSession && PKCS11_open_session(slot, 0)) return -1; CRYPTO_THREAD_write_lock(cpriv->rwlock); rv = pkcs11_find_keys(token, type); CRYPTO_THREAD_unlock(cpriv->rwlock); if (rv < 0) { pkcs11_destroy_keys(token, type); return -1; } } if (keyp) *keyp = keys->keys; if (countp) *countp = keys->num; return 0; }
/* * Find all keys of a given type (public or private) */ static int pkcs11_find_keys(PKCS11_TOKEN *token, unsigned int type) { PKCS11_SLOT *slot = TOKEN2SLOT(token); PKCS11_CTX *ctx = TOKEN2CTX(token); PKCS11_TOKEN_private *tpriv = PRIVTOKEN(token); PKCS11_SLOT_private *spriv = PRIVSLOT(slot); PKCS11_keys *keys = (type == CKO_PRIVATE_KEY) ? &tpriv->prv : &tpriv->pub; CK_OBJECT_CLASS key_search_class; CK_ATTRIBUTE key_search_attrs[1] = { {CKA_CLASS, &key_search_class, sizeof(key_search_class)}, }; int rv, res = -1; /* Tell the PKCS11 lib to enumerate all matching objects */ key_search_class = type; rv = CRYPTOKI_call(ctx, C_FindObjectsInit(spriv->session, key_search_attrs, 1)); CRYPTOKI_checkerr(PKCS11_F_PKCS11_ENUM_KEYS, rv); keys->num = 0; do { res = pkcs11_next_key(ctx, token, spriv->session, type); } while (res == 0); CRYPTOKI_call(ctx, C_FindObjectsFinal(spriv->session)); return (res < 0) ? -1 : 0; }
/* * Reopens the object associated with the key */ int pkcs11_reload_key(PKCS11_KEY *key) { PKCS11_KEY_private *kpriv = PRIVKEY(key); PKCS11_SLOT *slot = KEY2SLOT(key); PKCS11_SLOT_private *spriv = PRIVSLOT(slot); PKCS11_CTX *ctx = SLOT2CTX(slot); CK_OBJECT_CLASS key_search_class = key->isPrivate ? CKO_PRIVATE_KEY : CKO_PUBLIC_KEY; CK_ATTRIBUTE key_search_attrs[2] = { {CKA_CLASS, &key_search_class, sizeof(key_search_class)}, {CKA_ID, kpriv->id, kpriv->id_len}, }; CK_ULONG count; int rv; /* this is already covered with a per-ctx lock */ rv = CRYPTOKI_call(ctx, C_FindObjectsInit(spriv->session, key_search_attrs, 2)); CRYPTOKI_checkerr(PKCS11_F_PKCS11_ENUM_KEYS, rv); rv = CRYPTOKI_call(ctx, C_FindObjects(spriv->session, &kpriv->object, 1, &count)); CRYPTOKI_checkerr(PKCS11_F_PKCS11_ENUM_KEYS, rv); CRYPTOKI_call(ctx, C_FindObjectsFinal(spriv->session)); return 0; }
/* * Determines if user is authenticated with token */ int PKCS11_is_logged_in(PKCS11_SLOT * slot, int so, int * res) { PKCS11_SLOT_private *priv = PRIVSLOT(slot); PKCS11_CTX *ctx = priv->parent; CK_SESSION_INFO session_info; int rv; if (priv->loggedIn) { *res = 1; return 0; } if (!priv->haveSession) { /* SO gets a r/w session by default, * user gets a r/o session by default. */ if (PKCS11_open_session(slot, so)) return -1; } rv = CRYPTOKI_call(ctx, C_GetSessionInfo(priv->session, &session_info)); CRYPTOKI_checkerr(PKCS11_F_PKCS11_GETSESSIONINFO, rv); if (so) { *res = session_info.state == CKS_RW_SO_FUNCTIONS; } else { *res = session_info.state == CKS_RO_USER_FUNCTIONS || session_info.state == CKS_RW_USER_FUNCTIONS; } return 0; }
/* * Open a session with this slot */ static int pkcs11_open_session(PKCS11_SLOT * slot, int rw, int relogin) { PKCS11_SLOT_private *priv = PRIVSLOT(slot); PKCS11_CTX *ctx = SLOT2CTX(slot); int rv; if (relogin == 0) { CHECK_SLOT_FORK(slot); if (priv->haveSession) { CRYPTOKI_call(ctx, C_CloseSession(priv->session)); priv->haveSession = 0; } } rv = CRYPTOKI_call(ctx, C_OpenSession(priv->id, CKF_SERIAL_SESSION | (rw ? CKF_RW_SESSION : 0), NULL, NULL, &priv->session)); CRYPTOKI_checkerr(PKCS11_F_PKCS11_OPEN_SESSION, rv); priv->haveSession = 1; priv->prev_rw = rw; return 0; }
/* * Find all certs of a given type (public or private) */ static int pkcs11_find_certs(PKCS11_TOKEN *token) { PKCS11_SLOT *slot = TOKEN2SLOT(token); PKCS11_CTX *ctx = SLOT2CTX(slot); PKCS11_TOKEN_private *tpriv = PRIVTOKEN(token); PKCS11_SLOT_private *spriv = PRIVSLOT(slot); CK_OBJECT_CLASS cert_search_class; CK_ATTRIBUTE cert_search_attrs[] = { {CKA_CLASS, &cert_search_class, sizeof(cert_search_class)}, }; int rv, res = -1; /* Tell the PKCS11 lib to enumerate all matching objects */ cert_search_class = CKO_CERTIFICATE; rv = CRYPTOKI_call(ctx, C_FindObjectsInit(spriv->session, cert_search_attrs, 1)); CRYPTOKI_checkerr(PKCS11_F_PKCS11_ENUM_CERTS, rv); tpriv->ncerts = 0; do { res = pkcs11_next_cert(ctx, token, spriv->session); } while (res == 0); CRYPTOKI_call(ctx, C_FindObjectsFinal(spriv->session)); return (res < 0) ? -1 : 0; }
/* * Enumerate all certs on the card */ int pkcs11_enumerate_certs(PKCS11_TOKEN *token, PKCS11_CERT **certp, unsigned int *countp) { PKCS11_SLOT *slot = TOKEN2SLOT(token); PKCS11_CTX *ctx = SLOT2CTX(slot); PKCS11_TOKEN_private *tpriv = PRIVTOKEN(token); PKCS11_SLOT_private *spriv = PRIVSLOT(slot); PKCS11_CTX_private *cpriv = PRIVCTX(ctx); int rv; if (tpriv->ncerts < 0) { /* Make sure we have a session */ if (!spriv->haveSession && PKCS11_open_session(slot, 0)) return -1; CRYPTO_THREAD_write_lock(cpriv->rwlock); rv = pkcs11_find_certs(token); CRYPTO_THREAD_unlock(cpriv->rwlock); if (rv < 0) { pkcs11_destroy_certs(token); return -1; } } if (certp) *certp = tpriv->certs; if (countp) *countp = tpriv->ncerts; return 0; }
int pkcs11_getattr_var(PKCS11_TOKEN * token, CK_OBJECT_HANDLE object, unsigned int type, void *value, size_t * size) { return pkcs11_getattr_int(TOKEN2CTX(token), PRIVSLOT(TOKEN2SLOT(token))->session, object, type, value, size); }
static int pkcs11_check_token(PKCS11_CTX * ctx, PKCS11_SLOT * slot) { PKCS11_SLOT_private *priv = PRIVSLOT(slot); PKCS11_TOKEN_private *tpriv; CK_TOKEN_INFO info; int rv; if (slot->token) { pkcs11_destroy_token(slot->token); } else { slot->token = OPENSSL_malloc(sizeof(PKCS11_TOKEN)); if (slot->token == NULL) return -1; memset(slot->token, 0, sizeof(PKCS11_TOKEN)); } rv = CRYPTOKI_call(ctx, C_GetTokenInfo(priv->id, &info)); if (rv == CKR_TOKEN_NOT_PRESENT || rv == CKR_TOKEN_NOT_RECOGNIZED) { OPENSSL_free(slot->token); slot->token = NULL; return 0; } CRYPTOKI_checkerr(PKCS11_F_PKCS11_CHECK_TOKEN, rv); /* We have a token */ tpriv = OPENSSL_malloc(sizeof(PKCS11_TOKEN_private)); if (tpriv == NULL) return -1; memset(tpriv, 0, sizeof(PKCS11_TOKEN_private)); tpriv->parent = slot; tpriv->prv.keys = NULL; tpriv->prv.num = -1; tpriv->pub.keys = NULL; tpriv->pub.num = -1; tpriv->ncerts = -1; slot->token->label = PKCS11_DUP(info.label); slot->token->manufacturer = PKCS11_DUP(info.manufacturerID); slot->token->model = PKCS11_DUP(info.model); slot->token->serialnr = PKCS11_DUP(info.serialNumber); slot->token->initialized = (info.flags & CKF_TOKEN_INITIALIZED) ? 1 : 0; slot->token->loginRequired = (info.flags & CKF_LOGIN_REQUIRED) ? 1 : 0; slot->token->secureLogin = (info.flags & CKF_PROTECTED_AUTHENTICATION_PATH) ? 1 : 0; slot->token->userPinSet = (info.flags & CKF_USER_PIN_INITIALIZED) ? 1 : 0; slot->token->readOnly = (info.flags & CKF_WRITE_PROTECTED) ? 1 : 0; slot->token->hasRng = (info.flags & CKF_RNG) ? 1 : 0; slot->token->userPinCountLow = (info.flags & CKF_USER_PIN_COUNT_LOW) ? 1 : 0; slot->token->userPinFinalTry = (info.flags & CKF_USER_PIN_FINAL_TRY) ? 1 : 0; slot->token->userPinLocked = (info.flags & CKF_USER_PIN_LOCKED) ? 1 : 0; slot->token->userPinToBeChanged = (info.flags & CKF_USER_PIN_TO_BE_CHANGED) ? 1 : 0; slot->token->soPinCountLow = (info.flags & CKF_SO_PIN_COUNT_LOW) ? 1 : 0; slot->token->soPinFinalTry = (info.flags & CKF_SO_PIN_FINAL_TRY) ? 1 : 0; slot->token->soPinLocked = (info.flags & CKF_SO_PIN_LOCKED) ? 1 : 0; slot->token->soPinToBeChanged = (info.flags & CKF_SO_PIN_TO_BE_CHANGED) ? 1 : 0; slot->token->_private = tpriv; return 0; }
/* 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; }
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; }
/* * Store certificate */ int PKCS11_store_certificate(PKCS11_TOKEN * token, X509 * x509, char *label, unsigned char *id, size_t id_len, PKCS11_CERT ** ret_cert) { PKCS11_SLOT *slot = TOKEN2SLOT(token); PKCS11_CTX *ctx = TOKEN2CTX(token); CK_SESSION_HANDLE session; CK_OBJECT_HANDLE object; CK_ATTRIBUTE attrs[32]; unsigned int n = 0; int rv; /* First, make sure we have a session */ if (!PRIVSLOT(slot)->haveSession && PKCS11_open_session(slot, 1)) return -1; session = PRIVSLOT(slot)->session; /* Now build the template */ pkcs11_addattr_int(attrs + n++, CKA_CLASS, CKO_CERTIFICATE); pkcs11_addattr_bool(attrs + n++, CKA_TOKEN, TRUE); pkcs11_addattr_int(attrs + n++, CKA_CERTIFICATE_TYPE, CKC_X_509); pkcs11_addattr_obj(attrs + n++, CKA_VALUE, (pkcs11_i2d_fn) i2d_X509, x509); if (label) pkcs11_addattr_s(attrs + n++, CKA_LABEL, label); if (id && id_len) pkcs11_addattr(attrs + n++, CKA_ID, id, id_len); /* Now call the pkcs11 module to create the object */ rv = CRYPTOKI_call(ctx, C_CreateObject(session, attrs, n, &object)); /* Zap all memory allocated when building the template */ pkcs11_zap_attrs(attrs, n); CRYPTOKI_checkerr(PKCS11_F_PKCS11_STORE_CERTIFICATE, rv); /* Gobble the key object */ return pkcs11_init_cert(ctx, token, session, object, ret_cert); }
int PKCS11_reopen_session(PKCS11_SLOT * slot) { PKCS11_SLOT_private *priv = PRIVSLOT(slot); PKCS11_CTX *ctx = SLOT2CTX(slot); int rv; rv = CRYPTOKI_call(ctx, C_OpenSession(priv->id, CKF_SERIAL_SESSION | (priv->prev_rw ? CKF_RW_SESSION : 0), NULL, NULL, &priv->session)); CRYPTOKI_checkerr(PKCS11_F_PKCS11_OPEN_SESSION, rv); priv->haveSession = 1; return 0; }
/* * Authenticate with the card. relogin should be set if we automatically * relogin after a fork. */ static int pkcs11_login(PKCS11_SLOT * slot, int so, const char *pin, int relogin) { PKCS11_SLOT_private *priv = PRIVSLOT(slot); PKCS11_CTX *ctx = priv->parent; int rv; if (relogin == 0) { CHECK_SLOT_FORK(slot); /* Calling PKCS11_login 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->loggedIn) { /* already logged in, log out first */ if (PKCS11_logout(slot)) return -1; } } if (!priv->haveSession) { /* SO gets a r/w session by default, * user gets a r/o session by default. */ if (pkcs11_open_session(slot, so, relogin)) return -1; } rv = CRYPTOKI_call(ctx, C_Login(priv->session, so ? CKU_SO : CKU_USER, (CK_UTF8CHAR *) pin, pin ? strlen(pin) : 0)); if (rv && rv != CKR_USER_ALREADY_LOGGED_IN) /* logged in -> OK */ CRYPTOKI_checkerr(PKCS11_F_PKCS11_LOGIN, rv); priv->loggedIn = 1; if (priv->prev_pin != pin) { if (priv->prev_pin) { OPENSSL_cleanse(priv->prev_pin, strlen(priv->prev_pin)); OPENSSL_free(priv->prev_pin); } priv->prev_pin = BUF_strdup(pin); } priv->prev_so = so; return 0; }
/* * 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)); }
/* * Authenticate a private the key operation if needed */ int pkcs11_authenticate(PKCS11_KEY *key) { PKCS11_KEY_private *kpriv = PRIVKEY(key); PKCS11_TOKEN *token = KEY2TOKEN(key); PKCS11_SLOT *slot = TOKEN2SLOT(token); PKCS11_SLOT_private *spriv = PRIVSLOT(slot); PKCS11_CTX *ctx = SLOT2CTX(slot); char pin[MAX_PIN_LENGTH+1]; UI *ui; int rv; /* Handle CKF_PROTECTED_AUTHENTICATION_PATH */ if (token->secureLogin) { rv = CRYPTOKI_call(ctx, C_Login(spriv->session, CKU_CONTEXT_SPECIFIC, NULL, 0)); return rv == CKR_USER_ALREADY_LOGGED_IN ? 0 : rv; } /* Call UI to ask for a PIN */ ui = UI_new_method(kpriv->ui_method); if (ui == NULL) return PKCS11_UI_FAILED; if (kpriv->ui_user_data != NULL) UI_add_user_data(ui, kpriv->ui_user_data); memset(pin, 0, MAX_PIN_LENGTH+1); if (!UI_add_input_string(ui, "PKCS#11 key PIN: ", UI_INPUT_FLAG_DEFAULT_PWD, pin, 4, MAX_PIN_LENGTH)) { UI_free(ui); return PKCS11_UI_FAILED; } if (UI_process(ui)) { UI_free(ui); return PKCS11_UI_FAILED; } UI_free(ui); /* Login with the PIN */ rv = CRYPTOKI_call(ctx, C_Login(spriv->session, CKU_CONTEXT_SPECIFIC, (CK_UTF8CHAR *)pin, strlen(pin))); OPENSSL_cleanse(pin, MAX_PIN_LENGTH+1); return rv == CKR_USER_ALREADY_LOGGED_IN ? 0 : rv; }
/* * 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); }
void pkcs11_release_slot(PKCS11_CTX * ctx, PKCS11_SLOT * slot) { PKCS11_SLOT_private *priv = PRIVSLOT(slot); if (priv) { if (priv->prev_pin) { OPENSSL_cleanse(priv->prev_pin, strlen(priv->prev_pin)); OPENSSL_free(priv->prev_pin); } CRYPTO_destroy_dynlockid(priv->lockid); CRYPTOKI_call(ctx, C_CloseAllSessions(priv->id)); } OPENSSL_free(slot->_private); OPENSSL_free(slot->description); OPENSSL_free(slot->manufacturer); if (slot->token) { pkcs11_destroy_token(slot->token); OPENSSL_free(slot->token); } memset(slot, 0, sizeof(*slot)); }
/* * 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; }
int PKCS11_relogin(PKCS11_SLOT * slot) { PKCS11_SLOT_private *priv = PRIVSLOT(slot); return pkcs11_login(slot, priv->prev_so, priv->prev_pin, 1); }
/* * 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; }