VirtualBox

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

Last change on this file since 95670 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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