]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/openssl_opts_handler.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / common / openssl_opts_handler.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (c) 2020 Huawei Technologies Co., Ltd.
7 *
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.
12 *
13 */
14
15 #include "openssl_opts_handler.h"
16
17 #include <openssl/bio.h>
18 #include <openssl/conf.h>
19 #include <openssl/engine.h>
20 #include <mutex>
21 #include <vector>
22 #include <algorithm>
23
24 #include "common/debug.h"
25 #include "global/global_context.h"
26 #include "include/str_list.h"
27 #include "include/scope_guard.h"
28
29 using std::string;
30 using std::ostream;
31 using std::vector;
32
33 // -----------------------------------------------------------------------------
34 #define dout_context g_ceph_context
35 #define dout_subsys ceph_subsys_common
36 #undef dout_prefix
37 #define dout_prefix _prefix(_dout)
38
39 static ostream &_prefix(std::ostream *_dout)
40 {
41 return *_dout << "OpenSSLOptsHandler: ";
42 }
43 // -----------------------------------------------------------------------------
44
45 string construct_engine_conf(const string &opts)
46 {
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";
49
50 string engine_id, engine_statement, engine_detail;
51 const string id_prefix = "engine";
52 const string suffix = "_section";
53 const char delimiter = '\n';
54
55 int index = 1;
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;
61
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;
67 }
68
69 return conf_header + engine_header + engine_statement + engine_detail;
70 }
71
72 string get_openssl_error()
73 {
74 BIO *bio = BIO_new(BIO_s_mem());
75 if (bio == nullptr) {
76 return "failed to create BIO for more error printing";
77 }
78 ERR_print_errors(bio);
79 char* buf;
80 size_t len = BIO_get_mem_data(bio, &buf);
81 string ret(buf, len);
82 BIO_free(bio);
83 return ret;
84 }
85
86 void log_error(const string &err)
87 {
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;
92 }
93
94 void load_module(const string &engine_conf)
95 {
96 BIO *mem = BIO_new_mem_buf(engine_conf.c_str(), engine_conf.size());
97 if (mem == nullptr) {
98 log_error("failed to new BIO memory");
99 return;
100 }
101 auto sg_mem = make_scope_guard([&mem] { BIO_free(mem); });
102
103 CONF *conf = NCONF_new(nullptr);
104 if (conf == nullptr) {
105 log_error("failed to new OpenSSL CONF");
106 return;
107 }
108 auto sg_conf = make_scope_guard([&conf] { NCONF_free(conf); });
109
110 if (NCONF_load_bio(conf, mem, nullptr) <= 0) {
111 log_error("failed to load CONF from BIO:\n" + get_openssl_error());
112 return;
113 }
114
115 OPENSSL_load_builtin_modules();
116 ENGINE_load_builtin_engines();
117
118 if (CONF_modules_load(
119 conf, nullptr,
120 CONF_MFLAGS_DEFAULT_SECTION | CONF_MFLAGS_IGNORE_MISSING_FILE) <= 0) {
121 log_error("failed to load modules from CONF:\n" + get_openssl_error());
122 }
123 }
124
125 void init_engine()
126 {
127 string opts = g_ceph_context->_conf->openssl_engine_opts;
128 if (opts.empty()) {
129 return;
130 }
131 string engine_conf = construct_engine_conf(opts);
132 load_module(engine_conf);
133 }
134
135 void ceph::crypto::init_openssl_engine_once()
136 {
137 static std::once_flag flag;
138 std::call_once(flag, init_engine);
139 }