VirtualBox

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

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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