x509.cpp revision c9e08fdf5fa9ba16094b8e37f257f4267044ad6f
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync/* $Id$ */
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync/** @file
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * IPRT - X509 functions.
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync */
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync/*
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * Copyright (C) 2014 Oracle Corporation
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * available from http://www.virtualbox.org. This file is free software;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * you can redistribute it and/or modify it under the terms of the GNU
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * General Public License (GPL) as published by the Free Software
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * The contents of this file may alternatively be used under the terms
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * of the Common Development and Distribution License Version 1.0
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * VirtualBox OSE distribution, in which case the provisions of the
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * CDDL are applicable instead of those of the GPL.
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * You may elect to license modified versions of this file under the
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * terms and conditions of either the GPL or the CDDL or both.
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync */
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync/*******************************************************************************
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync* Header Files *
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync*******************************************************************************/
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync#include "internal/iprt.h"
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync#include <openssl/bio.h>
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync#include <openssl/err.h>
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync#include <openssl/pem.h>
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync#include <openssl/x509.h>
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync#include <openssl/x509v3.h>
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync#include <iprt/x509.h>
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync#include <iprt/assert.h>
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync#include <iprt/mem.h>
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync#include <iprt/err.h>
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync#include <iprt/sha.h>
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync#include <iprt/manifest.h>
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync#include <iprt/string.h>
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync/**
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * Preparation before start to work with openssl
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @returns none
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync */
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsyncRTDECL(void) RTX509PrepareOpenSSL()
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync{
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync OpenSSL_add_all_digests();
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync ERR_load_BIO_strings();
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync ERR_load_crypto_strings();
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync}
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsyncRT_EXPORT_SYMBOL(RTX509PrepareOpenSSL);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync/**
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * Read X509 certificate from the given memory buffer into the
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * internal structure.
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @returns iprt status code.
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @param pvBuf string representation
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * containing X509 certificate
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * in PEM format
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @param cbSize The amount of data (in bytes)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @param out_cert pointer to the structure where
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * the info about X509
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * certificate will be stored
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync */
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsyncstatic int RTX509ReadCertificateFromPEM(void *pvBuf, unsigned int cbSize, X509** out_cert)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync{
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync int rc = VINF_SUCCESS;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync BIO *bio_memory = BIO_new(BIO_s_mem());
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync int cbytes = BIO_write(bio_memory,(const void*)pvBuf ,cbSize) ;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *out_cert = PEM_read_bio_X509(bio_memory,NULL,0,NULL);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync BIO_free(bio_memory);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if(!*out_cert)
c9e08fdf5fa9ba16094b8e37f257f4267044ad6fvboxsync rc = VERR_X509_READING_CERT_FROM_BIO;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync return rc;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync}
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync/**
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * Convert X509 certificate from string to binary representation
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @returns iprt status code.
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @param pvBuf string representation
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * containing X509 certificate
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * in PEM format
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @param pOutSignature memory buffer where the binary
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * representation will be stored
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @param lengthOfSignature length of X509 certificate in
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * binary representation
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync */
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsyncstatic int RTX509ConvertCertificateToBinary(void *pvBuf, unsigned char** pOutSignature, unsigned int* lengthOfSignature)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync{
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync int rc = VINF_SUCCESS;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync char* beginSignatureStr = RTStrStr((char*)pvBuf, "=");
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync beginSignatureStr+=2;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync char* endSignatureStr = RTStrStr((char*)pvBuf, "-----BEGIN CERTIFICATE-----");
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync --endSignatureStr;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *lengthOfSignature = (endSignatureStr - beginSignatureStr)/2;//two hex digits in one byte
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *pOutSignature = (unsigned char *)RTMemAlloc(*lengthOfSignature);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync rc = RTStrConvertHexBytes(beginSignatureStr, *pOutSignature, *lengthOfSignature, 0);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if (RT_FAILURE(rc))
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync RTMemFree(*pOutSignature);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *pOutSignature = NULL;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync return rc;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync}
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync/**
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * Convert digest from string to binary representation
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @returns iprt status code.
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @param digest string representation
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @param pOutDigest memory buffer where the binary
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * representation will be stored
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @param digestType Type of digest
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @param lengthOfDigest length of digest in binary
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * representation
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync */
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsyncstatic int RTConvertDigestToBinary(const char* digest,
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync unsigned char** pOutDigest,
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync RTDIGESTTYPE digestType,
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync unsigned int* lengthOfDigest)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync{
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync int rc = VINF_SUCCESS;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if(digestType == RTDIGESTTYPE_SHA1)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *lengthOfDigest = RTSHA1_HASH_SIZE;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *pOutDigest = (unsigned char *)RTMemAlloc(RTSHA1_HASH_SIZE);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync rc = RTStrConvertHexBytes(digest, *pOutDigest, RTSHA1_HASH_SIZE, 0);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync else if(digestType == RTDIGESTTYPE_SHA256)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *lengthOfDigest = RTSHA256_HASH_SIZE;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *pOutDigest = (unsigned char *)RTMemAlloc(RTSHA256_HASH_SIZE);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync rc = RTStrConvertHexBytes(digest, *pOutDigest, RTSHA256_HASH_SIZE, 0);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync else
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync rc = VERR_MANIFEST_UNSUPPORTED_DIGEST_TYPE;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if (RT_FAILURE(rc))
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if(*pOutDigest != NULL)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync RTMemFree(*pOutDigest);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *pOutDigest = NULL;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync return rc;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync}
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsyncRTDECL(int) RTRSAVerify(void *pvBuf, unsigned int cbSize, const char* pManifestDigestIn, RTDIGESTTYPE digestType)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync{
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync int rc = VINF_SUCCESS;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync unsigned char* pSignatureRSA = NULL;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync unsigned char* pManifestDigestOut = NULL;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync X509 *certificate = NULL;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync EVP_PKEY * evp_key = NULL;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync RSA * rsa_key = NULL;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync while(1)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync unsigned int siglen = 0;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync rc = RTX509ConvertCertificateToBinary(pvBuf, &pSignatureRSA, &siglen);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if (RT_FAILURE(rc))
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync /*pSignatureRSA isn't allocated in this case, thus there is no need to free it*/
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync break;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync unsigned int diglen = 0;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync rc = RTConvertDigestToBinary(pManifestDigestIn,&pManifestDigestOut, digestType, &diglen);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if (RT_FAILURE(rc))
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync /*pManifestDigestOut isn't allocated in this case, thus there is no need to free it*/
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync break;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync rc = RTX509ReadCertificateFromPEM(pvBuf, cbSize, &certificate);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if (RT_FAILURE(rc))
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync /*memory for certificate isn't allocated in this case, thus there is no need to free it*/
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync break;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync evp_key = X509_get_pubkey(certificate);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if (evp_key == NULL)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
c9e08fdf5fa9ba16094b8e37f257f4267044ad6fvboxsync rc = VERR_X509_EXTRACT_PUBKEY_FROM_CERT;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync break;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync rsa_key = EVP_PKEY_get1_RSA(evp_key);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if (rsa_key == NULL)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
c9e08fdf5fa9ba16094b8e37f257f4267044ad6fvboxsync rc = VERR_X509_EXTRACT_RSA_FROM_PUBLIC_KEY;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync break;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync rc = RSA_verify(NID_sha1,
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync pManifestDigestOut,
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync diglen,
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync pSignatureRSA,
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync siglen,
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync rsa_key);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if (rc != 1)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
c9e08fdf5fa9ba16094b8e37f257f4267044ad6fvboxsync rc = VERR_X509_RSA_VERIFICATION_FUILURE;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync break;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }//end while(1)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if(rsa_key)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync RSA_free(rsa_key);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if(evp_key)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync EVP_PKEY_free(evp_key);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if(certificate)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync X509_free(certificate);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if (pManifestDigestOut)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync RTMemFree(pManifestDigestOut);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if (pSignatureRSA)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync RTMemFree(pSignatureRSA);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync return rc;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync}
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsyncRT_EXPORT_SYMBOL(RTRSAVerify);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync/**
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * Get X509 certificate basic constraints
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @returns iprt status code.
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @param pvBuf string representation
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * containing X509 certificate
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * in PEM format
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @param cbSize The amount of data (in bytes)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * @param pBasicConstraintsOut memory buffer where the
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * extracted basic constraints
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * will be stored in string
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync * representation
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync */
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsyncstatic int RTX509GetBasicConstraints(void *pvBuf, unsigned int cbSize, unsigned char** pBasicConstraintsOut)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync{
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync int rc = VINF_SUCCESS;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync BUF_MEM *bptr = NULL;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync X509 *certificate = NULL;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync char *errDesc = NULL;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync BIO *bio_memory = NULL;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync while (1)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync rc = RTX509ReadCertificateFromPEM(pvBuf, cbSize, &certificate);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync int loc = X509_get_ext_by_NID(certificate, NID_basic_constraints,-1);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if(loc == -1)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
c9e08fdf5fa9ba16094b8e37f257f4267044ad6fvboxsync rc = VERR_X509_NO_BASIC_CONSTARAINTS;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync break;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync X509_EXTENSION *ext = X509_get_ext(certificate, loc);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if(!ext)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
c9e08fdf5fa9ba16094b8e37f257f4267044ad6fvboxsync rc = VERR_X509_GETTING_EXTENSION_FROM_CERT;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync break;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync ASN1_OCTET_STRING *extdata = X509_EXTENSION_get_data(ext);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if(!extdata)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
c9e08fdf5fa9ba16094b8e37f257f4267044ad6fvboxsync rc = VERR_X509_GETTING_DATA_FROM_EXTENSION;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync break;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync bio_memory = BIO_new(BIO_s_mem());
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if(!X509V3_EXT_print(bio_memory, ext, 0, 0))
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
c9e08fdf5fa9ba16094b8e37f257f4267044ad6fvboxsync rc = VERR_X509_PRINT_EXTENSION_TO_BIO;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync break;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync BIO_ctrl(bio_memory,BIO_CTRL_FLUSH,0,NULL);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync BIO_ctrl(bio_memory,BIO_C_GET_BUF_MEM_PTR,0,(void *)&bptr);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync // now bptr contains the strings of the key_usage
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync unsigned char *buf = (unsigned char *)RTMemAlloc((bptr->length + 1)*sizeof(char));
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync memcpy(buf, bptr->data, bptr->length);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync // take care that bptr->data is NOT NULL terminated, so add '\0'
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync buf[bptr->length] = '\0';
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *pBasicConstraintsOut = buf;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync break;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if(certificate)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync X509_free(certificate);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync BIO_free(bio_memory);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync return rc;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync}
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsyncRTDECL(int) RTX509CertificateVerify(void *pvBuf, unsigned int cbSize)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync{
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync int rc = VINF_SUCCESS;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync X509 *certificate = NULL;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync X509_NAME * subject = NULL;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync X509_NAME * issuer = NULL;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync EVP_PKEY * evp_key = NULL;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync unsigned char* strBasicConstraints = NULL;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync while(1)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync rc = RTX509ReadCertificateFromPEM(pvBuf, cbSize, &certificate);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if (RT_FAILURE(rc))
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync break;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync rc = RTX509GetBasicConstraints(pvBuf, cbSize, &strBasicConstraints);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if (RT_FAILURE(rc))
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync break;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync issuer = X509_get_issuer_name(certificate);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if(strcmp("CA:TRUE", (const char*)strBasicConstraints) == 0)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync subject = X509_get_subject_name(certificate);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync int ki=0;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if(X509_name_cmp(issuer, subject) == 0)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync evp_key = X509_get_pubkey(certificate);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync ki=X509_verify(certificate,evp_key);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if(ki>0)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync /* if it's needed will do something with the verified certificate */
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync else
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync rc = VERR_X509_CERTIFICATE_VERIFICATION_FAILURE;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
8aaface4f6fe017f7cdcfb1c467086bcbd50614evboxsync else
8aaface4f6fe017f7cdcfb1c467086bcbd50614evboxsync {
c9e08fdf5fa9ba16094b8e37f257f4267044ad6fvboxsync rc = VINF_X509_NOT_SELFSIGNED_CERTIFICATE;
8aaface4f6fe017f7cdcfb1c467086bcbd50614evboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync else
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync {
c9e08fdf5fa9ba16094b8e37f257f4267044ad6fvboxsync rc = VINF_X509_NOT_SELFSIGNED_CERTIFICATE;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync break;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync }
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if(certificate)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync X509_free(certificate);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync if(evp_key)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync EVP_PKEY_free(evp_key);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync RTMemFree(strBasicConstraints);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync return rc;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync}
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsyncRT_EXPORT_SYMBOL(RTX509CertificateVerify);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsyncRTDECL(unsigned long) RTX509GetErrorDescription(char** pErrorDesc)
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync{
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync char *errorDescription = (char *)RTMemAlloc(256);// buffer must be at least 120 bytes long.
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync // see http://www.openssl.org/docs/crypto/ERR_error_string.html
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync unsigned long err = ERR_get_error();
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync ERR_error_string(err, errorDescription);
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync *pErrorDesc = errorDescription;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync return err;
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsync}
d9dcb7404c5146ec833ff95fd450ba177237db0bvboxsyncRT_EXPORT_SYMBOL(RTX509GetError);