]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/crypto/luks/FormatRequest.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / librbd / crypto / luks / FormatRequest.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "FormatRequest.h"
5
6 #include <stdlib.h>
7 #include <openssl/rand.h>
8 #include "common/dout.h"
9 #include "common/errno.h"
10 #include "include/compat.h"
11 #include "librbd/Utils.h"
12 #include "librbd/crypto/Utils.h"
13 #include "librbd/crypto/luks/Header.h"
14 #include "librbd/io/AioCompletion.h"
15 #include "librbd/io/ImageDispatchSpec.h"
16
17 #define dout_subsys ceph_subsys_rbd
18 #undef dout_prefix
19 #define dout_prefix *_dout << "librbd::crypto::luks::FormatRequest: " << this \
20 << " " << __func__ << ": "
21
22 namespace librbd {
23 namespace crypto {
24 namespace luks {
25
26 using librbd::util::create_context_callback;
27
28 template <typename I>
29 FormatRequest<I>::FormatRequest(
30 I* image_ctx, encryption_format_t format, encryption_algorithm_t alg,
31 std::string&& passphrase, ceph::ref_t<CryptoInterface>* result_crypto,
32 Context* on_finish,
33 bool insecure_fast_mode) : m_image_ctx(image_ctx), m_format(format),
34 m_alg(alg),
35 m_passphrase(std::move(passphrase)),
36 m_result_crypto(result_crypto),
37 m_on_finish(on_finish),
38 m_insecure_fast_mode(insecure_fast_mode),
39 m_header(image_ctx->cct) {
40 }
41
42 template <typename I>
43 void FormatRequest<I>::send() {
44 const char* type;
45 size_t sector_size;
46 switch (m_format) {
47 case RBD_ENCRYPTION_FORMAT_LUKS1:
48 type = CRYPT_LUKS1;
49 sector_size = 512;
50 break;
51 case RBD_ENCRYPTION_FORMAT_LUKS2:
52 type = CRYPT_LUKS2;
53 sector_size = 4096;
54 break;
55 default:
56 lderr(m_image_ctx->cct) << "unsupported format type: " << m_format
57 << dendl;
58 finish(-EINVAL);
59 return;
60 }
61
62 const char* cipher;
63 size_t key_size;
64 switch (m_alg) {
65 case RBD_ENCRYPTION_ALGORITHM_AES128:
66 cipher = "aes";
67 key_size = 32;
68 break;
69 case RBD_ENCRYPTION_ALGORITHM_AES256:
70 cipher = "aes";
71 key_size = 64;
72 break;
73 default:
74 lderr(m_image_ctx->cct) << "unsupported cipher algorithm: " << m_alg
75 << dendl;
76 finish(-EINVAL);
77 return;
78 }
79
80 // generate encryption key
81 unsigned char* key = (unsigned char*)alloca(key_size);
82 if (RAND_bytes((unsigned char *)key, key_size) != 1) {
83 lderr(m_image_ctx->cct) << "cannot generate random encryption key"
84 << dendl;
85 finish(-EAGAIN);
86 return;
87 }
88
89 // setup interface with libcryptsetup
90 auto r = m_header.init();
91 if (r < 0) {
92 finish(r);
93 return;
94 }
95
96 // format (create LUKS header)
97 r = m_header.format(type, cipher, reinterpret_cast<char*>(key), key_size,
98 "xts-plain64", sector_size,
99 m_image_ctx->get_object_size(), m_insecure_fast_mode);
100 if (r != 0) {
101 finish(r);
102 return;
103 }
104
105 m_image_ctx->image_lock.lock_shared();
106 uint64_t image_size = m_image_ctx->get_image_size(CEPH_NOSNAP);
107 m_image_ctx->image_lock.unlock_shared();
108
109 if (m_header.get_data_offset() >= image_size) {
110 lderr(m_image_ctx->cct) << "image is too small. format requires more than "
111 << m_header.get_data_offset() << " bytes" << dendl;
112 finish(-ENOSPC);
113 return;
114 }
115
116 // add keyslot (volume key encrypted with passphrase)
117 r = m_header.add_keyslot(m_passphrase.c_str(), m_passphrase.size());
118 if (r != 0) {
119 finish(r);
120 return;
121 }
122
123 r = util::build_crypto(m_image_ctx->cct, key, key_size,
124 m_header.get_sector_size(),
125 m_header.get_data_offset(), m_result_crypto);
126 ceph_memzero_s(key, key_size, key_size);
127 if (r != 0) {
128 finish(r);
129 return;
130 }
131
132 // read header from libcryptsetup interface
133 ceph::bufferlist bl;
134 r = m_header.read(&bl);
135 if (r < 0) {
136 finish(r);
137 return;
138 }
139
140 // write header to offset 0 of the image
141 auto ctx = create_context_callback<
142 FormatRequest<I>, &FormatRequest<I>::handle_write_header>(this);
143 auto aio_comp = io::AioCompletion::create_and_start(
144 ctx, librbd::util::get_image_ctx(m_image_ctx), io::AIO_TYPE_WRITE);
145
146 ZTracer::Trace trace;
147 auto req = io::ImageDispatchSpec::create_write(
148 *m_image_ctx, io::IMAGE_DISPATCH_LAYER_API_START, aio_comp,
149 {{0, bl.length()}}, std::move(bl),
150 m_image_ctx->get_data_io_context(), 0, trace);
151 req->send();
152 }
153
154 template <typename I>
155 void FormatRequest<I>::handle_write_header(int r) {
156 if (r < 0) {
157 lderr(m_image_ctx->cct) << "error writing header to image: "
158 << cpp_strerror(r) << dendl;
159 finish(r);
160 return;
161 }
162
163 finish(0);
164 }
165
166 template <typename I>
167 void FormatRequest<I>::finish(int r) {
168 ceph_memzero_s(
169 &m_passphrase[0], m_passphrase.capacity(), m_passphrase.size());
170 m_on_finish->complete(r);
171 delete this;
172 }
173
174 } // namespace luks
175 } // namespace crypto
176 } // namespace librbd
177
178 template class librbd::crypto::luks::FormatRequest<librbd::ImageCtx>;