VirtualBox

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

Last change on this file since 62477 was 62477, checked in by vboxsync, 8 years ago

(C) 2016

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