bf5a2ed371c0a47483665fc30b0765a8d80b6b1fvboxsync/* $Id$ */
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync/** @file
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * VBoxStub - VirtualBox's Windows installer stub (certificate manipulations).
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync *
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * NOTE: The content of this file is partly
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * grabbed from src/VBox/Additions/WINNT/tools/VBoxCertUtil.cpp
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync */
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync/*
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * Copyright (C) 2012 Oracle Corporation
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync *
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * available from http://www.virtualbox.org. This file is free software;
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * you can redistribute it and/or modify it under the terms of the GNU
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * General Public License (GPL) as published by the Free Software
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync */
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync/*******************************************************************************
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync* Header Files *
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync*******************************************************************************/
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync#include <Windows.h>
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync#include <Wincrypt.h>
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync#include <iprt/string.h>
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync#include <iprt/message.h>
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync#include <iprt/err.h>
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync/**
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * Reads a certificate from a (const char []) buffer, returning a context
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * or a the handle to a temporary memory store.
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync *
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * @returns true on success, false on failure (error message written).
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * @param kpCertBuf The pointer to the buffer containing the
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * certificates.
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * @param cbCertBuf Size of @param kpCertBuf in bytes.
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * @param ppOutCtx Where to return the handle to the temporary
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * memory store.
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync */
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsyncstatic bool readCertBuf(const unsigned char kpCertBuf[], DWORD cbCertBuf, PCCERT_CONTEXT *ppOutCtx)
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync{
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync *ppOutCtx = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync (PBYTE)kpCertBuf, cbCertBuf);
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync if (*ppOutCtx)
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync return true;
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync return false;
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync}
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync/**
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * Opens a certificate store.
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync *
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * @returns true on success, false on failure (error message written).
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * @param dwDst The destination, like
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * CERT_SYSTEM_STORE_LOCAL_MACHINE or
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * CERT_SYSTEM_STORE_CURRENT_USER.
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * @param pszStoreNm The store name.
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync */
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsyncstatic HCERTSTORE openCertStore(DWORD dwDst, const char *pszStoreNm)
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync{
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync HCERTSTORE hStore = NULL;
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync PRTUTF16 pwszStoreNm;
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync int rc = RTStrToUtf16(pszStoreNm, &pwszStoreNm);
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync if (RT_SUCCESS(rc))
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync {
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync /*
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * Make sure CERT_STORE_OPEN_EXISTING_FLAG is not set. This causes Windows XP
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * to return ACCESS_DENIED when installing TrustedPublisher certificates via
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * CertAddCertificateContextToStore() if the TrustedPublisher store never has
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * been used (through certmgr.exe and friends) yet.
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync *
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * According to MSDN, if neither CERT_STORE_OPEN_EXISTING_FLAG nor
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * CERT_STORE_CREATE_NEW_FLAG is set, the store will be either opened or
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * created accordingly.
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync */
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync dwDst &= ~CERT_STORE_OPEN_EXISTING_FLAG;
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync NULL /* hCryptProv = default */,
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync dwDst,
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync pwszStoreNm);
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync RTUtf16Free(pwszStoreNm);
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync }
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync return hStore;
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync}
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync/**
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * Adds a certificate to a store.
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync *
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * @returns true on success, false on failure (error message written).
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * @param dwDst The destination, like
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * CERT_SYSTEM_STORE_LOCAL_MACHINE or
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * CERT_SYSTEM_STORE_CURRENT_USER.
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * @param pszStoreNm The store name.
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * @param kpCertBuf Buffer that contains a certificate
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * @param cbCertBuf Size of @param kpCertBuf in bytes
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync */
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsyncbool addCertToStore(DWORD dwDst, const char *pszStoreNm, const unsigned char kpCertBuf[], DWORD cbCertBuf)
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync{
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync /*
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * Get certificate from buffer.
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync */
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync PCCERT_CONTEXT pSrcCtx = NULL;
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync bool fRc = false;
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync if (!readCertBuf(kpCertBuf, cbCertBuf, &pSrcCtx))
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync {
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync RTMsgError("Unable to get certificate context: %d", GetLastError());
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync return fRc;
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync }
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync /*
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * Open the certificates store.
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync */
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync HCERTSTORE hDstStore = openCertStore(dwDst, pszStoreNm);
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync if (hDstStore)
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync {
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync /*
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync * Finally, add certificate to store
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync */
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync if (CertAddCertificateContextToStore(hDstStore, pSrcCtx, CERT_STORE_ADD_REPLACE_EXISTING, NULL))
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync fRc = true;
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync else
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync RTMsgError("Unable to install certificate: %d", GetLastError());
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync CertCloseStore(hDstStore, CERT_CLOSE_STORE_CHECK_FLAG);
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync }
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync else
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync RTMsgError("Unable to open certificates store: %d", GetLastError());
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync /* Release resources */
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync CertFreeCertificateContext(pSrcCtx);
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync return fRc;
3a5ff19579e4b3e58a9cdea06fdab1fa6cc961d2vboxsync}