VirtualBox

source: vbox/trunk/src/VBox/Main/src-all/CryptoUtils.cpp@ 94793

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

Main,VMM: Implemented most of the functionality for encrypted VMs (encrypting log files is still missing), bugref:9955

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.6 KB
Line 
1/* $Id: CryptoUtils.cpp 94793 2022-05-03 11:47:03Z vboxsync $ */
2/** @file
3 * Main - Cryptographic utility functions used by both VBoxSVC and VBoxC.
4 */
5
6/*
7 * Copyright (C) 2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include <VBox/err.h>
19#include <VBox/log.h>
20#include <iprt/assert.h>
21#include <iprt/file.h>
22#include <iprt/vfs.h>
23
24#include "CryptoUtils.h"
25
26
27/*static*/
28DECLCALLBACK(int) SsmStream::i_ssmCryptoWrite(void *pvUser, uint64_t offStream, const void *pvBuf, size_t cbToWrite)
29{
30 SsmStream *pThis = static_cast<SsmStream *>(pvUser);
31
32 return RTVfsFileWriteAt(pThis->m_hVfsFile, (RTFOFF)offStream, pvBuf, cbToWrite, NULL /*pcbWritten*/);
33}
34
35
36/*static*/
37DECLCALLBACK(int) SsmStream::i_ssmCryptoRead(void *pvUser, uint64_t offStream, void *pvBuf, size_t cbToRead, size_t *pcbRead)
38{
39 SsmStream *pThis = static_cast<SsmStream *>(pvUser);
40
41 return RTVfsFileReadAt(pThis->m_hVfsFile, (RTFOFF)offStream, pvBuf, cbToRead, pcbRead);
42}
43
44
45/*static*/
46DECLCALLBACK(int) SsmStream::i_ssmCryptoSeek(void *pvUser, int64_t offSeek, unsigned uMethod, uint64_t *poffActual)
47{
48 SsmStream *pThis = static_cast<SsmStream *>(pvUser);
49
50 return RTVfsFileSeek(pThis->m_hVfsFile, (RTFOFF)offSeek, uMethod, poffActual);
51}
52
53
54/*static*/
55DECLCALLBACK(uint64_t) SsmStream::i_ssmCryptoTell(void *pvUser)
56{
57 SsmStream *pThis = static_cast<SsmStream *>(pvUser);
58
59 return (uint64_t)RTVfsFileTell(pThis->m_hVfsFile);
60}
61
62
63/*static*/
64DECLCALLBACK(int) SsmStream::i_ssmCryptoSize(void *pvUser, uint64_t *pcb)
65{
66 SsmStream *pThis = static_cast<SsmStream *>(pvUser);
67
68 return RTVfsFileQuerySize(pThis->m_hVfsFile, pcb);
69}
70
71
72/*static*/
73DECLCALLBACK(int) SsmStream::i_ssmCryptoIsOk(void *pvUser)
74{
75 RT_NOREF(pvUser);
76
77 /** @todo */
78 return VINF_SUCCESS;
79}
80
81
82/*static*/
83DECLCALLBACK(int) SsmStream::i_ssmCryptoClose(void *pvUser, bool fCancelled)
84{
85 SsmStream *pThis = static_cast<SsmStream *>(pvUser);
86
87 RT_NOREF(fCancelled); /** @todo */
88 RTVfsFileRelease(pThis->m_hVfsFile);
89 pThis->m_hVfsFile = NIL_RTVFSFILE;
90 return VINF_SUCCESS;
91}
92
93
94#ifdef VBOX_COM_INPROC
95SsmStream::SsmStream(Console *pParent, PCVMMR3VTABLE pVMM, SecretKeyStore *pKeyStore, const Utf8Str &strKeyId, const Utf8Str &strKeyStore)
96#else
97SsmStream::SsmStream(VirtualBox *pParent, SecretKeyStore *pKeyStore, const Utf8Str &strKeyId, const Utf8Str &strKeyStore)
98#endif
99{
100 m_StrmOps.u32Version = SSMSTRMOPS_VERSION;
101 m_StrmOps.pfnWrite = SsmStream::i_ssmCryptoWrite;
102 m_StrmOps.pfnRead = SsmStream::i_ssmCryptoRead;
103 m_StrmOps.pfnSeek = SsmStream::i_ssmCryptoSeek;
104 m_StrmOps.pfnTell = SsmStream::i_ssmCryptoTell;
105 m_StrmOps.pfnSize = SsmStream::i_ssmCryptoSize;
106 m_StrmOps.pfnIsOk = SsmStream::i_ssmCryptoIsOk;
107 m_StrmOps.pfnClose = SsmStream::i_ssmCryptoClose;
108 m_StrmOps.u32EndVersion = SSMSTRMOPS_VERSION;
109
110 m_pKeyStore = pKeyStore;
111 m_strKeyId = strKeyId;
112 m_strKeyStore = strKeyStore;
113 m_pParent = pParent;
114 m_hVfsFile = NIL_RTVFSFILE;
115 m_pSsm = NULL;
116 m_pCryptoIf = NULL;
117#ifdef VBOX_COM_INPROC
118 m_pVMM = pVMM;
119#endif
120}
121
122
123SsmStream::~SsmStream()
124{
125 close();
126
127 if (m_pCryptoIf)
128 m_pParent->i_releaseCryptoIf(m_pCryptoIf);
129
130 m_pCryptoIf = NULL;
131 m_pKeyStore = NULL;
132}
133
134
135int SsmStream::open(const Utf8Str &strFilename, bool fWrite, PSSMHANDLE *ppSsmHandle)
136{
137 /* Fast path, if the saved state is not encrypted we can skip everything and let SSM handle the file. */
138 if (m_strKeyId.isEmpty())
139 {
140 AssertReturn(!fWrite, VERR_NOT_SUPPORTED);
141
142#ifdef VBOX_COM_INPROC
143 int rc = m_pVMM->pfnSSMR3Open(strFilename.c_str(), NULL /*pStreamOps*/, NULL /*pvStreamOps*/,
144 0 /*fFlags*/, &m_pSsm);
145#else
146 int rc = SSMR3Open(strFilename.c_str(), NULL /*pStreamOps*/, NULL /*pvStreamOps*/,
147 0 /*fFlags*/, &m_pSsm);
148#endif
149 if ( RT_SUCCESS(rc)
150 && ppSsmHandle)
151 *ppSsmHandle = m_pSsm;
152
153 return rc;
154 }
155
156 int rc = VINF_SUCCESS;
157 if (!m_pCryptoIf)
158 {
159#ifdef VBOX_COM_INPROC
160 rc = m_pParent->i_retainCryptoIf(&m_pCryptoIf);
161 if (RT_FAILURE(rc))
162 return rc;
163#else
164 HRESULT hrc = m_pParent->i_retainCryptoIf(&m_pCryptoIf);
165 if (FAILED(hrc))
166 return VERR_COM_IPRT_ERROR;
167#endif
168 }
169
170 SecretKey *pKey;
171 rc = m_pKeyStore->retainSecretKey(m_strKeyId, &pKey);
172 if (RT_SUCCESS(rc))
173 {
174 RTVFSFILE hVfsFileSsm = NIL_RTVFSFILE;
175 uint32_t fOpen = fWrite
176 ? RTFILE_O_READWRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE
177 : RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE;
178
179 rc = RTVfsFileOpenNormal(strFilename.c_str(), fOpen, &hVfsFileSsm);
180 if (RT_SUCCESS(rc))
181 {
182 const char *pszPassword = (const char *)pKey->getKeyBuffer();
183
184 rc = m_pCryptoIf->pfnCryptoFileFromVfsFile(hVfsFileSsm, m_strKeyStore.c_str(), pszPassword, &m_hVfsFile);
185 if (RT_SUCCESS(rc))
186 {
187#ifdef VBOX_COM_INPROC
188 rc = m_pVMM->pfnSSMR3Open(NULL /*pszFilename*/, &m_StrmOps, this, 0 /*fFlags*/, &m_pSsm);
189#else
190 rc = SSMR3Open(NULL /*pszFilename*/, &m_StrmOps, this, 0 /*fFlags*/, &m_pSsm);
191#endif
192 if ( RT_SUCCESS(rc)
193 && ppSsmHandle)
194 *ppSsmHandle = m_pSsm;
195
196 if (RT_FAILURE(rc))
197 {
198 RTVfsFileRelease(m_hVfsFile);
199 m_hVfsFile = NIL_RTVFSFILE;
200 }
201 }
202
203 /* Also release in success case because the encrypted file handle retained a new reference to it. */
204 RTVfsFileRelease(hVfsFileSsm);
205 }
206
207 pKey->release();
208 }
209
210 return rc;
211}
212
213
214int SsmStream::open(const Utf8Str &strFilename)
215{
216#ifdef VBOX_COM_INPROC
217 RTVFSFILE hVfsFileSsm = NIL_RTVFSFILE;
218 uint32_t fOpen = RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE;
219
220 int rc = RTVfsFileOpenNormal(strFilename.c_str(), fOpen, &hVfsFileSsm);
221 if (RT_SUCCESS(rc))
222 {
223 if (m_strKeyId.isNotEmpty())
224 {
225 /* File is encrypted, set up machinery. */
226 if (!m_pCryptoIf)
227 rc = m_pParent->i_retainCryptoIf(&m_pCryptoIf);
228
229 if (RT_SUCCESS(rc))
230 {
231 SecretKey *pKey;
232 rc = m_pKeyStore->retainSecretKey(m_strKeyId, &pKey);
233 if (RT_SUCCESS(rc))
234 {
235 const char *pszPassword = (const char *)pKey->getKeyBuffer();
236
237 rc = m_pCryptoIf->pfnCryptoFileFromVfsFile(hVfsFileSsm, m_strKeyStore.c_str(), pszPassword, &m_hVfsFile);
238 pKey->release();
239 }
240
241 /* Also release in success case because the encrypted file handle retained a new reference to it. */
242 RTVfsFileRelease(hVfsFileSsm);
243 }
244 }
245 else /* File is not encrypted. */
246 m_hVfsFile = hVfsFileSsm;
247 }
248
249 return rc;
250#else
251 RT_NOREF(strFilename);
252 return VERR_NOT_SUPPORTED;
253#endif
254}
255
256
257int SsmStream::create(const Utf8Str &strFilename)
258{
259#ifdef VBOX_COM_INPROC
260 RTVFSFILE hVfsFileSsm = NIL_RTVFSFILE;
261 uint32_t fOpen = RTFILE_O_READWRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE;
262
263 int rc = RTVfsFileOpenNormal(strFilename.c_str(), fOpen, &hVfsFileSsm);
264 if (RT_SUCCESS(rc))
265 {
266 if (m_strKeyId.isNotEmpty())
267 {
268 /* File is encrypted, set up machinery. */
269 if (!m_pCryptoIf)
270 rc = m_pParent->i_retainCryptoIf(&m_pCryptoIf);
271
272 if (RT_SUCCESS(rc))
273 {
274 SecretKey *pKey;
275 rc = m_pKeyStore->retainSecretKey(m_strKeyId, &pKey);
276 if (RT_SUCCESS(rc))
277 {
278 const char *pszPassword = (const char *)pKey->getKeyBuffer();
279
280 rc = m_pCryptoIf->pfnCryptoFileFromVfsFile(hVfsFileSsm, m_strKeyStore.c_str(), pszPassword, &m_hVfsFile);
281 pKey->release();
282 }
283
284 /* Also release in success case because the encrypted file handle retained a new reference to it. */
285 RTVfsFileRelease(hVfsFileSsm);
286 if (RT_FAILURE(rc))
287 RTFileDelete(strFilename.c_str());
288 }
289 }
290 else /* File doesn't need to be encrypted. */
291 m_hVfsFile = hVfsFileSsm;
292 }
293
294 return rc;
295#else
296 RT_NOREF(strFilename);
297 return VERR_NOT_SUPPORTED;
298#endif
299}
300
301
302int SsmStream::querySsmStrmOps(PCSSMSTRMOPS *ppStrmOps, void **ppvStrmOpsUser)
303{
304 AssertReturn(m_hVfsFile != NIL_RTVFSFILE, VERR_INVALID_STATE);
305
306 *ppStrmOps = &m_StrmOps;
307 *ppvStrmOpsUser = this;
308 return VINF_SUCCESS;
309}
310
311
312int SsmStream::close(void)
313{
314 if (m_pSsm)
315 {
316#ifdef VBOX_COM_INPROC
317 int rc = m_pVMM->pfnSSMR3Close(m_pSsm);
318#else
319 int rc = SSMR3Close(m_pSsm);
320#endif
321 AssertRCReturn(rc, rc);
322 }
323
324 if (m_hVfsFile != NIL_RTVFSFILE)
325 RTVfsFileRelease(m_hVfsFile);
326
327 m_hVfsFile = NIL_RTVFSFILE;
328 m_pSsm = NULL;
329#ifdef VBOX_COM_INPROC
330 m_pVMM = NULL;
331#endif
332
333 return VINF_SUCCESS;
334}
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