VirtualBox

source: vbox/trunk/src/VBox/ImageMounter/vboximg-mount/vboximgCrypto.cpp

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.2 KB
Line 
1/* $Id: vboximgCrypto.cpp 106061 2024-09-16 14:03:52Z vboxsync $ $Revision: 106061 $ */
2
3/** @file
4 * vboximgCypto.cpp - Disk Image Flattening FUSE Program.
5 */
6
7/*
8 * Copyright (C) 2009-2024 Oracle and/or its affiliates.
9 *
10 * This file is part of VirtualBox base platform packages, as
11 * available from https://www.virtualbox.org.
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation, in version 3 of the
16 * License.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, see <https://www.gnu.org/licenses>.
25 *
26 * SPDX-License-Identifier: GPL-3.0-only
27 */
28
29#include <iprt/cdefs.h>
30#include <VBox/err.h>
31#include <VBox/settings.h>
32#include <VBox/vd.h>
33#include "vboximgCrypto.h"
34#include <VBox/log.h>
35#include <iprt/assert.h>
36#include <iprt/asm.h>
37#include <iprt/memsafer.h>
38
39/*
40 * Apparently there is a more COM:: oriented (but less efficient?) approach to dealing
41 * with the keystore and disk encryption, which will need to be investigated. Keeping
42 * all this duplicated code in a separate file until the ideal approach is determined.
43 */
44SecretKey::SecretKey(const uint8_t *pbKey, size_t cbKey, bool fKeyBufNonPageable)
45{
46 m_cRefs = 0;
47 m_fRemoveOnSuspend = false;
48 m_cUsers = 0;
49 m_cbKey = cbKey;
50
51 int rc = RTMemSaferAllocZEx((void **)&this->m_pbKey, cbKey,
52 fKeyBufNonPageable ? RTMEMSAFER_F_REQUIRE_NOT_PAGABLE : 0);
53 if (RT_SUCCESS(rc))
54 {
55 memcpy(this->m_pbKey, pbKey, cbKey);
56
57 /* Scramble content to make retrieving the key more difficult. */
58 rc = RTMemSaferScramble(this->m_pbKey, cbKey);
59 }
60 else
61 throw rc;
62}
63
64SecretKey::~SecretKey()
65{
66 Assert(!m_cRefs);
67
68 RTMemSaferFree(m_pbKey, m_cbKey);
69 m_cRefs = 0;
70 m_pbKey = NULL;
71 m_cbKey = 0;
72 m_fRemoveOnSuspend = false;
73 m_cUsers = 0;
74}
75
76uint32_t SecretKey::retain()
77{
78 uint32_t cRefs = ASMAtomicIncU32(&m_cRefs);
79 if (cRefs == 1)
80 {
81 int rc = RTMemSaferUnscramble(m_pbKey, m_cbKey);
82 AssertRC(rc);
83 }
84
85 return cRefs;
86}
87
88uint32_t SecretKey::release()
89{
90 uint32_t cRefs = ASMAtomicDecU32(&m_cRefs);
91 if (!cRefs)
92 {
93 int rc = RTMemSaferScramble(m_pbKey, m_cbKey);
94 AssertRC(rc);
95 }
96
97 return cRefs;
98}
99
100uint32_t SecretKey::refCount()
101{
102 return m_cRefs;
103}
104
105int SecretKey::setUsers(uint32_t cUsers)
106{
107 m_cUsers = cUsers;
108 return VINF_SUCCESS;
109}
110
111uint32_t SecretKey::getUsers()
112{
113 return m_cUsers;
114}
115
116int SecretKey::setRemoveOnSuspend(bool fRemoveOnSuspend)
117{
118 m_fRemoveOnSuspend = fRemoveOnSuspend;
119 return VINF_SUCCESS;
120}
121
122bool SecretKey::getRemoveOnSuspend()
123{
124 return m_fRemoveOnSuspend;
125}
126
127const void *SecretKey::getKeyBuffer()
128{
129 AssertReturn(m_cRefs > 0, NULL);
130 return m_pbKey;
131}
132
133size_t SecretKey::getKeySize()
134{
135 return m_cbKey;
136}
137
138SecretKeyStore::SecretKeyStore(bool fKeyBufNonPageable)
139{
140 m_fKeyBufNonPageable = fKeyBufNonPageable;
141}
142
143SecretKeyStore::~SecretKeyStore()
144{
145 int rc = deleteAllSecretKeys(false /* fSuspend */, true /* fForce */);
146 AssertRC(rc);
147}
148
149int SecretKeyStore::addSecretKey(const com::Utf8Str &strKeyId, const uint8_t *pbKey, size_t cbKey)
150{
151 /* Check that the ID is not existing already. */
152 SecretKeyMap::const_iterator it = m_mapSecretKeys.find(strKeyId);
153 if (it != m_mapSecretKeys.end())
154 return VERR_ALREADY_EXISTS;
155
156 SecretKey *pKey = NULL;
157 try
158 {
159 pKey = new SecretKey(pbKey, cbKey, m_fKeyBufNonPageable);
160
161 m_mapSecretKeys.insert(std::make_pair(strKeyId, pKey));
162 }
163 catch (int rc)
164 {
165 return rc;
166 }
167 catch (std::bad_alloc &)
168 {
169 if (pKey)
170 delete pKey;
171 return VERR_NO_MEMORY;
172 }
173
174 return VINF_SUCCESS;
175}
176
177int SecretKeyStore::deleteSecretKey(const com::Utf8Str &strKeyId)
178{
179 SecretKeyMap::iterator it = m_mapSecretKeys.find(strKeyId);
180 if (it == m_mapSecretKeys.end())
181 return VERR_NOT_FOUND;
182
183 SecretKey *pKey = it->second;
184 if (pKey->refCount() != 0)
185 return VERR_RESOURCE_IN_USE;
186
187 m_mapSecretKeys.erase(it);
188 delete pKey;
189
190 return VINF_SUCCESS;
191}
192
193int SecretKeyStore::retainSecretKey(const com::Utf8Str &strKeyId, SecretKey **ppKey)
194{
195 SecretKeyMap::const_iterator it = m_mapSecretKeys.find(strKeyId);
196 if (it == m_mapSecretKeys.end())
197 return VERR_NOT_FOUND;
198
199 SecretKey *pKey = it->second;
200 pKey->retain();
201
202 *ppKey = pKey;
203
204 return VINF_SUCCESS;
205}
206
207int SecretKeyStore::releaseSecretKey(const com::Utf8Str &strKeyId)
208{
209 SecretKeyMap::const_iterator it = m_mapSecretKeys.find(strKeyId);
210 if (it == m_mapSecretKeys.end())
211 return VERR_NOT_FOUND;
212
213 SecretKey *pKey = it->second;
214 pKey->release();
215 return VINF_SUCCESS;
216}
217
218int SecretKeyStore::deleteAllSecretKeys(bool fSuspend, bool fForce)
219{
220 /* First check whether a key is still in use. */
221 if (!fForce)
222 {
223 for (SecretKeyMap::iterator it = m_mapSecretKeys.begin();
224 it != m_mapSecretKeys.end();
225 ++it)
226 {
227 SecretKey *pKey = it->second;
228 if ( pKey->refCount()
229 && ( ( pKey->getRemoveOnSuspend()
230 && fSuspend)
231 || !fSuspend))
232 return VERR_RESOURCE_IN_USE;
233 }
234 }
235
236 SecretKeyMap::iterator it = m_mapSecretKeys.begin();
237 while (it != m_mapSecretKeys.end())
238 {
239 SecretKey *pKey = it->second;
240 if ( pKey->getRemoveOnSuspend()
241 || !fSuspend)
242 {
243 AssertMsg(!pKey->refCount(), ("No one should access the stored key at this point anymore!\n"));
244 delete pKey;
245 SecretKeyMap::iterator itNext = it;
246 ++itNext;
247 m_mapSecretKeys.erase(it);
248 it = itNext;
249 }
250 else
251 ++it;
252 }
253
254 return VINF_SUCCESS;
255}
256
257void vboxImageCryptoSetup(VDISKCRYPTOSETTINGS *pSettings, const char *pszCipher,
258 const char *pszKeyStore, const char *pszPassword,
259 bool fCreateKeyStore)
260{
261 pSettings->pszCipher = pszCipher;
262 pSettings->pszPassword = pszPassword;
263 pSettings->pszKeyStoreLoad = pszKeyStore;
264 pSettings->fCreateKeyStore = fCreateKeyStore;
265 pSettings->pbDek = NULL;
266 pSettings->cbDek = 0;
267 pSettings->vdFilterIfaces = NULL;
268
269 pSettings->vdIfCfg.pfnAreKeysValid = vboximgVdCryptoConfigAreKeysValid;
270 pSettings->vdIfCfg.pfnQuerySize = vboximgVdCryptoConfigQuerySize;
271 pSettings->vdIfCfg.pfnQuery = vboximgVdCryptoConfigQuery;
272 pSettings->vdIfCfg.pfnQueryBytes = NULL;
273
274 pSettings->vdIfCrypto.pfnKeyRetain = vboximgVdCryptoKeyRetain;
275 pSettings->vdIfCrypto.pfnKeyRelease = vboximgVdCryptoKeyRelease;
276 pSettings->vdIfCrypto.pfnKeyStorePasswordRetain = vboximgVdCryptoKeyStorePasswordRetain;
277 pSettings->vdIfCrypto.pfnKeyStorePasswordRelease = vboximgVdCryptoKeyStorePasswordRelease;
278 pSettings->vdIfCrypto.pfnKeyStoreSave = vboximgVdCryptoKeyStoreSave;
279 pSettings->vdIfCrypto.pfnKeyStoreReturnParameters = vboximgVdCryptoKeyStoreReturnParameters;
280
281 int rc = VDInterfaceAdd(&pSettings->vdIfCfg.Core,
282 "vboximgVdInterfaceCfgCrypto",
283 VDINTERFACETYPE_CONFIG, pSettings,
284 sizeof(VDINTERFACECONFIG), &pSettings->vdFilterIfaces);
285 AssertRC(rc);
286
287 rc = VDInterfaceAdd(&pSettings->vdIfCrypto.Core,
288 "vboximgVdInterfaceCrypto",
289 VDINTERFACETYPE_CRYPTO, pSettings,
290 sizeof(VDINTERFACECRYPTO), &pSettings->vdFilterIfaces);
291 AssertRC(rc);
292}
293
294DECLCALLBACK(bool) vboximgVdCryptoConfigAreKeysValid(void *pvUser, const char *pszzValid)
295{
296 /* Just return always true here. */
297 NOREF(pvUser);
298 NOREF(pszzValid);
299 return true;
300}
301
302DECLCALLBACK(int) vboximgVdCryptoConfigQuerySize(void *pvUser, const char *pszName, size_t *pcbValue)
303{
304 VDISKCRYPTOSETTINGS *pSettings = (VDISKCRYPTOSETTINGS *)pvUser;
305 AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE);
306 AssertPtrReturn(pcbValue, VERR_INVALID_POINTER);
307
308 size_t cbValue = 0;
309 if (!strcmp(pszName, "Algorithm"))
310 cbValue = strlen(pSettings->pszCipher) + 1;
311 else if (!strcmp(pszName, "KeyId"))
312 cbValue = sizeof("irrelevant");
313 else if (!strcmp(pszName, "KeyStore"))
314 {
315 if (!pSettings->pszKeyStoreLoad)
316 return VERR_CFGM_VALUE_NOT_FOUND;
317 cbValue = strlen(pSettings->pszKeyStoreLoad) + 1;
318 }
319 else if (!strcmp(pszName, "CreateKeyStore"))
320 cbValue = 2; /* Single digit + terminator. */
321 else
322 return VERR_CFGM_VALUE_NOT_FOUND;
323
324 *pcbValue = cbValue + 1 /* include terminator */;
325
326 return VINF_SUCCESS;
327}
328
329DECLCALLBACK(int) vboximgVdCryptoConfigQuery(void *pvUser, const char *pszName,
330 char *pszValue, size_t cchValue)
331{
332 VDISKCRYPTOSETTINGS *pSettings = (VDISKCRYPTOSETTINGS *)pvUser;
333 AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE);
334 AssertPtrReturn(pszValue, VERR_INVALID_POINTER);
335
336 const char *psz = NULL;
337 if (!strcmp(pszName, "Algorithm"))
338 psz = pSettings->pszCipher;
339 else if (!strcmp(pszName, "KeyId"))
340 psz = "irrelevant";
341 else if (!strcmp(pszName, "KeyStore"))
342 psz = pSettings->pszKeyStoreLoad;
343 else if (!strcmp(pszName, "CreateKeyStore"))
344 {
345 if (pSettings->fCreateKeyStore)
346 psz = "1";
347 else
348 psz = "0";
349 }
350 else
351 return VERR_CFGM_VALUE_NOT_FOUND;
352
353 size_t cch = strlen(psz);
354 if (cch >= cchValue)
355 return VERR_CFGM_NOT_ENOUGH_SPACE;
356
357 memcpy(pszValue, psz, cch + 1);
358 return VINF_SUCCESS;
359}
360
361DECLCALLBACK(int) vboximgVdCryptoKeyRetain(void *pvUser, const char *pszId,
362 const uint8_t **ppbKey, size_t *pcbKey)
363{
364 VDISKCRYPTOSETTINGS *pSettings = (VDISKCRYPTOSETTINGS *)pvUser;
365 NOREF(pszId);
366 NOREF(ppbKey);
367 NOREF(pcbKey);
368 AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE);
369 AssertMsgFailedReturn(("This method should not be called here!\n"), VERR_INVALID_STATE);
370}
371
372DECLCALLBACK(int) vboximgVdCryptoKeyRelease(void *pvUser, const char *pszId)
373{
374 VDISKCRYPTOSETTINGS *pSettings = (VDISKCRYPTOSETTINGS *)pvUser;
375 NOREF(pszId);
376 AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE);
377 AssertMsgFailedReturn(("This method should not be called here!\n"), VERR_INVALID_STATE);
378}
379
380DECLCALLBACK(int) vboximgVdCryptoKeyStorePasswordRetain(void *pvUser, const char *pszId, const char **ppszPassword)
381{
382 VDISKCRYPTOSETTINGS *pSettings = (VDISKCRYPTOSETTINGS *)pvUser;
383 AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE);
384
385 NOREF(pszId);
386 *ppszPassword = pSettings->pszPassword;
387 return VINF_SUCCESS;
388}
389
390DECLCALLBACK(int) vboximgVdCryptoKeyStorePasswordRelease(void *pvUser, const char *pszId)
391{
392 VDISKCRYPTOSETTINGS *pSettings = (VDISKCRYPTOSETTINGS *)pvUser;
393 AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE);
394 NOREF(pszId);
395 return VINF_SUCCESS;
396}
397
398DECLCALLBACK(int) vboximgVdCryptoKeyStoreSave(void *pvUser, const void *pvKeyStore, size_t cbKeyStore)
399{
400 VDISKCRYPTOSETTINGS *pSettings = (VDISKCRYPTOSETTINGS *)pvUser;
401 AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE);
402
403 pSettings->pszKeyStore = (char *)RTMemAllocZ(cbKeyStore);
404 if (!pSettings->pszKeyStore)
405 return VERR_NO_MEMORY;
406
407 memcpy(pSettings->pszKeyStore, pvKeyStore, cbKeyStore);
408 return VINF_SUCCESS;
409}
410
411DECLCALLBACK(int) vboximgVdCryptoKeyStoreReturnParameters(void *pvUser, const char *pszCipher,
412 const uint8_t *pbDek, size_t cbDek)
413{
414 VDISKCRYPTOSETTINGS *pSettings = (VDISKCRYPTOSETTINGS *)pvUser;
415 AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE);
416
417 pSettings->pszCipherReturned = RTStrDup(pszCipher);
418 pSettings->pbDek = pbDek;
419 pSettings->cbDek = cbDek;
420
421 return pSettings->pszCipherReturned ? VINF_SUCCESS : VERR_NO_MEMORY;
422}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette