static int store_pubkey(const char* db_name, const char* host, const char* service, time_t expiration, const gnutls_datum_t* pubkey) { FILE* fd = NULL; gnutls_datum_t b64key = { NULL, 0 }; int ret; ret = gnutls_mutex_lock(&_gnutls_file_mutex); if (ret != 0) return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR); ret = raw_pubkey_to_base64(pubkey, &b64key); if (ret < 0) { gnutls_assert(); goto cleanup; } fd = fopen(db_name, "ab+"); if (fd == NULL) { ret = gnutls_assert_val(GNUTLS_E_FILE_ERROR); goto cleanup; } if (service == NULL) service = "*"; if (host == NULL) host = "*"; fprintf(fd, "|g0|%s|%s|%lu|%.*s\n", host, service, (unsigned long)expiration, b64key.size, b64key.data); ret = 0; cleanup: if (fd != NULL) fclose(fd); gnutls_mutex_unlock(&_gnutls_file_mutex); gnutls_free(b64key.data); return ret; }
/*- * _gnutls_pkcs11_privkey_decrypt_data: * @key: Holds the key * @flags: should be 0 for now * @ciphertext: holds the data to be signed * @plaintext: will contain the plaintext, allocated with gnutls_malloc() * * This function will decrypt the given data using the public key algorithm * supported by the private key. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. -*/ int _gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key, unsigned int flags, const gnutls_datum_t * ciphertext, gnutls_datum_t * plaintext) { ck_rv_t rv; int ret; struct ck_mechanism mech; unsigned long siglen; unsigned req_login = 0; unsigned login_flags = SESSION_LOGIN|SESSION_CONTEXT_SPECIFIC; PKCS11_CHECK_INIT_PRIVKEY(key); if (key->pk_algorithm != GNUTLS_PK_RSA) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); mech.mechanism = CKM_RSA_PKCS; mech.parameter = NULL; mech.parameter_len = 0; ret = gnutls_mutex_lock(&key->mutex); if (ret != 0) return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR); /* Initialize signing operation; using the private key discovered * earlier. */ REPEAT_ON_INVALID_HANDLE(rv = pkcs11_decrypt_init(key->sinfo.module, key->sinfo.pks, &mech, key->ref)); if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } retry_login: if (key->reauth || req_login) { if (req_login) login_flags = SESSION_LOGIN|SESSION_FORCE_LOGIN; ret = pkcs11_login(&key->sinfo, &key->pin, key->uinfo, login_flags); if (ret < 0) { gnutls_assert(); _gnutls_debug_log("PKCS #11 login failed, trying operation anyway\n"); /* let's try the operation anyway */ } } /* Work out how long the plaintext must be: */ rv = pkcs11_decrypt(key->sinfo.module, key->sinfo.pks, ciphertext->data, ciphertext->size, NULL, &siglen); if (unlikely(rv == CKR_USER_NOT_LOGGED_IN && req_login == 0)) { req_login = 1; goto retry_login; } if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } plaintext->data = gnutls_malloc(siglen); plaintext->size = siglen; rv = pkcs11_decrypt(key->sinfo.module, key->sinfo.pks, ciphertext->data, ciphertext->size, plaintext->data, &siglen); if (rv != CKR_OK) { gnutls_free(plaintext->data); gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } plaintext->size = siglen; ret = 0; cleanup: gnutls_mutex_unlock(&key->mutex); return ret; }
/*- * _gnutls_pkcs11_privkey_sign_hash: * @key: Holds the key * @hash: holds the data to be signed (should be output of a hash) * @signature: will contain the signature allocated with gnutls_malloc() * * This function will sign the given data using a signature algorithm * supported by the private key. It is assumed that the given data * are the output of a hash function. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. -*/ int _gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key, const gnutls_datum_t * hash, gnutls_datum_t * signature) { ck_rv_t rv; int ret; struct ck_mechanism mech; gnutls_datum_t tmp = { NULL, 0 }; unsigned long siglen; struct pkcs11_session_info *sinfo; unsigned req_login = 0; unsigned login_flags = SESSION_LOGIN|SESSION_CONTEXT_SPECIFIC; PKCS11_CHECK_INIT_PRIVKEY(key); sinfo = &key->sinfo; mech.mechanism = pk_to_mech(key->pk_algorithm); mech.parameter = NULL; mech.parameter_len = 0; ret = gnutls_mutex_lock(&key->mutex); if (ret != 0) return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR); /* Initialize signing operation; using the private key discovered * earlier. */ REPEAT_ON_INVALID_HANDLE(rv = pkcs11_sign_init(sinfo->module, sinfo->pks, &mech, key->ref)); if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } retry_login: if (key->reauth || req_login) { if (req_login) login_flags = SESSION_LOGIN|SESSION_FORCE_LOGIN; ret = pkcs11_login(&key->sinfo, &key->pin, key->uinfo, login_flags); if (ret < 0) { gnutls_assert(); _gnutls_debug_log("PKCS #11 login failed, trying operation anyway\n"); /* let's try the operation anyway */ } } /* Work out how long the signature must be: */ rv = pkcs11_sign(sinfo->module, sinfo->pks, hash->data, hash->size, NULL, &siglen); if (unlikely(rv == CKR_USER_NOT_LOGGED_IN && req_login == 0)) { req_login = 1; goto retry_login; } if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } tmp.data = gnutls_malloc(siglen); tmp.size = siglen; rv = pkcs11_sign(sinfo->module, sinfo->pks, hash->data, hash->size, tmp.data, &siglen); if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); goto cleanup; } if (key->pk_algorithm == GNUTLS_PK_EC || key->pk_algorithm == GNUTLS_PK_DSA) { unsigned int hlen = siglen / 2; gnutls_datum_t r, s; if (siglen % 2 != 0) { gnutls_assert(); ret = GNUTLS_E_PK_SIGN_FAILED; goto cleanup; } r.data = tmp.data; r.size = hlen; s.data = &tmp.data[hlen]; s.size = hlen; ret = _gnutls_encode_ber_rs_raw(signature, &r, &s); if (ret < 0) { gnutls_assert(); goto cleanup; } gnutls_free(tmp.data); tmp.data = NULL; } else { signature->size = siglen; signature->data = tmp.data; } ret = 0; cleanup: gnutls_mutex_unlock(&key->mutex); if (sinfo != &key->sinfo) pkcs11_close_session(sinfo); if (ret < 0) gnutls_free(tmp.data); return ret; }