VirtualBox

Changeset 42125 in vbox for trunk


Ignore:
Timestamp:
Jul 12, 2012 10:39:18 AM (13 years ago)
Author:
vboxsync
Message:

optional encrypted store of the iSCSI initiator secret

Location:
trunk/src/VBox
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManage.cpp

    r41100 r42125  
    3737#include <iprt/asm.h>
    3838#include <iprt/buildconfig.h>
     39#include <iprt/ctype.h>
    3940#include <iprt/initterm.h>
    4041#include <iprt/path.h>
     
    245246
    246247
     248#ifndef VBOX_ONLY_DOCS
     249static RTEXITCODE settingsPasswordFile(ComPtr<IVirtualBox> virtualBox, const char *pszFile)
     250{
     251    size_t cbFile;
     252    char szPasswd[512];
     253    int vrc = VINF_SUCCESS;
     254    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
     255    bool fStdIn = !strcmp(pszFile, "stdin");
     256    PRTSTREAM pStrm;
     257    if (!fStdIn)
     258        vrc = RTStrmOpen(pszFile, "r", &pStrm);
     259    else
     260        pStrm = g_pStdIn;
     261    if (RT_SUCCESS(vrc))
     262    {
     263        vrc = RTStrmReadEx(pStrm, szPasswd, sizeof(szPasswd)-1, &cbFile);
     264        if (RT_SUCCESS(vrc))
     265        {
     266            if (cbFile >= sizeof(szPasswd)-1)
     267                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Provided password too long");
     268            else
     269            {
     270                unsigned i;
     271                for (i = 0; i < cbFile && !RT_C_IS_CNTRL(szPasswd[i]); i++)
     272                    ;
     273                szPasswd[i] = '\0';
     274                int rc;
     275                CHECK_ERROR(virtualBox, SetSettingsSecret(com::Bstr(szPasswd).raw()));
     276                if (FAILED(rc))
     277                    rcExit = RTEXITCODE_FAILURE;
     278            }
     279        }
     280        if (!fStdIn)
     281            RTStrmClose(pStrm);
     282    }
     283    else
     284        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Cannot open password file '%s' (%Rrc)", pszFile);
     285
     286    return rcExit;
     287}
     288#endif
     289
    247290int main(int argc, char *argv[])
    248291{
     
    260303    int  iCmd      = 1;
    261304    int  iCmdArg;
     305    const char *g_pszSettingsPw = NULL;
     306    const char *g_pszSettingsPwFile = NULL;
    262307
    263308    for (int i = 1; i < argc || argc <= iCmd; i++)
     
    316361            iCmd++;
    317362        }
     363        else if (!strcmp(argv[i], "--settingspw"))
     364        {
     365            if (i >= argc-1)
     366                return RTMsgErrorExit(RTEXITCODE_FAILURE,
     367                                      "Password expected");
     368            /* password for certain settings */
     369            g_pszSettingsPw = argv[i+1];
     370            iCmd += 2;
     371        }
     372        else if (!strcmp(argv[i], "--settingspwfile"))
     373        {
     374            if (i >= argc-1)
     375                return RTMsgErrorExit(RTEXITCODE_FAILURE,
     376                                      "No password file specified");
     377            g_pszSettingsPwFile = argv[i+1];
     378            iCmd += 2;
     379        }
    318380        else
    319         {
    320381            break;
    321         }
    322382    }
    323383
     
    447507        };
    448508
     509        if (g_pszSettingsPw)
     510        {
     511            int rc;
     512            CHECK_ERROR(virtualBox, SetSettingsSecret(Bstr(g_pszSettingsPw).raw()));
     513            if (FAILED(rc))
     514            {
     515                rcExit = RTEXITCODE_FAILURE;
     516                break;
     517            }
     518        }
     519        else if (g_pszSettingsPwFile)
     520        {
     521            rcExit = settingsPasswordFile(virtualBox, g_pszSettingsPwFile);
     522            if (rcExit != RTEXITCODE_SUCCESS)
     523                break;
     524        }
     525
    449526        HandlerArg  handlerArg = { 0, NULL, virtualBox, session };
    450527        int         commandIndex;
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp

    r41925 r42125  
    9999    if (u64Cmd == USAGE_ALL)
    100100        RTStrmPrintf(pStrm,
    101                      "VBoxManage [-v|--version]    print version number and exit\n"
    102                      "VBoxManage [-q|--nologo] ... suppress the logo\n"
     101                     "VBoxManage [-v|--version]          print version number and exit\n"
     102                     "VBoxManage [-q|--nologo]       ... suppress the logo\n"
     103                     "VBoxManage [--settingspw <pw>] ...\n"
     104                     "VBoxManage [--settingspwfile]  ... provide the settings password\n"
    103105                     "\n");
    104106
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r42105 r42125  
    21002100      <param name="value" type="wstring" dir="in">
    21012101        <desc>Value to assign to the key.</desc>
     2102      </param>
     2103    </method>
     2104
     2105    <method name="setSettingsSecret">
     2106      <desc>
     2107        Unlocks the secret data by passing the unlock password to the
     2108        server. The server will cache the password for that machine.
     2109
     2110        <result name="VBOX_E_INVALID_VM_STATE">
     2111          Virtual machine is not mutable.
     2112        </result>
     2113
     2114      </desc>
     2115      <param name="password" type="wstring" dir="in">
     2116        <desc>
     2117          The cipher key.
     2118        </desc>
    21022119      </param>
    21032120    </method>
  • trunk/src/VBox/Main/include/MediumImpl.h

    r41231 r42125  
    183183    bool getFirstRegistryMachineId(Guid &uuid) const;
    184184    void markRegistriesModified();
     185   
     186    HRESULT setPropertyDirect(const Utf8Str &aName, const Utf8Str &aValue);
    185187
    186188    HRESULT addBackReference(const Guid &aMachineId,
     
    188190    HRESULT removeBackReference(const Guid &aMachineId,
    189191                                const Guid &aSnapshotId = Guid::Empty);
     192
    190193
    191194    const Guid* getFirstMachineBackrefId() const;
  • trunk/src/VBox/Main/include/VirtualBoxImpl.h

    r41999 r42125  
    153153    STDMETHOD(GetExtraData)(IN_BSTR aKey, BSTR *aValue);
    154154    STDMETHOD(SetExtraData)(IN_BSTR aKey, IN_BSTR aValue);
     155    STDMETHOD(SetSettingsSecret)(IN_BSTR aKey);
    155156
    156157    STDMETHOD(CreateDHCPServer)(IN_BSTR aName, IDHCPServer ** aServer);
     
    286287    RWLockHandle& getMediaTreeLockHandle();
    287288
     289    int  encryptSetting(const Utf8Str &aPlaintext, Utf8Str *aCiphertext);
     290    int  decryptSetting(Utf8Str *aPlaintext, const Utf8Str &aCiphertext);
     291    void storeSettingsKey(const Utf8Str &aKey);
     292
    288293private:
    289294
     
    305310    HRESULT unregisterDHCPServer(DHCPServer *aDHCPServer,
    306311                                 bool aSaveRegistry = true);
     312   
     313    void decryptSettings();
     314    void decryptMediumSettings(Medium *pMedium);
     315    int  decryptSettingBytes(uint8_t *aPlaintext, const uint8_t *aCiphertext,
     316                             size_t aCiphertextSize) const;
     317    int  encryptSettingBytes(const uint8_t *aPlaintext, uint8_t *aCiphertext,
     318                             size_t aPlaintextSize, size_t aCiphertextSize) const;
    307319
    308320    struct Data;            // opaque data structure, defined in VirtualBoxImpl.cpp
  • trunk/src/VBox/Main/src-server/MediumImpl.cpp

    r42109 r42125  
    11801180    }
    11811181
     1182    /* try to decrypt an optional iSCSI initiator secret */
     1183    settings::StringsMap::const_iterator itCph = data.properties.find("InitiatorSecretEncrypted");
     1184    if (   itCph != data.properties.end()
     1185        && !itCph->second.isEmpty())
     1186    {
     1187        Utf8Str strPlaintext;
     1188        int vrc = m->pVirtualBox->decryptSetting(&strPlaintext, itCph->second);
     1189        if (RT_SUCCESS(vrc))
     1190            m->mapProperties["InitiatorSecret"] = strPlaintext;
     1191    }
     1192
    11821193    Utf8Str strFull;
    11831194    if (m->formatObj->getCapabilities() & MediumFormatCapabilities_File)
     
    37543765    /* optional properties */
    37553766    data.properties.clear();
     3767
     3768    /* handle iSCSI initiator secrets transparently */
     3769    bool fHaveInitiatorSecretEncrypted = false;
     3770    Utf8Str strCiphertext;
     3771    settings::StringsMap::const_iterator itPln = m->mapProperties.find("InitiatorSecret");
     3772    if (   itPln != m->mapProperties.end()
     3773        && !itPln->second.isEmpty())
     3774    {
     3775        /* Encrypt the plain secret. If that does not work (i.e. no settings key specified),
     3776         * just use the encrypted secret (if there is any). */
     3777        int rc = m->pVirtualBox->encryptSetting(itPln->second, &strCiphertext);
     3778        NOREF(rc);
     3779        fHaveInitiatorSecretEncrypted = true;
     3780    }
    37563781    for (settings::StringsMap::const_iterator it = m->mapProperties.begin();
    37573782         it != m->mapProperties.end();
     
    37633788            const Utf8Str &name = it->first;
    37643789            const Utf8Str &value = it->second;
    3765             data.properties[name] = value;
    3766         }
     3790            /* do NOT store the plain InitiatorSecret */
     3791            if (   !fHaveInitiatorSecretEncrypted
     3792                || !name.equals("InitiatorSecret"))
     3793                data.properties[name] = value;
     3794        }
     3795        if (fHaveInitiatorSecretEncrypted)
     3796            data.properties["InitiatorSecretEncrypted"] = strCiphertext;
    37673797    }
    37683798
     
    57995829
    58005830    return rc;
     5831}
     5832
     5833/**
     5834 * Like SetProperty but do not trigger a settings store. Only for internal use!
     5835 */
     5836HRESULT Medium::setPropertyDirect(const Utf8Str &aName, const Utf8Str &aValue)
     5837{
     5838    AutoCaller autoCaller(this);
     5839    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     5840
     5841    AutoWriteLock mlock(this COMMA_LOCKVAL_SRC_POS);
     5842
     5843    switch (m->state)
     5844    {
     5845        case MediumState_Created:
     5846        case MediumState_Inaccessible:
     5847            break;
     5848        default:
     5849            return setStateError();
     5850    }
     5851
     5852    m->mapProperties[aName] = aValue;
     5853
     5854    return S_OK;
    58015855}
    58025856
  • trunk/src/VBox/Main/src-server/VirtualBoxImpl.cpp

    r41999 r42125  
    1717
    1818#include <iprt/asm.h>
     19#include <iprt/base64.h>
    1920#include <iprt/buildconfig.h>
    2021#include <iprt/cpp/utils.h>
     
    2425#include <iprt/path.h>
    2526#include <iprt/process.h>
     27#include <iprt/rand.h>
     28#include <iprt/sha.h>
    2629#include <iprt/string.h>
    2730#include <iprt/stream.h>
     
    295298    /** The global autostart database for the user. */
    296299    AutostartDb * const                 pAutostartDb;
     300
     301    /** Settings secret */
     302    bool                                fSettingsCipherKeySet;
     303    uint8_t                             SettingsCipherKey[RTSHA512_HASH_SIZE];
    297304};
     305
    298306
    299307// constructor / destructor
     
    446454        if (FAILED(rc = initMachines()))
    447455            throw rc;
    448 
    449456
    450457#ifdef DEBUG
     
    19671974}
    19681975
     1976/**
     1977 *
     1978 */
     1979STDMETHODIMP VirtualBox::SetSettingsSecret(IN_BSTR aValue)
     1980{
     1981    storeSettingsKey(aValue);
     1982    decryptSettings();
     1983    return S_OK;
     1984}
     1985
     1986void VirtualBox::decryptMediumSettings(Medium *pMedium)
     1987{
     1988    Bstr bstrCipher;
     1989    HRESULT hrc = pMedium->GetProperty(Bstr("InitiatorSecretEncrypted").raw(),
     1990                                       bstrCipher.asOutParam());
     1991    if (SUCCEEDED(hrc))
     1992    {
     1993        Bstr bstrName;
     1994        pMedium->COMGETTER(Name)(bstrName.asOutParam());
     1995        Utf8Str strPlaintext;
     1996        int rc = decryptSetting(&strPlaintext, bstrCipher);
     1997        if (RT_SUCCESS(rc))
     1998            pMedium->setPropertyDirect("InitiatorSecret", strPlaintext);
     1999    }
     2000}
     2001
     2002/**
     2003 * Decrypt all encrypted settings.
     2004 *
     2005 * So far we only have encrypted iSCSI initiator secrets so we just go through
     2006 * all hard disk mediums and determine the plain 'InitiatorSecret' from
     2007 * 'InitiatorSecretEncrypted. The latter is stored as Base64 because medium
     2008 * properties need to be null-terminated strings.
     2009 */
     2010void VirtualBox::decryptSettings()
     2011{
     2012    AutoReadLock al(m->allHardDisks.getLockHandle() COMMA_LOCKVAL_SRC_POS);
     2013    for (MediaList::const_iterator mt = m->allHardDisks.begin();
     2014         mt != m->allHardDisks.end();
     2015         ++mt)
     2016    {
     2017        ComObjPtr<Medium> pMedium = *mt;
     2018        AutoCaller medCaller(pMedium);
     2019        if (FAILED(medCaller.rc()))
     2020            continue;
     2021        AutoWriteLock mlock(pMedium COMMA_LOCKVAL_SRC_POS);
     2022        decryptMediumSettings(pMedium);
     2023    }
     2024}
     2025
     2026/**
     2027 * Encode.
     2028 *
     2029 * @param aPlaintext      plaintext to be encrypted
     2030 * @param aCiphertext     resulting ciphertext (base64-encoded)
     2031 */
     2032int VirtualBox::encryptSetting(const Utf8Str &aPlaintext, Utf8Str *aCiphertext)
     2033{
     2034    uint8_t abCiphertext[32];
     2035    char    szCipherBase64[128];
     2036    size_t  cchCipherBase64;
     2037    int rc = encryptSettingBytes((uint8_t*)aPlaintext.c_str(), abCiphertext,
     2038                                 aPlaintext.length()+1, sizeof(abCiphertext));
     2039    if (RT_SUCCESS(rc))
     2040    {
     2041        rc = RTBase64Encode(abCiphertext, sizeof(abCiphertext),
     2042                            szCipherBase64, sizeof(szCipherBase64),
     2043                            &cchCipherBase64);
     2044        if (RT_SUCCESS(rc))
     2045            *aCiphertext = szCipherBase64;
     2046    }
     2047    return rc;
     2048}
     2049
     2050/**
     2051 * Decode.
     2052 *
     2053 * @param aPlaintext      resulting plaintext
     2054 * @param aCiphertext     ciphertext (base64-encoded) to decrypt
     2055 */
     2056int VirtualBox::decryptSetting(Utf8Str *aPlaintext, const Utf8Str &aCiphertext)
     2057{
     2058    uint8_t abPlaintext[64];
     2059    uint8_t abCiphertext[64];
     2060    size_t  cbCiphertext;
     2061    int rc = RTBase64Decode(aCiphertext.c_str(),
     2062                            abCiphertext, sizeof(abCiphertext),
     2063                            &cbCiphertext, NULL);
     2064    if (RT_SUCCESS(rc))
     2065    {
     2066        rc = decryptSettingBytes(abPlaintext, abCiphertext, cbCiphertext);
     2067        if (RT_SUCCESS(rc))
     2068        {
     2069            /* check if this is really a Null-terminated string. */
     2070            for (unsigned i = 0; i < cbCiphertext; i++)
     2071            {
     2072                if (abPlaintext[i] == '\0')
     2073                {
     2074                    *aPlaintext = Utf8Str((const char*)abPlaintext);
     2075                    return VINF_SUCCESS;
     2076                }
     2077            }
     2078            rc = VERR_INVALID_PARAMETER;
     2079        }
     2080    }
     2081    return rc;
     2082}
     2083
     2084/**
     2085 * Encrypt secret bytes. Use the m->SettingsCipherKey as key.
     2086 *
     2087 * @param aPlaintext      clear text to be encrypted
     2088 * @param aCiphertext     resulting encrypted text
     2089 * @param aPlaintextSize  size of the plaintext
     2090 * @param aCiphertextSize size of the ciphertext
     2091 */
     2092int VirtualBox::encryptSettingBytes(const uint8_t *aPlaintext, uint8_t *aCiphertext,
     2093                                    size_t aPlaintextSize, size_t aCiphertextSize) const
     2094{
     2095    unsigned i, j;
     2096    uint8_t aBytes[64];
     2097
     2098    if (!m->fSettingsCipherKeySet)
     2099        return VERR_INVALID_STATE;
     2100
     2101    if (aCiphertextSize > sizeof(aBytes))
     2102        return VERR_BUFFER_OVERFLOW;
     2103
     2104    for (i = 0, j = 0; i < aPlaintextSize && i < aCiphertextSize; i++)
     2105    {
     2106        aCiphertext[i] = (aPlaintext[i] ^ m->SettingsCipherKey[j]);
     2107        if (++j >= sizeof(m->SettingsCipherKey))
     2108            j = 0;
     2109    }
     2110
     2111    /* fill with random data to have a minimal length */
     2112    if (i < aCiphertextSize)
     2113    {
     2114        RTRandBytes(aBytes, aCiphertextSize - i);
     2115        for (; i < aCiphertextSize; i++)
     2116        {
     2117            aCiphertext[i] = aBytes[i] ^ m->SettingsCipherKey[j];
     2118            if (++j >= sizeof(m->SettingsCipherKey))
     2119                j = 0;
     2120        }
     2121    }
     2122
     2123    return VINF_SUCCESS;
     2124}
     2125
     2126/**
     2127 * Decrypt secret bytes. Use the m->SettingsCipherKey as key.
     2128 *
     2129 * @param aPlaintext      resulting plaintext
     2130 * @param aCiphertext     ciphertext to be decrypted
     2131 * @param aCiphertextSize size of the ciphertext == size of the plaintext
     2132 */
     2133int VirtualBox::decryptSettingBytes(uint8_t *aPlaintext,
     2134                                    const uint8_t *aCiphertext, size_t aCiphertextSize) const
     2135{
     2136    if (!m->fSettingsCipherKeySet)
     2137        return VERR_INVALID_STATE;
     2138
     2139    for (unsigned i = 0, j = 0; i < aCiphertextSize; i++)
     2140    {
     2141        aPlaintext[i] = aCiphertext[i] ^ m->SettingsCipherKey[j];
     2142        if (++j >= sizeof(m->SettingsCipherKey))
     2143            j = 0;
     2144    }
     2145
     2146    return VINF_SUCCESS;
     2147}
     2148
     2149/**
     2150 * Store a settings key.
     2151 *
     2152 * @param aKey          the key to store
     2153 */
     2154void VirtualBox::storeSettingsKey(const Utf8Str &aKey)
     2155{
     2156    RTSha512(aKey.c_str(), aKey.length(), m->SettingsCipherKey);
     2157    m->fSettingsCipherKeySet = true;
     2158}
     2159
    19692160// public methods only for internal purposes
    19702161/////////////////////////////////////////////////////////////////////////////
     
    39984189        rc = saveSettings();
    39994190    }
     4191    NOREF(rc); /* XXX */
    40004192}
    40014193
  • trunk/src/VBox/Storage/ISCSI.cpp

    r41785 r42125  
    37713771    /* Validate configuration, detect unknown keys. */
    37723772    if (!VDCFGAreKeysValid(pImage->pIfConfig,
    3773                            "TargetName\0InitiatorName\0LUN\0TargetAddress\0InitiatorUsername\0InitiatorSecret\0TargetUsername\0TargetSecret\0WriteSplit\0Timeout\0HostIPStack\0"))
     3773                           "TargetName\0"
     3774                           "InitiatorName\0"
     3775                           "LUN\0"
     3776                           "TargetAddress\0"
     3777                           "InitiatorUsername\0"
     3778                           "InitiatorSecret\0"
     3779                           "InitiatorSecretEncrypted\0"
     3780                           "TargetUsername\0"
     3781                           "TargetSecret\0"
     3782                           "WriteSplit\0"
     3783                           "Timeout\0"
     3784                           "HostIPStack\0"))
    37743785    {
    37753786        rc = vdIfError(pImage->pIfError, VERR_VD_ISCSI_UNKNOWN_CFG_VALUES, RT_SRC_POS, N_("iSCSI: configuration error: unknown configuration keys present"));
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette