13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * IPRT - Crypto - PEM file reader / writer.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Copyright (C) 2006-2014 Oracle Corporation
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 * 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 * 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* Header Files *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync*******************************************************************************/
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Looks for a PEM-like marker.
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.
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 /* Remember the start of the content for the purpose of calculating offsets. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Skip adhead by offStart */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return false;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Search the content.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Look for dashes.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbContent = (uint8_t const *)memchr(pbContent, '-', cbContent);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * There must be at least three to interest us.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync while (cDashes < cbContent && pbContent[cDashes] == '-')
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Match lead word.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && memcmp(pbContent, pszLeadWord, cchLeadWord) == 0
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Match one of the specified markers.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PCRTCRPEMMARKERWORD pWord = paMarkers[iMarker].paWords;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync } while (cbContent > 0 && RT_C_IS_BLANK(*pbContent));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * If there are three or more dashes following now, we've got a hit.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync while (cDashes < cbContent && pbContent[cDashes] == '-')
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Skip spaces and newline.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return true;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync } /* for each word in marker. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync } /* for each marker. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return false;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic bool rtCrPemFindMarkerSection(uint8_t const *pbContent, size_t cbContent, size_t offStart,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PCRTCRPEMMARKER *ppMatch, size_t *poffBegin, size_t *poffEnd, size_t *poffResume)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** @todo Detect BEGIN / END mismatch. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (rtCrPemFindMarker(pbContent, cbContent, offStart, "BEGIN", 5, paMarkers, cMarkers,
f6a7a5ea5c6903d1a5632f2febac4e489bd8beddvboxsync if (rtCrPemFindMarker(pbContent, cbContent, *poffBegin, "END", 3, pMatch, 1,
f6a7a5ea5c6903d1a5632f2febac4e489bd8beddvboxsync return true;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return false;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Does the decoding of a PEM-like data blob after it has been located.
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.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic int rtCrPemDecodeBase64(uint8_t const *pbContent, size_t cbContent, void **ppvDecoded, size_t *pcbDecoded)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync ssize_t cbDecoded = RTBase64DecodedSizeEx((const char *)pbContent, cbContent, NULL);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int rc = RTBase64DecodeEx((const char *)pbContent, cbContent, pvDecoded, cbDecoded, &cbActual, NULL);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Checks if the content of a file looks to be binary or not.
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.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic bool rtCrPemIsBinaryFile(uint8_t *pbFile, size_t cbFile)
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 while (cbFile-- > 0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ( b >= 0x7f
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync || (b < 32 && b != '\t' && b != '\n' && b != '\r' && b != '\f') )
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Ignore EOT (4), SUB (26) and NUL (0) at the end of the file. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return true;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (b == 0 && cbFile == 0)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return true;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return false;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return true;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncRTDECL(int) RTCrPemFreeSections(PCRTCRPEMSECTION pSectionHead)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PRTCRPEMSECTION pFree = (PRTCRPEMSECTION)pSectionHead;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncRTDECL(int) RTCrPemReadFile(const char *pszFilename, uint32_t fFlags, PCRTCRPEMMARKER paMarkers, size_t cMarkers,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PCRTCRPEMSECTION *ppSectionHead, PRTERRINFO pErrInfo)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int rc = RTFileReadAllEx(pszFilename, 0, 64U*_1M, RTFILE_RDALL_O_DENY_WRITE, (void **)&pbContent, &cbContent);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PRTCRPEMSECTION pSection = (PRTCRPEMSECTION)RTMemAllocZ(sizeof(*pSection));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Try locate the first section.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && rtCrPemFindMarkerSection(pbContent, cbContent, 0 /*offStart*/, paMarkers, cMarkers,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->pNext = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->pbData = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->cbData = 0;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->pszPreamble = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->cchPreamble = 0;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Decode the section. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** @todo copy the preamble as well. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = rtCrPemDecodeBase64(pbContent + offBegin, offEnd - offBegin,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* More sections? */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync || !rtCrPemFindMarkerSection(pbContent, cbContent, offResume, paMarkers, cMarkers,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync break; /* No. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* Ok, allocate a new record for it. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pSection = (PRTCRPEMSECTION)RTMemAllocZ(sizeof(*pSection));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * No PEM section found. Return the whole file as one binary section.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->pNext = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->pMarker = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->pszPreamble = NULL;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync //pSection->cchPreamble = 0;