Changeset 94726 in vbox
- Timestamp:
- Apr 27, 2022 5:39:33 PM (3 years ago)
- svn:sync-xref-src-repo-rev:
- 151106
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/settings.h
r94714 r94726 50 50 #include <VBox/com/Guid.h> 51 51 #include <VBox/com/string.h> 52 #include <VBox/VBoxCryptoIf.h> 52 53 53 54 #include <list> … … 618 619 619 620 com::Utf8Str strNvramPath; 621 com::Utf8Str strKeyId; 622 com::Utf8Str strKeyStore; 620 623 }; 621 624 … … 1368 1371 com::Guid uuid; 1369 1372 1373 enum 1374 { 1375 ParseState_NotParsed, 1376 ParseState_PasswordError, 1377 ParseState_Parsed 1378 } enmParseState; 1379 1370 1380 MachineUserData machineUserData; 1371 1381 1382 com::Utf8Str strStateKeyId; 1383 com::Utf8Str strStateKeyStore; 1372 1384 com::Utf8Str strStateFile; 1373 1385 bool fCurrentStateModified; // optional, default is true … … 1386 1398 SnapshotsList llFirstSnapshot; // first snapshot or empty list if there's none 1387 1399 1388 MachineConfigFile(const com::Utf8Str *pstrFilename); 1400 com::Utf8Str strKeyId; 1401 com::Utf8Str strKeyStore; // if not empty, the encryption is used 1402 com::Utf8Str strLogKeyId; 1403 com::Utf8Str strLogKeyStore; 1404 1405 MachineConfigFile(const com::Utf8Str *pstrFilename, 1406 PCVBOXCRYPTOIF pCryptoIf = NULL, 1407 const char *pszPassword = NULL); 1389 1408 1390 1409 bool operator==(const MachineConfigFile &m) const; … … 1394 1413 void importMachineXML(const xml::ElementNode &elmMachine); 1395 1414 1396 void write(const com::Utf8Str &strFilename );1415 void write(const com::Utf8Str &strFilename, PCVBOXCRYPTOIF pCryptoIf = NULL, const char *pszPassword = NULL); 1397 1416 1398 1417 enum … … 1404 1423 BuildMachineXML_SuppressSavedState = 0x10 1405 1424 }; 1425 1426 void copyEncryptionSettingsFrom(const MachineConfigFile &other); 1406 1427 void buildMachineXML(xml::ElementNode &elmMachine, 1407 1428 uint32_t fl, … … 1432 1453 void convertOldOSType_pre1_5(com::Utf8Str &str); 1433 1454 void readMachine(const xml::ElementNode &elmMachine); 1455 void readMachineEncrypted(const xml::ElementNode &elmMachine, PCVBOXCRYPTOIF pCryptoIf, const char *pszPassword); 1434 1456 1435 1457 void buildHardwareXML(xml::ElementNode &elmParent, const Hardware &hw, uint32_t fl, std::list<xml::ElementNode*> *pllElementsWithUuidAttributes); … … 1444 1466 void buildSnapshotXML(xml::ElementNode &elmParent, const Snapshot &snap); 1445 1467 1468 void buildMachineEncryptedXML(xml::ElementNode &elmMachine, 1469 uint32_t fl, 1470 std::list<xml::ElementNode*> *pllElementsWithUuidAttributes, 1471 PCVBOXCRYPTOIF pCryptoIf, 1472 const char *pszPassword); 1473 1446 1474 void bumpSettingsVersionIfNeeded(); 1447 1475 }; -
trunk/src/VBox/Main/xml/Settings.cpp
r94714 r94726 3026 3026 bool NvramSettings::areDefaultSettings() const 3027 3027 { 3028 return strNvramPath.isEmpty(); 3028 return strNvramPath.isEmpty() 3029 && strKeyId.isEmpty() 3030 && strKeyStore.isEmpty(); 3029 3031 } 3030 3032 … … 3037 3039 { 3038 3040 return (this == &g) 3039 || (strNvramPath == g.strNvramPath); 3041 || (strNvramPath == g.strNvramPath) 3042 || (strKeyId == g.strKeyId) 3043 || (strKeyStore == g.strKeyStore); 3040 3044 } 3041 3045 … … 3994 3998 * 3995 3999 * @param pstrFilename 3996 */ 3997 MachineConfigFile::MachineConfigFile(const Utf8Str *pstrFilename) 4000 * @param pCryptoIf Pointer to the cryptographic interface, required for an encrypted machine config. 4001 * @param pszPassword The password to use for an encrypted machine config. 4002 */ 4003 MachineConfigFile::MachineConfigFile(const Utf8Str *pstrFilename, PCVBOXCRYPTOIF pCryptoIf, const char *pszPassword) 3998 4004 : ConfigFileBase(pstrFilename), 4005 enmParseState(ParseState_NotParsed), 3999 4006 fCurrentStateModified(true), 4000 4007 fAborted(false) … … 4011 4018 while ((pelmRootChild = nlRootChildren.forAllNodes())) 4012 4019 { 4020 if (pelmRootChild->nameEquals("MachineEncrypted")) 4021 readMachineEncrypted(*pelmRootChild, pCryptoIf, pszPassword); 4013 4022 if (pelmRootChild->nameEquals("Machine")) 4014 4023 readMachine(*pelmRootChild); … … 4017 4026 // clean up memory allocated by XML engine 4018 4027 clearDocument(); 4028 4029 if (enmParseState == ParseState_NotParsed) 4030 enmParseState = ParseState_Parsed; 4019 4031 } 4020 4032 } … … 4029 4041 { 4030 4042 return (m->sv >= SettingsVersion_v1_11); 4043 } 4044 4045 /** 4046 * Public routine which copies encryption settings. Used by Machine::saveSettings 4047 * so that the encryption settings do not get lost when a copy of the Machine settings 4048 * file is made to see if settings have actually changed. 4049 * @param other 4050 */ 4051 void MachineConfigFile::copyEncryptionSettingsFrom(const MachineConfigFile &other) 4052 { 4053 strKeyId = other.strKeyId; 4054 strKeyStore = other.strKeyStore; 4031 4055 } 4032 4056 … … 4089 4113 && mediaRegistry == c.mediaRegistry // this one's deep 4090 4114 // skip mapExtraDataItems! there is no old state available as it's always forced 4091 && llFirstSnapshot == c.llFirstSnapshot); // this one's deep 4115 && llFirstSnapshot == c.llFirstSnapshot // this one's deep 4116 && strKeyId == c.strKeyId 4117 && strKeyStore == c.strKeyStore 4118 && strStateKeyId == c.strStateKeyId 4119 && strStateKeyStore == c.strStateKeyStore 4120 && strLogKeyId == c.strLogKeyId 4121 && strLogKeyStore == c.strLogKeyStore); 4092 4122 } 4093 4123 … … 5169 5199 pelmBIOSChild->getAttributeValue("value", hw.biosSettings.llTimeOffset); 5170 5200 if ((pelmBIOSChild = pelmHwChild->findChildElement("NVRAM"))) 5201 { 5171 5202 pelmBIOSChild->getAttributeValue("path", hw.nvramSettings.strNvramPath); 5203 if (m->sv >= SettingsVersion_v1_19) 5204 { 5205 pelmBIOSChild->getAttributeValue("keyId", hw.nvramSettings.strKeyId); 5206 pelmBIOSChild->getAttributeValue("keyStore", hw.nvramSettings.strKeyStore); 5207 } 5208 } 5172 5209 if ((pelmBIOSChild = pelmHwChild->findChildElement("SmbiosUuidLittleEndian"))) 5173 5210 pelmBIOSChild->getAttributeValue("enabled", hw.biosSettings.fSmbiosUuidLittleEndian); … … 6098 6135 convertOldOSType_pre1_5(machineUserData.strOsType); 6099 6136 6137 elmMachine.getAttributeValue("stateKeyId", strStateKeyId); 6138 elmMachine.getAttributeValue("stateKeyStore", strStateKeyStore); 6100 6139 elmMachine.getAttributeValuePath("stateFile", strStateFile); 6140 6141 elmMachine.getAttributeValue("strLogKeyId", strLogKeyId); 6142 elmMachine.getAttributeValue("strLogKeyStore", strLogKeyStore); 6101 6143 6102 6144 if (elmMachine.getAttributeValue("currentSnapshot", str)) … … 6193 6235 6194 6236 /** 6237 * Called from the constructor to decrypt the machine config and read 6238 * data from it. 6239 * @param elmMachine 6240 */ 6241 void MachineConfigFile::readMachineEncrypted(const xml::ElementNode &elmMachine, 6242 PCVBOXCRYPTOIF pCryptoIf = NULL, 6243 const char *pszPassword = NULL) 6244 { 6245 Utf8Str strUUID; 6246 if (elmMachine.getAttributeValue("uuid", strUUID)) 6247 { 6248 parseUUID(uuid, strUUID, &elmMachine); 6249 if (!elmMachine.getAttributeValue("keyId", strKeyId)) 6250 throw ConfigFileError(this, &elmMachine, N_("Required MachineEncrypted/@keyId attribute is missing")); 6251 if (!elmMachine.getAttributeValue("keyStore", strKeyStore)) 6252 throw ConfigFileError(this, &elmMachine, N_("Required MachineEncrypted/@keyStore attribute is missing")); 6253 6254 if (!pszPassword) 6255 { 6256 enmParseState = ParseState_PasswordError; 6257 return; 6258 } 6259 6260 VBOXCRYPTOCTX hCryptoCtx = NULL; 6261 int rc = pCryptoIf->pfnCryptoCtxLoad(strKeyStore.c_str(), pszPassword, &hCryptoCtx); 6262 if (RT_SUCCESS(rc)) 6263 { 6264 com::Utf8Str str = elmMachine.getValue(); 6265 IconBlob abEncrypted; /** @todo Rename IconBlob because this is not about icons. */ 6266 /** @todo This is not nice. */ 6267 try 6268 { 6269 parseBase64(abEncrypted, str, &elmMachine); 6270 } 6271 catch(...) 6272 { 6273 int rc2 = pCryptoIf->pfnCryptoCtxDestroy(hCryptoCtx); 6274 AssertRC(rc2); 6275 throw; 6276 } 6277 6278 IconBlob abDecrypted(abEncrypted.size()); 6279 size_t cbDecrypted = 0; 6280 rc = pCryptoIf->pfnCryptoCtxDecrypt(hCryptoCtx, false /*fPartial*/, 6281 &abEncrypted[0], abEncrypted.size(), 6282 uuid.raw(), sizeof(RTUUID), 6283 &abDecrypted[0], abDecrypted.size(), &cbDecrypted); 6284 int rc2 = pCryptoIf->pfnCryptoCtxDestroy(hCryptoCtx); 6285 AssertRC(rc2); 6286 6287 if (RT_SUCCESS(rc)) 6288 { 6289 abDecrypted.resize(cbDecrypted); 6290 xml::XmlMemParser parser; 6291 xml::Document *pDoc = new xml::Document; 6292 parser.read(&abDecrypted[0], abDecrypted.size(), m->strFilename, *pDoc); 6293 xml::ElementNode *pelmRoot = pDoc->getRootElement(); 6294 if (!pelmRoot || !pelmRoot->nameEquals("Machine")) 6295 throw ConfigFileError(this, pelmRoot, N_("Root element in Machine settings encrypted block must be \"Machine\"")); 6296 readMachine(*pelmRoot); 6297 delete pDoc; 6298 } 6299 } 6300 6301 if (RT_FAILURE(rc)) 6302 { 6303 if (rc == VERR_ACCESS_DENIED) 6304 enmParseState = ParseState_PasswordError; 6305 else 6306 throw ConfigFileError(this, &elmMachine, N_("Parsing config failed. (%Rrc)"), rc); 6307 } 6308 } 6309 else 6310 throw ConfigFileError(this, &elmMachine, N_("Required MachineEncrypted/@uuid attribute is missing")); 6311 } 6312 6313 /** 6195 6314 * Creates a \<Hardware\> node under elmParent and then writes out the XML 6196 6315 * keys under that. Called for both the \<Machine\> node and for snapshots. … … 6664 6783 } 6665 6784 6666 if (!hw.biosSettings.areDefaultSettings() )6785 if (!hw.biosSettings.areDefaultSettings() || !hw.nvramSettings.areDefaultSettings()) 6667 6786 { 6668 6787 xml::ElementNode *pelmBIOS = pelmHardware->createChild("BIOS"); … … 6718 6837 if (hw.biosSettings.fPXEDebugEnabled) 6719 6838 pelmBIOS->createChild("PXEDebug")->setAttribute("enabled", hw.biosSettings.fPXEDebugEnabled); 6720 if (!hw.nvramSettings.strNvramPath.isEmpty()) 6721 pelmBIOS->createChild("NVRAM")->setAttribute("path", hw.nvramSettings.strNvramPath); 6839 if (!hw.nvramSettings.areDefaultSettings()) 6840 { 6841 xml::ElementNode *pelmNvram = pelmBIOS->createChild("NVRAM"); 6842 if (!hw.nvramSettings.strNvramPath.isEmpty()) 6843 pelmNvram->setAttribute("path", hw.nvramSettings.strNvramPath); 6844 if (m->sv >= SettingsVersion_v1_9) 6845 { 6846 if (hw.nvramSettings.strKeyId.isNotEmpty()) 6847 pelmNvram->setAttribute("keyId", hw.nvramSettings.strKeyId); 6848 if (hw.nvramSettings.strKeyStore.isNotEmpty()) 6849 pelmNvram->setAttribute("keyStore", hw.nvramSettings.strKeyStore); 6850 } 6851 } 6722 6852 if (hw.biosSettings.fSmbiosUuidLittleEndian) 6723 6853 pelmBIOS->createChild("SmbiosUuidLittleEndian")->setAttribute("enabled", hw.biosSettings.fSmbiosUuidLittleEndian); … … 7901 8031 elmMachine.createChild("Description")->addContent(machineUserData.strDescription); 7902 8032 elmMachine.setAttribute("OSType", machineUserData.strOsType); 8033 8034 8035 if (m->sv >= SettingsVersion_v1_19) 8036 { 8037 if (strStateKeyId.length()) 8038 elmMachine.setAttribute("stateKeyId", strStateKeyId); 8039 if (strStateKeyStore.length()) 8040 elmMachine.setAttribute("stateKeyStore", strStateKeyStore); 8041 if (strLogKeyId.length()) 8042 elmMachine.setAttribute("strLogKeyId", strLogKeyId); 8043 if (strLogKeyStore.length()) 8044 elmMachine.setAttribute("strLogKeyStore", strLogKeyStore); 8045 } 7903 8046 if ( strStateFile.length() 7904 8047 && !(fl & BuildMachineXML_SuppressSavedState) … … 7974 8117 buildAutostartXML(elmMachine, autostart); 7975 8118 buildGroupsXML(elmMachine, machineUserData.llGroups); 8119 } 8120 8121 /** 8122 * Builds encrypted config. 8123 * 8124 * @sa MachineConfigFile::buildMachineXML 8125 */ 8126 void MachineConfigFile::buildMachineEncryptedXML(xml::ElementNode &elmMachine, 8127 uint32_t fl, 8128 std::list<xml::ElementNode*> *pllElementsWithUuidAttributes, 8129 PCVBOXCRYPTOIF pCryptoIf, 8130 const char *pszPassword = NULL) 8131 { 8132 if ( !pszPassword 8133 || !pCryptoIf) 8134 throw ConfigFileError(this, &elmMachine, N_("Password is required")); 8135 8136 xml::Document *pDoc = new xml::Document; 8137 xml::ElementNode *pelmRoot = pDoc->createRootElement("Machine"); 8138 pelmRoot->setAttribute("xmlns", VBOX_XML_NAMESPACE); 8139 // Have the code for producing a proper schema reference. Not used by most 8140 // tools, so don't bother doing it. The schema is not on the server anyway. 8141 #ifdef VBOX_WITH_SETTINGS_SCHEMA 8142 pelmRoot->setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); 8143 pelmRoot->setAttribute("xsi:schemaLocation", VBOX_XML_NAMESPACE " " VBOX_XML_SCHEMA); 8144 #endif 8145 8146 buildMachineXML(*pelmRoot, fl, pllElementsWithUuidAttributes); 8147 xml::XmlStringWriter writer; 8148 com::Utf8Str strMachineXml; 8149 int rc = writer.write(*pDoc, &strMachineXml); 8150 delete pDoc; 8151 if (RT_SUCCESS(rc)) 8152 { 8153 VBOXCRYPTOCTX hCryptoCtx; 8154 if (strKeyStore.isEmpty()) 8155 { 8156 rc = pCryptoIf->pfnCryptoCtxCreate("AES-GCM256", pszPassword, &hCryptoCtx); 8157 if (RT_SUCCESS(rc)) 8158 { 8159 char *pszNewKeyStore; 8160 rc = pCryptoIf->pfnCryptoCtxSave(hCryptoCtx, &pszNewKeyStore); 8161 if (RT_SUCCESS(rc)) 8162 { 8163 strKeyStore = pszNewKeyStore; 8164 RTStrFree(pszNewKeyStore); 8165 } 8166 else 8167 pCryptoIf->pfnCryptoCtxDestroy(hCryptoCtx); 8168 } 8169 } 8170 else 8171 rc = pCryptoIf->pfnCryptoCtxLoad(strKeyStore.c_str(), pszPassword, &hCryptoCtx); 8172 if (RT_SUCCESS(rc)) 8173 { 8174 IconBlob abEncrypted; 8175 size_t cbEncrypted = 0; 8176 rc = pCryptoIf->pfnCryptoCtxQueryEncryptedSize(hCryptoCtx, strMachineXml.length(), &cbEncrypted); 8177 if (RT_SUCCESS(rc)) 8178 { 8179 abEncrypted.resize(cbEncrypted); 8180 rc = pCryptoIf->pfnCryptoCtxEncrypt(hCryptoCtx, false /*fPartial*/, NULL /*pvIV*/, 0 /*cbIV*/, 8181 strMachineXml.c_str(), strMachineXml.length(), 8182 uuid.raw(), sizeof(RTUUID), 8183 &abEncrypted[0], abEncrypted.size(), &cbEncrypted); 8184 int rc2 = pCryptoIf->pfnCryptoCtxDestroy(hCryptoCtx); 8185 AssertRC(rc2); 8186 if (RT_SUCCESS(rc)) 8187 { 8188 abEncrypted.resize(cbEncrypted); 8189 toBase64(strMachineXml, abEncrypted); 8190 elmMachine.setAttribute("uuid", uuid.toStringCurly()); 8191 elmMachine.setAttribute("keyId", strKeyId); 8192 elmMachine.setAttribute("keyStore", strKeyStore); 8193 elmMachine.setContent(strMachineXml.c_str()); 8194 } 8195 } 8196 } 8197 8198 if (RT_FAILURE(rc)) 8199 throw ConfigFileError(this, &elmMachine, N_("Creating machine encrypted xml failed. (%Rrc)"), rc); 8200 } 8201 else 8202 throw ConfigFileError(this, &elmMachine, N_("Creating machine xml failed. (%Rrc)"), rc); 7976 8203 } 7977 8204 … … 8080 8307 if (m->sv < SettingsVersion_v1_19) 8081 8308 { 8082 // VirtualBox 7.0 adds iommu device. 8083 if (hardwareMachine.iommuType != IommuType_None) 8309 // VirtualBox 7.0 adds iommu device and full VM encryption. 8310 if ( hardwareMachine.iommuType != IommuType_None 8311 || strKeyId.isNotEmpty() 8312 || strKeyStore.isNotEmpty() 8313 || strStateKeyId.isNotEmpty() 8314 || strStateKeyStore.isNotEmpty() 8315 || hardwareMachine.nvramSettings.strKeyId.isNotEmpty() 8316 || hardwareMachine.nvramSettings.strKeyStore.isNotEmpty() 8317 || strLogKeyId.isNotEmpty() 8318 || strLogKeyStore.isEmpty()) 8084 8319 { 8085 8320 m->sv = SettingsVersion_v1_19; … … 8742 8977 * in particular if the file cannot be written. 8743 8978 */ 8744 void MachineConfigFile::write(const com::Utf8Str &strFilename )8979 void MachineConfigFile::write(const com::Utf8Str &strFilename, PCVBOXCRYPTOIF pCryptoIf, const char *pszPassword) 8745 8980 { 8746 8981 try … … 8752 8987 8753 8988 m->strFilename = strFilename; 8754 specialBackupIfFirstBump(); 8989 /* 8990 * Only create a backup if it is not encrypted. 8991 * Otherwise we get an unencrypted copy of the settings. 8992 */ 8993 if (strKeyId.isEmpty() && strKeyStore.isEmpty()) 8994 specialBackupIfFirstBump(); 8755 8995 createStubDocument(); 8756 8996 8757 xml::ElementNode *pelmMachine = m->pelmRoot->createChild("Machine"); 8758 buildMachineXML(*pelmMachine, 8759 MachineConfigFile::BuildMachineXML_IncludeSnapshots 8760 | MachineConfigFile::BuildMachineXML_MediaRegistry, 8761 // but not BuildMachineXML_WriteVBoxVersionAttribute 8762 NULL); /* pllElementsWithUuidAttributes */ 8997 if (strKeyStore.isNotEmpty()) 8998 { 8999 xml::ElementNode *pelmMachine = m->pelmRoot->createChild("MachineEncrypted"); 9000 buildMachineEncryptedXML(*pelmMachine, 9001 MachineConfigFile::BuildMachineXML_IncludeSnapshots 9002 | MachineConfigFile::BuildMachineXML_MediaRegistry, 9003 // but not BuildMachineXML_WriteVBoxVersionAttribute 9004 NULL, /* pllElementsWithUuidAttributes */ 9005 pCryptoIf, 9006 pszPassword); 9007 } 9008 else 9009 { 9010 xml::ElementNode *pelmMachine = m->pelmRoot->createChild("Machine"); 9011 buildMachineXML(*pelmMachine, 9012 MachineConfigFile::BuildMachineXML_IncludeSnapshots 9013 | MachineConfigFile::BuildMachineXML_MediaRegistry, 9014 // but not BuildMachineXML_WriteVBoxVersionAttribute 9015 NULL); /* pllElementsWithUuidAttributes */ 9016 } 8763 9017 8764 9018 // now go write the XML
Note:
See TracChangeset
for help on using the changeset viewer.