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