Переглянути джерело

DESERIALIZER: Implement decryption of password protected objects

This implements these functions:

OSSL_DESERIALIZER_CTX_set_cipher()
OSSL_DESERIALIZER_CTX_set_passphrase()
OSSL_DESERIALIZER_CTX_set_passphrase_ui()
OSSL_DESERIALIZER_CTX_set_passphrase_cb()

To be able to deal with multiple deserializers trying to work on the
same byte array and wanting to decrypt it while doing so, the
deserializer caches the passphrase.  This cache is cleared at the end
of OSSL_DESERIALIZER_from_bio().

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/12410)
Richard Levitte 3 роки тому
батько
коміт
7524b7b748

+ 2 - 0
crypto/serializer/build.info

@@ -1,3 +1,5 @@
+SOURCE[../../libcrypto]=serdes_pass.c
+
 SOURCE[../../libcrypto]=serializer_meth.c serializer_lib.c serializer_pkey.c
 SOURCE[../../libcrypto]=deserializer_meth.c deserializer_lib.c \
         deserializer_pkey.c

+ 8 - 1
crypto/serializer/deserializer_lib.c

@@ -29,12 +29,19 @@ static int deser_process(const OSSL_PARAM params[], void *arg);
 int OSSL_DESERIALIZER_from_bio(OSSL_DESERIALIZER_CTX *ctx, BIO *in)
 {
     struct deser_process_data_st data;
+    int ok = 0;
 
     memset(&data, 0, sizeof(data));
     data.ctx = ctx;
     data.bio = in;
 
-    return deser_process(NULL, &data);
+    ok = deser_process(NULL, &data);
+
+    /* Clear any cached passphrase */
+    OPENSSL_clear_free(ctx->cached_passphrase, ctx->cached_passphrase_len);
+    ctx->cached_passphrase = NULL;
+    ctx->cached_passphrase_len = 0;
+    return ok;
 }
 
 #ifndef OPENSSL_NO_STDIO

+ 71 - 0
crypto/serializer/deserializer_pkey.c

@@ -9,11 +9,82 @@
 
 #include <openssl/core_names.h>
 #include <openssl/evp.h>
+#include <openssl/ui.h>
 #include <openssl/deserializer.h>
+#include <openssl/core_names.h>
 #include <openssl/safestack.h>
 #include "crypto/evp.h"
 #include "serializer_local.h"
 
