summaryrefslogtreecommitdiffstats
path: root/src/help.rs
blob: 5d5e72cca58a1c89793dd820397d2d5443539ed8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/// Help text.
pub const HELP: &str = r###"# felix v2.8.0
A simple TUI file manager with vim-like keymapping.

## Usage
`fx` => Show items in the current directory.
`fx <directory path>` => Show items in the path.
Both relative and absolute path available.

## Options
`--help` | `-h`   => Print help.
`--log`  | `-l`   => Launch the app, automatically generating a log file.
`--init`          => Returns a shell script that can be sourcedfor
                     for shell integration.

## Manual
j / <Down>         :Go down.
k / <Up>           :Go up.
h / <Left>         :Go to the parent directory if exists.
l / <Right> / <CR> :Open item or change directory.
gg                 :Go to the top.
G                  :Go to the bottom.
z<CR>              :Go to the home directory.
z{keyword}<CR>     :Jump to a directory that matches the keyword.
                    (zoxide required)
<C-o>              :Jump backward.
<C-i>              :Jump forward.
i{file name}<CR>   :Create a new empty file.
I{dir name}<CR>    :Create a new empty directory.
o                  :Open item in a new window.
e                  :Unpack archive/compressed file.
dd                 :Delete and yank item.
yy                 :Yank item.
p                  :Put yanked item(s) from register zero
                    in the current directory.
:reg               :Show registers. To hide it, press v.
"ayy               :Yank item to register a.
"add               :Delete and yank item to register a.
"Ayy               :Append item to register a.
"Add               :Delete and append item to register a.
"ap                :Put item(s) from register a.
V                  :Switch to the linewise visual mode.
  - y              :In the visual mode, yank selected item(s).
  - d              :In the visual mode, delete and yank selected item(s).
  - "ay            :In the visual mode, yank items to register a.
  - "ad            :In the visual mode, delete and yank items to register a.
  - "Ay            :In the visual mode, append items to register a.
  - "Ad            :In the visual mode, delete and append items to register a.
u                  :Undo put/delete/rename.
<C-r>              :Redo put/delete/rename.
v                  :Toggle whether to show the preview.
s                  :Toggle between vertical / horizontal split in the preview mode.
<Alt-j>
 / <Alt-<Down>>    :Scroll down the preview text.
<Alt-k> / 
 / <Alt-<Up>>      :Scroll up the preview text.
<BS>               :Toggle whether to show hidden items.
t                  :Toggle the sort order (name <-> modified time).
:                  :Switch to the command line.
  - <C-r>a         :In the command line, paste item name in register a.
c                  :Switch to the rename mode.
/                  :Search items by a keyword.
n                  :Go forward to the item that matches the keyword.
N                  :Go backward to the item that matches the keyword.
<Esc>              :Return to the normal mode.
:cd<CR>            :Go to the home directory.
:cd{path}<CR>      :Go to the path.
:e<CR>             :Reload the current directory.
:trash<CR>         :Go to the trash directory.
:empty<CR>         :Empty the trash directory.
:h<CR>             :Show help.
:q<CR>             :Exit.
ZZ                 :Exit without cd to last working directory
                    (if `match_vim_exit_behavior` is `false`).
ZQ                 :cd into the last working directory and exit
                    (if shell setting is ready and `match_vim_exit_behavior is `false`).

## Preview feature
By default, text files and directories can be previewed.
To preview images, you need to install chafa (>= v1.10.0).
Please see https://hpjansson.org/chafa/

## Configuration

*Both `config.yaml` and `config.yml` work.*

### Linux
config file    : $XDG_CONFIG_HOME/felix/config.yaml(config.yml)
trash directory: $XDG_DATA_HOME/felix/trash
log files      : $XDG_DATA_HOME/felix/log

### macOS
On macOS, felix looks for the config file in the following locations:

1. `$HOME/Library/Application Support/felix/config.yaml(config.yml)`
2. `$HOME/.config/felix/config.yaml`

trash directory: $HOME/Library/Application Support/felix/trash
log files      : $HOME/Library/Application Support/felix/log

### Windows
config file     : $PROFILE\\AppData\\Roaming\\felix\\config.yaml(config.yml)
trash directory : $PROFILE\\AppData\\Local\\felix\\trash
log files       : $PROFILE\\AppData\\Local\\felix\\log

For more details, visit https://github.com/kyoheiu/felix
"###;
much bigger deal than just re-setting an allocated resource.)
*/
-#ifdef FIPS_MODULE
-# define get_entropy prov_crngt_get_entropy
-# define cleanup_entropy prov_crngt_cleanup_entropy
-#else
-# define get_entropy prov_drbg_get_entropy
-# define cleanup_entropy prov_drbg_cleanup_entropy
-#endif
-
/* NIST SP 800-90A DRBG recommends the use of a personalization string. */
static const char ossl_pers_string[] = DRBG_DEFAULT_PERS_STRING;
-static unsigned int master_reseed_interval = MASTER_RESEED_INTERVAL;
-static unsigned int slave_reseed_interval = SLAVE_RESEED_INTERVAL;
-
-static time_t master_reseed_time_interval = MASTER_RESEED_TIME_INTERVAL;
-static time_t slave_reseed_time_interval = SLAVE_RESEED_TIME_INTERVAL;
-
static const OSSL_DISPATCH *find_call(const OSSL_DISPATCH *dispatch,
int function);
+static int rand_drbg_restart(PROV_DRBG *drbg);
+
int drbg_lock(void *vctx)
{
PROV_DRBG *drbg = vctx;
@@ -71,14 +62,12 @@ void drbg_unlock(void *vctx)
static int drbg_lock_parent(PROV_DRBG *drbg)
{
void *parent = drbg->parent;
- const OSSL_DISPATCH *pfunc;
- if (parent != NULL) {
- pfunc = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_LOCK);
- if (pfunc != NULL && !OSSL_get_OP_rand_lock(pfunc)(parent)) {
- ERR_raise(ERR_LIB_PROV, RAND_R_PARENT_LOCKING_NOT_ENABLED);
- return 0;
- }
+ if (parent != NULL
+ && drbg->parent_lock != NULL
+ && !drbg->parent_lock(parent)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_PARENT_LOCKING_NOT_ENABLED);
+ return 0;
}
return 1;
}
@@ -86,74 +75,62 @@ static int drbg_lock_parent(PROV_DRBG *drbg)
static void drbg_unlock_parent(PROV_DRBG *drbg)
{
void *parent = drbg->parent;
- const OSSL_DISPATCH *pfunc;
- if (parent != NULL) {
- pfunc = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_UNLOCK);
- if (pfunc != NULL)
- OSSL_get_OP_rand_unlock(pfunc)(parent);
- }
+ if (parent != NULL && drbg->parent_unlock != NULL)
+ drbg->parent_unlock(parent);
}
-static int get_parent_strength(PROV_DRBG *drbg, int *str)
+static int get_parent_strength(PROV_DRBG *drbg, unsigned int *str)
{
OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
- const OSSL_DISPATCH *pfunc;
void *parent = drbg->parent;
+ int res;
- pfunc = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_GET_CTX_PARAMS);
- if (pfunc == NULL) {
- ERR_raise(ERR_LIB_PROV, RAND_R_UNABLE_TO_GET_PARENT_STRENGTH);
+ if (drbg->parent_get_ctx_params == NULL) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PARENT_STRENGTH);
return 0;
}
- *params = OSSL_PARAM_construct_int(OSSL_RAND_PARAM_STRENGTH, str);
+
+ *params = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_STRENGTH, str);
if (!drbg_lock_parent(drbg)) {
- ERR_raise(ERR_LIB_PROV, RAND_R_UNABLE_TO_LOCK_PARENT);
+ ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOCK_PARENT);
return 0;
}
- if (!OSSL_get_OP_rand_get_ctx_params(pfunc)(parent, params)) {
- drbg_unlock_parent(drbg);
- ERR_raise(ERR_LIB_PROV, RAND_R_UNABLE_TO_GET_PARENT_STRENGTH);
+ res = drbg->parent_get_ctx_params(parent, params);
+ drbg_unlock_parent(drbg);
+ if (!res) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_PARENT_STRENGTH);
return 0;
}
- drbg_unlock_parent(drbg);
return 1;
}
static unsigned int get_parent_reseed_count(PROV_DRBG *drbg)
{
OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
- const OSSL_DISPATCH *pfunc;
void *parent = drbg->parent;
unsigned int r;
- pfunc = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_GET_CTX_PARAMS);
- if (pfunc == NULL) {
- ERR_raise(ERR_LIB_PROV,
- RAND_R_UNABLE_TO_GET_PARENT_RESEED_PROP_COUNTER);
- goto err;
- }
- *params = OSSL_PARAM_construct_uint(OSSL_RAND_PARAM_RESEED_PROP_CTR, &r);
+ *params = OSSL_PARAM_construct_uint(OSSL_DRBG_PARAM_RESEED_CTR, &r);
if (!drbg_lock_parent(drbg)) {
- ERR_raise(ERR_LIB_PROV, RAND_R_UNABLE_TO_LOCK_PARENT);
+ ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_LOCK_PARENT);
goto err;
}
- if (!OSSL_get_OP_rand_get_ctx_params(pfunc)(parent, params)) {
+ if (!drbg->parent_get_ctx_params(parent, params)) {
drbg_unlock_parent(drbg);
- ERR_raise(ERR_LIB_PROV, RAND_R_UNABLE_TO_GET_RESEED_PROP_CTR);
+ ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_RESEED_PROP_CTR);
goto err;
}
drbg_unlock_parent(drbg);
return r;
err:
- r = tsan_load(&drbg->reseed_prop_counter) - 2;
+ r = tsan_load(&drbg->reseed_counter) - 2;
if (r == 0)
r = UINT_MAX;
return r;
}
-#ifndef FIPS_MODULE
/*
* Implements the get_entropy() callback (see RAND_DRBG_set_callbacks())
*
@@ -161,20 +138,19 @@ static unsigned int get_parent_reseed_count(PROV_DRBG *drbg)
* is fetched using the parent's RAND_DRBG_generate().
*
* Otherwise, the entropy is polled from the system entropy sources
- * using rand_pool_acquire_entropy().
+ * using prov_pool_acquire_entropy().
*
* If a random pool has been added to the DRBG using RAND_add(), then
* its entropy will be used up first.
*/
static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout,
- int entropy, size_t min_len, size_t max_len,
- int prediction_resistance)
+ int entropy, size_t min_len,
+ size_t max_len, int prediction_resistance)
{
size_t ret = 0;
size_t entropy_available = 0;
RAND_POOL *pool;
- int p_str;
- const OSSL_DISPATCH *pfunc;
+ unsigned int p_str;
if (drbg->parent != NULL) {
if (!get_parent_strength(drbg, &p_str))
@@ -184,7 +160,7 @@ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout,
* We currently don't support the algorithm from NIST SP 800-90C
* 10.1.2 to use a weaker DRBG as source
*/
- RANDerr(0, RAND_R_PARENT_STRENGTH_TOO_WEAK);
+ RANDerr(0, PROV_R_PARENT_STRENGTH_TOO_WEAK);
return 0;
}
}
@@ -193,9 +169,11 @@ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout,
pool = drbg->seed_pool;
pool->entropy_requested = entropy;
} else {
- pool = rand_pool_new(entropy, drbg->secure, min_len, max_len);
- if (pool == NULL)
+ pool = rand_pool_new(entropy, 1, min_len, max_len);
+ if (pool == NULL) {
+ ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
return 0;
+ }
}
if (drbg->parent != NULL) {
@@ -213,25 +191,23 @@ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout,
* generating bits from it. (Note: taking the lock will be a no-op
* if locking if drbg->parent->lock == NULL.)
*/
- pfunc = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_GENERATE);
- if (pfunc == NULL)
- return 0;
+ if (drbg->parent_generate == NULL)
+ goto err;
drbg_lock_parent(drbg);
- if (OSSL_get_OP_rand_generate(pfunc)(drbg->parent, buffer, bytes_needed,
- drbg->strength,
- prediction_resistance,
- (unsigned char *)&drbg,
- sizeof(drbg)) != 0)
+ if (drbg->parent_generate(drbg->parent, buffer, bytes_needed,
+ drbg->strength, prediction_resistance,
+ (unsigned char *)&drbg,
+ sizeof(drbg)) != 0)
bytes = bytes_needed;
- drbg->reseed_next_counter = get_parent_reseed_count(drbg);
drbg_unlock_parent(drbg);
+ drbg->parent_reseed_counter = get_parent_reseed_count(drbg);
rand_pool_add_end(pool, bytes, 8 * bytes);
entropy_available = rand_pool_entropy_available(pool);
}
} else {
/* Get entropy by polling system entropy sources. */
- entropy_available = rand_pool_acquire_entropy(pool);
+ entropy_available = prov_pool_acquire_entropy(pool);
}
if (entropy_available > 0) {
@@ -239,6 +215,7 @@ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout,
*pout = rand_pool_detach(pool);
}
+err:
if (drbg->seed_pool == NULL)
rand_pool_free(pool);
return ret;
@@ -251,14 +228,68 @@ static size_t prov_drbg_get_entropy(PROV_DRBG *drbg, unsigned char **pout,
static void prov_drbg_cleanup_entropy(PROV_DRBG *drbg,
unsigned char *out, size_t outlen)
{
- if (drbg->seed_pool == NULL) {
- if (drbg->secure)
- OPENSSL_secure_clear_free(out, outlen);
- else
- OPENSSL_clear_free(out, outlen);
+ OSSL_PARAM params[3], *p = params;
+
+ if (drbg->get_entropy_fn != NULL) {
+ if (drbg->cleanup_entropy_fn != NULL) {
+ *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_SIZE,
+ &outlen);
+ *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_DRBG_PARAM_RANDOM_DATA,
+ (void **)&out, 0);
+ *p = OSSL_PARAM_construct_end();
+
+ drbg->cleanup_entropy_fn(params, drbg->callback_arg);
+ }
+ } else if (drbg->seed_pool == NULL) {
+ OPENSSL_secure_clear_free(out, outlen);
}
}
+
+static size_t get_entropy(PROV_DRBG *drbg, unsigned char **pout, int entropy,
+ size_t min_len, size_t max_len,
+ int prediction_resistance)
+{
+ if (drbg->get_entropy_fn != NULL) {
+ OSSL_PARAM params[6], *p = params;
+ OSSL_PARAM out[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
+
+ *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_ENTROPY_REQUIRED,
+ &entropy);
+ *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_PREDICTION_RESISTANCE,
+ &prediction_resistance);
+ *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MIN_LENGTH,
+ &min_len);
+ *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MAX_LENGTH,
+ &max_len);
+ *p = OSSL_PARAM_construct_end();
+ *out = OSSL_PARAM_construct_octet_ptr(OSSL_DRBG_PARAM_RANDOM_DATA,
+ (void **)pout, 0);
+
+ if (drbg->get_entropy_fn(params, out, drbg->callback_arg))
+ return out->return_size;
+ ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_ENTROPY);
+ return 0;
+ }
+
+#ifdef FIPS_MODULE
+ if (drbg->parent == NULL)
+ return prov_crngt_get_entropy(drbg, pout, entropy, min_len, max_len,
+ prediction_resistance);
+#endif
+
+ return prov_drbg_get_entropy(drbg, pout, entropy, min_len, max_len,
+ prediction_resistance);
+}
+
+static void cleanup_entropy(PROV_DRBG *drbg, unsigned char *out, size_t outlen)
+{
+#ifdef FIPS_MODULE
+ if (drbg->parent == NULL)
+ prov_crngt_cleanup_entropy(drbg, out, outlen);
+ else
#endif
+ prov_drbg_cleanup_entropy(drbg, out, outlen);
+}
#ifndef PROV_RAND_GET_RANDOM_NONCE
typedef struct prov_drbg_nonce_global_st {
@@ -311,26 +342,63 @@ static size_t prov_drbg_get_nonce(PROV_DRBG *drbg,
unsigned char **pout,
int entropy, size_t min_len, size_t max_len)
{
- size_t ret = 0;
+ size_t ret = 0, n;
RAND_POOL *pool;
+ unsigned char *buf = NULL;
+ OPENSSL_CTX *libctx = PROV_LIBRARY_CONTEXT_OF(drbg->provctx);
PROV_DRBG_NONCE_GLOBAL *dngbl
- = openssl_ctx_get_data(drbg->libctx, OPENSSL_CTX_DRBG_NONCE_INDEX,
+ = openssl_ctx_get_data(libctx, OPENSSL_CTX_DRBG_NONCE_INDEX,
&drbg_nonce_ossl_ctx_method);
+ OSSL_PARAM params[5], *p = params;
+ OSSL_PARAM out[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
struct {
void *instance;
int count;
} data;
-
if (dngbl == NULL)
return 0;
+ if (drbg->get_nonce_fn != NULL) {
+ *p++ = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_ENTROPY_REQUIRED,
+ &entropy);
+ *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MIN_LENGTH,
+ &min_len);
+ *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_MAX_LENGTH,
+ &max_len);
+ *p = OSSL_PARAM_construct_end();
+ *out = OSSL_PARAM_construct_octet_ptr(OSSL_DRBG_PARAM_RANDOM_DATA,
+ (void **)pout, 0);
+
+ if (drbg->get_nonce_fn(params, out, drbg->callback_arg))
+ return out->return_size;
+ ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_GET_NONCE);
+ return 0;
+ }
+ if (drbg->parent != NULL) {
+ if (drbg->parent_nonce != NULL) {
+ n = drbg->parent_nonce(drbg->parent, NULL, 0, drbg->min_noncelen,
+ drbg->max_noncelen);
+ if (n > 0 && (buf = OPENSSL_malloc(n)) != NULL) {
+ ret = drbg->parent_nonce(drbg->parent, buf, 0,
+ drbg->min_noncelen,
+ drbg->max_noncelen);
+ if (ret == n) {
+ *pout = buf;
+ return ret;
+ }
+ OPENSSL_free(buf);
+ }
+ }
+ }
+
+ /* Use the built in nonce source */
memset(&data, 0, sizeof(data));
pool = rand_pool_new(0, 0, min_len, max_len);
if (pool == NULL)
return 0;
- if (rand_pool_add_nonce_data(pool) == 0)
+ if (prov_pool_add_nonce_data(pool) == 0)
goto err;
data.instance = drbg;
@@ -348,17 +416,30 @@ static size_t prov_drbg_get_nonce(PROV_DRBG *drbg,
return ret;
}
-#endif
-/*
- * Implements the cleanup_nonce() callback (see PROV_DRBG_set_callbacks())
- *
- */
-static void prov_drbg_cleanup_nonce(PROV_DRBG *drbg,
- unsigned char *out, size_t outlen)
+static void prov_drbg_clear_nonce(PROV_DRBG *drbg, unsigned char *nonce,
+ size_t noncelen)
{
- OPENSSL_clear_free(out, outlen);
+ OSSL_PARAM params[3], *p = params;
+
+ if (drbg->get_nonce_fn != NULL) {
+ if (drbg->cleanup_nonce_fn != NULL) {
+ *p++ = OSSL_PARAM_construct_size_t(OSSL_DRBG_PARAM_SIZE,
+ &noncelen);
+ *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_DRBG_PARAM_RANDOM_DATA,
+ (void **)&nonce, 0);
+ *p = OSSL_PARAM_construct_end();
+
+ drbg->cleanup_nonce_fn(params, drbg->callback_arg);
+ }
+ } else {
+ OPENSSL_clear_free(nonce, noncelen);
+ }
}
+#else
+# define prov_drbg_clear_nonce(drbg, nonce, len) \
+ OPENSSL_clear_free((nonce), (len))
+#endif /* PROV_RAND_GET_RANDOM_NONCE */
/*
* Instantiate |drbg|, after it has been initialized. Use |pers| and
@@ -368,23 +449,16 @@ static void prov_drbg_cleanup_nonce(PROV_DRBG *drbg,
*
* Returns 1 on success, 0 on failure.
*/
-int PROV_DRBG_instantiate(PROV_DRBG *drbg, int strength,
+int PROV_DRBG_instantiate(PROV_DRBG *drbg, unsigned int strength,
int prediction_resistance,
- const unsigned char *pers, size_t perslen,
- int (*ifnc)(PROV_DRBG *drbg,
- const unsigned char *ent, size_t ent_len,
- const unsigned char *nonce,
- size_t nonce_len,
- const unsigned char *pstr,
- size_t pstr_len))
+ const unsigned char *pers, size_t perslen)
{
unsigned char *nonce = NULL, *entropy = NULL;
size_t noncelen = 0, entropylen = 0;
size_t min_entropy, min_entropylen, max_entropylen;
- const OSSL_DISPATCH *pnonce;
if (strength > drbg->strength) {
- PROVerr(0, RAND_R_INSUFFICIENT_DRBG_STRENGTH);
+ PROVerr(0, PROV_R_INSUFFICIENT_DRBG_STRENGTH);
goto end;
}
min_entropy = drbg->strength;
@@ -396,50 +470,54 @@ int PROV_DRBG_instantiate(PROV_DRBG *drbg, int strength,
perslen = sizeof(ossl_pers_string);
}
if (perslen > drbg->max_perslen) {
- PROVerr(0, RAND_R_PERSONALISATION_STRING_TOO_LONG);
+ PROVerr(0, PROV_R_PERSONALISATION_STRING_TOO_LONG);
goto end;
}
- if (drbg->state != DRBG_UNINITIALISED) {
- if (drbg->state == DRBG_ERROR)
- PROVerr(0, RAND_R_IN_ERROR_STATE);
+ if (drbg->state != EVP_RAND_STATE_UNINITIALISED) {
+ if (drbg->state == EVP_RAND_STATE_ERROR)
+ PROVerr(0, PROV_R_IN_ERROR_STATE);
else
- PROVerr(0, RAND_R_ALREADY_INSTANTIATED);
+ PROVerr(0, PROV_R_ALREADY_INSTANTIATED);
goto end;
}
- drbg->state = DRBG_ERROR;
+ drbg->state = EVP_RAND_STATE_ERROR;
if (drbg->min_noncelen > 0) {
+ if (drbg->parent_nonce != NULL) {
+ noncelen = drbg->parent_nonce(drbg->parent, NULL, drbg->strength,
+ drbg->min_noncelen,
+ drbg->max_noncelen);
+ if (noncelen == 0) {
+ PROVerr(0, PROV_R_ERROR_RETRIEVING_NONCE);
+ goto end;
+ }
+ nonce = OPENSSL_malloc(noncelen);
+ if (nonce == NULL) {
+ PROVerr(0, PROV_R_ERROR_RETRIEVING_NONCE);
+ goto end;
+ }
+ if (noncelen != drbg->parent_nonce(drbg->parent, nonce,
+ drbg->strength,
+ drbg->min_noncelen,
+ drbg->max_noncelen)) {
+ PROVerr(0, PROV_R_ERROR_RETRIEVING_NONCE);
+ OPENSSL_free(nonce);
+ }
#ifndef PROV_RAND_GET_RANDOM_NONCE
- if (drbg->parent != NULL)
+ } else if (drbg->parent != NULL) {
#endif
- {
- pnonce = find_call(drbg->parent_dispatch, OSSL_FUNC_RAND_NONCE);
- if (pnonce == NULL) {
- /*
- * NIST SP800-90Ar1 section 9.1 says you can combine getting
- * the entropy and nonce in 1 call by increasing the entropy
- * with 50% and increasing the minimum length to accommodate
- * the length of the nonce. We do this in case a nonce is
- * required and there is no parental nonce capability.
- */
- min_entropy += drbg->strength / 2;
- min_entropylen += drbg->min_noncelen;
- max_entropylen += drbg->max_noncelen;
- } else {
- drbg_lock_parent(drbg);
- noncelen = OSSL_get_OP_rand_nonce(pnonce)(drbg->parent, &nonce,
- drbg->strength / 2,
- drbg->min_noncelen,
- drbg->max_noncelen);
- drbg_unlock_parent(drbg);
- if (noncelen < drbg->min_noncelen
- || noncelen > drbg->max_noncelen) {
- PROVerr(0, RAND_R_ERROR_RETRIEVING_NONCE);
- goto end;
- }
- }
+ /*
+ * NIST SP800-90Ar1 section 9.1 says you can combine getting
+ * the entropy and nonce in 1 call by increasing the entropy
+ * with 50% and increasing the minimum length to accommodate
+ * the length of the nonce. We do this in case a nonce is
+ * required and there is no parental nonce capability.
+ */
+ min_entropy += drbg->strength / 2;
+ min_entropylen += drbg->min_noncelen;
+ max_entropylen += drbg->max_noncelen;
}
#ifndef PROV_RAND_GET_RANDOM_NONCE
else { /* parent == NULL */
@@ -448,17 +526,17 @@ int PROV_DRBG_instantiate(PROV_DRBG *drbg, int strength,
drbg->max_noncelen);
if (noncelen < drbg->min_noncelen
|| noncelen > drbg->max_noncelen) {
- PROVerr(0, RAND_R_ERROR_RETRIEVING_NONCE);
+ PROVerr(0, PROV_R_ERROR_RETRIEVING_NONCE);
goto end;
}
}
#endif
}
- drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter);
+ drbg->reseed_next_counter = tsan_load(&drbg->reseed_counter);
if (drbg->reseed_next_counter) {
drbg->reseed_next_counter++;
- if(!drbg->reseed_next_counter)
+ if (!drbg->reseed_next_counter)
drbg->reseed_next_counter = 1;
}
@@ -467,31 +545,44 @@ int PROV_DRBG_instantiate(PROV_DRBG *drbg, int strength,
prediction_resistance);
if (entropylen < min_entropylen
|| entropylen > max_entropylen) {
- PROVerr(0, RAND_R_ERROR_RETRIEVING_ENTROPY);
+ PROVerr(0, PROV_R_ERROR_RETRIEVING_ENTROPY);
goto end;
}
- if (!ifnc(drbg, entropy, entropylen, nonce, noncelen, pers, perslen)) {
- PROVerr(0, RAND_R_ERROR_INSTANTIATING_DRBG);
+ if (!drbg->instantiate(drbg, entropy, entropylen, nonce, noncelen,
+ pers, perslen)) {
+ PROVerr(0, PROV_R_ERROR_INSTANTIATING_DRBG);
goto end;
}
- drbg->state = DRBG_READY;
+ drbg->state = EVP_RAND_STATE_READY;
drbg->reseed_gen_counter = 1;
drbg->reseed_time = time(NULL);
- tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_counter);
+ tsan_store(&drbg->reseed_counter, drbg->reseed_next_counter);
end:
if (entropy != NULL)
cleanup_entropy(drbg, entropy, entropylen);
- if (nonce != NULL)
- prov_drbg_cleanup_nonce(drbg, nonce, noncelen);
- if (drbg->state == DRBG_READY)
+ prov_drbg_clear_nonce(drbg, nonce, noncelen);
+ if (drbg->state == EVP_RAND_STATE_READY)
return 1;
return 0;
}
/*
+ * Uninstantiate |drbg|. Must be instantiated before it can be used.
+ *
+ * Requires that drbg->lock is already locked for write, if non-null.
+ *
+ * Returns 1 on success, 0 on failure.
+ */
+int PROV_DRBG_uninstantiate(PROV_DRBG *drbg)
+{
+ drbg->state = EVP_RAND_STATE_UNINITIALISED;
+ return 1;
+}
+
+/*
* Reseed |drbg|, mixing in the specified data
*
* Requires that drbg->lock is already locked for write, if non-null.
@@ -500,60 +591,101 @@ int PROV_DRBG_instantiate(PROV_DRBG *drbg, int strength,
*/
int PROV_DRBG_reseed(PROV_DRBG *drbg, int prediction_resistance,
const unsigned char *ent, size_t ent_len,
- const unsigned char *adin, size_t adinlen,
- int (*reseed)(PROV_DRBG *drbg,
- const unsigned char *ent, size_t ent_len,
- const unsigned char *adin, size_t adin_len))
+ const unsigned char *adin, size_t adinlen)
{
unsigned char *entropy = NULL;
size_t entropylen = 0;
- if (drbg->state == DRBG_ERROR) {
- PROVerr(0, RAND_R_IN_ERROR_STATE);
- return 0;
+ if (drbg->state != EVP_RAND_STATE_READY) {
+ /* try to recover from previous errors */
+ rand_drbg_restart(drbg);
+
+ if (drbg->state == EVP_RAND_STATE_ERROR) {
+ PROVerr(0, PROV_R_IN_ERROR_STATE);
+ return 0;
+ }
+ if (drbg->state == EVP_RAND_STATE_UNINITIALISED) {
+ PROVerr(0, PROV_R_NOT_INSTANTIATED);
+ return 0;
+ }
}
- if (drbg->state == DRBG_UNINITIALISED) {
- PROVerr(0, RAND_R_NOT_INSTANTIATED);
- return 0;
+
+ if (ent != NULL) {
+ if (ent_len < drbg->min_entropylen) {
+ RANDerr(0, RAND_R_ENTROPY_OUT_OF_RANGE);
+ drbg->state = EVP_RAND_STATE_ERROR;
+ return 0;
+ }
+ if (ent_len > drbg->max_entropylen) {
+ RANDerr(0, RAND_R_ENTROPY_INPUT_TOO_LONG);
+ drbg->state = EVP_RAND_STATE_ERROR;
+ return 0;
+ }
}
if (adin == NULL) {
adinlen = 0;
} else if (adinlen > drbg->max_adinlen) {
- PROVerr(0, RAND_R_ADDITIONAL_INPUT_TOO_LONG);
+ PROVerr(0, PROV_R_ADDITIONAL_INPUT_TOO_LONG);
return 0;
}
- drbg->state = DRBG_ERROR;
+ drbg->state = EVP_RAND_STATE_ERROR;
- drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter);
+ drbg->reseed_next_counter = tsan_load(&drbg->reseed_counter);
if (drbg->reseed_next_counter) {
drbg->reseed_next_counter++;
- if(!drbg->reseed_next_counter)
+ if (!drbg->reseed_next_counter)
drbg->reseed_next_counter = 1;
}
+ if (ent != NULL) {
+#ifdef FIP_MODULE
+ /*
+ * NIST SP-800-90A mandates that entropy *shall not* be provided
+ * by the consuming application. Instead the data is added as additional
+ * input.
+ *
+ * (NIST SP-800-90Ar1, Sections 9.1 and 9.2)
+ */
+ if (!drbg->reseed(drbg, NULL, 0, ent, ent_len)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_RESEED);
+ return 0;
+ }
+#else
+ if (!drbg->reseed(drbg, ent, ent_len, adin, adinlen)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_RESEED);
+ return 0;
+ }
+ /* There isn't much point adding the same additional input twice */
+ adin = NULL;
+ adinlen = 0;
+#endif
+ }
+
+ /* Reseed using our sources in addition */
entropylen = get_entropy(drbg, &entropy, drbg->strength,
drbg->min_entropylen, drbg->max_entropylen,
prediction_resistance);
if (entropylen < drbg->min_entropylen
|| entropylen > drbg->max_entropylen) {
- PROVerr(0, RAND_R_ERROR_RETRIEVING_ENTROPY);
+ PROVerr(0, PROV_R_ERROR_RETRIEVING_ENTROPY);
goto end;
}
- if (!reseed(drbg, entropy, entropylen, adin, adinlen))
+ if (!drbg->reseed(drbg, entropy, entropylen, adin, adinlen))
goto end;
- drbg->state = DRBG_READY;
+ drbg->state = EVP_RAND_STATE_READY;
drbg->reseed_gen_counter = 1;
drbg->reseed_time = time(NULL);
- tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_counter);
+ tsan_store(&drbg->reseed_counter, drbg->reseed_next_counter);
+ if (drbg->parent != NULL)
+ drbg->parent_reseed_counter = get_parent_reseed_count(drbg);
end:
- if (entropy != NULL)
- OPENSSL_cleanse(entropy, entropylen);
- if (drbg->state == DRBG_READY)
+ cleanup_entropy(drbg, entropy, entropylen);
+ if (drbg->state == EVP_RAND_STATE_READY)
return 1;
return 0;
}
@@ -569,35 +701,36 @@ int PROV_DRBG_reseed(PROV_DRBG *drbg, int prediction_resistance,
*
*/
int PROV_DRBG_generate(PROV_DRBG *drbg, unsigned char *out, size_t outlen,
- int strength, int prediction_resistance,
- const unsigned char *adin, size_t adinlen,
- int (*generate)(PROV_DRBG *, unsigned char *out,
- size_t outlen, const unsigned char *adin,
- size_t adin_len),
- int (*reseed)(PROV_DRBG *drbg, const unsigned char *ent,
- size_t ent_len, const unsigned char *adin,
- size_t adin