summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorvboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f>2020-05-06 15:31:33 +0000
committervboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f>2020-05-06 15:31:33 +0000
commit6714f5189add13a59b9156643852579b29150c7e (patch)
tree72a98ee8fe58e0072701379fc7a9aeae2fd3e5ba /src
parent4426157eec2b0d6af24c41b9810b2adabb6e0a0a (diff)
downloadVirtualBox-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.kmk6
-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.cpp234
-rw-r--r--src/VBox/Runtime/common/vfs/vfsprintf.cpp74
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;