Add UI functionality to duplicate the user data
authorRichard Levitte <levitte@openssl.org>
Sun, 28 May 2017 07:35:11 +0000 (09:35 +0200)
committerRichard Levitte <levitte@openssl.org>
Wed, 31 May 2017 17:00:24 +0000 (19:00 +0200)
This can be used by engines that need to retain the data for a longer time
than just the call where this user data is passed.

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3575)

CHANGES
crypto/ui/ui_err.c
crypto/ui/ui_lib.c
crypto/ui/ui_locl.h
doc/man3/UI_create_method.pod
doc/man3/UI_new.pod
include/openssl/ui.h
util/libcrypto.num

diff --git a/CHANGES b/CHANGES
index ae9d7ea1426ff68618bccff76f29f2e3cca410ce..701771c718f2733f0c3927331bc1d513b4001203 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,11 @@
 
  Changes between 1.1.0f and 1.1.1 [xx XXX xxxx]
 
+  *) In the UI interface, make it possible to duplicate the user data.  This
+     can be used by engines that need to retain the data for a longer time
+     than just the call where this user data is passed.
+     [Richard Levitte]
+
   *) Fragmented SSL/TLS alerts are no longer accepted. An alert message is 2
      bytes long. In theory it is permissible in SSLv3 - TLSv1.2 to fragment such
      alerts across multiple records (some of which could be empty). In practice
index c8640feaf1ecfd740f0f157fbf461c24f0422029..d60c72dcbacc31289590fb8c07513be44d452912 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -31,6 +31,7 @@ static ERR_STRING_DATA UI_str_functs[] = {
     {ERR_FUNC(UI_F_UI_DUP_INFO_STRING), "UI_dup_info_string"},
     {ERR_FUNC(UI_F_UI_DUP_INPUT_BOOLEAN), "UI_dup_input_boolean"},
     {ERR_FUNC(UI_F_UI_DUP_INPUT_STRING), "UI_dup_input_string"},
+    {ERR_FUNC(UI_F_UI_DUP_USER_DATA), "UI_dup_user_data"},
     {ERR_FUNC(UI_F_UI_DUP_VERIFY_STRING), "UI_dup_verify_string"},
     {ERR_FUNC(UI_F_UI_GET0_RESULT), "UI_get0_result"},
     {ERR_FUNC(UI_F_UI_NEW_METHOD), "UI_new_method"},
@@ -54,6 +55,8 @@ static ERR_STRING_DATA UI_str_reasons[] = {
     {ERR_REASON(UI_R_UNKNOWN_CONTROL_COMMAND), "unknown control command"},
     {ERR_REASON(UI_R_UNKNOWN_TTYGET_ERRNO_VALUE),
      "unknown ttyget errno value"},
+    {ERR_REASON(UI_R_USER_DATA_DUPLICATION_UNSUPPORTED),
+     "user data duplication unsupported"},
     {0, NULL}
 };
 
index e48e4add1de355d875b4de9d80e4b81fd5ddacbd..f4e01bcf38af537f949b6fcc2d57ffecc1d6db79 100644 (file)
@@ -73,6 +73,9 @@ void UI_free(UI *ui)
 {
     if (ui == NULL)
         return;
+    if ((ui->flags & UI_FLAG_DUPL_DATA) != 0) {
+        ui->meth->ui_destroy_data(ui, ui->user_data);
+    }
     sk_UI_STRING_pop_free(ui->strings, free_string);
     CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI, ui, &ui->ex_data);
     CRYPTO_THREAD_lock_free(ui->lock);
@@ -387,10 +390,38 @@ char *UI_construct_prompt(UI *ui, const char *object_desc,
 void *UI_add_user_data(UI *ui, void *user_data)
 {
     void *old_data = ui->user_data;
+
+    if ((ui->flags & UI_FLAG_DUPL_DATA) != 0) {
+        ui->meth->ui_destroy_data(ui, old_data);
+        old_data = NULL;
+    }
     ui->user_data = user_data;
+    ui->flags &= ~UI_FLAG_DUPL_DATA;
     return old_data;
 }
 
+int UI_dup_user_data(UI *ui, void *user_data)
+{
+    void *duplicate = NULL;
+
+    if (ui->meth->ui_duplicate_data == NULL
+        || ui->meth->ui_destroy_data == NULL) {
+        UIerr(UI_F_UI_DUP_USER_DATA, UI_R_USER_DATA_DUPLICATION_UNSUPPORTED);
+        return -1;
+    }
+
+    duplicate = ui->meth->ui_duplicate_data(ui, user_data);
+    if (duplicate == NULL) {
+        UIerr(UI_F_UI_DUP_USER_DATA, ERR_R_MALLOC_FAILURE);
+        return -1;
+    }
+
+    (void)UI_add_user_data(ui, duplicate);
+    ui->flags |= UI_FLAG_DUPL_DATA;
+
+    return 0;
+}
+
 void *UI_get0_user_data(UI *ui)
 {
     return ui->user_data;
@@ -624,6 +655,18 @@ int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui))
     return -1;
 }
 
