13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/* $Id$ */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** @file
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * IPRT - Crypto - PEM file reader / writer.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Copyright (C) 2006-2014 Oracle Corporation
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * available from http://www.virtualbox.org. This file is free software;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * you can redistribute it and/or modify it under the terms of the GNU
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * General Public License (GPL) as published by the Free Software
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * The contents of this file may alternatively be used under the terms
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * of the Common Development and Distribution License Version 1.0
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * VirtualBox OSE distribution, in which case the provisions of the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * CDDL are applicable instead of those of the GPL.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * You may elect to license modified versions of this file under the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * terms and conditions of either the GPL or the CDDL or both.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/*******************************************************************************
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync* Header Files *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync*******************************************************************************/
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include "internal/iprt.h"
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include <iprt/crypto/pem.h>
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include <iprt/base64.h>
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include <iprt/ctype.h>
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include <iprt/err.h>
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include <iprt/mem.h>
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include <iprt/file.h>
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include <iprt/string.h>
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/**
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Looks for a PEM-like marker.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @returns true if found, fasle if not.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pbContent Start of the content to search thru.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param cbContent The size of the content to search.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param offStart The offset into pbContent to start searching.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pszLeadWord The lead word (BEGIN/END).
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param cchLeadWord The length of the lead word.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param paMarkers Pointer to an array of markers.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param cMarkers Number of markers in the array.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param ppMatch Where to return the pointer to the matching
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * marker. Optional.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param poffBegin Where to return the start offset of the marker.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Optional.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param poffEnd Where to return the end offset of the marker
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * (trailing whitespace and newlines will be
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * skipped). Optional.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic bool rtCrPemFindMarker(uint8_t const *pbContent, size_t cbContent, size_t offStart,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync const char *pszLeadWord, size_t cchLeadWord, PCRTCRPEMMARKER paMarkers, size_t cMarkers,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PCRTCRPEMMARKER *ppMatch, size_t *poffBegin, size_t *poffEnd)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Remember the start of the content for the purpose of calculating offsets. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint8_t const * const pbStart = pbContent;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Skip adhead by offStart */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (offStart >= cbContent)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return false;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbContent += offStart;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbContent -= offStart;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Search the content.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync while (cbContent > 6)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Look for dashes.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint8_t const *pbStartSearch = pbContent;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbContent = (uint8_t const *)memchr(pbContent, '-', cbContent);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (!pbContent)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync break;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbContent -= pbContent - pbStartSearch;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (cbContent < 6)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync break;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * There must be at least three to interest us.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ( pbContent[1] == '-'
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && pbContent[2] == '-')
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync unsigned cDashes = 3;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync while (cDashes < cbContent && pbContent[cDashes] == '-')
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cDashes++;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (poffBegin)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *poffBegin = pbContent - pbStart;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbContent -= cDashes;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbContent += cDashes;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Match lead word.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ( cbContent > cchLeadWord
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && memcmp(pbContent, pszLeadWord, cchLeadWord) == 0
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && RT_C_IS_BLANK(pbContent[cchLeadWord]) )
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbContent += cchLeadWord;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbContent -= cchLeadWord;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync while (cbContent > 0 && RT_C_IS_BLANK(*pbContent))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbContent++;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbContent--;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Match one of the specified markers.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint8_t const *pbSavedContent = pbContent;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync size_t const cbSavedContent = cbContent;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint32_t iMarker = 0;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync while (iMarker < cMarkers)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbContent = pbSavedContent;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbContent = cbSavedContent;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint32_t cWords = paMarkers[iMarker].cWords;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PCRTCRPEMMARKERWORD pWord = paMarkers[iMarker].paWords;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync while (cWords > 0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint32_t const cchWord = pWord->cchWord;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (cbContent <= cchWord)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync break;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (memcmp(pbContent, pWord->pszWord, cchWord))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync break;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbContent += cchWord;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbContent -= cchWord;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (!cbContent || !RT_C_IS_BLANK(*pbContent))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync break;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync do
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbContent++;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbContent--;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync } while (cbContent > 0 && RT_C_IS_BLANK(*pbContent));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cWords--;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (cWords == 0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * If there are three or more dashes following now, we've got a hit.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ( cbContent > 3
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && pbContent[0] == '-'
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && pbContent[1] == '-'
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && pbContent[2] == '-')
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cDashes = 3;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync while (cDashes < cbContent && pbContent[cDashes] == '-')
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cDashes++;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbContent -= cDashes;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbContent += cDashes;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Skip spaces and newline.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync while (cbContent > 0 && RT_C_IS_SPACE(*pbContent))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbContent++, cbContent--;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (poffEnd)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *poffEnd = pbContent - pbStart;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (*ppMatch)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *ppMatch = &paMarkers[iMarker];
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return true;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync break;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync } /* for each word in marker. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync } /* for each marker. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbContent++;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbContent--;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return false;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic bool rtCrPemFindMarkerSection(uint8_t const *pbContent, size_t cbContent, size_t offStart,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PCRTCRPEMMARKER paMarkers, size_t cMarkers,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PCRTCRPEMMARKER *ppMatch, size_t *poffBegin, size_t *poffEnd, size_t *poffResume)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** @todo Detect BEGIN / END mismatch. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PCRTCRPEMMARKER pMatch;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (rtCrPemFindMarker(pbContent, cbContent, offStart, "BEGIN", 5, paMarkers, cMarkers,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync &pMatch, NULL /*poffStart*/, poffBegin))
f6a7a5ea5c6903d1a5632f2febac4e489bd8beddvboxsync {
f6a7a5ea5c6903d1a5632f2febac4e489bd8beddvboxsync if (rtCrPemFindMarker(pbContent, cbContent, *poffBegin, "END", 3, pMatch, 1,
f6a7a5ea5c6903d1a5632f2febac4e489bd8beddvboxsync NULL /*ppMatch*/, poffEnd, poffResume))
f6a7a5ea5c6903d1a5632f2febac4e489bd8beddvboxsync {
f6a7a5ea5c6903d1a5632f2febac4e489bd8beddvboxsync *ppMatch = pMatch;
f6a7a5ea5c6903d1a5632f2febac4e489bd8beddvboxsync return true;
f6a7a5ea5c6903d1a5632f2febac4e489bd8beddvboxsync }
f6a7a5ea5c6903d1a5632f2febac4e489bd8beddvboxsync }
f6a7a5ea5c6903d1a5632f2febac4e489bd8beddvboxsync *ppMatch = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return false;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/**
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Does the decoding of a PEM-like data blob after it has been located.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @returns IPRT status ocde
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pbContent The start of the PEM-like content (text).
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param cbContent The max size of the PEM-like content.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param ppvDecoded Where to return a heap block containing the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * decoded content.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pcbDecoded Where to return the size of the decoded content.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic int rtCrPemDecodeBase64(uint8_t const *pbContent, size_t cbContent, void **ppvDecoded, size_t *pcbDecoded)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync ssize_t cbDecoded = RTBase64DecodedSizeEx((const char *)pbContent, cbContent, NULL);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (cbDecoded < 0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return VERR_INVALID_BASE64_ENCODING;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pcbDecoded = cbDecoded;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync void *pvDecoded = RTMemAlloc(cbDecoded);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (!pvDecoded)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return VERR_NO_MEMORY;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync size_t cbActual;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int rc = RTBase64DecodeEx((const char *)pbContent, cbContent, pvDecoded, cbDecoded, &cbActual, NULL);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (RT_SUCCESS(rc))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (cbActual == (size_t)cbDecoded)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *ppvDecoded = pvDecoded;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return VINF_SUCCESS;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = VERR_INTERNAL_ERROR_3;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RTMemFree(pvDecoded);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return rc;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/**
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Checks if the content of a file looks to be binary or not.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @returns true if likely to be binary, false if not binary.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param pbFile The file bytes to scan.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @param cbFile The number of bytes.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic bool rtCrPemIsBinaryFile(uint8_t *pbFile, size_t cbFile)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Assume a well formed PEM file contains only 7-bit ASCII and restricts
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * itself to the following control characters:
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * tab, newline, return, form feed
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync while (cbFile-- > 0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint8_t const b = *pbFile++;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ( b >= 0x7f
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync || (b < 32 && b != '\t' && b != '\n' && b != '\r' && b != '\f') )
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Ignore EOT (4), SUB (26) and NUL (0) at the end of the file. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ( (b == 4 || b == 26)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && ( cbFile == 0
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync || ( cbFile == 1
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && *pbFile == '\0')))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return true;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (b == 0 && cbFile == 0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return true;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return false;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return true;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncRTDECL(int) RTCrPemFreeSections(PCRTCRPEMSECTION pSectionHead)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync while (pSectionHead != NULL)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PRTCRPEMSECTION pFree = (PRTCRPEMSECTION)pSectionHead;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pSectionHead = pSectionHead->pNext;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (pFree->pMarker)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (pFree->pbData)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RTMemFree(pFree->pbData);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pFree->pbData = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pFree->cbData = 0;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (pFree->pszPreamble)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RTMemFree(pFree->pszPreamble);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pFree->pszPreamble = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pFree->cchPreamble = 0;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RTFileReadAllFree(pFree->pbData, pFree->cbData);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Assert(!pFree->pszPreamble);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pFree->pbData = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pFree->cbData = 0;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return VINF_SUCCESS;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncRTDECL(int) RTCrPemReadFile(const char *pszFilename, uint32_t fFlags, PCRTCRPEMMARKER paMarkers, size_t cMarkers,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PCRTCRPEMSECTION *ppSectionHead, PRTERRINFO pErrInfo)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn(!fFlags, VERR_INVALID_FLAGS);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync size_t cbContent;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint8_t *pbContent;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int rc = RTFileReadAllEx(pszFilename, 0, 64U*_1M, RTFILE_RDALL_O_DENY_WRITE, (void **)&pbContent, &cbContent);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (RT_SUCCESS(rc))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PRTCRPEMSECTION pSection = (PRTCRPEMSECTION)RTMemAllocZ(sizeof(*pSection));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (pSection)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Try locate the first section.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync size_t offBegin, offEnd, offResume;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PCRTCRPEMMARKER pMatch;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ( !rtCrPemIsBinaryFile(pbContent, cbContent)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && rtCrPemFindMarkerSection(pbContent, cbContent, 0 /*offStart*/, paMarkers, cMarkers,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync &pMatch, &offBegin, &offEnd, &offResume) )
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PCRTCRPEMSECTION *ppNext = ppSectionHead;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync for (;;)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->pNext = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pSection->pMarker = pMatch;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->pbData = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->cbData = 0;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->pszPreamble = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->cchPreamble = 0;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *ppNext = pSection;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync ppNext = &pSection->pNext;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Decode the section. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** @todo copy the preamble as well. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = rtCrPemDecodeBase64(pbContent + offBegin, offEnd - offBegin,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync (void **)&pSection->pbData, &pSection->cbData);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (RT_FAILURE(rc))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pSection->pbData = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pSection->cbData = 0;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync break;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* More sections? */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ( offResume + 12 >= cbContent
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync || offResume >= cbContent
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync || !rtCrPemFindMarkerSection(pbContent, cbContent, offResume, paMarkers, cMarkers,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync &pMatch, &offBegin, &offEnd, &offResume) )
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync break; /* No. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Ok, allocate a new record for it. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pSection = (PRTCRPEMSECTION)RTMemAllocZ(sizeof(*pSection));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (RT_UNLIKELY(!pSection))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = VERR_NO_MEMORY;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync break;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (RT_SUCCESS(rc))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RTFileReadAllFree(pbContent, cbContent);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return rc;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RTCrPemFreeSections(*ppSectionHead);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * No PEM section found. Return the whole file as one binary section.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->pNext = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->pMarker = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pSection->pbData = pbContent;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pSection->cbData = cbContent;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->pszPreamble = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->cchPreamble = 0;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *ppSectionHead = pSection;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return VINF_SUCCESS;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = VERR_NO_MEMORY;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RTFileReadAllFree(pbContent, cbContent);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *ppSectionHead = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return rc;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync