1*b077aed3SPierre Pronchery /*
2*b077aed3SPierre Pronchery * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
3*b077aed3SPierre Pronchery *
4*b077aed3SPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use
5*b077aed3SPierre Pronchery * this file except in compliance with the License. You can obtain a copy
6*b077aed3SPierre Pronchery * in the file LICENSE in the source distribution or at
7*b077aed3SPierre Pronchery * https://www.openssl.org/source/license.html
8*b077aed3SPierre Pronchery */
9*b077aed3SPierre Pronchery
10*b077aed3SPierre Pronchery #include <string.h>
11*b077aed3SPierre Pronchery #include <openssl/err.h>
12*b077aed3SPierre Pronchery #include <openssl/ui.h>
13*b077aed3SPierre Pronchery #include "apps_ui.h"
14*b077aed3SPierre Pronchery
15*b077aed3SPierre Pronchery static UI_METHOD *ui_method = NULL;
16*b077aed3SPierre Pronchery static const UI_METHOD *ui_base_method = NULL;
17*b077aed3SPierre Pronchery
ui_open(UI * ui)18*b077aed3SPierre Pronchery static int ui_open(UI *ui)
19*b077aed3SPierre Pronchery {
20*b077aed3SPierre Pronchery int (*opener)(UI *ui) = UI_method_get_opener(ui_base_method);
21*b077aed3SPierre Pronchery
22*b077aed3SPierre Pronchery if (opener != NULL)
23*b077aed3SPierre Pronchery return opener(ui);
24*b077aed3SPierre Pronchery return 1;
25*b077aed3SPierre Pronchery }
26*b077aed3SPierre Pronchery
ui_read(UI * ui,UI_STRING * uis)27*b077aed3SPierre Pronchery static int ui_read(UI *ui, UI_STRING *uis)
28*b077aed3SPierre Pronchery {
29*b077aed3SPierre Pronchery int (*reader)(UI *ui, UI_STRING *uis) = NULL;
30*b077aed3SPierre Pronchery
31*b077aed3SPierre Pronchery if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD
32*b077aed3SPierre Pronchery && UI_get0_user_data(ui)) {
33*b077aed3SPierre Pronchery switch (UI_get_string_type(uis)) {
34*b077aed3SPierre Pronchery case UIT_PROMPT:
35*b077aed3SPierre Pronchery case UIT_VERIFY:
36*b077aed3SPierre Pronchery {
37*b077aed3SPierre Pronchery const char *password =
38*b077aed3SPierre Pronchery ((PW_CB_DATA *)UI_get0_user_data(ui))->password;
39*b077aed3SPierre Pronchery
40*b077aed3SPierre Pronchery if (password != NULL) {
41*b077aed3SPierre Pronchery UI_set_result(ui, uis, password);
42*b077aed3SPierre Pronchery return 1;
43*b077aed3SPierre Pronchery }
44*b077aed3SPierre Pronchery }
45*b077aed3SPierre Pronchery break;
46*b077aed3SPierre Pronchery case UIT_NONE:
47*b077aed3SPierre Pronchery case UIT_BOOLEAN:
48*b077aed3SPierre Pronchery case UIT_INFO:
49*b077aed3SPierre Pronchery case UIT_ERROR:
50*b077aed3SPierre Pronchery break;
51*b077aed3SPierre Pronchery }
52*b077aed3SPierre Pronchery }
53*b077aed3SPierre Pronchery
54*b077aed3SPierre Pronchery reader = UI_method_get_reader(ui_base_method);
55*b077aed3SPierre Pronchery if (reader != NULL)
56*b077aed3SPierre Pronchery return reader(ui, uis);
57*b077aed3SPierre Pronchery /* Default to the empty password if we've got nothing better */
58*b077aed3SPierre Pronchery UI_set_result(ui, uis, "");
59*b077aed3SPierre Pronchery return 1;
60*b077aed3SPierre Pronchery }
61*b077aed3SPierre Pronchery
ui_write(UI * ui,UI_STRING * uis)62*b077aed3SPierre Pronchery static int ui_write(UI *ui, UI_STRING *uis)
63*b077aed3SPierre Pronchery {
64*b077aed3SPierre Pronchery int (*writer)(UI *ui, UI_STRING *uis) = NULL;
65*b077aed3SPierre Pronchery
66*b077aed3SPierre Pronchery if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD
67*b077aed3SPierre Pronchery && UI_get0_user_data(ui)) {
68*b077aed3SPierre Pronchery switch (UI_get_string_type(uis)) {
69*b077aed3SPierre Pronchery case UIT_PROMPT:
70*b077aed3SPierre Pronchery case UIT_VERIFY:
71*b077aed3SPierre Pronchery {
72*b077aed3SPierre Pronchery const char *password =
73*b077aed3SPierre Pronchery ((PW_CB_DATA *)UI_get0_user_data(ui))->password;
74*b077aed3SPierre Pronchery
75*b077aed3SPierre Pronchery if (password != NULL)
76*b077aed3SPierre Pronchery return 1;
77*b077aed3SPierre Pronchery }
78*b077aed3SPierre Pronchery break;
79*b077aed3SPierre Pronchery case UIT_NONE:
80*b077aed3SPierre Pronchery case UIT_BOOLEAN:
81*b077aed3SPierre Pronchery case UIT_INFO:
82*b077aed3SPierre Pronchery case UIT_ERROR:
83*b077aed3SPierre Pronchery break;
84*b077aed3SPierre Pronchery }
85*b077aed3SPierre Pronchery }
86*b077aed3SPierre Pronchery
87*b077aed3SPierre Pronchery writer = UI_method_get_writer(ui_base_method);
88*b077aed3SPierre Pronchery if (writer != NULL)
89*b077aed3SPierre Pronchery return writer(ui, uis);
90*b077aed3SPierre Pronchery return 1;
91*b077aed3SPierre Pronchery }
92*b077aed3SPierre Pronchery
ui_close(UI * ui)93*b077aed3SPierre Pronchery static int ui_close(UI *ui)
94*b077aed3SPierre Pronchery {
95*b077aed3SPierre Pronchery int (*closer)(UI *ui) = UI_method_get_closer(ui_base_method);
96*b077aed3SPierre Pronchery
97*b077aed3SPierre Pronchery if (closer != NULL)
98*b077aed3SPierre Pronchery return closer(ui);
99*b077aed3SPierre Pronchery return 1;
100*b077aed3SPierre Pronchery }
101*b077aed3SPierre Pronchery
102*b077aed3SPierre Pronchery /* object_name defaults to prompt_info from ui user data if present */
ui_prompt_construct(UI * ui,const char * phrase_desc,const char * object_name)103*b077aed3SPierre Pronchery static char *ui_prompt_construct(UI *ui, const char *phrase_desc,
104*b077aed3SPierre Pronchery const char *object_name)
105*b077aed3SPierre Pronchery {
106*b077aed3SPierre Pronchery PW_CB_DATA *cb_data = (PW_CB_DATA *)UI_get0_user_data(ui);
107*b077aed3SPierre Pronchery
108*b077aed3SPierre Pronchery if (phrase_desc == NULL)
109*b077aed3SPierre Pronchery phrase_desc = "pass phrase";
110*b077aed3SPierre Pronchery if (object_name == NULL && cb_data != NULL)
111*b077aed3SPierre Pronchery object_name = cb_data->prompt_info;
112*b077aed3SPierre Pronchery return UI_construct_prompt(NULL, phrase_desc, object_name);
113*b077aed3SPierre Pronchery }
114*b077aed3SPierre Pronchery
set_base_ui_method(const UI_METHOD * ui_meth)115*b077aed3SPierre Pronchery int set_base_ui_method(const UI_METHOD *ui_meth)
116*b077aed3SPierre Pronchery {
117*b077aed3SPierre Pronchery if (ui_meth == NULL)
118*b077aed3SPierre Pronchery ui_meth = UI_null();
119*b077aed3SPierre Pronchery ui_base_method = ui_meth;
120*b077aed3SPierre Pronchery return 1;
121*b077aed3SPierre Pronchery }
122*b077aed3SPierre Pronchery
setup_ui_method(void)123*b077aed3SPierre Pronchery int setup_ui_method(void)
124*b077aed3SPierre Pronchery {
125*b077aed3SPierre Pronchery ui_base_method = UI_null();
126*b077aed3SPierre Pronchery #ifndef OPENSSL_NO_UI_CONSOLE
127*b077aed3SPierre Pronchery ui_base_method = UI_OpenSSL();
128*b077aed3SPierre Pronchery #endif
129*b077aed3SPierre Pronchery ui_method = UI_create_method("OpenSSL application user interface");
130*b077aed3SPierre Pronchery return ui_method != NULL
131*b077aed3SPierre Pronchery && 0 == UI_method_set_opener(ui_method, ui_open)
132*b077aed3SPierre Pronchery && 0 == UI_method_set_reader(ui_method, ui_read)
133*b077aed3SPierre Pronchery && 0 == UI_method_set_writer(ui_method, ui_write)
134*b077aed3SPierre Pronchery && 0 == UI_method_set_closer(ui_method, ui_close)
135*b077aed3SPierre Pronchery && 0 == UI_method_set_prompt_constructor(ui_method,
136*b077aed3SPierre Pronchery ui_prompt_construct);
137*b077aed3SPierre Pronchery }
138*b077aed3SPierre Pronchery
destroy_ui_method(void)139*b077aed3SPierre Pronchery void destroy_ui_method(void)
140*b077aed3SPierre Pronchery {
141*b077aed3SPierre Pronchery if (ui_method != NULL) {
142*b077aed3SPierre Pronchery UI_destroy_method(ui_method);
143*b077aed3SPierre Pronchery ui_method = NULL;
144*b077aed3SPierre Pronchery }
145*b077aed3SPierre Pronchery }
146*b077aed3SPierre Pronchery
get_ui_method(void)147*b077aed3SPierre Pronchery const UI_METHOD *get_ui_method(void)
148*b077aed3SPierre Pronchery {
149*b077aed3SPierre Pronchery return ui_method;
150*b077aed3SPierre Pronchery }
151*b077aed3SPierre Pronchery
ui_malloc(int sz,const char * what)152*b077aed3SPierre Pronchery static void *ui_malloc(int sz, const char *what)
153*b077aed3SPierre Pronchery {
154*b077aed3SPierre Pronchery void *vp = OPENSSL_malloc(sz);
155*b077aed3SPierre Pronchery
156*b077aed3SPierre Pronchery if (vp == NULL) {
157*b077aed3SPierre Pronchery BIO_printf(bio_err, "Could not allocate %d bytes for %s\n", sz, what);
158*b077aed3SPierre Pronchery ERR_print_errors(bio_err);
159*b077aed3SPierre Pronchery exit(1);
160*b077aed3SPierre Pronchery }
161*b077aed3SPierre Pronchery return vp;
162*b077aed3SPierre Pronchery }
163*b077aed3SPierre Pronchery
password_callback(char * buf,int bufsiz,int verify,PW_CB_DATA * cb_data)164*b077aed3SPierre Pronchery int password_callback(char *buf, int bufsiz, int verify, PW_CB_DATA *cb_data)
165*b077aed3SPierre Pronchery {
166*b077aed3SPierre Pronchery int res = 0;
167*b077aed3SPierre Pronchery UI *ui;
168*b077aed3SPierre Pronchery int ok = 0;
169*b077aed3SPierre Pronchery char *buff = NULL;
170*b077aed3SPierre Pronchery int ui_flags = 0;
171*b077aed3SPierre Pronchery const char *prompt_info = NULL;
172*b077aed3SPierre Pronchery char *prompt;
173*b077aed3SPierre Pronchery
174*b077aed3SPierre Pronchery if ((ui = UI_new_method(ui_method)) == NULL)
175*b077aed3SPierre Pronchery return 0;
176*b077aed3SPierre Pronchery
177*b077aed3SPierre Pronchery if (cb_data != NULL && cb_data->prompt_info != NULL)
178*b077aed3SPierre Pronchery prompt_info = cb_data->prompt_info;
179*b077aed3SPierre Pronchery prompt = UI_construct_prompt(ui, "pass phrase", prompt_info);
180*b077aed3SPierre Pronchery if (prompt == NULL) {
181*b077aed3SPierre Pronchery BIO_printf(bio_err, "Out of memory\n");
182*b077aed3SPierre Pronchery UI_free(ui);
183*b077aed3SPierre Pronchery return 0;
184*b077aed3SPierre Pronchery }
185*b077aed3SPierre Pronchery
186*b077aed3SPierre Pronchery ui_flags |= UI_INPUT_FLAG_DEFAULT_PWD;
187*b077aed3SPierre Pronchery UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0);
188*b077aed3SPierre Pronchery
189*b077aed3SPierre Pronchery /* We know that there is no previous user data to return to us */
190*b077aed3SPierre Pronchery (void)UI_add_user_data(ui, cb_data);
191*b077aed3SPierre Pronchery
192*b077aed3SPierre Pronchery ok = UI_add_input_string(ui, prompt, ui_flags, buf,
193*b077aed3SPierre Pronchery PW_MIN_LENGTH, bufsiz - 1);
194*b077aed3SPierre Pronchery
195*b077aed3SPierre Pronchery if (ok >= 0 && verify) {
196*b077aed3SPierre Pronchery buff = ui_malloc(bufsiz, "password buffer");
197*b077aed3SPierre Pronchery ok = UI_add_verify_string(ui, prompt, ui_flags, buff,
198*b077aed3SPierre Pronchery PW_MIN_LENGTH, bufsiz - 1, buf);
199*b077aed3SPierre Pronchery }
200*b077aed3SPierre Pronchery if (ok >= 0)
201*b077aed3SPierre Pronchery do {
202*b077aed3SPierre Pronchery ok = UI_process(ui);
203*b077aed3SPierre Pronchery } while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0));
204*b077aed3SPierre Pronchery
205*b077aed3SPierre Pronchery OPENSSL_clear_free(buff, (unsigned int)bufsiz);
206*b077aed3SPierre Pronchery
207*b077aed3SPierre Pronchery if (ok >= 0)
208*b077aed3SPierre Pronchery res = strlen(buf);
209*b077aed3SPierre Pronchery if (ok == -1) {
210*b077aed3SPierre Pronchery BIO_printf(bio_err, "User interface error\n");
211*b077aed3SPierre Pronchery ERR_print_errors(bio_err);
212*b077aed3SPierre Pronchery OPENSSL_cleanse(buf, (unsigned int)bufsiz);
213*b077aed3SPierre Pronchery res = 0;
214*b077aed3SPierre Pronchery }
215*b077aed3SPierre Pronchery if (ok == -2) {
216*b077aed3SPierre Pronchery BIO_printf(bio_err, "aborted!\n");
217*b077aed3SPierre Pronchery OPENSSL_cleanse(buf, (unsigned int)bufsiz);
218*b077aed3SPierre Pronchery res = 0;
219*b077aed3SPierre Pronchery }
220*b077aed3SPierre Pronchery UI_free(ui);
221*b077aed3SPierre Pronchery OPENSSL_free(prompt);
222*b077aed3SPierre Pronchery return res;
223*b077aed3SPierre Pronchery }
224