VirtualBox

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

Last change on this file since 83743 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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