0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync/* $Id$ */
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync/** @file
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync * Main - Secret key interface.
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync */
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync/*
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync * Copyright (C) 2015 Oracle Corporation
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync *
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync * available from http://www.virtualbox.org. This file is free software;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync * you can redistribute it and/or modify it under the terms of the GNU
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync * General Public License (GPL) as published by the Free Software
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync */
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync#include <VBox/err.h>
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync#include <VBox/log.h>
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync#include <iprt/assert.h>
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync#include <iprt/asm.h>
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync#include <iprt/memsafer.h>
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync#include "SecretKeyStore.h"
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncSecretKey::SecretKey(const uint8_t *pbKey, size_t cbKey, bool fKeyBufNonPageable)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync m_cRefs = 0;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync m_fRemoveOnSuspend = false;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync m_cUsers = 0;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync m_cbKey = cbKey;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync int rc = RTMemSaferAllocZEx((void **)&this->m_pbKey, cbKey,
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync fKeyBufNonPageable ? RTMEMSAFER_F_REQUIRE_NOT_PAGABLE : 0);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync if (RT_SUCCESS(rc))
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync {
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync memcpy(this->m_pbKey, pbKey, cbKey);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync /* Scramble content to make retrieving the key more difficult. */
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync rc = RTMemSaferScramble(this->m_pbKey, cbKey);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync }
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync else
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync throw rc;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncSecretKey::~SecretKey()
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync Assert(!m_cRefs);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync RTMemSaferFree(m_pbKey, m_cbKey);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync m_cRefs = 0;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync m_pbKey = NULL;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync m_cbKey = 0;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync m_fRemoveOnSuspend = false;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync m_cUsers = 0;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncuint32_t SecretKey::retain()
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync uint32_t cRefs = ASMAtomicIncU32(&m_cRefs);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync if (cRefs == 1)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync {
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync int rc = RTMemSaferUnscramble(m_pbKey, m_cbKey);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync AssertRC(rc);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync }
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return cRefs;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncuint32_t SecretKey::release()
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync uint32_t cRefs = ASMAtomicDecU32(&m_cRefs);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync if (!cRefs)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync {
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync int rc = RTMemSaferScramble(m_pbKey, m_cbKey);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync AssertRC(rc);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync }
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return cRefs;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncuint32_t SecretKey::refCount()
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return m_cRefs;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncint SecretKey::setUsers(uint32_t cUsers)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync m_cUsers = cUsers;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return VINF_SUCCESS;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncuint32_t SecretKey::getUsers()
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return m_cUsers;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncint SecretKey::setRemoveOnSuspend(bool fRemoveOnSuspend)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync m_fRemoveOnSuspend = fRemoveOnSuspend;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return VINF_SUCCESS;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncbool SecretKey::getRemoveOnSuspend()
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return m_fRemoveOnSuspend;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncconst void *SecretKey::getKeyBuffer()
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync AssertReturn(m_cRefs > 0, NULL);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return m_pbKey;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncsize_t SecretKey::getKeySize()
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return m_cbKey;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncSecretKeyStore::SecretKeyStore(bool fKeyBufNonPageable)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync m_fKeyBufNonPageable = fKeyBufNonPageable;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncSecretKeyStore::~SecretKeyStore()
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync int rc = deleteAllSecretKeys(false /* fSuspend */, true /* fForce */);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync AssertRC(rc);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncint SecretKeyStore::addSecretKey(const com::Utf8Str &strKeyId, const uint8_t *pbKey, size_t cbKey)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync /* Check that the ID is not existing already. */
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync SecretKeyMap::const_iterator it = m_mapSecretKeys.find(strKeyId);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync if (it != m_mapSecretKeys.end())
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return VERR_ALREADY_EXISTS;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync try
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync {
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync SecretKey *pKey = new SecretKey(pbKey, cbKey, m_fKeyBufNonPageable);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync m_mapSecretKeys.insert(std::make_pair(strKeyId, pKey));
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync }
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync catch (int rc)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync {
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return rc;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync }
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return VINF_SUCCESS;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncint SecretKeyStore::deleteSecretKey(const com::Utf8Str &strKeyId)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
c7902f6ecf779fa9df37b8600f05ed557aff6f49vboxsync SecretKeyMap::iterator it = m_mapSecretKeys.find(strKeyId);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync if (it == m_mapSecretKeys.end())
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return VERR_NOT_FOUND;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync SecretKey *pKey = it->second;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync if (pKey->refCount() != 0)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return VERR_RESOURCE_IN_USE;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync m_mapSecretKeys.erase(it);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync delete pKey;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return VINF_SUCCESS;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncint SecretKeyStore::retainSecretKey(const com::Utf8Str &strKeyId, SecretKey **ppKey)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync SecretKeyMap::const_iterator it = m_mapSecretKeys.find(strKeyId);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync if (it == m_mapSecretKeys.end())
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return VERR_NOT_FOUND;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync SecretKey *pKey = it->second;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync pKey->retain();
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync *ppKey = pKey;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return VINF_SUCCESS;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncint SecretKeyStore::releaseSecretKey(const com::Utf8Str &strKeyId)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync SecretKeyMap::const_iterator it = m_mapSecretKeys.find(strKeyId);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync if (it == m_mapSecretKeys.end())
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return VERR_NOT_FOUND;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync SecretKey *pKey = it->second;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync pKey->release();
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return VINF_SUCCESS;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsyncint SecretKeyStore::deleteAllSecretKeys(bool fSuspend, bool fForce)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync{
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync /* First check whether a key is still in use. */
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync if (!fForce)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync {
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync for (SecretKeyMap::iterator it = m_mapSecretKeys.begin();
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync it != m_mapSecretKeys.end();
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync it++)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync {
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync SecretKey *pKey = it->second;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync if ( pKey->refCount()
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync && ( ( pKey->getRemoveOnSuspend()
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync && fSuspend)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync || !fSuspend))
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return VERR_RESOURCE_IN_USE;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync }
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync }
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync SecretKeyMap::iterator it = m_mapSecretKeys.begin();
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync while (it != m_mapSecretKeys.end())
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync {
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync SecretKey *pKey = it->second;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync if ( pKey->getRemoveOnSuspend()
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync || !fSuspend)
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync {
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync AssertMsg(!pKey->refCount(), ("No one should access the stored key at this point anymore!\n"));
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync delete pKey;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync m_mapSecretKeys.erase(it++);
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync }
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync else
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync it++;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync }
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync return VINF_SUCCESS;
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync}
0df8f2889273aee65079da0f4b5727a4ac6d3e7bvboxsync