1/*
2 * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License").  You may not use
5 * this file except in compliance with the License.  You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10#include <openssl/err.h>
11#include <openssl/ui.h>
12#include <openssl/core_names.h>
13#include "internal/cryptlib.h"
14#include "internal/passphrase.h"
15
16void ossl_pw_clear_passphrase_data(struct ossl_passphrase_data_st *data)
17{
18    if (data != NULL) {
19        if (data->type == is_expl_passphrase)
20            OPENSSL_clear_free(data->_.expl_passphrase.passphrase_copy,
21                               data->_.expl_passphrase.passphrase_len);
22        ossl_pw_clear_passphrase_cache(data);
23        memset(data, 0, sizeof(*data));
24    }
25}
26
27void ossl_pw_clear_passphrase_cache(struct ossl_passphrase_data_st *data)
28{
29    OPENSSL_clear_free(data->cached_passphrase, data->cached_passphrase_len);
30    data->cached_passphrase = NULL;
31}
32
33int ossl_pw_set_passphrase(struct ossl_passphrase_data_st *data,
34                           const unsigned char *passphrase,
35                           size_t passphrase_len)
36{
37    if (!ossl_assert(data != NULL && passphrase != NULL)) {
38        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
39        return 0;
40    }
41    ossl_pw_clear_passphrase_data(data);
42    data->type = is_expl_passphrase;
43    data->_.expl_passphrase.passphrase_copy =
44        passphrase_len != 0 ? OPENSSL_memdup(passphrase, passphrase_len)
45                            : OPENSSL_malloc(1);
46    if (data->_.expl_passphrase.passphrase_copy == NULL) {
47        ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
48        return 0;
49    }
50    data->_.expl_passphrase.passphrase_len = passphrase_len;
51    return 1;
52}
53
54int ossl_pw_set_pem_password_cb(struct ossl_passphrase_data_st *data,
55                                pem_password_cb *cb, void *cbarg)
56{
57    if (!ossl_assert(data != NULL && cb != NULL)) {
58        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
59        return 0;
60    }
61    ossl_pw_clear_passphrase_data(data);
62    data->type = is_pem_password;
63    data->_.pem_password.password_cb = cb;
64    data->_.pem_password.password_cbarg = cbarg;
65    return 1;
66}
67
68int ossl_pw_set_ossl_passphrase_cb(struct ossl_passphrase_data_st *data,
69                                   OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg)
70{
71    if (!ossl_assert(data != NULL && cb != NULL)) {
72        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
73        return 0;
74    }
75    ossl_pw_clear_passphrase_data(data);
76    data->type = is_ossl_passphrase;
77    data->_.ossl_passphrase.passphrase_cb = cb;
78    data->_.ossl_passphrase.passphrase_cbarg = cbarg;
79    return 1;
80}
81
82int ossl_pw_set_ui_method(struct ossl_passphrase_data_st *data,
83                          const UI_METHOD *ui_method, void *ui_data)
84{
85    if (!ossl_assert(data != NULL && ui_method != NULL)) {
86        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
87        return 0;
88    }
89    ossl_pw_clear_passphrase_data(data);
90    data->type = is_ui_method;
91    data->_.ui_method.ui_method = ui_method;
92    data->_.ui_method.ui_method_data = ui_data;
93    return 1;
94}
95
96int ossl_pw_enable_passphrase_caching(struct ossl_passphrase_data_st *data)
97{
98    data->flag_cache_passphrase = 1;
99    return 1;
100}
101
102int ossl_pw_disable_passphrase_caching(struct ossl_passphrase_data_st *data)
103{
104    data->flag_cache_passphrase = 0;
105    return 1;
106}
107
108
109/*-
110 * UI_METHOD processor.  It differs from UI_UTIL_read_pw() like this:
111 *
112 * 1.  It constructs a prompt on its own, based on |prompt_info|.
113 * 2.  It allocates a buffer for password and verification on its own
114 *     to compensate for NUL terminator in UI password strings.
115 * 3.  It raises errors.
116 * 4.  It reports back the length of the prompted pass phrase.
117 */
118static int do_ui_passphrase(char *pass, size_t pass_size, size_t *pass_len,
119                            const char *prompt_info, int verify,
120                            const UI_METHOD *ui_method, void *ui_data)
121{
122    char *prompt = NULL, *ipass = NULL, *vpass = NULL;
123    int prompt_idx = -1, verify_idx = -1, res;
124    UI *ui = NULL;
125    int ret = 0;
126
127    if (!ossl_assert(pass != NULL && pass_size != 0 && pass_len != NULL)) {
128        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
129        return 0;
130    }
131
132    if ((ui = UI_new()) == NULL) {
133        ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
134        return 0;
135    }
136
137    if (ui_method != NULL) {
138        UI_set_method(ui, ui_method);
139        if (ui_data != NULL)
140            UI_add_user_data(ui, ui_data);
141    }
142
143    /* Get an application constructed prompt */
144    prompt = UI_construct_prompt(ui, "pass phrase", prompt_info);
145    if (prompt == NULL) {
146        ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
147        goto end;
148    }
149
150    /* Get a buffer for verification prompt */
151    ipass = OPENSSL_zalloc(pass_size + 1);
152    if (ipass == NULL) {
153        ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
154        goto end;
155    }
156
157    prompt_idx = UI_add_input_string(ui, prompt,
158                                     UI_INPUT_FLAG_DEFAULT_PWD,
159                                     ipass, 0, pass_size) - 1;
160    if (prompt_idx < 0) {
161        ERR_raise(ERR_LIB_CRYPTO, ERR_R_UI_LIB);
162        goto end;
163    }
164
165    if (verify) {
166        /* Get a buffer for verification prompt */
167        vpass = OPENSSL_zalloc(pass_size + 1);
168        if (vpass == NULL) {
169            ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
170            goto end;
171        }
172        verify_idx = UI_add_verify_string(ui, prompt,
173                                          UI_INPUT_FLAG_DEFAULT_PWD,
174                                          vpass, 0, pass_size,
175                                          ipass) - 1;
176        if (verify_idx < 0) {
177            ERR_raise(ERR_LIB_CRYPTO, ERR_R_UI_LIB);
178            goto end;
179        }
180    }
181
182    switch (UI_process(ui)) {
183    case -2:
184        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERRUPTED_OR_CANCELLED);
185        break;
186    case -1:
187        ERR_raise(ERR_LIB_CRYPTO, ERR_R_UI_LIB);
188        break;
189    default:
190        res = UI_get_result_length(ui, prompt_idx);
191        if (res < 0) {
192            ERR_raise(ERR_LIB_CRYPTO, ERR_R_UI_LIB);
193            break;
194        }
195        *pass_len = (size_t)res;
196        memcpy(pass, ipass, *pass_len);
197        ret = 1;
198        break;
199    }
200
201 end:
202    OPENSSL_clear_free(vpass, pass_size + 1);
203    OPENSSL_clear_free(ipass, pass_size + 1);
204    OPENSSL_free(prompt);
205    UI_free(ui);
206    return ret;
207}
208
209/* Central pw prompting dispatcher */
210int ossl_pw_get_passphrase(char *pass, size_t pass_size, size_t *pass_len,
211                           const OSSL_PARAM params[], int verify,
212                           struct ossl_passphrase_data_st *data)
213{
214    const char *source = NULL;
215    size_t source_len = 0;
216    const char *prompt_info = NULL;
217    const UI_METHOD *ui_method = NULL;
218    UI_METHOD *allocated_ui_method = NULL;
219    void *ui_data = NULL;
220    const OSSL_PARAM *p = NULL;
221    int ret;
222
223    /* Handle explicit and cached passphrases */
224
225    if (data->type == is_expl_passphrase) {
226        source = data->_.expl_passphrase.passphrase_copy;
227        source_len = data->_.expl_passphrase.passphrase_len;
228    } else if (data->flag_cache_passphrase && data->cached_passphrase != NULL) {
229        source = data->cached_passphrase;
230        source_len = data->cached_passphrase_len;
231    }
232
233    if (source != NULL) {
234        if (source_len > pass_size)
235            source_len = pass_size;
236        memcpy(pass, source, source_len);
237        *pass_len = source_len;
238        return 1;
239    }
240
241    /* Handle the is_ossl_passphrase case...  that's pretty direct */
242
243    if (data->type == is_ossl_passphrase) {
244        OSSL_PASSPHRASE_CALLBACK *cb = data->_.ossl_passphrase.passphrase_cb;
245        void *cbarg = data->_.ossl_passphrase.passphrase_cbarg;
246
247        ret = cb(pass, pass_size, pass_len, params, cbarg);
248        goto do_cache;
249    }
250
251    /* Handle the is_pem_password and is_ui_method cases */
252
253    if ((p = OSSL_PARAM_locate_const(params,
254                                     OSSL_PASSPHRASE_PARAM_INFO)) != NULL) {
255        if (p->data_type != OSSL_PARAM_UTF8_STRING) {
256            ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT,
257                           "Prompt info data type incorrect");
258            return 0;
259        }
260        prompt_info = p->data;
261    }
262
263    if (data->type == is_pem_password) {
264        /* We use a UI wrapper for PEM */
265        pem_password_cb *cb = data->_.pem_password.password_cb;
266
267        ui_method = allocated_ui_method =
268            UI_UTIL_wrap_read_pem_callback(cb, verify);
269        ui_data = data->_.pem_password.password_cbarg;
270
271        if (ui_method == NULL) {
272            ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
273            return 0;
274        }
275    } else if (data->type == is_ui_method) {
276        ui_method = data->_.ui_method.ui_method;
277        ui_data = data->_.ui_method.ui_method_data;
278    }
279
280    if (ui_method == NULL) {
281        ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT,
282                       "No password method specified");
283        return 0;
284    }
285
286    ret = do_ui_passphrase(pass, pass_size, pass_len, prompt_info, verify,
287                           ui_method, ui_data);
288
289    UI_destroy_method(allocated_ui_method);
290
291 do_cache:
292    if (ret && data->flag_cache_passphrase) {
293        if (data->cached_passphrase == NULL
294            || *pass_len > data->cached_passphrase_len) {
295            void *new_cache =
296                OPENSSL_clear_realloc(data->cached_passphrase,
297                                      data->cached_passphrase_len,
298                                      *pass_len + 1);
299
300            if (new_cache == NULL) {
301                OPENSSL_cleanse(pass, *pass_len);
302                ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
303                return 0;
304            }
305            data->cached_passphrase = new_cache;
306        }
307        memcpy(data->cached_passphrase, pass, *pass_len);
308        data->cached_passphrase[*pass_len] = '\0';
309        data->cached_passphrase_len = *pass_len;
310    }
311
312    return ret;
313}
314
315static int ossl_pw_get_password(char *buf, int size, int rwflag,
316                                void *userdata, const char *info)
317{
318    size_t password_len = 0;
319    OSSL_PARAM params[] = {
320        OSSL_PARAM_utf8_string(OSSL_PASSPHRASE_PARAM_INFO, NULL, 0),
321        OSSL_PARAM_END
322    };
323
324    params[0].data = (void *)info;
325    if (ossl_pw_get_passphrase(buf, (size_t)size, &password_len, params,
326                               rwflag, userdata))
327        return (int)password_len;
328    return -1;
329}
330
331int ossl_pw_pem_password(char *buf, int size, int rwflag, void *userdata)
332{
333    return ossl_pw_get_password(buf, size, rwflag, userdata, "PEM");
334}
335
336int ossl_pw_pvk_password(char *buf, int size, int rwflag, void *userdata)
337{
338    return ossl_pw_get_password(buf, size, rwflag, userdata, "PVK");
339}
340
341int ossl_pw_passphrase_callback_enc(char *pass, size_t pass_size,
342                                    size_t *pass_len,
343                                    const OSSL_PARAM params[], void *arg)
344{
345    return ossl_pw_get_passphrase(pass, pass_size, pass_len, params, 1, arg);
346}
347
348int ossl_pw_passphrase_callback_dec(char *pass, size_t pass_size,
349                                    size_t *pass_len,
350                                    const OSSL_PARAM params[], void *arg)
351{
352    return ossl_pw_get_passphrase(pass, pass_size, pass_len, params, 0, arg);
353}
354