13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/* $Id$ */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/** @file
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * IPRT - ASN.1, Encoding.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Copyright (C) 2006-2014 Oracle Corporation
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *
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 *
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 *
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
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/*******************************************************************************
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync* Header Files *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync*******************************************************************************/
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include "internal/iprt.h"
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include <iprt/asn1.h>
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include <iprt/assert.h>
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include <iprt/bignum.h>
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include <iprt/ctype.h>
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include <iprt/err.h>
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync#include <iprt/formats/asn1.h>
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/*******************************************************************************
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync* Structures and Typedefs *
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync*******************************************************************************/
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/**
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Argument package for rtAsn1EncodePrepareCallback passed by RTAsn1EncodePrepare.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsynctypedef struct RTASN1ENCODEPREPARGS
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** The size at this level. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint32_t cb;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** RTASN1ENCODE_F_XXX. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint32_t fFlags;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** Pointer to the error info. (optional) */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PRTERRINFO pErrInfo;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync} RTASN1ENCODEPREPARGS;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/**
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Argument package for rtAsn1EncodeWriteCallback passed by RTAsn1EncodeWrite.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsynctypedef struct RTASN1ENCODEWRITEARGS
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** RTASN1ENCODE_F_XXX. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint32_t fFlags;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** Pointer to the writer funtion. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PFNRTASN1ENCODEWRITER pfnWriter;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** User argument to the writer function. */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync void *pvUser;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /** Pointer to the error info. (optional) */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PRTERRINFO pErrInfo;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync} RTASN1ENCODEWRITEARGS;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncRTDECL(int) RTAsn1EncodeRecalcHdrSize(PRTASN1CORE pAsn1Core, uint32_t fFlags, PRTERRINFO pErrInfo)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn((fFlags & RTASN1ENCODE_F_RULE_MASK) == RTASN1ENCODE_F_DER, VERR_INVALID_FLAGS);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int rc = VINF_SUCCESS;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint8_t cbHdr;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ((pAsn1Core->fFlags & (RTASN1CORE_F_PRESENT | RTASN1CORE_F_DUMMY | RTASN1CORE_F_DEFAULT)) == RTASN1CORE_F_PRESENT)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * The minimum header size is two bytes.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbHdr = 2;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Add additional bytes for encoding the tag.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint32_t uTag = pAsn1Core->uTag;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (uTag >= ASN1_TAG_USE_LONG_FORM)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn(pAsn1Core->uTag != UINT32_MAX, RTErrInfoSet(pErrInfo, VERR_ASN1_DUMMY_OBJECT, "uTag=UINT32_MAX"));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync do
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbHdr++;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uTag >>= 7;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync } while (uTag > 0);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Add additional bytes for encoding the content length.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint32_t cb = pAsn1Core->cb;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (cb >= 0x80)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn(cb < _1G, RTErrInfoSetF(pErrInfo, VERR_ASN1_TOO_LONG, "cb=%u (%#x)", cb, cb));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (cb <= UINT32_C(0xffff))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (cb <= UINT32_C(0xff))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbHdr += 1;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbHdr += 2;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (cb <= UINT32_C(0xffffff))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbHdr += 3;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbHdr += 4;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Not present, dummy or otherwise not encoded.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync cbHdr = 0;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (pAsn1Core->fFlags & RTASN1CORE_F_DEFAULT)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = VINF_ASN1_NOT_ENCODED;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Assert(RTASN1CORE_IS_DUMMY(pAsn1Core));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Assert(pAsn1Core->pOps && pAsn1Core->pOps->pfnEnum);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = VINF_SUCCESS;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Update the header length.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pAsn1Core->cbHdr = cbHdr;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return rc;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/**
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @callback_method_impl{FNRTASN1ENUMCALLBACK}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic DECLCALLBACK(int) rtAsn1EncodePrepareCallback(PRTASN1CORE pAsn1Core, const char *pszName, uint32_t uDepth, void *pvUser)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RTASN1ENCODEPREPARGS *pArgs = (RTASN1ENCODEPREPARGS *)pvUser;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (RTASN1CORE_IS_PRESENT(pAsn1Core))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Depth first, where relevant.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint32_t const cbSaved = pArgs->cb;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (pAsn1Core->pOps)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Use the encoding preparation method when available.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int rc;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (pAsn1Core->pOps->pfnEncodePrep)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = pAsn1Core->pOps->pfnEncodePrep(pAsn1Core, pArgs->fFlags, pArgs->pErrInfo);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else if (pAsn1Core->pOps->pfnEnum)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Recurse to prepare the child objects (if any).
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = pAsn1Core->pOps->pfnEnum(pAsn1Core, rtAsn1EncodePrepareCallback, uDepth + 1, pArgs);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (RT_SUCCESS(rc))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pAsn1Core->cb = pArgs->cb - cbSaved;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Must be a primitive type if DER.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ( (pAsn1Core->fClass & ASN1_TAGFLAG_CONSTRUCTED)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && (pArgs->fFlags & RTASN1ENCODE_F_DER) )
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 = VINF_SUCCESS;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (RT_SUCCESS(rc))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = RTAsn1EncodeRecalcHdrSize(pAsn1Core, pArgs->fFlags, pArgs->pErrInfo);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (RT_FAILURE(rc))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return rc;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertFailed();
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pAsn1Core->cb = 0;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pAsn1Core->cbHdr = 0;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
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 */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (pAsn1Core->cbHdr > 0 || RTASN1CORE_IS_DUMMY(pAsn1Core))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pArgs->cb = RTASN1CORE_GET_RAW_ASN1_SIZE(pAsn1Core) + cbSaved;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pArgs->cb = cbSaved;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return VINF_SUCCESS;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncRTDECL(int) RTAsn1EncodePrepare(PRTASN1CORE pRoot, uint32_t fFlags, uint32_t *pcbEncoded, PRTERRINFO pErrInfo)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn((fFlags & RTASN1ENCODE_F_RULE_MASK) == RTASN1ENCODE_F_DER, VERR_INVALID_FLAGS);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * This is implemented as a recursive enumeration of the ASN.1 object structure.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RTASN1ENCODEPREPARGS Args;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Args.cb = 0;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Args.fFlags = fFlags;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Args.pErrInfo = pErrInfo;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int rc = rtAsn1EncodePrepareCallback(pRoot, "root", 0, &Args);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (pcbEncoded)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pcbEncoded = RTASN1CORE_GET_RAW_ASN1_SIZE(pRoot);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return rc;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncRTDECL(int) RTAsnEncodeWriteHeader(PCRTASN1CORE pAsn1Core, uint32_t fFlags, FNRTASN1ENCODEWRITER pfnWriter, void *pvUser,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PRTERRINFO pErrInfo)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn((fFlags & RTASN1ENCODE_F_RULE_MASK) == RTASN1ENCODE_F_DER, VERR_INVALID_FLAGS);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ((pAsn1Core->fFlags & (RTASN1CORE_F_PRESENT | RTASN1CORE_F_DUMMY | RTASN1CORE_F_DEFAULT)) == RTASN1CORE_F_PRESENT)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint8_t abHdr[16]; /* 2 + max 5 tag + max 4 length = 11 */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint8_t *pbDst = &abHdr[0];
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Encode the tag.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint32_t uTag = pAsn1Core->uTag;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (uTag < ASN1_TAG_USE_LONG_FORM)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = (uint8_t)uTag | (pAsn1Core->fClass & ~ASN1_TAG_MASK);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn(pAsn1Core->uTag != UINT32_MAX, RTErrInfoSet(pErrInfo, VERR_ASN1_DUMMY_OBJECT, "uTag=UINT32_MAX"));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
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 if (uTag <= UINT32_C(0x7f))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = uTag;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else if (uTag <= UINT32_C(0x3fff)) /* 2**(7*2) = 0x4000 (16384) */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = (uTag >> 7) | 0x80;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = uTag & 0x7f;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else if (uTag <= UINT32_C(0x1fffff)) /* 2**(7*3) = 0x200000 (2097152) */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = (uTag >> 14) | 0x80;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = ((uTag >> 7) & 0x7f) | 0x80;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = uTag & 0x7f;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else if (uTag <= UINT32_C(0xfffffff)) /* 2**(7*4) = 0x10000000 (268435456) */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = (uTag >> 21) | 0x80;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = ((uTag >> 14) & 0x7f) | 0x80;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = ((uTag >> 7) & 0x7f) | 0x80;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = uTag & 0x7f;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = (uTag >> 28) | 0x80;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = ((uTag >> 21) & 0x7f) | 0x80;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = ((uTag >> 14) & 0x7f) | 0x80;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = ((uTag >> 7) & 0x7f) | 0x80;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = uTag & 0x7f;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Encode the length.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync uint32_t cb = pAsn1Core->cb;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (cb < 0x80)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync *pbDst++ = (uint8_t)cb;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn(cb < _1G, RTErrInfoSetF(pErrInfo, VERR_ASN1_TOO_LONG, "cb=%u (%#x)", cb, cb));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (cb <= UINT32_C(0xffff))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (cb <= UINT32_C(0xff))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst[0] = 0x81;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst[1] = (uint8_t)cb;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst += 2;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst[0] = 0x82;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst[1] = cb >> 8;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst[2] = (uint8_t)cb;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst += 3;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (cb <= UINT32_C(0xffffff))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst[0] = 0x83;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst[1] = (uint8_t)(cb >> 16);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst[2] = (uint8_t)(cb >> 8);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst[3] = (uint8_t)cb;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst += 4;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst[0] = 0x84;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst[1] = (uint8_t)(cb >> 24);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst[2] = (uint8_t)(cb >> 16);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst[3] = (uint8_t)(cb >> 8);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst[4] = (uint8_t)cb;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pbDst += 5;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync size_t const cbHdr = pbDst - &abHdr[0];
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Assert(sizeof(abHdr) >= cbHdr);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Assert(pAsn1Core->cbHdr == cbHdr);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Write it.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return pfnWriter(abHdr, cbHdr, pvUser, pErrInfo);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Not present, dummy or otherwise not encoded.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Assert(pAsn1Core->cbHdr == 0);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (pAsn1Core->fFlags & RTASN1CORE_F_DEFAULT)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return VINF_ASN1_NOT_ENCODED;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Assert(RTASN1CORE_IS_DUMMY(pAsn1Core));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Assert(pAsn1Core->pOps && pAsn1Core->pOps->pfnEnum);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return VINF_SUCCESS;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync/**
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * @callback_method_impl{FNRTASN1ENUMCALLBACK}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncstatic DECLCALLBACK(int) rtAsn1EncodeWriteCallback(PRTASN1CORE pAsn1Core, const char *pszName, uint32_t uDepth, void *pvUser)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RTASN1ENCODEWRITEARGS *pArgs = (RTASN1ENCODEWRITEARGS *)pvUser;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync int rc;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (RTASN1CORE_IS_PRESENT(pAsn1Core))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * If there is an write method, use it.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ( pAsn1Core->pOps
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && pAsn1Core->pOps->pfnEncodeWrite)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = pAsn1Core->pOps->pfnEncodeWrite(pAsn1Core, pArgs->fFlags, pArgs->pfnWriter, pArgs->pvUser, pArgs->pErrInfo);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * Generic path. Start by writing the header for this object.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = RTAsnEncodeWriteHeader(pAsn1Core, pArgs->fFlags, pArgs->pfnWriter, pArgs->pvUser, pArgs->pErrInfo);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (RT_SUCCESS(rc))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
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 */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if ( pAsn1Core->pOps
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync && pAsn1Core->pOps->pfnEnum)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (rc != VINF_ASN1_NOT_ENCODED)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = pAsn1Core->pOps->pfnEnum(pAsn1Core, rtAsn1EncodeWriteCallback, uDepth + 1, pArgs);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else if (pAsn1Core->cb && rc != VINF_ASN1_NOT_ENCODED)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync {
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Assert(!RTASN1CORE_IS_DUMMY(pAsn1Core));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertPtrReturn(pAsn1Core->uData.pv,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RTErrInfoSetF(pArgs->pErrInfo, VERR_ASN1_INVALID_DATA_POINTER,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync "Invalid uData pointer %p for no pfnEnum object with %#x bytes of content",
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync pAsn1Core->uData.pv, pAsn1Core->cb));
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = pArgs->pfnWriter(pAsn1Core->uData.pv, pAsn1Core->cb, pArgs->pvUser, pArgs->pErrInfo);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync if (RT_SUCCESS(rc))
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = VINF_SUCCESS;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync }
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync else
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync rc = VINF_SUCCESS;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return rc;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsyncRTDECL(int) RTAsn1EncodeWrite(PCRTASN1CORE pRoot, uint32_t fFlags, FNRTASN1ENCODEWRITER pfnWriter, void *pvUser,
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync PRTERRINFO pErrInfo)
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync{
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync AssertReturn((fFlags & RTASN1ENCODE_F_RULE_MASK) == RTASN1ENCODE_F_DER, VERR_INVALID_FLAGS);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync /*
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync * This is implemented as a recursive enumeration of the ASN.1 object structure.
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync */
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync RTASN1ENCODEWRITEARGS Args;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Args.fFlags = fFlags;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Args.pfnWriter = pfnWriter;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Args.pvUser = pvUser;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync Args.pErrInfo = pErrInfo;
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync return rtAsn1EncodeWriteCallback((PRTASN1CORE)pRoot, "root", 0, &Args);
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync}
13493ab7596e827b8d0caab2c89e635dd65f78f9vboxsync