VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/asn1/asn1-ut-octetstring.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.0 KB
Line 
1/* $Id: asn1-ut-octetstring.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - ASN.1, Octet String.
4 *
5 * @remarks This file should remain very similar to asn1-ut-bitstring.cpp.
6 */
7
8/*
9 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
10 *
11 * This file is part of VirtualBox base platform packages, as
12 * available from https://www.virtualbox.org.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation, in version 3 of the
17 * License.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <https://www.gnu.org/licenses>.
26 *
27 * The contents of this file may alternatively be used under the terms
28 * of the Common Development and Distribution License Version 1.0
29 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
30 * in the VirtualBox distribution, in which case the provisions of the
31 * CDDL are applicable instead of those of the GPL.
32 *
33 * You may elect to license modified versions of this file under the
34 * terms and conditions of either the GPL or the CDDL or both.
35 *
36 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
37 */
38
39
40/*********************************************************************************************************************************
41* Header Files *
42*********************************************************************************************************************************/
43#include "internal/iprt.h"
44#include <iprt/asn1.h>
45
46#include <iprt/alloca.h>
47#include <iprt/bignum.h>
48#include <iprt/ctype.h>
49#include <iprt/err.h>
50#include <iprt/string.h>
51#include <iprt/uni.h>
52
53#include <iprt/formats/asn1.h>
54
55
56/*********************************************************************************************************************************
57* Structures and Typedefs *
58*********************************************************************************************************************************/
59typedef struct RTASN1OCTETSTRINGWRITERCTX
60{
61 /** Pointer to the output buffer. */
62 uint8_t *pbBuf;
63 /** The current buffer offset. */
64 uint32_t offBuf;
65 /** The size of the buffer. */
66 uint32_t cbBuf;
67} RTASN1OCTETSTRINGWRITERCTX;
68
69
70/** @callback_method_impl{FNRTASN1ENCODEWRITER,
71 * Used to refresh the content of octet and bit strings. } */
72static DECLCALLBACK(int) rtAsn1OctetStringEncodeWriter(const void *pvBuf, size_t cbToWrite, void *pvUser, PRTERRINFO pErrInfo)
73{
74 RTASN1OCTETSTRINGWRITERCTX *pCtx = (RTASN1OCTETSTRINGWRITERCTX *)pvUser;
75 AssertReturn(cbToWrite <= pCtx->cbBuf - pCtx->offBuf,
76 RTErrInfoSetF(pErrInfo, VERR_BUFFER_OVERFLOW,
77 "cbToWrite=%#x offBuf=%#x cbBuf=%#x", cbToWrite, pCtx->cbBuf, pCtx->offBuf));
78 memcpy(&pCtx->pbBuf[pCtx->offBuf], pvBuf, cbToWrite);
79 pCtx->offBuf += (uint32_t)cbToWrite;
80 return VINF_SUCCESS;
81}
82
83
84/** @callback_method_impl{FNRTASN1ENCODEWRITER,
85 * Used to compare the encoded raw content of an octet or bit string with the
86 * encapsulated object. } */
87static DECLCALLBACK(int) rtAsn1OctetStringEncodeCompare(const void *pvBuf, size_t cbToWrite, void *pvUser, PRTERRINFO pErrInfo)
88{
89 RTASN1OCTETSTRINGWRITERCTX *pCtx = (RTASN1OCTETSTRINGWRITERCTX *)pvUser;
90 RT_NOREF_PV(pErrInfo);
91 AssertReturn(cbToWrite <= pCtx->cbBuf - pCtx->offBuf, VERR_BUFFER_OVERFLOW);
92 if (memcmp(&pCtx->pbBuf[pCtx->offBuf], pvBuf, cbToWrite) != 0)
93 return VERR_NOT_EQUAL;
94 pCtx->offBuf += (uint32_t)cbToWrite;
95 return VINF_SUCCESS;
96}
97
98
99/*
100 * ASN.1 OCTET STRING - Specific Methods
101 */
102
103RTDECL(int) RTAsn1OctetString_RefreshContent(PRTASN1OCTETSTRING pThis, uint32_t fFlags,
104 PCRTASN1ALLOCATORVTABLE pAllocator, PRTERRINFO pErrInfo)
105{
106 AssertReturn(pThis->pEncapsulated, VERR_INVALID_STATE);
107
108 uint32_t cbEncoded;
109 int rc = RTAsn1EncodePrepare(pThis->pEncapsulated, fFlags, &cbEncoded, pErrInfo);
110 if (RT_SUCCESS(rc))
111 {
112 pThis->Asn1Core.cb = cbEncoded;
113
114 rc = RTAsn1ContentReallocZ(&pThis->Asn1Core, cbEncoded, pAllocator);
115 if (RT_SUCCESS(rc))
116 {
117 /* Initialize the writer context. */
118 RTASN1OCTETSTRINGWRITERCTX Ctx;
119 Ctx.pbBuf = (uint8_t *)pThis->Asn1Core.uData.pu8;
120 Ctx.cbBuf = cbEncoded;
121 Ctx.offBuf = 0;
122
123 rc = RTAsn1EncodeWrite(pThis->pEncapsulated, fFlags, rtAsn1OctetStringEncodeWriter, &Ctx, pErrInfo);
124 if (RT_SUCCESS(rc))
125 {
126 if (Ctx.offBuf == cbEncoded)
127 return VINF_SUCCESS;
128
129 rc = RTErrInfoSetF(pErrInfo, rc, "Expected %#x bytes, got %#x", cbEncoded, Ctx.offBuf);
130 }
131 }
132 else
133 rc = RTErrInfoSetF(pErrInfo, rc, "Error allocating %#x bytes for storing content\n", cbEncoded);
134 }
135 return rc;
136}
137
138
139RTDECL(int) RTAsn1OctetString_AllocContent(PRTASN1OCTETSTRING pThis, void const *pvSrc, size_t cb,
140 PCRTASN1ALLOCATORVTABLE pAllocator)
141{
142 AssertReturn(!pThis->pEncapsulated, VERR_INVALID_STATE);
143 int rc;
144 if (pvSrc)
145 rc = RTAsn1ContentDup(&pThis->Asn1Core, pvSrc, cb, pAllocator);
146 else
147 rc = RTAsn1ContentAllocZ(&pThis->Asn1Core, cb, pAllocator);
148 return rc;
149}
150
151
152RTDECL(int) RTAsn1OctetString_SetContent(PRTASN1OCTETSTRING pThis, void const *pvSrc, size_t cbSrc,
153 PCRTASN1ALLOCATORVTABLE pAllocator)
154{
155 AssertPtrReturn(pvSrc, VERR_INVALID_POINTER);
156 return RTAsn1OctetString_AllocContent(pThis, pvSrc, cbSrc, pAllocator);
157}
158
159
160RTDECL(bool) RTAsn1OctetString_AreContentBytesValid(PCRTASN1OCTETSTRING pThis, uint32_t fFlags)
161{
162 if (pThis->pEncapsulated)
163 {
164 /* Check the encoded length of the octets. */
165 uint32_t cbEncoded;
166 int rc = RTAsn1EncodePrepare(pThis->pEncapsulated, fFlags, &cbEncoded, NULL);
167 if (RT_FAILURE(rc))
168 return false;
169 if (pThis->Asn1Core.cb != cbEncoded)
170 return false;
171
172 /* Check the encoded bytes, if there are any. */
173 if (cbEncoded)
174 {
175 if (!pThis->Asn1Core.uData.pv)
176 return false;
177
178 /* Check the other bytes. */
179 RTASN1OCTETSTRINGWRITERCTX Ctx;
180 Ctx.pbBuf = (uint8_t *)pThis->Asn1Core.uData.pu8;
181 Ctx.cbBuf = cbEncoded;
182 Ctx.offBuf = 0;
183 rc = RTAsn1EncodeWrite(pThis->pEncapsulated, fFlags, rtAsn1OctetStringEncodeCompare, &Ctx, NULL);
184 if (RT_FAILURE(rc))
185 return false;
186 }
187 }
188 return true;
189}
190
191
192/*
193 * ASN.1 OCTET STRING - Standard Methods.
194 */
195
196/** @interface_method_impl{FNRTASN1COREVTENCODEPREP} */
197static DECLCALLBACK(int) RTAsn1OctetString_EncodePrep(PRTASN1CORE pThisCore, uint32_t fFlags, PRTERRINFO pErrInfo)
198{
199 PRTASN1OCTETSTRING pThis = (PRTASN1OCTETSTRING)pThisCore;
200 if (!pThis->pEncapsulated)
201 {
202 Assert(pThis->Asn1Core.cb == 0 || pThis->Asn1Core.uData.pv);
203 return VINF_SUCCESS;
204 }
205
206 /* Figure out the size of the encapsulated content. */
207 uint32_t cbEncoded;
208 int rc = RTAsn1EncodePrepare(pThis->pEncapsulated, fFlags, &cbEncoded, pErrInfo);
209 if (RT_SUCCESS(rc))
210 {
211 /* Free the bytes if they don't match up. */
212 if (pThis->Asn1Core.uData.pv)
213 {
214 bool fMustFree = pThis->Asn1Core.cb != cbEncoded;
215 if (!fMustFree)
216 {
217 RTASN1OCTETSTRINGWRITERCTX Ctx;
218 Ctx.pbBuf = (uint8_t *)pThis->Asn1Core.uData.pu8;
219 Ctx.cbBuf = cbEncoded;
220 Ctx.offBuf = 0;
221 rc = RTAsn1EncodeWrite(pThis->pEncapsulated, fFlags, rtAsn1OctetStringEncodeCompare, &Ctx, NULL);
222 fMustFree = RT_FAILURE_NP(rc);
223 }
224 if (fMustFree)
225 RTAsn1ContentFree(&pThis->Asn1Core);
226 }
227
228 pThis->Asn1Core.cb = cbEncoded;
229 rc = RTAsn1EncodeRecalcHdrSize(&pThis->Asn1Core, fFlags, pErrInfo);
230 }
231 return rc;
232}
233
234
235/** @interface_method_impl{FNRTASN1COREVTENCODEWRITE} */
236static DECLCALLBACK(int) RTAsn1OctetString_EncodeWrite(PRTASN1CORE pThisCore, uint32_t fFlags, PFNRTASN1ENCODEWRITER pfnWriter,
237 void *pvUser, PRTERRINFO pErrInfo)
238{
239 PRTASN1OCTETSTRING pThis = (PRTASN1OCTETSTRING)pThisCore;
240
241 /*
242 * First the header.
243 */
244 int rc = RTAsn1EncodeWriteHeader(&pThis->Asn1Core, fFlags, pfnWriter, pvUser, pErrInfo);
245 if (RT_SUCCESS(rc) && rc != VINF_ASN1_NOT_ENCODED)
246 {
247 /*
248 * If nothing is encapsulated, the core points to the content (if we have any).
249 */
250 if (!pThis->pEncapsulated)
251 {
252 if (pThis->Asn1Core.cb > 0)
253 rc = pfnWriter(pThis->Asn1Core.uData.pu8, pThis->Asn1Core.cb, pvUser, pErrInfo);
254 }
255 /*
256 * Call upon the encapsulated content to serialize itself.
257 */
258 else
259 rc = RTAsn1EncodeWrite(pThis->pEncapsulated, fFlags, pfnWriter, pvUser, pErrInfo);
260 }
261 return rc;
262}
263
264
265RT_DECL_DATA_CONST(RTASN1COREVTABLE const) g_RTAsn1OctetString_Vtable =
266{
267 "OctetString",
268 sizeof(RTASN1OCTETSTRING),
269 ASN1_TAG_OCTET_STRING,
270 ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_PRIMITIVE,
271 0,
272 (PFNRTASN1COREVTDTOR)RTAsn1OctetString_Delete,
273 (PFNRTASN1COREVTENUM)RTAsn1OctetString_Enum,
274 (PFNRTASN1COREVTCLONE)RTAsn1OctetString_Clone,
275 (PFNRTASN1COREVTCOMPARE)RTAsn1OctetString_Compare,
276 (PFNRTASN1COREVTCHECKSANITY)RTAsn1OctetString_CheckSanity,
277 RTAsn1OctetString_EncodePrep,
278 RTAsn1OctetString_EncodeWrite
279};
280
281
282RTDECL(int) RTAsn1OctetString_Init(PRTASN1OCTETSTRING pThis, PCRTASN1ALLOCATORVTABLE pAllocator)
283{
284 RT_ZERO(*pThis);
285
286 RTAsn1Core_InitEx(&pThis->Asn1Core, ASN1_TAG_OCTET_STRING, ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_PRIMITIVE,
287 &g_RTAsn1OctetString_Vtable, RTASN1CORE_F_PRESENT | RTASN1CORE_F_PRIMITE_TAG_STRUCT);
288 /*pThis->pEncapsulated = NULL;*/
289 RTAsn1MemInitAllocation(&pThis->EncapsulatedAllocation, pAllocator);
290
291 return VINF_SUCCESS;
292}
293
294
295RTDECL(int) RTAsn1OctetString_Clone(PRTASN1OCTETSTRING pThis, PCRTASN1OCTETSTRING pSrc, PCRTASN1ALLOCATORVTABLE pAllocator)
296{
297 AssertPtr(pSrc); AssertPtr(pThis); AssertPtr(pAllocator);
298
299 RT_ZERO(*pThis);
300 if (RTAsn1OctetString_IsPresent(pSrc))
301 {
302 AssertReturn(pSrc->Asn1Core.pOps == &g_RTAsn1OctetString_Vtable, VERR_INTERNAL_ERROR_3);
303
304 int rc;
305 if (!pSrc->pEncapsulated)
306 rc = RTAsn1Core_CloneContent(&pThis->Asn1Core, &pSrc->Asn1Core, pAllocator);
307 else
308 rc = RTAsn1Core_CloneNoContent(&pThis->Asn1Core, &pSrc->Asn1Core);
309 if (RT_FAILURE(rc))
310 return rc;
311
312 RTAsn1MemInitAllocation(&pThis->EncapsulatedAllocation, pAllocator);
313 if (pSrc->pEncapsulated)
314 {
315 PCRTASN1COREVTABLE pOps = pSrc->pEncapsulated->pOps;
316 Assert(!pOps || pOps->pfnClone);
317 if (pOps && pOps->pfnClone)
318 {
319 /* We can clone the decoded encapsulated object. */
320 rc = RTAsn1MemAllocZ(&pThis->EncapsulatedAllocation, (void **)&pThis->pEncapsulated, pOps->cbStruct);
321 if (RT_SUCCESS(rc))
322 {
323 rc = pOps->pfnClone(pThis->pEncapsulated, pSrc->pEncapsulated, pAllocator);
324 if (RT_FAILURE(rc))
325 RTAsn1MemFree(&pThis->EncapsulatedAllocation, pThis->pEncapsulated);
326 }
327 }
328 else
329 {
330 /* Borrow the encapsulated pointer and use RTAsn1OctetString_RefreshContent
331 to get an accurate copy of the bytes. */
332 pThis->pEncapsulated = pSrc->pEncapsulated;
333 rc = RTAsn1OctetString_RefreshContent(pThis, RTASN1ENCODE_F_DER, pAllocator, NULL);
334 pThis->pEncapsulated = NULL;
335 }
336 if (RT_FAILURE(rc))
337 {
338 RTAsn1ContentFree(&pThis->Asn1Core);
339 RT_ZERO(*pThis);
340 return rc;
341 }
342 }
343 }
344 return VINF_SUCCESS;
345}
346
347
348RTDECL(void) RTAsn1OctetString_Delete(PRTASN1OCTETSTRING pThis)
349{
350 if ( pThis
351 && RTAsn1OctetString_IsPresent(pThis))
352 {
353 Assert(pThis->Asn1Core.pOps == &g_RTAsn1OctetString_Vtable);
354
355 /* Destroy the encapsulated object. */
356 if (pThis->pEncapsulated)
357 {
358 RTAsn1VtDelete(pThis->pEncapsulated);
359 if (pThis->EncapsulatedAllocation.cbAllocated)
360 RTAsn1MemFree(&pThis->EncapsulatedAllocation, pThis->pEncapsulated);
361 }
362
363 /* Delete content and wipe the content. */
364 RTAsn1ContentFree(&pThis->Asn1Core);
365 RT_ZERO(*pThis);
366 }
367}
368
369
370RTDECL(int) RTAsn1OctetString_Enum(PRTASN1OCTETSTRING pThis, PFNRTASN1ENUMCALLBACK pfnCallback, uint32_t uDepth, void *pvUser)
371{
372 Assert(pThis && (!RTAsn1OctetString_IsPresent(pThis) || pThis->Asn1Core.pOps == &g_RTAsn1OctetString_Vtable));
373
374 /* Enumerate the encapsulated object if present. */
375 if (pThis->pEncapsulated)
376 return pfnCallback(pThis->pEncapsulated, "Encapsulated", uDepth + 1, pvUser);
377 return VINF_SUCCESS;
378}
379
380
381RTDECL(int) RTAsn1OctetString_Compare(PCRTASN1OCTETSTRING pLeft, PCRTASN1OCTETSTRING pRight)
382{
383 Assert(pLeft && (!RTAsn1OctetString_IsPresent(pLeft) || pLeft->Asn1Core.pOps == &g_RTAsn1OctetString_Vtable));
384 Assert(pRight && (!RTAsn1OctetString_IsPresent(pRight) || pRight->Asn1Core.pOps == &g_RTAsn1OctetString_Vtable));
385
386 int iDiff;
387 if (RTAsn1OctetString_IsPresent(pLeft))
388 {
389 if (RTAsn1OctetString_IsPresent(pRight))
390 {
391 /* Since it's really hard to tell whether encapsulated objects have
392 been modified or not, we might have to refresh both objects
393 while doing this compare. We'll try our best to avoid it though. */
394 if (pLeft->pEncapsulated || pRight->pEncapsulated)
395 {
396 if ( pLeft->pEncapsulated
397 && pRight->pEncapsulated
398 && pLeft->pEncapsulated->pOps == pRight->pEncapsulated->pOps)
399 iDiff = pLeft->pEncapsulated->pOps->pfnCompare(pLeft->pEncapsulated, pRight->pEncapsulated);
400 else
401 {
402 /* No direct comparison of encapsulated objects possible,
403 make sure we've got the rigth bytes then. */
404 if ( pLeft->pEncapsulated
405 && !RTAsn1OctetString_AreContentBytesValid(pLeft, RTASN1ENCODE_F_DER))
406 {
407 int rc = RTAsn1OctetString_RefreshContent((PRTASN1OCTETSTRING)pLeft, RTASN1ENCODE_F_DER,
408 pLeft->EncapsulatedAllocation.pAllocator, NULL);
409 AssertRC(rc);
410 }
411
412 if ( pRight->pEncapsulated
413 && !RTAsn1OctetString_AreContentBytesValid(pRight, RTASN1ENCODE_F_DER))
414 {
415 int rc = RTAsn1OctetString_RefreshContent((PRTASN1OCTETSTRING)pRight, RTASN1ENCODE_F_DER,
416 pRight->EncapsulatedAllocation.pAllocator, NULL);
417 AssertRC(rc);
418 }
419
420 /* Compare the content bytes. */
421 iDiff = RTAsn1Core_CompareEx(&pLeft->Asn1Core, &pRight->Asn1Core, true /*fIgnoreTagAndClass*/);
422 }
423 }
424 /*
425 * No encapsulated object, just compare the raw content bytes.
426 */
427 else
428 iDiff = RTAsn1Core_CompareEx(&pLeft->Asn1Core, &pRight->Asn1Core, true /*fIgnoreTagAndClass*/);
429 }
430 else
431 iDiff = -1;
432 }
433 else
434 iDiff = 0 - (int)RTAsn1OctetString_IsPresent(pRight);
435 return iDiff;
436}
437
438
439RTDECL(int) RTAsn1OctetString_CheckSanity(PCRTASN1OCTETSTRING pThis, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag)
440{
441 if (RT_UNLIKELY(!RTAsn1OctetString_IsPresent(pThis)))
442 return RTErrInfoSetF(pErrInfo, VERR_ASN1_NOT_PRESENT, "%s: Missing (OCTET STRING).", pszErrorTag);
443
444 if (pThis->pEncapsulated)
445 return pThis->pEncapsulated->pOps->pfnCheckSanity(pThis->pEncapsulated, fFlags & RTASN1_CHECK_SANITY_F_COMMON_MASK,
446 pErrInfo, pszErrorTag);
447 return VINF_SUCCESS;
448}
449
450
451/*
452 * Generate code for the associated collection types.
453 */
454#define RTASN1TMPL_TEMPLATE_FILE "../common/asn1/asn1-ut-octetstring-template.h"
455#include <iprt/asn1-generator-internal-header.h>
456#include <iprt/asn1-generator-core.h>
457#include <iprt/asn1-generator-init.h>
458#include <iprt/asn1-generator-sanity.h>
459
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use