diff options
author | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2020-05-06 15:31:33 +0000 |
---|---|---|
committer | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2020-05-06 15:31:33 +0000 |
commit | 6714f5189add13a59b9156643852579b29150c7e (patch) | |
tree | 72a98ee8fe58e0072701379fc7a9aeae2fd3e5ba /src | |
parent | 4426157eec2b0d6af24c41b9810b2adabb6e0a0a (diff) | |
download | VirtualBox-svn-6714f5189add13a59b9156643852579b29150c7e.tar.gz |
IPRT: PEM writer functions. bugref:9699
git-svn-id: https://www.virtualbox.org/svn/vbox/trunk@84163 cfe28804-0f27-0410-a406-dd0f0b0b656f
Diffstat (limited to 'src')
-rw-r--r-- | src/VBox/Runtime/Makefile.kmk | 6 | ||||
-rw-r--r-- | src/VBox/Runtime/common/crypto/pemfile-read.cpp (renamed from src/VBox/Runtime/common/crypto/pemfile.cpp) | 3 | ||||
-rw-r--r-- | src/VBox/Runtime/common/crypto/pemfile-write.cpp | 234 | ||||
-rw-r--r-- | src/VBox/Runtime/common/vfs/vfsprintf.cpp | 74 |
4 files changed, 280 insertions, 37 deletions
diff --git a/src/VBox/Runtime/Makefile.kmk b/src/VBox/Runtime/Makefile.kmk index 225ff337962..fcd6ef2a16c 100644 --- a/src/VBox/Runtime/Makefile.kmk +++ b/src/VBox/Runtime/Makefile.kmk @@ -392,7 +392,8 @@ RuntimeR3_SOURCES = \ common/crypto/rsa-core.cpp \ common/crypto/rsa-init.cpp \ common/crypto/rsa-sanity.cpp \ - common/crypto/pemfile.cpp \ + common/crypto/pemfile-read.cpp \ + common/crypto/pemfile-write.cpp \ common/crypto/pkcs7-asn1-decoder.cpp \ common/crypto/pkcs7-core.cpp \ common/crypto/pkcs7-init.cpp \ @@ -1681,7 +1682,8 @@ RuntimeBldProg_SOURCES = \ common/checksum/sha256str.cpp \ common/checksum/sha512str.cpp \ common/crypto/digest-core.cpp \ - common/crypto/pemfile.cpp \ + common/crypto/pemfile-read.cpp \ + common/crypto/pemfile-write.cpp \ common/crypto/pkcs7-asn1-decoder.cpp \ common/crypto/pkcs7-core.cpp \ common/crypto/pkcs7-init.cpp \ diff --git a/src/VBox/Runtime/common/crypto/pemfile.cpp b/src/VBox/Runtime/common/crypto/pemfile-read.cpp index 92c6e1ccdf5..675123b5087 100644 --- a/src/VBox/Runtime/common/crypto/pemfile.cpp +++ b/src/VBox/Runtime/common/crypto/pemfile-read.cpp @@ -1,6 +1,6 @@ /* $Id$ */ /** @file - * IPRT - Crypto - PEM file reader / writer. + * IPRT - Crypto - PEM file reader. * * See RFC-1341 for the original ideas for the format, but keep in mind * that the format was hijacked and put to different uses. We're aiming at @@ -650,3 +650,4 @@ RTDECL(const char *) RTCrPemFindFirstSectionInContent(void const *pvContent, siz return (const char *)pvContent + offBegin; return NULL; } + diff --git a/src/VBox/Runtime/common/crypto/pemfile-write.cpp b/src/VBox/Runtime/common/crypto/pemfile-write.cpp new file mode 100644 index 00000000000..fb9fa2bac2c --- /dev/null +++ b/src/VBox/Runtime/common/crypto/pemfile-write.cpp @@ -0,0 +1,234 @@ +/* $Id$ */ +/** @file + * IPRT - Crypto - PEM file writer. + */ + +/* + * Copyright (C) 2006-2020 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "internal/iprt.h" +#include <iprt/crypto/pem.h> + +#include <iprt/asn1.h> +#include <iprt/base64.h> +#include <iprt/err.h> +#include <iprt/string.h> +#include <iprt/vfs.h> + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** + * Used by rtCrPemWriteAsn1Callback to buffer data before outputting it as + * BASE64. + * + * An encoded line is 64 characters long plus a newline, covering 48 bytes + * of binary data. We want about 4KB of output: + * 4096 / 65 = 63.015384615384615384615384615385 + * 64 * 65 + 1 = 4161 (0x1041) + */ +typedef struct PEMOUTPUTASN1 +{ + size_t cbPending; + PFNRTSTROUTPUT pfnOutput; + void *pvUser; + size_t cchRet; + uint8_t abBlock[0x0c00]; + char szBlock[0x1060]; +} PEMOUTPUTASN1; +typedef PEMOUTPUTASN1 *PPEMOUTPUTASN1; + + + +RTDECL(size_t) RTCrPemWriteBlob(PFNRTSTROUTPUT pfnOutput, void *pvUser, + const void *pvContent, size_t cbContent, const char *pszMarker) +{ + /* + * -----BEGIN XXXXX----- + */ + size_t cchRet = pfnOutput(pvUser, RT_STR_TUPLE("-----BEGIN ")); + size_t const cchMarker = strlen(pszMarker); + cchRet += pfnOutput(pvUser, pszMarker, cchMarker); + cchRet += pfnOutput(pvUser, RT_STR_TUPLE("-----\n")); + + /* + * base64 - in reasonably sized stack blocks. + * An encoded line is 64 characters long plus a newline, covering 48 bytes + * of binary data. We want about 4KB of output: + * 4096 / 65 = 63.015384615384615384615384615385 + * 64 * 65 + 1 = 4161 (0x1041) + */ + const size_t cbMaxBlock = 64 * 48; + while (cbContent > 0) + { + char szBlock[0x1060]; + size_t cbBlock = RT_MIN(cbContent, cbMaxBlock); + size_t cchBlock = 0; + int rc = RTBase64Encode(pvContent, cbBlock, szBlock, sizeof(szBlock), &cchBlock); + AssertRC(rc); + szBlock[cchBlock++] = '\n'; + szBlock[cchBlock] = '\0'; + + cchRet += pfnOutput(pvUser, szBlock, cchBlock); + + pvContent = (uint8_t const *)pvContent + cbBlock; + cbContent -= cbBlock; + } + + /* + * -----END XXXXX----- + */ + cchRet += pfnOutput(pvUser, RT_STR_TUPLE("-----END ")); + cchRet += pfnOutput(pvUser, pszMarker, cchMarker); + cchRet += pfnOutput(pvUser, RT_STR_TUPLE("-----\n")); + + /* termination call */ + cchRet += pfnOutput(pvUser, NULL, 0); + + return cchRet; +} + + +/** @callback_method_impl{FNRTASN1ENCODEWRITER} */ +static DECLCALLBACK(int) rtCrPemWriteAsn1Callback(const void *pvBuf, size_t cbToWrite, void *pvUser, PRTERRINFO pErrInfo) +{ + PPEMOUTPUTASN1 pThis = (PPEMOUTPUTASN1)pvUser; + AssertCompile((sizeof(pThis->abBlock) % 48) == 0); + + while (cbToWrite > 0) + { + size_t offDst = pThis->cbPending; + AssertStmt(offDst <= sizeof(pThis->abBlock), offDst = sizeof(pThis->abBlock)); + size_t cbDst = sizeof(pThis->abBlock) - offDst; + if (cbToWrite < cbDst) + { + /* Buffer not full: Append and return. */ + memcpy(&pThis->abBlock[offDst], pvBuf, cbToWrite); + pThis->cbPending = offDst + cbToWrite; + break; + } + + /* Fill the buffer and flush it: */ + memcpy(&pThis->abBlock[offDst], pvBuf, cbDst); + Assert(offDst + cbDst == sizeof(pThis->abBlock)); + + size_t cchBlock = 0; + int rc = RTBase64Encode(pThis->abBlock, sizeof(pThis->abBlock), pThis->szBlock, sizeof(pThis->szBlock), &cchBlock); + AssertRC(rc); + pThis->szBlock[cchBlock++] = '\n'; + pThis->szBlock[cchBlock] = '\0'; + + pThis->cchRet += pThis->pfnOutput(pThis->pvUser, pThis->szBlock, cchBlock); + pThis->cbPending = 0; + + /* Advance. */ + pvBuf = (uint8_t const *)pvBuf + cbDst; + cbToWrite -= cbDst; + } + + RT_NOREF(pErrInfo); + return VINF_SUCCESS; +} + + +RTDECL(ssize_t) RTCrPemWriteAsn1(PFNRTSTROUTPUT pfnOutput, void *pvUser, PRTASN1CORE pRoot, + uint32_t fFlags, const char *pszMarker, PRTERRINFO pErrInfo) +{ + AssertReturn(!fFlags, VERR_INVALID_FLAGS); + + /* + * Prepare the ASN.1 data for DER encoding. + */ + int rc = RTAsn1EncodePrepare(pRoot, RTASN1ENCODE_F_DER, NULL /*pcbEncoded*/, pErrInfo); + AssertRCReturn(rc, rc); + + /* + * -----BEGIN XXXXX----- + */ + size_t cchRet = pfnOutput(pvUser, RT_STR_TUPLE("-----BEGIN ")); + size_t const cchMarker = strlen(pszMarker); + cchRet += pfnOutput(pvUser, pszMarker, cchMarker); + cchRet += pfnOutput(pvUser, RT_STR_TUPLE("-----\n")); + + /* + * BASE64 + */ + PEMOUTPUTASN1 This; + This.pfnOutput = pfnOutput; + This.pvUser = pvUser; + This.cchRet = 0; + This.cbPending = 0; + rc = RTAsn1EncodeWrite(pRoot, RTASN1ENCODE_F_DER, rtCrPemWriteAsn1Callback, &This, pErrInfo); + AssertRCReturn(rc, rc); + cchRet += This.cchRet; + + Assert(This.cbPending <= sizeof(This.abBlock)); + if (This.cbPending) + { + size_t cchBlock = 0; + rc = RTBase64Encode(This.abBlock, This.cbPending, This.szBlock, sizeof(This.szBlock), &cchBlock); + AssertRC(rc); + This.szBlock[cchBlock++] = '\n'; + This.szBlock[cchBlock] = '\0'; + + cchRet += pfnOutput(pvUser, This.szBlock, cchBlock); + } + + /* + * -----END XXXXX----- + */ + cchRet += pfnOutput(pvUser, RT_STR_TUPLE("-----END ")); + cchRet += pfnOutput(pvUser, pszMarker, cchMarker); + cchRet += pfnOutput(pvUser, RT_STR_TUPLE("-----\n")); + + /* termination call */ + cchRet += pfnOutput(pvUser, NULL, 0); + + return cchRet; +} + + +RTDECL(ssize_t) RTCrPemWriteAsn1ToVfsIoStrm(RTVFSIOSTREAM hVfsIos, PRTASN1CORE pRoot, + uint32_t fFlags, const char *pszMarker, PRTERRINFO pErrInfo) +{ + VFSIOSTRMOUTBUF Buf; + VFSIOSTRMOUTBUF_INIT(&Buf, hVfsIos); + ssize_t cchRet = RTCrPemWriteAsn1(RTVfsIoStrmStrOutputCallback, &Buf, pRoot, fFlags, pszMarker, pErrInfo); + Assert(Buf.offBuf == 0); + return RT_SUCCESS(Buf.rc) ? (ssize_t)cchRet : Buf.rc; +} + + +RTDECL(ssize_t) RTCrPemWriteAsn1ToVfsFile(RTVFSFILE hVfsFile, PRTASN1CORE pRoot, + uint32_t fFlags, const char *pszMarker, PRTERRINFO pErrInfo) +{ + RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hVfsFile); + AssertReturn(hVfsIos != NIL_RTVFSIOSTREAM, VERR_INVALID_HANDLE); + ssize_t cchRet = RTCrPemWriteAsn1ToVfsIoStrm(hVfsIos, pRoot, fFlags, pszMarker, pErrInfo); + RTVfsIoStrmRelease(hVfsIos); + return cchRet; +} + diff --git a/src/VBox/Runtime/common/vfs/vfsprintf.cpp b/src/VBox/Runtime/common/vfs/vfsprintf.cpp index 89527ba66b7..d27a6419740 100644 --- a/src/VBox/Runtime/common/vfs/vfsprintf.cpp +++ b/src/VBox/Runtime/common/vfs/vfsprintf.cpp @@ -34,20 +34,8 @@ #include <iprt/string.h> -/********************************************************************************************************************************* -* Structures and Typedefs * -*********************************************************************************************************************************/ -typedef struct PRINTFBUF -{ - RTVFSIOSTREAM hVfsIos; - int rc; - size_t offBuf; - char szBuf[256]; -} PRINTFBUF; - - /** Writes the buffer to the VFS file. */ -static void FlushPrintfBuffer(PRINTFBUF *pBuf) +static void FlushPrintfBuffer(PVFSIOSTRMOUTBUF pBuf) { if (pBuf->offBuf) { @@ -60,27 +48,49 @@ static void FlushPrintfBuffer(PRINTFBUF *pBuf) } -/** @callback_method_impl{FNRTSTROUTPUT} */ -static DECLCALLBACK(size_t) MyPrintfOutputter(void *pvArg, const char *pachChars, size_t cbChars) +/** + * @callback_method_impl{FNRTSTROUTPUT, + * For use with VFSIOSTRMOUTBUF.} + */ +RTDECL(size_t) RTVfsIoStrmStrOutputCallback(void *pvArg, const char *pachChars, size_t cbChars) { - PRINTFBUF *pBuf = (PRINTFBUF *)pvArg; + PVFSIOSTRMOUTBUF pBuf = (PVFSIOSTRMOUTBUF)pvArg; + AssertReturn(pBuf->cbSelf == sizeof(*pBuf), 0); + if (cbChars != 0) { - size_t offSrc = 0; - while (offSrc < cbChars) + if (cbChars <= sizeof(pBuf->szBuf) * 3 / 2) { - size_t cbLeft = sizeof(pBuf->szBuf) - pBuf->offBuf - 1; - if (cbLeft > 0) + /* + * Small piece of output: Buffer it. + */ + size_t offSrc = 0; + while (offSrc < cbChars) { - size_t cbToCopy = RT_MIN(cbChars - offSrc, cbLeft); - memcpy(&pBuf->szBuf[pBuf->offBuf], &pachChars[offSrc], cbToCopy); - pBuf->offBuf += cbToCopy; - pBuf->szBuf[pBuf->offBuf] = '\0'; - if (cbLeft > cbToCopy) - break; - offSrc += cbToCopy; + size_t cbLeft = sizeof(pBuf->szBuf) - pBuf->offBuf - 1; + if (cbLeft > 0) + { + size_t cbToCopy = RT_MIN(cbChars - offSrc, cbLeft); + memcpy(&pBuf->szBuf[pBuf->offBuf], &pachChars[offSrc], cbToCopy); + pBuf->offBuf += cbToCopy; + pBuf->szBuf[pBuf->offBuf] = '\0'; + if (cbLeft > cbToCopy) + break; + offSrc += cbToCopy; + } + FlushPrintfBuffer(pBuf); } + } + else + { + /* + * Large chunk of output: Output it directly. + */ FlushPrintfBuffer(pBuf); + + int rc = RTVfsIoStrmWrite(pBuf->hVfsIos, pachChars, cbChars, true /*fBlocking*/, NULL); + if (RT_FAILURE(rc)) + pBuf->rc = rc; } } else /* Special zero byte write at the end of the formatting. */ @@ -89,16 +99,12 @@ static DECLCALLBACK(size_t) MyPrintfOutputter(void *pvArg, const char *pachChars } - RTDECL(ssize_t) RTVfsIoStrmPrintfV(RTVFSIOSTREAM hVfsIos, const char *pszFormat, va_list va) { - PRINTFBUF Buf; - Buf.hVfsIos = hVfsIos; - Buf.rc = VINF_SUCCESS; - Buf.offBuf = 0; - Buf.szBuf[0] = '\0'; + VFSIOSTRMOUTBUF Buf; + VFSIOSTRMOUTBUF_INIT(&Buf, hVfsIos); - size_t cchRet = RTStrFormatV(MyPrintfOutputter, &Buf, NULL, NULL, pszFormat, va); + size_t cchRet = RTStrFormatV(RTVfsIoStrmStrOutputCallback, &Buf, NULL, NULL, pszFormat, va); if (RT_SUCCESS(Buf.rc)) return cchRet; return Buf.rc; |