From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- src/VBox/Runtime/common/crypto/pemfile-write.cpp | 266 +++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 src/VBox/Runtime/common/crypto/pemfile-write.cpp (limited to 'src/VBox/Runtime/common/crypto/pemfile-write.cpp') 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 00000000..c37b653e --- /dev/null +++ b/src/VBox/Runtime/common/crypto/pemfile-write.cpp @@ -0,0 +1,266 @@ +/* $Id: pemfile-write.cpp $ */ +/** @file + * IPRT - Crypto - PEM file writer. + */ + +/* + * Copyright (C) 2006-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox 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. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "internal/iprt.h" +#include + +#include +#include +#include +#include +#include + + +/********************************************************************************************************************************* +* 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 = RTBase64EncodeEx(pvContent, cbBlock, RTBASE64_FLAGS_EOL_LF, + 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; +} + + +RTDECL(ssize_t) RTCrPemWriteBlobToVfsIoStrm(RTVFSIOSTREAM hVfsIos, const void *pvContent, size_t cbContent, const char *pszMarker) +{ + VFSIOSTRMOUTBUF Buf; + VFSIOSTRMOUTBUF_INIT(&Buf, hVfsIos); + size_t cchRet = RTCrPemWriteBlob(RTVfsIoStrmStrOutputCallback, &Buf, pvContent, cbContent, pszMarker); + Assert(Buf.offBuf == 0); + return RT_SUCCESS(Buf.rc) ? (ssize_t)cchRet : Buf.rc; +} + + +RTDECL(ssize_t) RTCrPemWriteBlobToVfsFile(RTVFSFILE hVfsFile, const void *pvContent, size_t cbContent, const char *pszMarker) +{ + RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hVfsFile); + AssertReturn(hVfsIos != NIL_RTVFSIOSTREAM, VERR_INVALID_HANDLE); + ssize_t cchRet = RTCrPemWriteBlobToVfsIoStrm(hVfsIos, pvContent, cbContent, pszMarker); + RTVfsIoStrmRelease(hVfsIos); + 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 = RTBase64EncodeEx(pThis->abBlock, sizeof(pThis->abBlock), RTBASE64_FLAGS_EOL_LF, + 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 = RTBase64EncodeEx(This.abBlock, This.cbPending, RTBASE64_FLAGS_EOL_LF, + 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; +} -- cgit v1.2.3