VirtualBox

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

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

© 2023 Oracle
ContactPrivacy policyTerms of Use