1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (c) 2020 Huawei Technologies Co., Ltd.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
15 #include "openssl_opts_handler.h"
17 #include <openssl/bio.h>
18 #include <openssl/conf.h>
19 #include <openssl/engine.h>
24 #include "common/debug.h"
25 #include "global/global_context.h"
26 #include "include/str_list.h"
27 #include "include/scope_guard.h"
33 // -----------------------------------------------------------------------------
34 #define dout_context g_ceph_context
35 #define dout_subsys ceph_subsys_common
37 #define dout_prefix _prefix(_dout)
39 static ostream
&_prefix(std::ostream
*_dout
)
41 return *_dout
<< "OpenSSLOptsHandler: ";
43 // -----------------------------------------------------------------------------
45 string
construct_engine_conf(const string
&opts
)
47 const string conf_header
= "openssl_conf=openssl_def\n[openssl_def]\n";
48 const string engine_header
= "engines=engine_section\n[engine_section]\n";
50 string engine_id
, engine_statement
, engine_detail
;
51 const string id_prefix
= "engine";
52 const string suffix
= "_section";
53 const char delimiter
= '\n';
56 vector
<string
> confs
= get_str_vec(opts
, ":");
57 for (auto conf
: confs
) {
58 // Construct engine section statement like "engine1=engine1_section"
59 engine_id
= id_prefix
+ std::to_string(index
++);
60 engine_statement
+= engine_id
+ "=" + engine_id
+ suffix
+ delimiter
;
62 // Adapt to OpenSSL parser
63 // Replace ',' with '\n' and add section in front
64 std::replace(conf
.begin(), conf
.end(), ',', delimiter
);
65 engine_detail
+= "[" + engine_id
+ suffix
+ "]" + delimiter
;
66 engine_detail
+= conf
+ delimiter
;
69 return conf_header
+ engine_header
+ engine_statement
+ engine_detail
;
72 string
get_openssl_error()
74 BIO
*bio
= BIO_new(BIO_s_mem());
76 return "failed to create BIO for more error printing";
78 ERR_print_errors(bio
);
80 size_t len
= BIO_get_mem_data(bio
, &buf
);
86 void log_error(const string
&err
)
88 derr
<< "Intended OpenSSL engine acceleration failed.\n"
89 << "set by openssl_engine_opts = "
90 << g_ceph_context
->_conf
->openssl_engine_opts
91 << "\ndetail error information:\n" << err
<< dendl
;
94 void load_module(const string
&engine_conf
)
96 BIO
*mem
= BIO_new_mem_buf(engine_conf
.c_str(), engine_conf
.size());
98 log_error("failed to new BIO memory");
101 auto sg_mem
= make_scope_guard([&mem
] { BIO_free(mem
); });
103 CONF
*conf
= NCONF_new(nullptr);
104 if (conf
== nullptr) {
105 log_error("failed to new OpenSSL CONF");
108 auto sg_conf
= make_scope_guard([&conf
] { NCONF_free(conf
); });
110 if (NCONF_load_bio(conf
, mem
, nullptr) <= 0) {
111 log_error("failed to load CONF from BIO:\n" + get_openssl_error());
115 OPENSSL_load_builtin_modules();
116 #pragma GCC diagnostic push
117 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
119 #pragma clang diagnostic push
120 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
121 ENGINE_load_builtin_engines();
122 #pragma clang diagnostic pop
123 #pragma GCC diagnostic pop
125 if (CONF_modules_load(
127 CONF_MFLAGS_DEFAULT_SECTION
| CONF_MFLAGS_IGNORE_MISSING_FILE
) <= 0) {
128 log_error("failed to load modules from CONF:\n" + get_openssl_error());
134 string opts
= g_ceph_context
->_conf
->openssl_engine_opts
;
138 string engine_conf
= construct_engine_conf(opts
);
139 load_module(engine_conf
);
142 void ceph::crypto::init_openssl_engine_once()
144 static std::once_flag flag
;
145 std::call_once(flag
, init_engine
);