VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/asn1/asn1-ut-bitstring.cpp@ 56290

Last change on this file since 56290 was 56290, checked in by vboxsync, 10 years ago

IPRT: Updated (C) year.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.4 KB
Line 
1/* $Id: asn1-ut-bitstring.cpp 56290 2015-06-09 14:01:31Z vboxsync $ */
2/** @file
3 * IPRT - ASN.1, Bit String Type.
4 *
5 * @remarks This file should remain very similar to asn1-ut-octetstring.cpp.
6 */
7
8/*
9 * Copyright (C) 2006-2015 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 RTASN1BITSTRINGWRITERCTX
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} RTASN1BITSTRINGWRITERCTX;
57
58
59/** @callback_method_impl{FNRTASN1ENCODEWRITER,
60 * Used to refresh the content of octet and bit strings. } */
61static DECLCALLBACK(int) rtAsn1BitStringEncodeWriter(const void *pvBuf, size_t cbToWrite, void *pvUser, PRTERRINFO pErrInfo)
62{
63 RTASN1BITSTRINGWRITERCTX *pCtx = (RTASN1BITSTRINGWRITERCTX *)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) rtAsn1BitStringEncodeCompare(const void *pvBuf, size_t cbToWrite, void *pvUser, PRTERRINFO pErrInfo)
77{
78 RTASN1BITSTRINGWRITERCTX *pCtx = (RTASN1BITSTRINGWRITERCTX *)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/*
89 * ASN.1 BIT STRING - Special Methods.
90 */
91
92RTDECL(uint64_t) RTAsn1BitString_GetAsUInt64(PCRTASN1BITSTRING pThis)
93{
94 /*
95 * Extract the first 64 bits in host order.
96 */
97 uint8_t const *pb = pThis->uBits.pu8;
98 uint64_t uRet = 0;
99 uint32_t cShift = 0;
100 uint32_t cBits = RT_MIN(pThis->cBits, 64);
101 while (cBits > 0)
102 {
103 uint8_t b = *pb++;
104#if 1 /* We don't have a bit-order constant... */
105 b = ((b & 0x01) << 7)
106 | ((b & 0x02) << 5)
107 | ((b & 0x04) << 3)
108 | ((b & 0x08) << 1)
109 | ((b & 0x10) >> 1)
110 | ((b & 0x20) >> 3)
111 | ((b & 0x40) >> 5)
112 | ((b & 0x80) >> 7);
113#endif
114 if (cBits < 8)
115 {
116 b &= RT_BIT_32(cBits) - 1;
117 uRet |= (uint64_t)b << cShift;
118 break;
119 }
120 uRet |= (uint64_t)b << cShift;
121 cShift += 8;
122 cBits -= 8;
123 }
124
125 return uRet;
126}
127
128
129RTDECL(int) RTAsn1BitString_RefreshContent(PRTASN1BITSTRING pThis, uint32_t fFlags,
130 PCRTASN1ALLOCATORVTABLE pAllocator, PRTERRINFO pErrInfo)
131{
132 AssertReturn(pThis->pEncapsulated, VERR_INVALID_STATE);
133
134 uint32_t cbEncoded;
135 int rc = RTAsn1EncodePrepare(pThis->pEncapsulated, fFlags, &cbEncoded, pErrInfo);
136 if (RT_SUCCESS(rc))
137 {
138 pThis->Asn1Core.cb = 1 + cbEncoded;
139 pThis->cBits = cbEncoded * 8;
140 AssertReturn(pThis->cBits / 8 == cbEncoded, RTErrInfoSetF(pErrInfo, VERR_TOO_MUCH_DATA, "cbEncoded=%#x", cbEncoded));
141
142 rc = RTAsn1ContentReallocZ(&pThis->Asn1Core, cbEncoded + 1, pAllocator);
143 if (RT_SUCCESS(rc))
144 {
145 pThis->uBits.pu8 = pThis->Asn1Core.uData.pu8 + 1;
146
147 /* Initialize the writer context and write the first byte concerning unused bits. */
148 RTASN1BITSTRINGWRITERCTX Ctx;
149 Ctx.pbBuf = (uint8_t *)pThis->Asn1Core.uData.pu8;
150 Ctx.cbBuf = cbEncoded + 1;
151 Ctx.offBuf = 1;
152 *Ctx.pbBuf = 0;
153
154 rc = RTAsn1EncodeWrite(pThis->pEncapsulated, fFlags, rtAsn1BitStringEncodeWriter, &Ctx, pErrInfo);
155 if (RT_SUCCESS(rc))
156 {
157 if (Ctx.offBuf == cbEncoded + 1)
158 return VINF_SUCCESS;
159
160 rc = RTErrInfoSetF(pErrInfo, rc, "Expected %#x + 1 bytes, got %#x", cbEncoded, Ctx.offBuf);
161 }
162 }
163 else
164 rc = RTErrInfoSetF(pErrInfo, rc, "Error allocating %#x + 1 bytes for storing content\n", cbEncoded);
165 }
166 return rc;
167}
168
169
170RTDECL(bool) RTAsn1BitString_AreContentBitsValid(PCRTASN1BITSTRING pThis, uint32_t fFlags)
171{
172 if (pThis->pEncapsulated)
173 {
174 if (pThis->cBits & 7)
175 return false;
176
177 /* Check the encoded length of the bits. */
178 uint32_t cbEncoded;
179 int rc = RTAsn1EncodePrepare(pThis->pEncapsulated, fFlags, &cbEncoded, NULL);
180 if (RT_FAILURE(rc))
181 return false;
182 if (pThis->Asn1Core.cb != 1 + cbEncoded)
183 return false;
184
185 /* Check the encoded bits, if there are any. */
186 if (cbEncoded)
187 {
188 if (!pThis->Asn1Core.uData.pv)
189 return false;
190
191 /* Check the first byte, the unused bit count. */
192 if (*pThis->Asn1Core.uData.pu8 != 0)
193 return false;
194
195 /* Check the other bytes. */
196 RTASN1BITSTRINGWRITERCTX Ctx;
197 Ctx.pbBuf = (uint8_t *)pThis->Asn1Core.uData.pu8;
198 Ctx.cbBuf = cbEncoded + 1;
199 Ctx.offBuf = 1;
200 rc = RTAsn1EncodeWrite(pThis->pEncapsulated, fFlags, rtAsn1BitStringEncodeCompare, &Ctx, NULL);
201 if (RT_FAILURE(rc))
202 return false;
203 }
204 }
205 return true;
206}
207
208
209
210
211/*
212 * ASN.1 BIT STRING - Standard Methods.
213 */
214
215/** @interface_method_impl{FNRTASN1COREVTENCODEPREP} */
216static DECLCALLBACK(int) RTAsn1BitString_EncodePrep(PRTASN1CORE pThisCore, uint32_t fFlags, PRTERRINFO pErrInfo)
217{
218 PRTASN1BITSTRING pThis = (PRTASN1BITSTRING)pThisCore;
219 if (!pThis->pEncapsulated)
220 {
221 Assert(pThis->cBits == 0 || pThis->Asn1Core.uData.pv);
222 return VINF_SUCCESS;
223 }
224
225 /* Figure out the size of the encapsulated content. */
226 uint32_t cbEncoded;
227 int rc = RTAsn1EncodePrepare(pThis->pEncapsulated, fFlags, &cbEncoded, pErrInfo);
228 if (RT_SUCCESS(rc))
229 {
230 /* Free the bytes if they don't match up. */
231 if (pThis->Asn1Core.uData.pv)
232 {
233 bool fMustFree = pThis->Asn1Core.cb != 1 + cbEncoded || (pThis->cBits & 7);
234 if (!fMustFree)
235 {
236 RTASN1BITSTRINGWRITERCTX Ctx;
237 Ctx.pbBuf = (uint8_t *)pThis->Asn1Core.uData.pu8;
238 Ctx.cbBuf = 1 + cbEncoded;
239 Ctx.offBuf = 1;
240 fMustFree = *Ctx.pbBuf != 0;
241 if (!fMustFree)
242 {
243 rc = RTAsn1EncodeWrite(pThis->pEncapsulated, fFlags, rtAsn1BitStringEncodeCompare, &Ctx, NULL);
244 fMustFree = RT_FAILURE_NP(rc);
245 }
246 }
247 if (fMustFree)
248 {
249 pThis->uBits.pv = NULL;
250 RTAsn1ContentFree(&pThis->Asn1Core);
251 }
252 }
253 pThis->Asn1Core.cb = 1 + cbEncoded;
254 pThis->cBits = cbEncoded * 8;
255
256 rc = RTAsn1EncodeRecalcHdrSize(&pThis->Asn1Core, fFlags, pErrInfo);
257 }
258 return rc;
259}
260
261
262/** @interface_method_impl{FNRTASN1COREVTENCODEWRITE} */
263static DECLCALLBACK(int) RTAsn1BitString_EncodeWrite(PRTASN1CORE pThisCore, uint32_t fFlags, PFNRTASN1ENCODEWRITER pfnWriter,
264 void *pvUser, PRTERRINFO pErrInfo)
265{
266 PRTASN1BITSTRING pThis = (PRTASN1BITSTRING)pThisCore;
267
268 AssertReturn(RT_ALIGN(pThis->cBits, 7) / 8 + 1 == pThis->Asn1Core.cb, VERR_INTERNAL_ERROR_3);
269
270 /*
271 * First the header.
272 */
273 int rc = RTAsnEncodeWriteHeader(&pThis->Asn1Core, fFlags, pfnWriter, pvUser, pErrInfo);
274 if (RT_SUCCESS(rc) && rc != VINF_ASN1_NOT_ENCODED)
275 {
276 /*
277 * The content starts with an unused bit count. Calculate it in case we
278 * need to write it out.
279 */
280 uint8_t cUnusedBits = 0;
281 if ((pThis->cBits & 7) != 0)
282 cUnusedBits = 8 - (pThis->cBits & 7);
283
284 /*
285 * If nothing is encapsulated, the core points to the content (if we have any).
286 */
287 if (!pThis->pEncapsulated)
288 {
289 if (pThis->cBits > 0)
290 {
291 Assert(pThis->Asn1Core.uData.pu8[0] == cUnusedBits);
292 rc = pfnWriter(pThis->Asn1Core.uData.pu8, pThis->Asn1Core.cb, pvUser, pErrInfo);
293 }
294 else
295 rc = pfnWriter(&cUnusedBits, sizeof(cUnusedBits), pvUser, pErrInfo);
296 }
297 /*
298 * Write the unused bit count and then call upon the encapsulated
299 * content to serialize itself.
300 */
301 else
302 {
303 rc = pfnWriter(&cUnusedBits, sizeof(cUnusedBits), pvUser, pErrInfo);
304 if (RT_SUCCESS(rc))
305 rc = RTAsn1EncodeWrite(pThis->pEncapsulated, fFlags, pfnWriter, pvUser, pErrInfo);
306 }
307 }
308 return rc;
309}
310
311
312RT_DECL_DATA_CONST(RTASN1COREVTABLE const) g_RTAsn1BitString_Vtable =
313{
314 "RTAsn1BitString",
315 sizeof(RTASN1BITSTRING),
316 ASN1_TAG_BIT_STRING,
317 ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_PRIMITIVE,
318 0,
319 (PFNRTASN1COREVTDTOR)RTAsn1BitString_Delete,
320 (PFNRTASN1COREVTENUM)RTAsn1BitString_Enum,
321 (PFNRTASN1COREVTCLONE)RTAsn1BitString_Clone,
322 (PFNRTASN1COREVTCOMPARE)RTAsn1BitString_Compare,
323 (PFNRTASN1COREVTCHECKSANITY)RTAsn1BitString_CheckSanity,
324 RTAsn1BitString_EncodePrep,
325 RTAsn1BitString_EncodeWrite
326};
327
328
329RTDECL(int) RTAsn1BitString_Init(PRTASN1BITSTRING pThis, PCRTASN1ALLOCATORVTABLE pAllocator)
330{
331 RT_ZERO(*pThis);
332
333 RTAsn1Core_InitEx(&pThis->Asn1Core, ASN1_TAG_BIT_STRING, ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_PRIMITIVE,
334 &g_RTAsn1BitString_Vtable, RTASN1CORE_F_PRESENT | RTASN1CORE_F_PRIMITE_TAG_STRUCT);
335 /*pThis->cBits = 0;
336 pThis->cMaxBits = 0;
337 pThis->uBits.pv = NULL;
338 pThis->pEncapsulated = NULL; */
339 RTAsn1MemInitAllocation(&pThis->EncapsulatedAllocation, pAllocator);
340
341 return VINF_SUCCESS;
342}
343
344
345RTDECL(int) RTAsn1BitString_Clone(PRTASN1BITSTRING pThis, PCRTASN1BITSTRING pSrc, PCRTASN1ALLOCATORVTABLE pAllocator)
346{
347 AssertPtr(pSrc); AssertPtr(pThis); AssertPtr(pAllocator);
348
349 RT_ZERO(*pThis);
350 if (RTAsn1BitString_IsPresent(pSrc))
351 {
352 AssertReturn(pSrc->Asn1Core.pOps == &g_RTAsn1BitString_Vtable, VERR_INTERNAL_ERROR_3);
353
354 int rc;
355 if (!pSrc->pEncapsulated)
356 rc = RTAsn1Core_CloneContent(&pThis->Asn1Core, &pSrc->Asn1Core, pAllocator);
357 else
358 rc = RTAsn1Core_CloneNoContent(&pThis->Asn1Core, &pSrc->Asn1Core);
359 if (RT_FAILURE(rc))
360 return rc;
361
362 RTAsn1MemInitAllocation(&pThis->EncapsulatedAllocation, pAllocator);
363 pThis->cBits = pSrc->cBits;
364 pThis->cMaxBits = pSrc->cMaxBits;
365 if (!pSrc->pEncapsulated)
366 pThis->uBits.pv = pThis->Asn1Core.uData.pu8 ? pThis->Asn1Core.uData.pu8 + 1 : NULL;
367 else
368 {
369 PCRTASN1COREVTABLE pOps = pSrc->pEncapsulated->pOps;
370 Assert(!pOps || pOps->pfnClone);
371 if (pOps && pOps->pfnClone)
372 {
373 /* We can clone the decoded encapsulated object. */
374 rc = RTAsn1MemAllocZ(&pThis->EncapsulatedAllocation, (void **)&pThis->pEncapsulated, pOps->cbStruct);
375 if (RT_SUCCESS(rc))
376 {
377 rc = pOps->pfnClone(pThis->pEncapsulated, pSrc->pEncapsulated, pAllocator);
378 if (RT_FAILURE(rc))
379 RTAsn1MemFree(&pThis->EncapsulatedAllocation, pThis->pEncapsulated);
380 }
381 }
382 else
383 {
384 /* Borrow the encapsulated pointer and use RTAsn1BitString_RefreshContent
385 to get an accurate copy of the bytes. */
386 pThis->pEncapsulated = pSrc->pEncapsulated;
387 rc = RTAsn1BitString_RefreshContent(pThis, RTASN1ENCODE_F_DER, pAllocator, NULL);
388 pThis->pEncapsulated = NULL;
389 }
390 if (RT_FAILURE(rc))
391 {
392 RTAsn1ContentFree(&pThis->Asn1Core);
393 RT_ZERO(*pThis);
394 return rc;
395 }
396 }
397 }
398 return VINF_SUCCESS;
399}
400
401
402RTDECL(void) RTAsn1BitString_Delete(PRTASN1BITSTRING pThis)
403{
404 if ( pThis
405 && RTAsn1BitString_IsPresent(pThis))
406 {
407 Assert(pThis->Asn1Core.pOps == &g_RTAsn1BitString_Vtable);
408
409 /* Destroy the encapsulated object. */
410 if (pThis->pEncapsulated)
411 {
412 RTAsn1VtDelete(pThis->pEncapsulated);
413 if (pThis->EncapsulatedAllocation.cbAllocated)
414 RTAsn1MemFree(&pThis->EncapsulatedAllocation, pThis->pEncapsulated);
415 }
416
417 /* Delete content and wipe the content. */
418 RTAsn1ContentFree(&pThis->Asn1Core);
419 RT_ZERO(*pThis);
420 }
421}
422
423
424RTDECL(int) RTAsn1BitString_Enum(PRTASN1BITSTRING pThis, PFNRTASN1ENUMCALLBACK pfnCallback, uint32_t uDepth, void *pvUser)
425{
426 Assert(pThis && (!RTAsn1BitString_IsPresent(pThis) || pThis->Asn1Core.pOps == &g_RTAsn1BitString_Vtable));
427
428 /* Enumerate the encapsulated object if present. */
429 if (pThis->pEncapsulated)
430 return pfnCallback(pThis->pEncapsulated, "Encapsulated", uDepth + 1, pvUser);
431 return VINF_SUCCESS;
432}
433
434
435RTDECL(int) RTAsn1BitString_Compare(PCRTASN1BITSTRING pLeft, PCRTASN1BITSTRING pRight)
436{
437 Assert(pLeft && (!RTAsn1BitString_IsPresent(pLeft) || pLeft->Asn1Core.pOps == &g_RTAsn1BitString_Vtable));
438 Assert(pRight && (!RTAsn1BitString_IsPresent(pRight) || pRight->Asn1Core.pOps == &g_RTAsn1BitString_Vtable));
439
440 int iDiff;
441 if (RTAsn1BitString_IsPresent(pLeft))
442 {
443 if (RTAsn1BitString_IsPresent(pRight))
444 {
445 /* Since it's really hard to tell whether encapsulated objects have
446 been modified or not, we might have to refresh both objects
447 while doing this compare. We'll try our best to avoid it though. */
448 if (pLeft->pEncapsulated || pRight->pEncapsulated)
449 {
450 if ( pLeft->pEncapsulated
451 && pRight->pEncapsulated
452 && pLeft->pEncapsulated->pOps == pRight->pEncapsulated->pOps)
453 iDiff = pLeft->pEncapsulated->pOps->pfnCompare(pLeft->pEncapsulated, pRight->pEncapsulated);
454 else
455 {
456 /* No direct comparison of encapsulated objects possible,
457 make sure we've got the rigth bytes then. */
458 if ( pLeft->pEncapsulated
459 && !RTAsn1BitString_AreContentBitsValid(pLeft, RTASN1ENCODE_F_DER))
460 {
461 int rc = RTAsn1BitString_RefreshContent((PRTASN1BITSTRING)pLeft, RTASN1ENCODE_F_DER,
462 pLeft->EncapsulatedAllocation.pAllocator, NULL);
463 AssertRC(rc);
464 }
465
466 if ( pRight->pEncapsulated
467 && !RTAsn1BitString_AreContentBitsValid(pRight, RTASN1ENCODE_F_DER))
468 {
469 int rc = RTAsn1BitString_RefreshContent((PRTASN1BITSTRING)pRight, RTASN1ENCODE_F_DER,
470 pRight->EncapsulatedAllocation.pAllocator, NULL);
471 AssertRC(rc);
472 }
473
474 /* Compare the content bytes. */
475 iDiff = RTAsn1Core_CompareEx(&pLeft->Asn1Core, &pRight->Asn1Core, true /*fIgnoreTagAndClass*/);
476 }
477 }
478 /*
479 * No encapsulated object, just compare the raw content bytes.
480 */
481 else
482 iDiff = RTAsn1Core_CompareEx(&pLeft->Asn1Core, &pRight->Asn1Core, true /*fIgnoreTagAndClass*/);
483 }
484 else
485 iDiff = -1;
486 }
487 else
488 iDiff = 0 - (int)RTAsn1BitString_IsPresent(pRight);
489 return iDiff;
490}
491
492
493RTDECL(int) RTAsn1BitString_CheckSanity(PCRTASN1BITSTRING pThis, uint32_t fFlags, PRTERRINFO pErrInfo, const char *pszErrorTag)
494{
495 if (RT_UNLIKELY(!RTAsn1BitString_IsPresent(pThis)))
496 return RTErrInfoSetF(pErrInfo, VERR_ASN1_NOT_PRESENT, "%s: Missing (BIT STRING).", pszErrorTag);
497
498 if (pThis->cBits > pThis->cMaxBits)
499 return RTErrInfoSetF(pErrInfo, VERR_ASN1_BITSTRING_OUT_OF_BOUNDS, "%s: Exceeding max bits: cBits=%u cMaxBits=%u.",
500 pszErrorTag, pThis->cBits, pThis->cMaxBits);
501
502 if (pThis->pEncapsulated)
503 return pThis->pEncapsulated->pOps->pfnCheckSanity(pThis->pEncapsulated, fFlags & RTASN1_CHECK_SANITY_F_COMMON_MASK,
504 pErrInfo, pszErrorTag);
505 return VINF_SUCCESS;
506}
507
508/*
509 * Generate code for the associated collection types.
510 */
511#define RTASN1TMPL_TEMPLATE_FILE "../common/asn1/asn1-ut-bitstring-template.h"
512#include <iprt/asn1-generator-internal-header.h>
513#include <iprt/asn1-generator-core.h>
514#include <iprt/asn1-generator-init.h>
515#include <iprt/asn1-generator-sanity.h>
516
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