Changeset 94735 in vbox for trunk/src/VBox/Main/src-server
- Timestamp:
- Apr 28, 2022 12:54:21 PM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-server/MachineImpl.cpp
r94661 r94735 69 69 #include <iprt/env.h> 70 70 #include <iprt/lockvalidator.h> 71 #include <iprt/memsafer.h> 71 72 #include <iprt/process.h> 72 73 #include <iprt/cpp/utils.h> … … 78 79 #include <VBox/com/array.h> 79 80 #include <VBox/com/list.h> 81 #include <VBox/VBoxCryptoIf.h> 80 82 81 83 #include <VBox/err.h> … … 110 112 // defines / prototypes 111 113 ///////////////////////////////////////////////////////////////////////////// 114 115 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 116 # define BUF_DATA_SIZE _64K 117 118 enum CipherMode 119 { 120 CipherModeGcm = 0, 121 CipherModeCtr, 122 CipherModeXts, 123 CipherModeMax 124 }; 125 126 enum AesSize 127 { 128 Aes128 = 0, 129 Aes256, 130 AesMax 131 }; 132 133 const char *g_apszCipher[AesMax][CipherModeMax] = 134 { 135 {"AES-GCM128", "AES-CTR128", "AES-XTS128-PLAIN64"}, 136 {"AES-GCM256", "AES-CTR256", "AES-XTS256-PLAIN64"} 137 }; 138 const char *g_apszCipherAlgo[AesMax] = {"AES-128", "AES-256"}; 139 140 static const char *getCipherString(const char *pszAlgo, const int iMode) 141 { 142 if (iMode >= CipherModeMax) 143 return pszAlgo; 144 145 for (int i = 0; i < AesMax; i++) 146 { 147 if (strcmp(pszAlgo, g_apszCipherAlgo[i]) == 0) 148 return g_apszCipher[i][iMode]; 149 } 150 return pszAlgo; 151 } 152 153 static const char *getCipherStringWithoutMode(const char *pszAlgo) 154 { 155 for (int i = 0; i < AesMax; i++) 156 { 157 for (int j = 0; j < CipherModeMax; j++) 158 { 159 if (strcmp(pszAlgo, g_apszCipher[i][j]) == 0) 160 return g_apszCipherAlgo[i]; 161 } 162 } 163 return pszAlgo; 164 } 165 #endif 112 166 113 167 ///////////////////////////////////////////////////////////////////////////// … … 144 198 mSession.mLockType = LockType_Null; 145 199 mSession.mState = SessionState_Unlocked; 200 201 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 202 mpKeyStore = NULL; 203 #endif 146 204 } 147 205 … … 310 368 if (aPassword.isNotEmpty() || aPasswordId.isNotEmpty()) 311 369 return setError(VBOX_E_NOT_SUPPORTED, tr("Full VM encryption is not available with this build")); 312 #else313 /** @todo */314 RT_NOREF(aCipher, aPasswordId, aPassword);315 370 #endif 316 371 … … 322 377 if (FAILED(rc)) return rc; 323 378 379 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 380 com::Utf8Str strSsmKeyId; 381 com::Utf8Str strSsmKeyStore; 382 com::Utf8Str strNVRAMKeyId; 383 com::Utf8Str strNVRAMKeyStore; 384 385 if (aPassword.isNotEmpty() && aPasswordId.isNotEmpty()) 386 { 387 /* Resolve the cryptographic interface. */ 388 PCVBOXCRYPTOIF pCryptoIf = NULL; 389 HRESULT hrc = aParent->i_retainCryptoIf(&pCryptoIf); 390 if (SUCCEEDED(hrc)) 391 { 392 CipherMode aenmMode[] = {CipherModeGcm, CipherModeGcm, CipherModeGcm, CipherModeCtr}; 393 com::Utf8Str *astrKeyId[] = {&mData->mstrKeyId, &strSsmKeyId, &strNVRAMKeyId, &mData->mstrLogKeyId}; 394 com::Utf8Str *astrKeyStore[] = {&mData->mstrKeyStore, &strSsmKeyStore, &strNVRAMKeyStore, &mData->mstrLogKeyStore}; 395 396 for (uint32_t i = 0; i < RT_ELEMENTS(astrKeyId); i++) 397 { 398 const char *pszCipher = getCipherString(aCipher.c_str(), aenmMode[i]); 399 if (!pszCipher) 400 { 401 hrc = setError(VBOX_E_NOT_SUPPORTED, 402 tr("The cipher '%s' is not supported"), aCipher.c_str()); 403 break; 404 } 405 406 VBOXCRYPTOCTX hCryptoCtx; 407 int vrc = pCryptoIf->pfnCryptoCtxCreate(pszCipher, aPassword.c_str(), &hCryptoCtx); 408 if (RT_FAILURE(vrc)) 409 { 410 hrc = setErrorBoth(E_FAIL, vrc, tr("New key store creation failed, (%Rrc)"), vrc); 411 break; 412 } 413 414 char *pszKeyStore; 415 vrc = pCryptoIf->pfnCryptoCtxSave(hCryptoCtx, &pszKeyStore); 416 int vrc2 = pCryptoIf->pfnCryptoCtxDestroy(hCryptoCtx); 417 AssertRC(vrc2); 418 419 if (RT_FAILURE(vrc)) 420 { 421 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Saving the key store failed, (%Rrc)"), vrc); 422 break; 423 } 424 425 *(astrKeyStore[i]) = pszKeyStore; 426 RTMemFree(pszKeyStore); 427 *(astrKeyId[i]) = aPasswordId; 428 } 429 430 HRESULT hrc2 = aParent->i_releaseCryptoIf(pCryptoIf); 431 Assert(hrc2 == S_OK); 432 433 if (FAILED(hrc)) 434 return hrc; /* Error is set. */ 435 } 436 else 437 return hrc; /* Error is set. */ 438 } 439 #endif 440 324 441 rc = i_tryCreateMachineConfigFile(fForceOverwrite); 325 442 if (FAILED(rc)) return rc; … … 335 452 if (SUCCEEDED(rc)) 336 453 { 454 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 455 mSSData->strStateKeyId = strSsmKeyId; 456 mSSData->strStateKeyStore = strSsmKeyStore; 457 #endif 458 337 459 // set to true now to cause uninit() to call uninitDataAndChildObjects() on failure 338 460 mData->mAccessible = TRUE; … … 417 539 if (SUCCEEDED(rc)) 418 540 { 541 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 542 if (aPassword.isNotEmpty() && aPasswordId.isNotEmpty()) 543 { 544 size_t cbPassword = aPassword.length() + 1; 545 uint8_t *pbPassword = (uint8_t *)aPassword.c_str(); 546 mData->mpKeyStore->addSecretKey(aPasswordId, pbPassword, cbPassword); 547 } 548 #endif 549 419 550 if (mData->mAccessible) 420 551 autoInitSpan.setSucceeded(); … … 460 591 LogFlowThisFunc(("(Init_Registered) aConfigFile='%s\n", strConfigFile.c_str())); 461 592 593 PCVBOXCRYPTOIF pCryptoIf = NULL; 462 594 #ifndef VBOX_WITH_FULL_VM_ENCRYPTION 463 595 if (strPassword.isNotEmpty()) 464 596 return setError(VBOX_E_NOT_SUPPORTED, tr("Full VM encryption is not available with this build")); 465 597 #else 466 /** @todo */ 467 RT_NOREF(strPassword); 598 if (strPassword.isNotEmpty()) 599 { 600 /* Get at the crpytographic interface. */ 601 HRESULT hrc = aParent->i_retainCryptoIf(&pCryptoIf); 602 if (FAILED(hrc)) 603 return hrc; /* Error is set. */ 604 } 468 605 #endif 469 606 … … 497 634 { 498 635 // load and parse machine XML; this will throw on XML or logic errors 499 mData->pMachineConfigFile = new settings::MachineConfigFile(&mData->m_strConfigFileFull); 636 mData->pMachineConfigFile = new settings::MachineConfigFile(&mData->m_strConfigFileFull, 637 pCryptoIf, 638 strPassword.c_str()); 500 639 501 640 // reject VM UUID duplicates, they can happen if someone … … 514 653 unconst(mData->mUuid) = mData->pMachineConfigFile->uuid; 515 654 516 rc = i_loadMachineDataFromSettings(*mData->pMachineConfigFile, 517 NULL /* puuidRegistry */); 518 if (FAILED(rc)) throw rc; 519 520 /* At this point the changing of the current state modification 521 * flag is allowed. */ 522 i_allowStateModification(); 523 524 i_commit(); 655 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 656 // No exception is thrown if config is encrypted, allowing us to get the uuid and the encryption fields. 657 // We fill in the encryptions fields, and the rest will be filled in if all data parsed. 658 mData->mstrKeyId = mData->pMachineConfigFile->strKeyId; 659 mData->mstrKeyStore = mData->pMachineConfigFile->strKeyStore; 660 #endif 661 662 if (mData->pMachineConfigFile->enmParseState == settings::MachineConfigFile::ParseState_PasswordError) 663 { 664 // We just set the inaccessible state and fill the error info allowing the caller 665 // to register the machine with encrypted config even if the password is incorrect 666 mData->mAccessible = FALSE; 667 668 /* fetch the current error info */ 669 mData->mAccessError = com::ErrorInfo(); 670 671 throw setError(VBOX_E_PASSWORD_INCORRECT, 672 tr("Decryption of the machine {%RTuuid} failed. Incorrect or unknown password"), 673 mData->pMachineConfigFile->uuid.raw()); 674 } 675 else 676 { 677 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 678 if (strPassword.isNotEmpty()) 679 { 680 size_t cbKey = strPassword.length() + 1; /* Include terminator */ 681 const uint8_t *pbKey = (const uint8_t *)strPassword.c_str(); 682 mData->mpKeyStore->addSecretKey(mData->mstrKeyId, pbKey, cbKey); 683 } 684 #endif 685 686 rc = i_loadMachineDataFromSettings(*mData->pMachineConfigFile, 687 NULL /* puuidRegistry */); 688 if (FAILED(rc)) throw rc; 689 690 /* At this point the changing of the current state modification 691 * flag is allowed. */ 692 i_allowStateModification(); 693 694 i_commit(); 695 } 525 696 } 526 697 catch (HRESULT err) … … 550 721 } 551 722 } 723 724 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 725 if (pCryptoIf) 726 { 727 HRESULT hrc2 = aParent->i_releaseCryptoIf(pCryptoIf); 728 Assert(hrc2 == S_OK); 729 } 730 #endif 552 731 553 732 LogFlowThisFunc(("mName='%s', mRegistered=%RTbool, mAccessible=%RTbool " … … 684 863 vrc1); 685 864 865 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 866 /** @todo Only create when the machine is going to be encrypted. */ 867 /* Non-pageable memory is not accessible for non-VM process */ 868 mData->mpKeyStore = new SecretKeyStore(false /* fKeyBufNonPageable */); 869 AssertReturn(mData->mpKeyStore, VERR_NO_MEMORY); 870 #endif 871 686 872 LogFlowThisFuncLeave(); 687 873 … … 762 948 mData->mRegistered = FALSE; 763 949 764 try 765 { 766 // load and parse machine XML; this will throw on XML or logic errors 767 mData->pMachineConfigFile = new settings::MachineConfigFile(&mData->m_strConfigFileFull); 768 769 if (mData->mUuid != mData->pMachineConfigFile->uuid) 770 throw setError(E_FAIL, 771 tr("Machine UUID {%RTuuid} in '%s' doesn't match its UUID {%s} in the registry file '%s'"), 772 mData->pMachineConfigFile->uuid.raw(), 773 mData->m_strConfigFileFull.c_str(), 774 mData->mUuid.toString().c_str(), 775 mParent->i_settingsFilePath().c_str()); 776 777 rc = i_loadMachineDataFromSettings(*mData->pMachineConfigFile, 778 NULL /* const Guid *puuidRegistry */); 779 if (FAILED(rc)) throw rc; 780 } 781 catch (HRESULT err) 782 { 783 /* we assume that error info is set by the thrower */ 784 rc = err; 785 } 786 catch (...) 787 { 788 rc = VirtualBoxBase::handleUnexpectedExceptions(this, RT_SRC_POS); 789 } 790 791 /* Restore the registered flag (even on failure) */ 792 mData->mRegistered = TRUE; 950 PCVBOXCRYPTOIF pCryptoIf = NULL; 951 SecretKey *pKey = NULL; 952 const char *pszPassword = NULL; 953 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 954 /* Resolve password and cryptographic support interface if machine is encrypted. */ 955 if (mData->mstrKeyId.isNotEmpty()) 956 { 957 /* Get at the crpytographic interface. */ 958 rc = mParent->i_retainCryptoIf(&pCryptoIf); 959 if (SUCCEEDED(rc)) 960 { 961 int vrc = mData->mpKeyStore->retainSecretKey(mData->mstrKeyId, &pKey); 962 if (RT_SUCCESS(vrc)) 963 pszPassword = (const char *)pKey->getKeyBuffer(); 964 else 965 rc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Failed to retain key for key ID '%s' with %Rrc"), 966 mData->mstrKeyId.c_str(), vrc); 967 } 968 } 969 #else 970 RT_NOREF(pKey); 971 #endif 972 973 if (SUCCEEDED(rc)) 974 { 975 try 976 { 977 // load and parse machine XML; this will throw on XML or logic errors 978 mData->pMachineConfigFile = new settings::MachineConfigFile(&mData->m_strConfigFileFull, 979 pCryptoIf, pszPassword); 980 981 if (mData->mUuid != mData->pMachineConfigFile->uuid) 982 throw setError(E_FAIL, 983 tr("Machine UUID {%RTuuid} in '%s' doesn't match its UUID {%s} in the registry file '%s'"), 984 mData->pMachineConfigFile->uuid.raw(), 985 mData->m_strConfigFileFull.c_str(), 986 mData->mUuid.toString().c_str(), 987 mParent->i_settingsFilePath().c_str()); 988 989 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 990 // If config is encrypted, no exception is thrown allowing us to get the uuid and the encryption fields. 991 // We fill in the encryptions fields, and the rest will be filled in if all data parsed 992 mData->mstrKeyId = mData->pMachineConfigFile->strKeyId; 993 mData->mstrKeyStore = mData->pMachineConfigFile->strKeyStore; 994 995 if (mData->pMachineConfigFile->enmParseState == settings::MachineConfigFile::ParseState_PasswordError) 996 throw setError(VBOX_E_PASSWORD_INCORRECT, 997 tr("Config decryption of the machine {%RTuuid} failed. Incorrect or unknown password"), 998 mData->pMachineConfigFile->uuid.raw()); 999 #endif 1000 1001 rc = i_loadMachineDataFromSettings(*mData->pMachineConfigFile, 1002 NULL /* const Guid *puuidRegistry */); 1003 if (FAILED(rc)) throw rc; 1004 } 1005 catch (HRESULT err) 1006 { 1007 /* we assume that error info is set by the thrower */ 1008 rc = err; 1009 } 1010 catch (...) 1011 { 1012 rc = VirtualBoxBase::handleUnexpectedExceptions(this, RT_SRC_POS); 1013 } 1014 1015 /* Restore the registered flag (even on failure) */ 1016 mData->mRegistered = TRUE; 1017 } 1018 1019 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 1020 if (pCryptoIf) 1021 mParent->i_releaseCryptoIf(pCryptoIf); 1022 if (pKey) 1023 mData->mpKeyStore->releaseSecretKey(mData->mstrKeyId); 1024 #endif 793 1025 } 794 1026 … … 929 1161 if (mData->mAccessible) 930 1162 uninitDataAndChildObjects(); 1163 1164 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 1165 if (mData->mpKeyStore != NULL) 1166 delete mData->mpKeyStore; 1167 #endif 931 1168 932 1169 /* free the essential data structure last */ … … 10002 10239 10003 10240 HRESULT rc = S_OK; 10241 PCVBOXCRYPTOIF pCryptoIf = NULL; 10242 const char *pszPassword = NULL; 10243 SecretKey *pKey = NULL; 10244 10245 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 10246 if (mData->mstrKeyId.isNotEmpty()) 10247 { 10248 /* VM is going to be encrypted. */ 10249 alock.release(); /** @todo Revise the locking. */ 10250 rc = mParent->i_retainCryptoIf(&pCryptoIf); 10251 alock.acquire(); 10252 if (FAILED(rc)) return rc; /* Error is set. */ 10253 10254 int vrc = mData->mpKeyStore->retainSecretKey(mData->mstrKeyId, &pKey); 10255 if (RT_SUCCESS(vrc)) 10256 pszPassword = (const char *)pKey->getKeyBuffer(); 10257 else 10258 { 10259 mParent->i_releaseCryptoIf(pCryptoIf); 10260 return setErrorBoth(VBOX_E_IPRT_ERROR, vrc, 10261 tr("Failed to retain VM encryption password using ID '%s' with %Rrc"), 10262 mData->mstrKeyId.c_str(), vrc); 10263 } 10264 } 10265 #else 10266 RT_NOREF(pKey); 10267 #endif 10268 10004 10269 bool fNeedsWrite = false; 10005 10270 bool fSettingsFileIsNew = false; … … 10010 10275 rc = i_prepareSaveSettings(pfNeedsGlobalSaveSettings, 10011 10276 &fSettingsFileIsNew); 10012 if (FAILED(rc)) return rc; 10277 if (FAILED(rc)) 10278 { 10279 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 10280 if (pCryptoIf) 10281 { 10282 alock.release(); /** @todo Revise the locking. */ 10283 mParent->i_releaseCryptoIf(pCryptoIf); 10284 alock.acquire(); 10285 } 10286 if (pKey) 10287 mData->mpKeyStore->releaseSecretKey(mData->mstrKeyId); 10288 #endif 10289 return rc; 10290 } 10013 10291 10014 10292 // keep a pointer to the current settings structures … … 10021 10299 pNewConfig = new settings::MachineConfigFile(NULL); 10022 10300 pNewConfig->copyBaseFrom(*mData->pMachineConfigFile); 10301 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 10302 pNewConfig->strKeyId = mData->mstrKeyId; 10303 pNewConfig->strKeyStore = mData->mstrKeyStore; 10304 #endif 10023 10305 10024 10306 // now go and copy all the settings data from COM to the settings structures … … 10058 10340 10059 10341 if (fNeedsWrite) 10342 { 10060 10343 // now spit it all out! 10061 pNewConfig->write(mData->m_strConfigFileFull); 10344 pNewConfig->write(mData->m_strConfigFileFull, pCryptoIf, pszPassword); 10345 if (aFlags & SaveS_RemoveBackup) 10346 RTFileDelete((mData->m_strConfigFileFull + "-prev").c_str()); 10347 } 10062 10348 10063 10349 mData->pMachineConfigFile = pNewConfig; … … 10085 10371 rc = VirtualBoxBase::handleUnexpectedExceptions(this, RT_SRC_POS); 10086 10372 } 10373 10374 #ifdef VBOX_WITH_FULL_VM_ENCRYPTION 10375 if (pCryptoIf) 10376 { 10377 alock.release(); /** @todo Revise the locking. */ 10378 mParent->i_releaseCryptoIf(pCryptoIf); 10379 alock.acquire(); 10380 } 10381 if (pKey) 10382 mData->mpKeyStore->releaseSecretKey(mData->mstrKeyId); 10383 #endif 10087 10384 10088 10385 if (fNeedsWrite)
Note:
See TracChangeset
for help on using the changeset viewer.