+int OSSL_DESERIALIZER_CTX_set_cipher(OSSL_DESERIALIZER_CTX *ctx,
+                                     const char *cipher_name,
+                                     const char *propquery)
+{
+    OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END };
+
+    params[0] =
+        OSSL_PARAM_construct_utf8_string(OSSL_DESERIALIZER_PARAM_CIPHER,
+                                         (void *)cipher_name, 0);
+    params[1] =
+        OSSL_PARAM_construct_utf8_string(OSSL_DESERIALIZER_PARAM_PROPERTIES,
+                                         (void *)propquery, 0);
+
+    return OSSL_DESERIALIZER_CTX_set_params(ctx, params);
+}
+
+int OSSL_DESERIALIZER_CTX_set_passphrase(OSSL_DESERIALIZER_CTX *ctx,
+                                         const unsigned char *kstr,
+                                         size_t klen)
+{
+    OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END };
+
+    params[0] = OSSL_PARAM_construct_octet_string(OSSL_DESERIALIZER_PARAM_PASS,
+                                                  (void *)kstr, klen);
+
+    return OSSL_DESERIALIZER_CTX_set_params(ctx, params);
+}
+
+static void deserializer_ctx_reset_passphrase_ui(OSSL_DESERIALIZER_CTX *ctx)
+{
+    UI_destroy_method(ctx->allocated_ui_method);
+    ctx->allocated_ui_method = NULL;
+    ctx->ui_method = NULL;
+    ctx->ui_data = NULL;
+}
+
+int OSSL_DESERIALIZER_CTX_set_passphrase_ui(OSSL_DESERIALIZER_CTX *ctx,
+                                            const UI_METHOD *ui_method,
+                                            void *ui_data)
+{
+    if (!ossl_assert(ctx != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    deserializer_ctx_reset_passphrase_ui(ctx);
+    ctx->ui_method = ui_method;
+    ctx->ui_data = ui_data;
+    return 1;
+}
+
+int OSSL_DESERIALIZER_CTX_set_passphrase_cb(OSSL_DESERIALIZER_CTX *ctx,
+                                            pem_password_cb *cb, void *cbarg)
+{
+    if (!ossl_assert(ctx != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    deserializer_ctx_reset_passphrase_ui(ctx);
+    if (cb == NULL)
+        return 1;
+    ctx->ui_method =
+        ctx->allocated_ui_method = UI_UTIL_wrap_read_pem_callback(cb, 0);
+    ctx->ui_data = cbarg;
+
+    return ctx->ui_method != NULL;
+}
+
 /*
  * Support for OSSL_DESERIALIZER_CTX_new_by_EVP_PKEY:
  * Handle an object reference

+ 159 - 0
crypto/serializer/serdes_pass.c

@@ -0,0 +1,159 @@
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/err.h>
+#include <openssl/ui.h>
+#include <openssl/core_names.h>
+#include "internal/cryptlib.h"
+#include "serializer_local.h"
+
+/* Passphrase callbacks for any who need it */
+
+/*
+ * First, define the generic passphrase function that supports both
+ * outgoing (with passphrase verify) and incoming (without passphrase
+ * verify) passphrase reading.
+ */
+static int do_passphrase(char *pass, size_t pass_size, size_t *pass_len,
+                         const OSSL_PARAM params[], void *arg, int verify,
+                         const UI_METHOD *ui_method, void *ui_data, int errlib)
+{
+    const OSSL_PARAM *p;
+    const char *prompt_info = NULL;
+    char *prompt = NULL, *vpass = NULL;
+    int prompt_idx = -1, verify_idx = -1;
+    UI *ui = NULL;
+    int ret = 0;
+
+    if (!ossl_assert(pass != NULL && pass_size != 0 && pass_len != NULL)) {
+        ERR_raise(errlib, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    if ((p = OSSL_PARAM_locate_const(params,
+                                     OSSL_PASSPHRASE_PARAM_INFO)) != NULL) {
+        if (p->data_type != OSSL_PARAM_UTF8_STRING)
+            return 0;
+        prompt_info = p->data;
+    }
+
+    if ((ui = UI_new()) == NULL) {
+        ERR_raise(errlib, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    UI_set_method(ui, ui_method);
+    UI_add_user_data(ui, ui_data);
+
+    /* Get an application constructed prompt */
+    prompt = UI_construct_prompt(ui, "pass phrase", prompt_info);
+   if (prompt == NULL) {
+        ERR_raise(errlib, ERR_R_MALLOC_FAILURE);
+        goto end;
+    }
+
+    prompt_idx = UI_add_input_string(ui, prompt,
+                                     UI_INPUT_FLAG_DEFAULT_PWD,
+                                     pass, 0, pass_size - 1) - 1;
+    if (prompt_idx < 0) {
+        ERR_raise(errlib, ERR_R_UI_LIB);
+        goto end;
+    }
+
+    if (verify) {
+        /* Get a buffer for verification prompt */
+        vpass = OPENSSL_zalloc(pass_size);
+        if (vpass == NULL) {
+            ERR_raise(errlib, ERR_R_MALLOC_FAILURE);
+            goto end;
+        }
+        verify_idx = UI_add_verify_string(ui, prompt,
+                                          UI_INPUT_FLAG_DEFAULT_PWD,
+                                          vpass, 0, pass_size - 1,
+                                          pass) - 1;
+        if (verify_idx < 0) {
+            ERR_raise(errlib, ERR_R_UI_LIB);
+            goto end;
+        }
+    }
+
+    switch (UI_process(ui)) {
+    case -2:
+        ERR_raise(errlib, ERR_R_INTERRUPTED_OR_CANCELLED);
+        break;
+    case -1:
+        ERR_raise(errlib, ERR_R_UI_LIB);
+        break;
+    default:
+        *pass_len = (size_t)UI_get_result_length(ui, prompt_idx);
+        ret = 1;
+        break;
+    }
+
+ end:
+    OPENSSL_free(vpass);
+    OPENSSL_free(prompt);
+    UI_free(ui);
+    return ret;
+}
+
+/*
+ * Serializers typically want to get an outgoing passphrase, while
+ * deserializers typically want to get en incoming passphrase.
+ */
+int ossl_serializer_passphrase_out_cb(char *pass, size_t pass_size,
+                                      size_t *pass_len,
+                                      const OSSL_PARAM params[], void *arg)
+{
+    OSSL_SERIALIZER_CTX *ctx = arg;
+
+    if (!ossl_assert(ctx != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    return do_passphrase(pass, pass_size, pass_len, params, arg, 1,
+                         ctx->ui_method, ctx->ui_data,
+                         ERR_LIB_OSSL_SERIALIZER);
+}
+
+int ossl_deserializer_passphrase_in_cb(char *pass, size_t pass_size,
+                                       size_t *pass_len,
+                                       const OSSL_PARAM params[], void *arg)
+{
+    OSSL_DESERIALIZER_CTX *ctx = arg;
+
+    if (!ossl_assert(ctx != NULL)) {
+        ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    if (ctx->cached_passphrase != NULL) {
+        size_t len = ctx->cached_passphrase_len;
+
+        if (len > pass_size)
+            len = pass_size;
+        memcpy(pass, ctx->cached_passphrase, len);
+        *pass_len = len;
+        return 1;
+    } else {
+        if ((ctx->cached_passphrase = OPENSSL_zalloc(pass_size)) == NULL) {
+            ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+    }
+    if (do_passphrase(pass, pass_size, pass_len, params, arg, 0,
+                      ctx->ui_method, ctx->ui_data,
+                      ERR_LIB_OSSL_DESERIALIZER)) {
+        memcpy(ctx->cached_passphrase, pass, *pass_len);
+        ctx->cached_passphrase_len = *pass_len;
+        return 1;
+    }
+    return 0;
+}

+ 16 - 0
crypto/serializer/serializer_local.h

@@ -110,4 +110,20 @@ struct ossl_deserializer_ctx_st {
      * intermediary storage.
      */
     UI_METHOD *allocated_ui_method;
+    /*
+     * Because the same input may pass through more than one deserializer,
+     * we cache any passphrase passed to us.  The desrializing processor
+     * must clear this at the end of a run.
+     */
+    unsigned char *cached_passphrase;
+    size_t cached_passphrase_len;
 };
+
+/* Passphrase callbacks, found in serdes_pass.c */
+
+/*
+ * Serializers typically want to get an outgoing passphrase, while
+ * deserializers typically want to get en incoming passphrase.
+ */
+OSSL_PASSPHRASE_CALLBACK ossl_serializer_passphrase_out_cb;
+OSSL_PASSPHRASE_CALLBACK ossl_deserializer_passphrase_in_cb;

+ 2 - 106
crypto/serializer/serializer_pkey.c

@@ -107,110 +107,6 @@ static void cache_serializers(const char *name, void *data)
         d->error = 1;
 }
 
-/*
- * Support for OSSL_SERIALIZER_CTX_new_by_TYPE and OSSL_SERIALIZER_to_bio:
- * Passphrase callbacks
- */
-
-/*
- * First, we define the generic passphrase function that supports both
- * outgoing (with passphrase verify) and incoming (without passphrase verify)
- * passphrase reading.
- */
-static int serializer_passphrase(char *pass, size_t pass_size,
-                                 size_t *pass_len, int verify,
-                                 const OSSL_PARAM params[], void *arg)
-{
-    OSSL_SERIALIZER_CTX *ctx = arg;
-    const OSSL_PARAM *p;
-    const char *prompt_info = NULL;
-    char *prompt = NULL, *vpass = NULL;
-    int prompt_idx = -1, verify_idx = -1;
-    UI *ui = NULL;
-    int ret = 0;
-
-    if (!ossl_assert(ctx != NULL && pass != NULL
-                    && pass_size != 0 && pass_len != NULL)) {
-        ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
-        return 0;
-    }
-
-    if ((p = OSSL_PARAM_locate_const(params,
-                                     OSSL_PASSPHRASE_PARAM_INFO)) != NULL) {
-        if (p->data_type != OSSL_PARAM_UTF8_STRING)
-            return 0;
-        prompt_info = p->data;
-    }
-
-    if ((ui = UI_new()) == NULL) {
-        ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE);
-        return 0;
-    }
-
-    UI_set_method(ui, ctx->ui_method);
-    UI_add_user_data(ui, ctx->ui_data);
-
-    /* Get an application constructed prompt */
-    prompt = UI_construct_prompt(ui, "pass phrase", prompt_info);
-   if (prompt == NULL) {
-        ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE);
-        goto end;
-    }
-
-    prompt_idx = UI_add_input_string(ui, prompt,
-                                     UI_INPUT_FLAG_DEFAULT_PWD,
-                                     pass, 0, pass_size - 1) - 1;
-    if (prompt_idx < 0) {
-        ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_UI_LIB);
-        goto end;
-    }
-
-    if (verify) {
-        /* Get a buffer for verification prompt */
-        vpass = OPENSSL_zalloc(pass_size);
-        if (vpass == NULL) {
-            ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE);
-            goto end;
-        }
-        verify_idx = UI_add_verify_string(ui, prompt,
-                                          UI_INPUT_FLAG_DEFAULT_PWD,
-                                          vpass, 0, pass_size - 1,
-                                          pass) - 1;
-        if (verify_idx < 0) {
-            ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_UI_LIB);
-            goto end;
-        }
-    }
-
-    switch (UI_process(ui)) {
-    case -2:
-        ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_INTERRUPTED_OR_CANCELLED);
-        break;
-    case -1:
-        ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_UI_LIB);
-        break;
-    default:
-        *pass_len = (size_t)UI_get_result_length(ui, prompt_idx);
-        ret = 1;
-        break;
-    }
-
- end:
-    OPENSSL_free(vpass);
-    OPENSSL_free(prompt);
-    UI_free(ui);
-    return ret;
-}
-
-/* Ensure correct function definition for outgoing passphrase reader */
-static OSSL_PASSPHRASE_CALLBACK serializer_passphrase_out_cb;
-static int serializer_passphrase_out_cb(char *pass, size_t pass_size,
-                                        size_t *pass_len,
-                                        const OSSL_PARAM params[], void *arg)
-{
-    return serializer_passphrase(pass, pass_size, pass_len, 1, params, arg);
-}
-
 /*
  * Support for OSSL_SERIALIZER_to_bio:
  * writing callback for the OSSL_PARAM (the implementation doesn't have
@@ -229,7 +125,7 @@ static int serializer_write_cb(const OSSL_PARAM params[], void *arg)
     BIO *out = write_data->out;
 
     return ctx->ser->serialize_data(ctx->serctx, params, (OSSL_CORE_BIO *)out,
-                                    serializer_passphrase_out_cb, ctx);
+                                    ossl_serializer_passphrase_out_cb, ctx);
 }
 
 /*
@@ -266,7 +162,7 @@ static int serializer_EVP_PKEY_to_bio(OSSL_SERIALIZER_CTX *ctx, BIO *out)
 
     return ctx->ser->serialize_object(ctx->serctx, keydata,
                                       (OSSL_CORE_BIO *)out,
-                                      serializer_passphrase_out_cb, ctx);
+                                      ossl_serializer_passphrase_out_cb, ctx);
 }
 
 /*

+ 3 - 0
include/openssl/core_names.h

@@ -404,6 +404,9 @@ extern "C" {
 #define OSSL_SERIALIZER_PARAM_PROPERTIES        OSSL_ALG_PARAM_PROPERTIES
 #define OSSL_SERIALIZER_PARAM_PASS              "passphrase"
 
+#define OSSL_DESERIALIZER_PARAM_CIPHER          OSSL_ALG_PARAM_CIPHER
+#define OSSL_DESERIALIZER_PARAM_PROPERTIES      OSSL_ALG_PARAM_PROPERTIES
+#define OSSL_DESERIALIZER_PARAM_PASS            "passphrase"
 #define OSSL_DESERIALIZER_PARAM_INPUT_TYPE      "input-type"
 #define OSSL_DESERIALIZER_PARAM_DATA_TYPE       "data-type"
 #define OSSL_DESERIALIZER_PARAM_DATA            "data"