VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/crypto/pemfile-write.cpp@ 84204

Last change on this file since 84204 was 84168, checked in by vboxsync, 5 years ago

IPRT: PEM writer functions. [build fix] bugref:9699

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.1 KB
Line 
1/* $Id: pemfile-write.cpp 84168 2020-05-06 15:38:07Z vboxsync $ */
2/** @file
3 * IPRT - Crypto - PEM file writer.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "internal/iprt.h"
32#include <iprt/crypto/pem.h>
33
34#include <iprt/asn1.h>
35#include <iprt/base64.h>
36#include <iprt/errcore.h>
37#include <iprt/string.h>
38#include <iprt/vfs.h>
39
40
41/*********************************************************************************************************************************
42* Structures and Typedefs *
43*********************************************************************************************************************************/
44/**
45 * Used by rtCrPemWriteAsn1Callback to buffer data before outputting it as
46 * BASE64.
47 *
48 * An encoded line is 64 characters long plus a newline, covering 48 bytes
49 * of binary data. We want about 4KB of output:
50 * 4096 / 65 = 63.015384615384615384615384615385
51 * 64 * 65 + 1 = 4161 (0x1041)
52 */
53typedef struct PEMOUTPUTASN1
54{
55 size_t cbPending;
56 PFNRTSTROUTPUT pfnOutput;
57 void *pvUser;
58 size_t cchRet;
59 uint8_t abBlock[0x0c00];
60 char szBlock[0x1060];
61} PEMOUTPUTASN1;
62typedef PEMOUTPUTASN1 *PPEMOUTPUTASN1;
63
64
65
66RTDECL(size_t) RTCrPemWriteBlob(PFNRTSTROUTPUT pfnOutput, void *pvUser,
67 const void *pvContent, size_t cbContent, const char *pszMarker)
68{
69 /*
70 * -----BEGIN XXXXX-----
71 */
72 size_t cchRet = pfnOutput(pvUser, RT_STR_TUPLE("-----BEGIN "));
73 size_t const cchMarker = strlen(pszMarker);
74 cchRet += pfnOutput(pvUser, pszMarker, cchMarker);
75 cchRet += pfnOutput(pvUser, RT_STR_TUPLE("-----\n"));
76
77 /*
78 * base64 - in reasonably sized stack blocks.
79 * An encoded line is 64 characters long plus a newline, covering 48 bytes
80 * of binary data. We want about 4KB of output:
81 * 4096 / 65 = 63.015384615384615384615384615385
82 * 64 * 65 + 1 = 4161 (0x1041)
83 */
84 const size_t cbMaxBlock = 64 * 48;
85 while (cbContent > 0)
86 {
87 char szBlock[0x1060];
88 size_t cbBlock = RT_MIN(cbContent, cbMaxBlock);
89 size_t cchBlock = 0;
90 int rc = RTBase64Encode(pvContent, cbBlock, szBlock, sizeof(szBlock), &cchBlock);
91 AssertRC(rc);
92 szBlock[cchBlock++] = '\n';
93 szBlock[cchBlock] = '\0';
94
95 cchRet += pfnOutput(pvUser, szBlock, cchBlock);
96
97 pvContent = (uint8_t const *)pvContent + cbBlock;
98 cbContent -= cbBlock;
99 }
100
101 /*
102 * -----END XXXXX-----
103 */
104 cchRet += pfnOutput(pvUser, RT_STR_TUPLE("-----END "));
105 cchRet += pfnOutput(pvUser, pszMarker, cchMarker);
106 cchRet += pfnOutput(pvUser, RT_STR_TUPLE("-----\n"));
107
108 /* termination call */
109 cchRet += pfnOutput(pvUser, NULL, 0);
110
111 return cchRet;
112}
113
114
115/** @callback_method_impl{FNRTASN1ENCODEWRITER} */
116static DECLCALLBACK(int) rtCrPemWriteAsn1Callback(const void *pvBuf, size_t cbToWrite, void *pvUser, PRTERRINFO pErrInfo)
117{
118 PPEMOUTPUTASN1 pThis = (PPEMOUTPUTASN1)pvUser;
119 AssertCompile((sizeof(pThis->abBlock) % 48) == 0);
120
121 while (cbToWrite > 0)
122 {
123 size_t offDst = pThis->cbPending;
124 AssertStmt(offDst <= sizeof(pThis->abBlock), offDst = sizeof(pThis->abBlock));
125 size_t cbDst = sizeof(pThis->abBlock) - offDst;
126 if (cbToWrite < cbDst)
127 {
128 /* Buffer not full: Append and return. */
129 memcpy(&pThis->abBlock[offDst], pvBuf, cbToWrite);
130 pThis->cbPending = offDst + cbToWrite;
131 break;
132 }
133
134 /* Fill the buffer and flush it: */
135 memcpy(&pThis->abBlock[offDst], pvBuf, cbDst);
136 Assert(offDst + cbDst == sizeof(pThis->abBlock));
137
138 size_t cchBlock = 0;
139 int rc = RTBase64Encode(pThis->abBlock, sizeof(pThis->abBlock), pThis->szBlock, sizeof(pThis->szBlock), &cchBlock);
140 AssertRC(rc);
141 pThis->szBlock[cchBlock++] = '\n';
142 pThis->szBlock[cchBlock] = '\0';
143
144 pThis->cchRet += pThis->pfnOutput(pThis->pvUser, pThis->szBlock, cchBlock);
145 pThis->cbPending = 0;
146
147 /* Advance. */
148 pvBuf = (uint8_t const *)pvBuf + cbDst;
149 cbToWrite -= cbDst;
150 }
151
152 RT_NOREF(pErrInfo);
153 return VINF_SUCCESS;
154}
155
156
157RTDECL(ssize_t) RTCrPemWriteAsn1(PFNRTSTROUTPUT pfnOutput, void *pvUser, PRTASN1CORE pRoot,
158 uint32_t fFlags, const char *pszMarker, PRTERRINFO pErrInfo)
159{
160 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
161
162 /*
163 * Prepare the ASN.1 data for DER encoding.
164 */
165 int rc = RTAsn1EncodePrepare(pRoot, RTASN1ENCODE_F_DER, NULL /*pcbEncoded*/, pErrInfo);
166 AssertRCReturn(rc, rc);
167
168 /*
169 * -----BEGIN XXXXX-----
170 */
171 size_t cchRet = pfnOutput(pvUser, RT_STR_TUPLE("-----BEGIN "));
172 size_t const cchMarker = strlen(pszMarker);
173 cchRet += pfnOutput(pvUser, pszMarker, cchMarker);
174 cchRet += pfnOutput(pvUser, RT_STR_TUPLE("-----\n"));
175
176 /*
177 * BASE64
178 */
179 PEMOUTPUTASN1 This;
180 This.pfnOutput = pfnOutput;
181 This.pvUser = pvUser;
182 This.cchRet = 0;
183 This.cbPending = 0;
184 rc = RTAsn1EncodeWrite(pRoot, RTASN1ENCODE_F_DER, rtCrPemWriteAsn1Callback, &This, pErrInfo);
185 AssertRCReturn(rc, rc);
186 cchRet += This.cchRet;
187
188 Assert(This.cbPending <= sizeof(This.abBlock));
189 if (This.cbPending)
190 {
191 size_t cchBlock = 0;
192 rc = RTBase64Encode(This.abBlock, This.cbPending, This.szBlock, sizeof(This.szBlock), &cchBlock);
193 AssertRC(rc);
194 This.szBlock[cchBlock++] = '\n';
195 This.szBlock[cchBlock] = '\0';
196
197 cchRet += pfnOutput(pvUser, This.szBlock, cchBlock);
198 }
199
200 /*
201 * -----END XXXXX-----
202 */
203 cchRet += pfnOutput(pvUser, RT_STR_TUPLE("-----END "));
204 cchRet += pfnOutput(pvUser, pszMarker, cchMarker);
205 cchRet += pfnOutput(pvUser, RT_STR_TUPLE("-----\n"));
206
207 /* termination call */
208 cchRet += pfnOutput(pvUser, NULL, 0);
209
210 return cchRet;
211}
212
213
214RTDECL(ssize_t) RTCrPemWriteAsn1ToVfsIoStrm(RTVFSIOSTREAM hVfsIos, PRTASN1CORE pRoot,
215 uint32_t fFlags, const char *pszMarker, PRTERRINFO pErrInfo)
216{
217 VFSIOSTRMOUTBUF Buf;
218 VFSIOSTRMOUTBUF_INIT(&Buf, hVfsIos);
219 ssize_t cchRet = RTCrPemWriteAsn1(RTVfsIoStrmStrOutputCallback, &Buf, pRoot, fFlags, pszMarker, pErrInfo);
220 Assert(Buf.offBuf == 0);
221 return RT_SUCCESS(Buf.rc) ? (ssize_t)cchRet : Buf.rc;
222}
223
224
225RTDECL(ssize_t) RTCrPemWriteAsn1ToVfsFile(RTVFSFILE hVfsFile, PRTASN1CORE pRoot,
226 uint32_t fFlags, const char *pszMarker, PRTERRINFO pErrInfo)
227{
228 RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hVfsFile);
229 AssertReturn(hVfsIos != NIL_RTVFSIOSTREAM, VERR_INVALID_HANDLE);
230 ssize_t cchRet = RTCrPemWriteAsn1ToVfsIoStrm(hVfsIos, pRoot, fFlags, pszMarker, pErrInfo);
231 RTVfsIoStrmRelease(hVfsIos);
232 return cchRet;
233}
234
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette