VirtualBox

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

Last change on this file since 53528 was 51770, checked in by vboxsync, 11 years ago

Merged in iprt++ dev branch.

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