13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * IPRT - ASN.1, Encoding.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Copyright (C) 2006-2014 Oracle Corporation
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * available from http://www.virtualbox.org. This file is free software;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * you can redistribute it and/or modify it under the terms of the GNU
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * General Public License (GPL) as published by the Free Software
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * The contents of this file may alternatively be used under the terms
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * of the Common Development and Distribution License Version 1.0
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * VirtualBox OSE distribution, in which case the provisions of the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * CDDL are applicable instead of those of the GPL.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * You may elect to license modified versions of this file under the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * terms and conditions of either the GPL or the CDDL or both.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/*******************************************************************************
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync* Header Files *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync*******************************************************************************/
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/*******************************************************************************
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync* Structures and Typedefs *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync*******************************************************************************/
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Argument package for rtAsn1EncodePrepareCallback passed by RTAsn1EncodePrepare.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** The size at this level. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** RTASN1ENCODE_F_XXX. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** Pointer to the error info. (optional) */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Argument package for rtAsn1EncodeWriteCallback passed by RTAsn1EncodeWrite.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** RTASN1ENCODE_F_XXX. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** Pointer to the writer funtion. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** User argument to the writer function. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** Pointer to the error info. (optional) */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncRTDECL(int) RTAsn1EncodeRecalcHdrSize(PRTASN1CORE pAsn1Core, uint32_t fFlags, PRTERRINFO pErrInfo)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn((fFlags & RTASN1ENCODE_F_RULE_MASK) == RTASN1ENCODE_F_DER, VERR_INVALID_FLAGS);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ((pAsn1Core->fFlags & (RTASN1CORE_F_PRESENT | RTASN1CORE_F_DUMMY | RTASN1CORE_F_DEFAULT)) == RTASN1CORE_F_PRESENT)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * The minimum header size is two bytes.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Add additional bytes for encoding the tag.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn(pAsn1Core->uTag != UINT32_MAX, RTErrInfoSet(pErrInfo, VERR_ASN1_DUMMY_OBJECT, "uTag=UINT32_MAX"));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync } while (uTag > 0);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Add additional bytes for encoding the content length.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn(cb < _1G, RTErrInfoSetF(pErrInfo, VERR_ASN1_TOO_LONG, "cb=%u (%#x)", cb, cb));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Not present, dummy or otherwise not encoded.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Assert(pAsn1Core->pOps && pAsn1Core->pOps->pfnEnum);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Update the header length.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @callback_method_impl{FNRTASN1ENUMCALLBACK}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic DECLCALLBACK(int) rtAsn1EncodePrepareCallback(PRTASN1CORE pAsn1Core, const char *pszName, uint32_t uDepth, void *pvUser)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RTASN1ENCODEPREPARGS *pArgs = (RTASN1ENCODEPREPARGS *)pvUser;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Depth first, where relevant.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Use the encoding preparation method when available.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = pAsn1Core->pOps->pfnEncodePrep(pAsn1Core, pArgs->fFlags, pArgs->pErrInfo);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Recurse to prepare the child objects (if any).
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = pAsn1Core->pOps->pfnEnum(pAsn1Core, rtAsn1EncodePrepareCallback, uDepth + 1, pArgs);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Must be a primitive type if DER.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ( (pAsn1Core->fClass & ASN1_TAGFLAG_CONSTRUCTED)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return RTErrInfoSetF(pArgs->pErrInfo, VERR_ASN1_EXPECTED_PRIMITIVE,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Expected primitive ASN.1 object: uTag=%#x fClass=%#x cb=%u",
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RTASN1CORE_GET_TAG(pAsn1Core), pAsn1Core->fClass, pAsn1Core->cb);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = RTAsn1EncodeRecalcHdrSize(pAsn1Core, pArgs->fFlags, pArgs->pErrInfo);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Recalculate the output size, thus far. Dummy objects propagates the
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * content size, but the header size is zero. Other objects with
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * header size zero are not encoded and should be omitted entirely.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (pAsn1Core->cbHdr > 0 || RTASN1CORE_IS_DUMMY(pAsn1Core))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pArgs->cb = RTASN1CORE_GET_RAW_ASN1_SIZE(pAsn1Core) + cbSaved;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncRTDECL(int) RTAsn1EncodePrepare(PRTASN1CORE pRoot, uint32_t fFlags, uint32_t *pcbEncoded, PRTERRINFO pErrInfo)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn((fFlags & RTASN1ENCODE_F_RULE_MASK) == RTASN1ENCODE_F_DER, VERR_INVALID_FLAGS);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * This is implemented as a recursive enumeration of the ASN.1 object structure.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int rc = rtAsn1EncodePrepareCallback(pRoot, "root", 0, &Args);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncRTDECL(int) RTAsnEncodeWriteHeader(PCRTASN1CORE pAsn1Core, uint32_t fFlags, FNRTASN1ENCODEWRITER pfnWriter, void *pvUser,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn((fFlags & RTASN1ENCODE_F_RULE_MASK) == RTASN1ENCODE_F_DER, VERR_INVALID_FLAGS);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ((pAsn1Core->fFlags & (RTASN1CORE_F_PRESENT | RTASN1CORE_F_DUMMY | RTASN1CORE_F_DEFAULT)) == RTASN1CORE_F_PRESENT)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint8_t abHdr[16]; /* 2 + max 5 tag + max 4 length = 11 */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Encode the tag.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = (uint8_t)uTag | (pAsn1Core->fClass & ~ASN1_TAG_MASK);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn(pAsn1Core->uTag != UINT32_MAX, RTErrInfoSet(pErrInfo, VERR_ASN1_DUMMY_OBJECT, "uTag=UINT32_MAX"));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /* In the long form, the tag is encoded MSB style with the 8th bit
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync of each byte indicating the whether there are more byte. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = ASN1_TAG_USE_LONG_FORM | (pAsn1Core->fClass & ~ASN1_TAG_MASK);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else if (uTag <= UINT32_C(0x3fff)) /* 2**(7*2) = 0x4000 (16384) */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else if (uTag <= UINT32_C(0x1fffff)) /* 2**(7*3) = 0x200000 (2097152) */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else if (uTag <= UINT32_C(0xfffffff)) /* 2**(7*4) = 0x10000000 (268435456) */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Encode the length.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn(cb < _1G, RTErrInfoSetF(pErrInfo, VERR_ASN1_TOO_LONG, "cb=%u (%#x)", cb, cb));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Write it.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Not present, dummy or otherwise not encoded.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Assert(pAsn1Core->pOps && pAsn1Core->pOps->pfnEnum);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @callback_method_impl{FNRTASN1ENUMCALLBACK}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic DECLCALLBACK(int) rtAsn1EncodeWriteCallback(PRTASN1CORE pAsn1Core, const char *pszName, uint32_t uDepth, void *pvUser)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RTASN1ENCODEWRITEARGS *pArgs = (RTASN1ENCODEWRITEARGS *)pvUser;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * If there is an write method, use it.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = pAsn1Core->pOps->pfnEncodeWrite(pAsn1Core, pArgs->fFlags, pArgs->pfnWriter, pArgs->pvUser, pArgs->pErrInfo);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Generic path. Start by writing the header for this object.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = RTAsnEncodeWriteHeader(pAsn1Core, pArgs->fFlags, pArgs->pfnWriter, pArgs->pvUser, pArgs->pErrInfo);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * If there is an enum function, call it to assemble the content.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Otherwise ASSUME the pointer in the header points to the content.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = pAsn1Core->pOps->pfnEnum(pAsn1Core, rtAsn1EncodeWriteCallback, uDepth + 1, pArgs);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else if (pAsn1Core->cb && rc != VINF_ASN1_NOT_ENCODED)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RTErrInfoSetF(pArgs->pErrInfo, VERR_ASN1_INVALID_DATA_POINTER,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Invalid uData pointer %p for no pfnEnum object with %#x bytes of content",
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = pArgs->pfnWriter(pAsn1Core->uData.pv, pAsn1Core->cb, pArgs->pvUser, pArgs->pErrInfo);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncRTDECL(int) RTAsn1EncodeWrite(PCRTASN1CORE pRoot, uint32_t fFlags, FNRTASN1ENCODEWRITER pfnWriter, void *pvUser,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn((fFlags & RTASN1ENCODE_F_RULE_MASK) == RTASN1ENCODE_F_DER, VERR_INVALID_FLAGS);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * This is implemented as a recursive enumeration of the ASN.1 object structure.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return rtAsn1EncodeWriteCallback((PRTASN1CORE)pRoot, "root", 0, &Args);