+int UI_method_set_data_duplicator(UI_METHOD *method,
+                                  void *(*duplicator) (UI *ui, void *ui_data),
+                                  void (*destructor)(UI *ui, void *ui_data))
+{
+    if (method != NULL) {
+        method->ui_duplicate_data = duplicator;
+        method->ui_destroy_data = destructor;
+        return 0;
+    }
+    return -1;
+}
+
 int UI_method_set_prompt_constructor(UI_METHOD *method,
                                      char *(*prompt_constructor) (UI *ui,
                                                                   const char
@@ -686,6 +729,20 @@ char *(*UI_method_get_prompt_constructor(const UI_METHOD *method))
     return NULL;
 }
 
+void *(*UI_method_get_data_duplicator(const UI_METHOD *method)) (UI *, void *)
+{
+    if (method != NULL)
+        return method->ui_duplicate_data;
+    return NULL;
+}
+
+void (*UI_method_get_data_destructor(const UI_METHOD *method)) (UI *, void *)
+{
+    if (method != NULL)
+        return method->ui_destroy_data;
+    return NULL;
+}
+
 const void *UI_method_get_ex_data(const UI_METHOD *method, int idx)
 {
     return CRYPTO_get_ex_data(&method->ex_data, idx);
index 94a9e359f0051a22caff45eacc87a75f69f8db8e..1b0d596ccd9178157fc19c8681bae63902a5890b 100644 (file)
@@ -37,6 +37,12 @@ struct ui_method_st {
     int (*ui_flush) (UI *ui);
     int (*ui_read_string) (UI *ui, UI_STRING *uis);
     int (*ui_close_session) (UI *ui);
+    /*
+     * Duplicate the ui_data that often comes alongside a ui_method.  This
+     * allows some backends to save away UI information for later use.
+     */
+    void *(*ui_duplicate_data) (UI *ui, void *ui_data);
+    void (*ui_destroy_data) (UI *ui, void *ui_data);
     /*
      * Construct a prompt in a user-defined manner.  object_desc is a textual
      * short description of the object, for example "pass phrase", and
@@ -92,6 +98,7 @@ struct ui_st {
     void *user_data;
     CRYPTO_EX_DATA ex_data;
 # define UI_FLAG_REDOABLE        0x0001
+# define UI_FLAG_DUPL_DATA       0x0002 /* user_data was duplicated */
 # define UI_FLAG_PRINT_ERRORS    0x0100
     int flags;
 
index 1c40153a3fb90dc881d5d718bfd080a70207b751..aefd41dac396b75070b85cfd739873e821a4a622 100644 (file)
@@ -5,9 +5,11 @@
 UI_METHOD,
 UI_create_method, UI_destroy_method, UI_method_set_opener,
 UI_method_set_writer, UI_method_set_flusher, UI_method_set_reader,
-UI_method_set_closer, UI_method_set_prompt_constructor,
-UI_method_set_ex_data, UI_method_get_opener, UI_method_get_writer,
-UI_method_get_flusher, UI_method_get_reader, UI_method_get_closer,
+UI_method_set_closer, UI_method_set_data_duplicator,
+UI_method_set_prompt_constructor, UI_method_set_ex_data,
+UI_method_get_opener, UI_method_get_writer, UI_method_get_flusher,
+UI_method_get_reader, UI_method_get_closer,
+UI_method_get_data_duplicator, UI_method_get_data_destructor,
 UI_method_get_prompt_constructor, UI_method_get_ex_data - user
 interface method creation and destruction
 
@@ -26,6 +28,9 @@ interface method creation and destruction
  int UI_method_set_reader(UI_METHOD *method,
                           int (*reader) (UI *ui, UI_STRING *uis));
  int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui));
+ int UI_method_set_data_duplicator(UI_METHOD *method,
+                                   void *(*duplicator) (UI *ui, void *ui_data),
+                                   void (*destructor)(UI *ui, void *ui_data));
  int UI_method_set_prompt_constructor(UI_METHOD *method,
                                       char *(*prompt_constructor) (UI *ui,
                                                                    const char
@@ -40,6 +45,8 @@ interface method creation and destruction
  int (*UI_method_get_closer(const UI_METHOD *method)) (UI *);
  char *(*UI_method_get_prompt_constructor(const UI_METHOD *method))
      (UI *, const char *, const char *);
+ void *(*UI_method_get_data_duplicator(const UI_METHOD *method)) (UI *, void *);
+ void (*UI_method_get_data_destructor(const UI_METHOD *method)) (UI *, void *);
  const void *UI_method_get_ex_data(const UI_METHOD *method, int idx);
 
 =head1 DESCRIPTION
@@ -148,6 +155,9 @@ UI_method_set_flusher(), UI_method_set_reader() and
 UI_method_set_closer() set the five main method function to the given
 function pointer.
 
+UI_method_set_data_duplicator() sets the user data duplicator and destructor.
+See L<UI_dup_user_data(3)>.
+
 UI_method_set_prompt_constructor() sets the prompt constructor.
 See L<UI_construct_prompt(3)>.
 
@@ -158,8 +168,9 @@ get that index.
 
 UI_method_get_opener(), UI_method_get_writer(),
 UI_method_get_flusher(), UI_method_get_reader(),
-UI_method_get_closer() and UI_method_get_prompt_constructor() return
-the different method functions.
+UI_method_get_closer(), UI_method_get_data_duplicator(),
+UI_method_get_data_destructor() and UI_method_get_prompt_constructor()
+return the different method functions.
 
 UI_method_get_ex_data() returns the application data previously stored
 with UI_method_set_ex_data().
@@ -171,17 +182,19 @@ error.
 
 UI_method_set_opener(), UI_method_set_writer(),
 UI_method_set_flusher(), UI_method_set_reader(),
-UI_method_set_closer() and UI_method_set_prompt_constructor() return
-0 on success, -1 if the given B<method> is NULL.
+UI_method_set_closer(), UI_method_set_data_duplicator() and
+UI_method_set_prompt_constructor()
+return 0 on success, -1 if the given B<method> is NULL.
 
 UI_method_set_ex_data() returns 1 on success and 0 on error (because
 CRYPTO_set_ex_data() does so).
 
 UI_method_get_opener(), UI_method_get_writer(),
 UI_method_get_flusher(), UI_method_get_reader(),
-UI_method_get_closer() and UI_method_get_prompt_constructor() return
-the requested function pointer if it's set in the method, otherwise
-NULL.
+UI_method_get_closer(), UI_method_get_data_duplicator(),
+UI_method_get_data_destructor() and UI_method_get_prompt_constructor()
+return the requested function pointer if it's set in the method,
+otherwise NULL.
 
 UI_method_get_ex_data() returns a pointer to the application specific
 data associated with the method.
@@ -190,6 +203,12 @@ data associated with the method.
 
 L<UI(3)>, L<CRYPTO_get_ex_data(3)>, L<UI_STRING(3)>
 
+=head1 HISTORY
+
+UI_method_set_data_duplicator(), UI_method_get_data_duplicator() and
+UI_method_get_data_destructor()
+were added in OpenSSL 1.1.1.
+
 =head1 COPYRIGHT
 
 Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
index 5b98cf8d0d20adce6cf72973f5ce0d838e61f859..60a3fd672e932fb6ac99649ec4c096954a566f31 100644 (file)
@@ -7,9 +7,9 @@ UI_new, UI_new_method, UI_free, UI_add_input_string, UI_dup_input_string,
 UI_add_verify_string, UI_dup_verify_string, UI_add_input_boolean,
 UI_dup_input_boolean, UI_add_info_string, UI_dup_info_string,
 UI_add_error_string, UI_dup_error_string, UI_construct_prompt,
-UI_add_user_data, UI_get0_user_data, UI_get0_result, UI_process,
-UI_ctrl, UI_set_default_method, UI_get_default_method, UI_get_method,
-UI_set_method, UI_OpenSSL, UI_null - user interface
+UI_add_user_data, UI_dup_user_data, UI_get0_user_data, UI_get0_result,
+UI_process, UI_ctrl, UI_set_default_method, UI_get_default_method,
+UI_get_method, UI_set_method, UI_OpenSSL, UI_null - user interface
 
 =head1 SYNOPSIS
 
@@ -44,6 +44,7 @@ UI_set_method, UI_OpenSSL, UI_null - user interface
         const char *object_desc, const char *object_name);
 
  void *UI_add_user_data(UI *ui, void *user_data);
+ int UI_dup_user_data(UI *ui, void *user_data);
  void *UI_get0_user_data(UI *ui);
 
  const char *UI_get0_result(UI *ui, int i);
@@ -76,16 +77,19 @@ carry out the actual prompting.
 The first thing to do is to create a UI with UI_new() or UI_new_method(),
 then add information to it with the UI_add or UI_dup functions.  Also,
 user-defined random data can be passed down to the underlying method
-through calls to UI_add_user_data.  The default UI method doesn't care
-about these data, but other methods might.  Finally, use UI_process()
-to actually perform the prompting and UI_get0_result() to find the result
-to the prompt.
+through calls to UI_add_user_data() or UI_dup_user_data().  The default
+UI method doesn't care about these data, but other methods might.  Finally,
+use UI_process() to actually perform the prompting and UI_get0_result()
+to find the result to the prompt.
 
 A UI can contain more than one prompt, which are performed in the given
 sequence.  Each prompt gets an index number which is returned by the
 UI_add and UI_dup functions, and has to be used to get the corresponding
 result with UI_get0_result().
 
+UI_process() can be called more than once on the same UI, thereby allowing
+a UI to have a long lifetime, but can just as well have a short lifetime.
+
 The functions are as follows:
 
 UI_new() creates a new UI using the default UI method.  When done with
@@ -149,13 +153,20 @@ description "pass phrase" and the file name "foo.key", that becomes
 string and may include encodings that will be processed by the other
 method functions.
 
-UI_add_user_data() adds a piece of memory for the method to use at any
+UI_add_user_data() adds a user data pointer for the method to use at any
 time.  The builtin UI method doesn't care about this info.  Note that several
 calls to this function doesn't add data, it replaces the previous blob
 with the one given as argument.
 
+UI_dup_user_data() duplicates the user data and works as an alternative
+to UI_add_user_data() when the user data needs to be preserved for a longer
+duration, perhaps even the lifetime of the application.  The UI object takes
+ownership of this duplicate and will free it whenever it gets replaced or
+the UI is destroyed.  UI_dup_user_data() returns 0 on success, or -1 on memory
+allocation failure or if the method doesn't have a duplicator function.
+
 UI_get0_user_data() retrieves the data that has last been given to the
-UI with UI_add_user_data().
+UI with UI_add_user_data() or UI_dup_user_data.
 
 UI_get0_result() returns a pointer to the result buffer associated with
 the information indexed by I<i>.
@@ -191,6 +202,11 @@ For Windows, if the OPENSSL_WIN32_UTF8 environment variable is set,
 the built-in method UI_OpenSSL() will produce UTF-8 encoded strings
 instead.
 
+=head1 HISTORY
+
+UI_dup_user_data()
+was added in OpenSSL 1.1.1.
+
 =head1 COPYRIGHT
 
 Copyright 2001-2017 The OpenSSL Project Authors. All Rights Reserved.
index fd8f8986411472befde37cec043a37e8f3c6a76a..c770e0ae0ce440f66671bcc183c3a66465e35f4f 100644 (file)
@@ -158,6 +158,12 @@ char *UI_construct_prompt(UI *ui_method,
  * methods may not, however.
  */
 void *UI_add_user_data(UI *ui, void *user_data);
+/*
+ * Alternatively, this function is used to duplicate the user data.
+ * This uses the duplicator method function.  The destroy function will
+ * be used to free the user data in this case.
+ */
+int UI_dup_user_data(UI *ui, void *user_data);
 /* We need a user data retrieving function as well.  */
 void *UI_get0_user_data(UI *ui);
 
@@ -285,6 +291,9 @@ int UI_method_set_flusher(UI_METHOD *method, int (*flusher) (UI *ui));
 int UI_method_set_reader(UI_METHOD *method,
                          int (*reader) (UI *ui, UI_STRING *uis));
 int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui));
+int UI_method_set_data_duplicator(UI_METHOD *method,
+                                  void *(*duplicator) (UI *ui, void *ui_data),
+                                  void (*destructor)(UI *ui, void *ui_data));
 int UI_method_set_prompt_constructor(UI_METHOD *method,
                                      char *(*prompt_constructor) (UI *ui,
                                                                   const char
@@ -299,6 +308,8 @@ int (*UI_method_get_reader(const UI_METHOD *method)) (UI *, UI_STRING *);
 int (*UI_method_get_closer(const UI_METHOD *method)) (UI *);
 char *(*UI_method_get_prompt_constructor(const UI_METHOD *method))
     (UI *, const char *, const char *);
+void *(*UI_method_get_data_duplicator(const UI_METHOD *method)) (UI *, void *);
+void (*UI_method_get_data_destructor(const UI_METHOD *method)) (UI *, void *);
 const void *UI_method_get_ex_data(const UI_METHOD *method, int idx);
 
 /*
@@ -335,7 +346,7 @@ int UI_UTIL_read_pw_string(char *buf, int length, const char *prompt,
                            int verify);
 int UI_UTIL_read_pw(char *buf, char *buff, int size, const char *prompt,
                     int verify);
-    UI_METHOD *UI_UTIL_wrap_read_pem_callback(pem_password_cb *cb, int rwflag);
+UI_METHOD *UI_UTIL_wrap_read_pem_callback(pem_password_cb *cb, int rwflag);
 
 /* BEGIN ERROR CODES */
 /*
@@ -360,6 +371,7 @@ int ERR_load_UI_strings(void);
 # define UI_F_UI_DUP_INFO_STRING                          102
 # define UI_F_UI_DUP_INPUT_BOOLEAN                        110
 # define UI_F_UI_DUP_INPUT_STRING                         103
+# define UI_F_UI_DUP_USER_DATA                            118
 # define UI_F_UI_DUP_VERIFY_STRING                        106
 # define UI_F_UI_GET0_RESULT                              107
 # define UI_F_UI_NEW_METHOD                               104
@@ -379,6 +391,7 @@ int ERR_load_UI_strings(void);
 # define UI_R_SYSQIOW_ERROR                               111
 # define UI_R_UNKNOWN_CONTROL_COMMAND                     106
 # define UI_R_UNKNOWN_TTYGET_ERRNO_VALUE                  108
+# define UI_R_USER_DATA_DUPLICATION_UNSUPPORTED           112
 
 #  ifdef  __cplusplus
 }
index 813818cf98752a3a3b30879f492e59654470fce7..6bb9129fbf5b365714da487f313c361c6f2a48b8 100644 (file)
@@ -4292,3 +4292,7 @@ PEM_read_bio_ex                         4234      1_1_1   EXIST::FUNCTION:
 PEM_bytes_read_bio_secmem               4235   1_1_1   EXIST::FUNCTION:
 EVP_DigestSign                          4236   1_1_1   EXIST::FUNCTION:
 EVP_DigestVerify                        4237   1_1_1   EXIST::FUNCTION:
+UI_method_get_data_duplicator           4238   1_1_1   EXIST::FUNCTION:UI
+UI_method_set_data_duplicator           4239   1_1_1   EXIST::FUNCTION:UI
+UI_dup_user_data                        4240   1_1_1   EXIST::FUNCTION:UI
+UI_method_get_data_destructor           4241   1_1_1   EXIST::FUNCTION:UI