Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arm_uc_mmDerManifestParser.c Source File

arm_uc_mmDerManifestParser.c

00001 // ----------------------------------------------------------------------------
00002 // Copyright 2016-2017 ARM Ltd.
00003 //
00004 // SPDX-License-Identifier: Apache-2.0
00005 //
00006 // Licensed under the Apache License, Version 2.0 (the "License");
00007 // you may not use this file except in compliance with the License.
00008 // You may obtain a copy of the License at
00009 //
00010 //     http://www.apache.org/licenses/LICENSE-2.0
00011 //
00012 // Unless required by applicable law or agreed to in writing, software
00013 // distributed under the License is distributed on an "AS IS" BASIS,
00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 // See the License for the specific language governing permissions and
00016 // limitations under the License.
00017 // ----------------------------------------------------------------------------
00018 
00019 #include "arm_uc_mmDerManifestParser.h"
00020 
00021 #include <stdio.h>
00022 
00023 #define DER_MANDATORY 0
00024 #define DER_OPTIONAL 1
00025 
00026 #define ARM_UC_MM_DER_ELEMENT_INIT(ID, TAG, OPT, CHILDREN)\
00027     {.id = (ID), .subElements = (CHILDREN), .tag = (TAG), .optional = (OPT), .nSubElements = sizeof(CHILDREN)/sizeof(struct arm_uc_mmDerElement)}
00028 #define ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ID, TAG, OPT)\
00029     {.id = (ID), .subElements = NULL, .tag = (TAG), .optional = (OPT), .nSubElements = 0}
00030 
00031 
00032 /**
00033  * @brief Descriptor for the apply period of a manifest.
00034  *
00035  * applyPeriod SEQUENCE {
00036  *     validFrom     INTEGER,
00037  *     validTo       INTEGER
00038  * }
00039  */
00040 static const struct arm_uc_mmDerElement ManifestApplyPeriod[] = {
00041     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_VALID_FROM, ARM_UC_MM_ASN1_INTEGER, DER_MANDATORY),
00042     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_VALID_TO, ARM_UC_MM_ASN1_INTEGER, DER_MANDATORY),
00043 };
00044 /**
00045  * @brief Descriptor of the encryptionMode
00046  *
00047  * encryptionMode  CHOICE {
00048  *     enum    ENUMERATED {
00049  *         invalid(0),
00050  *         aes-128-ctr-ecc-secp256r1-sha256(1),
00051  *         none-ecc-secp256r1-sha256(2),
00052  *         none-none-sha256(3)
00053  *     },
00054  *     objectId    OBJECT IDENTIFIER
00055  * }
00056  */
00057 static const struct arm_uc_mmDerElement encryptionModeChoice[] = {
00058     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_ENC_ENUM, ARM_UC_MM_ASN1_ENUMERATED, DER_MANDATORY),
00059     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_ENC_OID, ARM_UC_MM_ASN1_OID, DER_MANDATORY),
00060 };
00061 /**
00062  * @brief Descriptor for resource aliases
00063  *
00064  * ResourceAlias ::= SEQUENCE {
00065  *     hash        OCTET STRING,
00066  *     url         Url
00067  * }
00068  */
00069 static const struct arm_uc_mmDerElement manifestResourceAlias[] = {
00070     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_RESOURCE_ALIAS_HASH, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00071     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_RESOURCE_ALIAS_URL, ARM_UC_MM_ASN1_UTF8_STRING, DER_MANDATORY),
00072 };
00073 /**
00074  * @brief Descriptor of an Alias container
00075  *
00076  */
00077 static const struct arm_uc_mmDerElement manifestResourceAliases[] = {
00078     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_RESOURCE_ALIAS, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, manifestResourceAlias)
00079 };
00080 
00081 /**
00082  * @brief Descriptor of the firmware format
00083  *
00084  * format      CHOICE {F
00085  *     enum    ENUMERATED {
00086  *         undefined(0), raw-binary(1), cbor(2), hex-location-length-data(3), elf(4)
00087  *     },
00088  *     objectId    OBJECT IDENTIFIER
00089  * },
00090  */
00091 static const struct arm_uc_mmDerElement manifestFwFmtChoice[] = {
00092     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_FMT_ENUM, ARM_UC_MM_ASN1_ENUMERATED, DER_MANDATORY),
00093     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_FMT_OID, ARM_UC_MM_ASN1_OID, DER_MANDATORY),
00094 };
00095 
00096 /**
00097  * @brief Descriptor of the certificate reference used for ECDH
00098  * @details References an ECC certificate, which is used to perform ECDH with the target device's private key. This will
00099  * allow derivation of a shared secret, which has been used to encrypt the symmetric encryption key.
00100  * NOTE: this is the same ASN.1 sequence as arm_uc_mmSignatureCertificateReference, but it is duplicated in the parser to reduce parsing time.
00101  *
00102  * CertificateReference ::= SEQUENCE {
00103  *     fingerprint  Bytes,
00104  *     url          Url
00105  * }
00106  *
00107  */
00108 static const struct arm_uc_mmDerElement manifestFwCryptIdCertRef[] = {
00109     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_FINGERPRINT, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00110     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_URL, ARM_UC_MM_ASN1_UTF8_STRING, DER_OPTIONAL),
00111 };
00112 /**
00113  * @brief Descriptor of the Local Info ID choice
00114  * @details Describes either a locally held pre-shared key or a certificate.
00115  *
00116  * id CHOICE {
00117  *     key OCTET STRING,
00118  *     certificate CertificateReference
00119  * },
00120  */
00121 static const struct arm_uc_mmDerElement manifestFwCryptIdChoice[] = {
00122     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_LOCAL, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00123     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CERT_REF, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, manifestFwCryptIdCertRef),
00124 };
00125 /**
00126  * @brief Descriptor of the encryption key options
00127  * @details Encryption is currently not supported.
00128  * When supported, the encryption key will be delivered either as an encrypted blob in the manifest, or in a key table,
00129  * which is referenced in the Resource Reference below.
00130  *
00131  * key      CHOICE {
00132  *   keyTable  Url,
00133  *   cipherKey OCTET STRING
00134  * } OPTIONAL
00135  *
00136  */
00137 static const struct arm_uc_mmDerElement manifestFwCryptKeyChoice[] = {
00138     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_CRYPT_KEY_KEYTABLE_REF, ARM_UC_MM_ASN1_UTF8_STRING, DER_MANDATORY),
00139     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_CRYPT_KEY_CIPHERKEY, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00140 };
00141 /**
00142  * @brief Descriptor of cryptographic information block
00143  * @details Contains the information necessary to manage the encryption of the payload.
00144  * encryptionInfo SEQUENCE {
00145  *     initVector OCTET STRING,
00146  *     id,
00147  *     key
00148  * } OPTIONAL,
00149  */
00150 static const struct arm_uc_mmDerElement manifestFwCryptInfo[] = {
00151     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_CRYPT_IV, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00152     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_FW_CRYPT_ID_CHOICE, ARM_UC_MM_ASN1_CHOICE, DER_MANDATORY, manifestFwCryptIdChoice),
00153     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_FW_CRYPT_KEY_CHOICE, ARM_UC_MM_ASN1_CHOICE, DER_OPTIONAL, manifestFwCryptKeyChoice),
00154 };
00155 
00156 /**
00157  * @brief Descriptor of a firmware resource reference.
00158  * @details Provides a hash, URL, and size of a payload
00159  *
00160  * ResourceReference ::= SEQUENCE {
00161  *   hash        OCTET STRING,
00162  *   url     Url OPTIONAL,
00163  *   size    INTEGER
00164  * }
00165  */
00166 static const struct arm_uc_mmDerElement manifestFwRsrcRef[] = {
00167     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_RSRC_REF_HASH, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00168     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_RSRC_REF_URL, ARM_UC_MM_ASN1_UTF8_STRING, DER_OPTIONAL),
00169     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_RSRC_REF_SIZE, ARM_UC_MM_ASN1_INTEGER, DER_MANDATORY),
00170 };
00171 
00172 /**
00173  * @brief Descriptor of a payload description block
00174  * @details Describes the payload, including:
00175  * * The payload format
00176  * * Any cryptographic information required to decrypt the payload
00177  * * The storage identifier for payload (where to store it on the target)
00178  * * The resource reference of the payload (where it is stored, etc)
00179  * * A free-text version field
00180  *
00181  * FirmwareDescription ::= SEQUENCE {
00182  *    format,
00183  *    encryptionInfo OPTIONAL,
00184  *    storageIdentifier UTF8String,
00185  *    reference    ResourceReference,
00186  *    version     UTF8String OPTIONAL
00187  * }
00188  */
00189 static const struct arm_uc_mmDerElement arm_uc_mmManifestFirmwareDescriptionElements[] = {
00190     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_FW_FMT_CHOICE, ARM_UC_MM_ASN1_CHOICE, DER_MANDATORY, manifestFwFmtChoice),
00191     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_FW_CRYPT_INFO, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_OPTIONAL, manifestFwCryptInfo),
00192     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_STRG_ID, ARM_UC_MM_ASN1_UTF8_STRING, DER_MANDATORY),
00193     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_FW_RSRC_REF, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, manifestFwRsrcRef),
00194     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_FW_VER, ARM_UC_MM_ASN1_UTF8_STRING, DER_OPTIONAL),
00195 };
00196 
00197 const struct arm_uc_mmDerElement arm_uc_mmManifestFirmwareDescription[] = {
00198     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_FIRMWARE, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_OPTIONAL, arm_uc_mmManifestFirmwareDescriptionElements),
00199 };
00200 
00201 /**
00202  * @brief Descriptor of a manifest dependency reference
00203  * @details Provides a hash, URL, and size of a manifest dependency
00204  * ResourceReference ::= SEQUENCE {
00205  *     hash        OCTET STRING,
00206  *     url     Url OPTIONAL,
00207  *     size    INTEGER
00208  * }
00209  */
00210 static const struct arm_uc_mmDerElement arm_uc_mmManifestDependency[] = {
00211     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_DEP_REF_HASH, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00212     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_DEP_REF_URL, ARM_UC_MM_ASN1_UTF8_STRING, DER_OPTIONAL),
00213     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_DEP_REF_SIZE, ARM_UC_MM_ASN1_INTEGER, DER_MANDATORY),
00214 };
00215 /**
00216  * @brief Descriptor of a manifest dependency container
00217  * @details Contains manifest dependency references
00218  */
00219 const struct arm_uc_mmDerElement arm_uc_mmManifestDependencies[] = {
00220     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_DEP, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, arm_uc_mmManifestDependency)
00221 };
00222 
00223 /**
00224  * @brief Descriptor of the manifest sequence
00225  * @details Contains all the information necessary to describe a manifest.
00226  *
00227  * Manifest ::= SEQUENCE {
00228  *     manifestVersion     ENUMERATED {
00229  *       v1(1)
00230  *     },
00231  *     description UTF8String OPTIONAL,
00232  *     timestamp   INTEGER,
00233  *     vendorId    UUID,
00234  *     classId     UUID,
00235  *     deviceId    UUID,
00236  *     nonce       OCTET STRING,
00237  *     vendorInfo  OCTET STRING,
00238  *     applyPeriod OPTIONAL,
00239  *     applyImmediately    BOOLEAN,
00240  *     encryptionMode  CHOICE {
00241  *         enum    ENUMERATED {
00242  *             invalid(0),
00243  *             aes-128-ctr-ecc-secp256r1-sha256(1),
00244  *             none-ecc-secp256r1-sha256(2),
00245  *             none-none-sha256(3)
00246  *         },
00247  *         objectId    OBJECT IDENTIFIER
00248  *     },
00249  *     aliases         SEQUENCE OF ResourceAlias,
00250  *     dependencies    SEQUENCE OF ResourceReference,
00251  *     firmware        FirmwareDescription OPTIONAL
00252  */
00253 static const struct arm_uc_mmDerElement ManifestElements[] = {
00254     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_VERSION, ARM_UC_MM_ASN1_ENUMERATED, DER_MANDATORY),
00255     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_DESC, ARM_UC_MM_ASN1_UTF8_STRING, DER_OPTIONAL),
00256     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_TIMESTAMP, ARM_UC_MM_ASN1_INTEGER, DER_MANDATORY),
00257     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_VENDOR_UUID, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00258     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_CLASS_UUID, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00259     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_DEVICE_UUID, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00260     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_NONCE, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00261     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_VENDOR_INFO, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00262     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_APPLY_PERIOD, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_OPTIONAL, ManifestApplyPeriod),
00263     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_MFST_APPLY_IMMEDIATELY, ARM_UC_MM_ASN1_BOOLEAN, DER_MANDATORY),
00264     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_ENCRYPTION_MODE_CHOICE, ARM_UC_MM_ASN1_CHOICE, DER_OPTIONAL, encryptionModeChoice),
00265     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_RESOURCE_ALIASES, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, manifestResourceAliases),
00266     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_DEPS, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, arm_uc_mmManifestDependencies),
00267     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST_FIRMWARE, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_OPTIONAL, arm_uc_mmManifestFirmwareDescriptionElements),
00268 };
00269 
00270 /**
00271  * @brief Descriptor of the Resource Choice
00272  * @details The resource can be one of a limited number of options. Currently, the supported resource types are Manifest
00273  * and Firmware Image. The firmware image is simply an OCTET STRING, whereas the Manifest is an ASN.1 SEQUENCE (DER
00274  * encoded)
00275  *
00276  * resource CHOICE {
00277  *     manifest Manifest,
00278  *     firmware Firmware
00279  * }
00280  */
00281 static const struct arm_uc_mmDerElement ResourceChoiceElements[] = {
00282     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_MFST, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, ManifestElements),
00283     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_FW_IMAGE, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00284 };
00285 
00286 /**
00287  * @brief Descriptor of a Resource object.
00288  * @details A resource is composed of an optional reference URL, a resource type identifier, and a resource.
00289  *
00290  * Resource ::= SEQUENCE {
00291  *     url     Url OPTIONAL,
00292  *     resourceType        ENUMERATED {
00293  *         manifest(0), firmware(1)
00294  *     },
00295  *     resource
00296  * }
00297  */
00298 static const struct arm_uc_mmDerElement ResourceElements[] = {
00299     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_RESOURCE_URL, ARM_UC_MM_ASN1_UTF8_STRING, DER_OPTIONAL),
00300     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_RESOURCE_TYPE, ARM_UC_MM_ASN1_ENUMERATED, DER_MANDATORY),
00301     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_RESOURCE_CHOICE, ARM_UC_MM_ASN1_CHOICE, DER_MANDATORY, ResourceChoiceElements),
00302 };
00303 /**
00304 * @brief Descriptor of the certificate reference used for ECDSA signature verification
00305 * @details References an ECC certificate, which is used to perform ECDSA with the target device's public key. The
00306 * certificate used to sign the manifest is used to determine the permissions to be applied to the manifest.
00307 * NOTE: this is the same ASN.1 sequence as manifestFwCryptIdCertRef, but it is duplicated in the parser to reduce parsing time.
00308 *
00309 * CertificateReference ::= SEQUENCE {
00310 *     fingerprint  Bytes,
00311 *     url          Url
00312 * }
00313 
00314  */
00315 static const struct arm_uc_mmDerElement arm_uc_mmSignatureCertificateReference[] = {
00316     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_SIG_CERT_FINGERPRINT, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00317     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_SIG_CERT_URL, ARM_UC_MM_ASN1_UTF8_STRING, DER_OPTIONAL),
00318 };
00319 /**
00320  * @brief Certificate Reference container
00321  */
00322 const struct arm_uc_mmDerElement arm_uc_mmSignatureCertificateReferences[] = {
00323     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_SIG_CERT, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, arm_uc_mmSignatureCertificateReference),
00324 };
00325 
00326 const struct arm_uc_mmDerElement arm_uc_mmSignatureBlock[] = {
00327     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_SIG_SIGNATURE, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00328     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_SIG_CERTS, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, arm_uc_mmSignatureCertificateReferences),
00329 };
00330 const struct arm_uc_mmDerElement arm_uc_mmSignatures[] = {
00331     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_SIG_SIGNATURE_BLOCK, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, arm_uc_mmSignatureBlock),
00332 };
00333 const struct arm_uc_mmDerElement arm_uc_mmMacBlock[] = {
00334     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_SIG_MAC_PSKID, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00335     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_SIG_MAC_KEYTABLE_VERSION, ARM_UC_MM_ASN1_INTEGER, DER_MANDATORY),
00336     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_SIG_MAC_KEYTABLE_IV, ARM_UC_MM_ASN1_OCTET_STRING, DER_OPTIONAL),
00337     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_SIG_MAC_KEYTABLE_REF, ARM_UC_MM_ASN1_UTF8_STRING, DER_OPTIONAL),
00338     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_SIG_MAC_KEYTABLE_INDEX_SIZE, ARM_UC_MM_ASN1_INTEGER, DER_MANDATORY),
00339     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_SIG_MAC_KEYTABLE_RECORD_SIZE, ARM_UC_MM_ASN1_INTEGER, DER_MANDATORY),
00340 };
00341 const struct arm_uc_mmDerElement arm_uc_mmMacs[] = {
00342     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_SIG_MAC_BLOCK, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, arm_uc_mmMacBlock),
00343 };
00344 /**
00345  * @brief Descriptor of a resource signature
00346  * @details Contains the signature of the resource object. To facilitate fast integrity checking, a hash is also
00347  * provided. The certificate references allow the target device to establish a chain of trust.
00348  *
00349  * ResourceSignature ::= SEQUENCE {
00350  *     certificates SEQUENCE OF CertificateReference,
00351  *     hash        OCTET STRING,
00352  *     signature   OCTET STRING
00353  * }
00354  */
00355 const struct arm_uc_mmDerElement arm_uc_mmResourceSignature[] = {
00356     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_DER_SIG_HASH, ARM_UC_MM_ASN1_OCTET_STRING, DER_MANDATORY),
00357     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_SIG_SIGNATURES, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, arm_uc_mmSignatures),
00358     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_SIG_MACS, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_OPTIONAL, arm_uc_mmMacs),
00359 };
00360 /**
00361  * @brief Descriptor of a signed resource.
00362  * @details The signed resource is a container for a resource and a signature.
00363  * SignedResource ::= SEQUENCE {
00364  *     resource  Resource,
00365  *     signature ResourceSignature
00366  * }
00367  */
00368 static const struct arm_uc_mmDerElement SignedResourceElements[] = {
00369     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_RESOURCE, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, ResourceElements),
00370     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_SIG, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, arm_uc_mmResourceSignature),
00371 };
00372 /**
00373  * @brief Container of a Signed Resource.
00374  */
00375 static const struct arm_uc_mmDerElement SignedResource =
00376     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_DER_ROOT, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY,
00377                                SignedResourceElements);
00378 
00379 static const struct arm_uc_mmDerElement KeyTableEntryElements[] = {
00380     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_KT_HASH, ARM_UC_MM_ASN1_CONTEXT_SPECIFIC | 0, DER_OPTIONAL),
00381     ARM_UC_MM_DER_ELEMENT_INIT_LEAF(ARM_UC_MM_KT_PAYLOAD_KEY, ARM_UC_MM_ASN1_CONTEXT_SPECIFIC | 1, DER_OPTIONAL),
00382 };
00383 const struct arm_uc_mmDerElement arm_uc_mmKeyTableEntry[] = {
00384     ARM_UC_MM_DER_ELEMENT_INIT(ARM_UC_MM_KT_ROOT, ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE, DER_MANDATORY, KeyTableEntryElements)
00385 };
00386 
00387 #include "update-client-common/arm_uc_trace.h"
00388 
00389 enum arm_uc_mmDerParserLogLevels {
00390     DER_PARSER_LOG_LEVEL_NONE,
00391     DER_PARSER_LOG_LEVEL_DESCRIPTORS,
00392     DER_PARSER_LOG_LEVEL_TAGS,
00393     DER_PARSER_LOG_LEVEL_SIZES,
00394     DER_PARSER_LOG_LEVEL_VALUES,
00395     DER_PARSER_LOG_LEVEL_MAX
00396 };
00397 uint32_t arm_uc_mm_derRecurseDepth;
00398 
00399 #ifndef ARM_UC_DER_PARSER_TRACE_ENABLE
00400 #define ARM_UC_DER_PARSER_TRACE_ENABLE 0
00401 #endif
00402 
00403 #if ARM_UC_DER_PARSER_TRACE_ENABLE
00404 volatile uint32_t arm_uc_mm_der_gDebugLevel = DER_PARSER_LOG_LEVEL_MAX;
00405 
00406 #define DER_PARSER_LOG_INDENT(LOG_LEVEL)\
00407 do { \
00408     if((LOG_LEVEL) <= arm_uc_mm_der_gDebugLevel) \
00409     { \
00410         for (uint32_t i = 0; i < arm_uc_mm_derRecurseDepth; i++) \
00411         { \
00412             printf("  "); \
00413         } \
00414     } \
00415 } while(0)
00416 
00417 #define DER_PARSER_LOG(LOG_LEVEL,...)\
00418     do { \
00419         if((LOG_LEVEL) <= arm_uc_mm_der_gDebugLevel) \
00420         { \
00421             printf(__VA_ARGS__); \
00422         } \
00423     } while(0)
00424 #else
00425 #define DER_PARSER_LOG_INDENT(LOG_LEVEL)
00426 #define DER_PARSER_LOG(LOG_LEVEL,...)
00427 #endif
00428 
00429 /*
00430  * ASN.1 DER decoding routines
00431  */
00432 int ARM_UC_MM_ASN1_get_len(unsigned char **p,
00433                            const unsigned char *end,
00434                            size_t *len)
00435 {
00436     if ((end - *p) < 1) {
00437         return (ARM_UC_DP_ERR_ASN1_OUT_OF_DATA);
00438     }
00439 
00440     if ((**p & 0x80) == 0) {
00441         *len = *(*p)++;
00442     } else {
00443         switch (**p & 0x7F) {
00444             case 1:
00445                 if ((end - *p) < 2) {
00446                     UC_MMGR_TRACE("error: DER parser out of data");
00447                     return (ARM_UC_DP_ERR_ASN1_OUT_OF_DATA);
00448                 }
00449 
00450                 *len = (*p)[1];
00451                 (*p) += 2;
00452                 break;
00453 
00454             case 2:
00455                 if ((end - *p) < 3) {
00456                     UC_MMGR_TRACE("error: DER parser out of data");
00457                     return (ARM_UC_DP_ERR_ASN1_OUT_OF_DATA);
00458                 }
00459 
00460                 *len = ((size_t)(*p)[1] << 8) | (*p)[2];
00461                 (*p) += 3;
00462                 break;
00463 
00464             case 3:
00465                 if ((end - *p) < 4) {
00466                     UC_MMGR_TRACE("error: DER parser out of data");
00467                     return (ARM_UC_DP_ERR_ASN1_OUT_OF_DATA);
00468                 }
00469 
00470                 *len = ((size_t)(*p)[1] << 16) |
00471                        ((size_t)(*p)[2] << 8) | (*p)[3];
00472                 (*p) += 4;
00473                 break;
00474 
00475             case 4:
00476                 if ((end - *p) < 5) {
00477                     UC_MMGR_TRACE("error: DER parser out of data");
00478                     return (ARM_UC_DP_ERR_ASN1_OUT_OF_DATA);
00479                 }
00480 
00481                 *len = ((size_t)(*p)[1] << 24) | ((size_t)(*p)[2] << 16) |
00482                        ((size_t)(*p)[3] << 8) | (*p)[4];
00483                 (*p) += 5;
00484                 break;
00485 
00486             default:
00487                 UC_MMGR_TRACE("error: DER parser invalid length");
00488                 return (ARM_UC_DP_ERR_ASN1_INVALID_LENGTH);
00489         }
00490     }
00491 
00492     if (*len > (size_t)(end - *p)) {
00493         UC_MMGR_TRACE("error: DER parser out of data");
00494         return (ARM_UC_DP_ERR_ASN1_OUT_OF_DATA);
00495     }
00496 
00497     return (0);
00498 }
00499 
00500 int ARM_UC_MM_ASN1_get_tag(unsigned char **p,
00501                            const unsigned char *end,
00502                            size_t *len, int tag)
00503 {
00504     if ((end - *p) < 1) {
00505         UC_MMGR_TRACE("error: DER parser out of data");
00506         return (ARM_UC_DP_ERR_ASN1_OUT_OF_DATA);
00507     }
00508 
00509     if (**p != tag) {
00510         /* DER Unexpected Tag should not be traced, since that return code occurs 
00511          * regularly in correct manifests: it is used to detect when optional fields
00512          * are absent.
00513          * DO NOT TRACE
00514          */
00515         return (ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG);
00516     }
00517 
00518     (*p)++;
00519 
00520     return (ARM_UC_MM_ASN1_get_len(p, end, len));
00521 }
00522 
00523 
00524 const char *ARM_UC_mmDERDescID2Str(uint32_t id)
00525 {
00526     switch (id) {
00527 #define ENUM_AUTO(name) case name: return #name;
00528             ARM_UC_MM_DER_ID_LIST
00529 #undef ENUM_AUTO
00530         default:
00531             return "Unknown DER ID";
00532     }
00533 }
00534 
00535 /**
00536  * @brief Internal state of the parser
00537  */
00538 struct ARM_UC_MM_DERParserState {
00539     uint32_t nValues;         //!< Number of values remaining to parse
00540     const int32_t *valueIDs; //!< Current element of the value identifier array
00541     arm_uc_buffer_t *buffers; //!< Current buffer of the value output array
00542 };
00543 /**
00544  * @brief Converts a buffer to an unsigned 32-bit integer
00545  * @details Assumes that the buffer is an unsigned, big-endian integer and returns it.
00546  * Limitations:
00547  * * Expects the buffer to be 4 bytes long or less
00548  * * Does not trap NULL buffers
00549  * * Does not trap NULL pointers
00550  * * Does not permit sign extension of negative values
00551  * @param[in] buf The buffer to convert to an integer
00552  * @return The integer value of the buffer
00553  */
00554 uint32_t ARM_UC_mmDerBuf2Uint(arm_uc_buffer_t *buf)
00555 {
00556     uint32_t rc = 0;
00557     unsigned i;
00558     // Handle case for 5 byte long value with signess-byte in beginning
00559     unsigned j = ((buf->size > sizeof(uint32_t) && buf->ptr[0] == 0) ? 1 : 0);
00560     for (i = j; i < buf->size; i++) {
00561         rc = (rc << 8) | buf->ptr[i];
00562     }
00563     return rc;
00564 }
00565 /**
00566  * @brief Converts a buffer to an unsigned 64-bit integer
00567  * @details Assumes that the buffer is an unsigned, big-endian integer and returns it.
00568  * Limitations:
00569  * * Expects the buffer to be 8 bytes long or less
00570  * * Does not trap NULL buffers
00571  * * Does not trap NULL pointers
00572  * * Does not permit sign extension of negative values
00573  * @param[in] buf The buffer to convert to an integer
00574  * @return The integer value of the buffer
00575  */
00576 uint64_t ARM_UC_mmDerBuf2Uint64(arm_uc_buffer_t *buf)
00577 {
00578     uint64_t rc = 0;
00579     unsigned i;
00580     for (i = 0; i < buf->size && i < sizeof(uint64_t); i++) {
00581         rc = (rc << 8) | buf->ptr[i];
00582     }
00583     return rc;
00584 }
00585 
00586 /**
00587  * @brief Extracts the next tag in the DER string
00588  * @details Validates the length of the string, then extracts the next value, interpreting it as a tag.
00589  * Limitations:
00590  * * Does not verify that any of the pointers are non-NULL
00591  * * Does not validate tag values
00592  * @param[in] p The current position in DER string
00593  * @param[in] end The last position in the DER string
00594  * @param[out] tag The extracted DER tag
00595  * @retval 1 if the end has been encountered
00596  * @retval 0 if the tag was successfully retrieved
00597  */
00598 int ARM_UC_mmDERPeekTag(uint8_t *p, uint8_t *end, int *tag)
00599 {
00600     if ((end - p) < 1) {
00601         return (1);
00602     }
00603     *tag = *p;
00604     return 0;
00605 }
00606 
00607 /**
00608  * @brief Extracts one or more tagged values from DER encoded data
00609  * @details Recursively traverses the DER tree, searching for the identified values.
00610  * The parser parses the input data, identified by `*pos` according to the following rules:
00611  *
00612  * * If the current descriptor is a choice, `ARM_UC_mmDERGetValues` attempts to resolve the choice.
00613  *     * Obtain the actual tag
00614  *     * Loop through each child of the choice element and compare it to the tag
00615  *     * If no tag mathces, return `ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG`
00616  *     * Otherwise replace `desc` with the descriptor of the matching tag
00617  * * Get the tag for the current descriptor
00618  * * If the tag is not found
00619  *     * If it was optional, exit with success
00620  *     * Otherwise, exit with ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG
00621  * * If the descriptor ID matches the current extraction ID
00622  *     * Extract the value into the current buffer.
00623  *     * Advance the ID pointer, the buffer pointer, and decrement the value pointer.
00624  * * If the descriptor is a sequence with more than one child, recurse into it (single-child sequences are SEQUENCE OF)
00625  *     * For each child element,
00626  *         * If the end has been not reached or the child descriptor is mandatory
00627  *             * call `ARM_UC_mmDERGetValues` with the child descriptor.
00628  * * If the end does not match pos
00629  *     * fail with `ARM_UC_DP_ERR_ASN1_LENGTH_MISMATCH`
00630  * * Otherwise
00631  *     * Update the current position
00632  * * return success
00633  *
00634  * WARNING: ARM_UC_mmDERGetValues cannot resolve choices between two different sequences.
00635  *
00636  * NOTE: Choices are not currently returnable
00637  * NOTE: An optimization should be possible to reduce the parsing time by skipping elements whose descriptors do not
00638  *       contain the next requested element ID
00639  * NOTE: Length mismatch checking is not currently supported.
00640  *
00641  * To parse a SEQUENCE OF element, search for the SEQUENCE OF. Then, iterate through its elements with
00642  * `ARM_UC_mmDERGetSequenceElement`. With each element, call `ARM_UC_mmDERParseTree` with the descriptor for the
00643  * contents of the SEQUENCE OF.
00644  *
00645  * @param[in] desc Contains the current parsing descriptor
00646  * @param[in] pos Pointer to pointer that holds the current parsing location
00647  * @param[in] end Pointer to the end of the current element's container
00648  * @param[in,out] state Parser state. Contains the parser's
00649  * @retval ARM_UC_DP_ERR_ASN1_OUT_OF_DATA     The parser has run out of data before running out of descriptors
00650  * @retval ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG  The parser has encountered an encoding error, or unsupported DER document
00651  * @retval ARM_UC_DP_ERR_ASN1_LENGTH_MISMATCH The elements of the DER tree do not have consistent lengths.
00652  * @retval 0                                Success!
00653  */
00654 int32_t ARM_UC_mmDERGetValues(const struct arm_uc_mmDerElement *desc, uint8_t **pos, uint8_t *end,
00655                               struct ARM_UC_MM_DERParserState *state)
00656 {
00657     size_t len;
00658     int rc;
00659     uint8_t *ElementEnd;
00660     DER_PARSER_LOG_INDENT(DER_PARSER_LOG_LEVEL_DESCRIPTORS);
00661     DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_DESCRIPTORS, "%s", ARM_UC_mmDERDescID2Str(desc->id));
00662 
00663     // TODO: return a choice result when a choice ID is in the list.
00664     // Resolve the a choice. Cannot distinguish choices between two sequences.
00665     if (desc->tag == ARM_UC_MM_ASN1_CHOICE) {
00666         int tag;
00667         unsigned i;
00668         DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_DESCRIPTORS, "\n");
00669         // Get the tag of the next element and identify the descriptor that matches that tag.
00670         rc = ARM_UC_mmDERPeekTag(*pos, end, &tag);
00671         if (rc) {
00672             return rc;
00673         }
00674         rc = (ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG);
00675         arm_uc_mm_derRecurseDepth++;
00676         for (i = 0; i < desc->nSubElements; i++) {
00677             if (tag == desc->subElements[i].tag) {
00678                 // desc = &desc->subElements[i];
00679                 // rc = 0;
00680                 rc = ARM_UC_mmDERGetValues(&desc->subElements[i], pos, end, state);
00681                 break;
00682             } else {
00683                 DER_PARSER_LOG_INDENT(DER_PARSER_LOG_LEVEL_DESCRIPTORS);
00684                 DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_DESCRIPTORS, "%s (skipped)\n", ARM_UC_mmDERDescID2Str(desc->subElements[i].id));
00685             }
00686         }
00687         arm_uc_mm_derRecurseDepth--;
00688         // If the matching tag is not in one of the desctiptors, then a parse error has been encountered.
00689         // if (rc)
00690         return rc;
00691     }
00692     // Store the entry position for saving sequences
00693     uint8_t *seqpos = *pos;
00694     // Get the next tag & length, advancing the parse position to just after the tag/length pair.
00695     rc = ARM_UC_MM_ASN1_get_tag(pos, end, &len, desc->tag);
00696     // If an optional tag was expected, but not encountered, it is not an error unless it was requested by the user.
00697     if (rc == ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG && desc->optional && desc->id != (unsigned)(state->valueIDs[0])) {
00698         DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_DESCRIPTORS, " (skipped)\n");
00699         return 0;
00700     } // TODO evaluate length handling in ARM_UC_MM_ASN1_get_tag
00701     // If an error was encountered, abort.
00702     if (rc) {
00703         DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_DESCRIPTORS, " (error %d)\n", rc);
00704         return rc;
00705     }
00706     // If the encountered tag is one of the requested IDs, record its location and size, then move on to the next value
00707     if (desc->id == (unsigned)(state->valueIDs[0])) {
00708         // If the element is a sequence, store the whole element, not just the content.
00709         if (desc->tag == (ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE) && desc->nSubElements != 1) {
00710             state->buffers[0].ptr = seqpos;
00711             state->buffers[0].size = len + (*pos - seqpos);
00712             state->buffers[0].size_max = len + (*pos - seqpos);
00713         } else {
00714             state->buffers[0].ptr = *pos;
00715             state->buffers[0].size = len;
00716             state->buffers[0].size_max = len;
00717         }
00718         state->nValues--;
00719         state->valueIDs++;
00720         state->buffers++;
00721         DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_DESCRIPTORS, " (stored)\n");
00722     } else {
00723         DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_DESCRIPTORS, "\n");
00724     }
00725     DER_PARSER_LOG_INDENT(DER_PARSER_LOG_LEVEL_TAGS);
00726     DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_TAGS, "%02X", desc->tag);
00727     DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_SIZES, " %X", len);
00728     if (desc->tag != (ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE)) {
00729         DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_VALUES, " ");
00730         for (uint32_t i = 0; i < len; i++) {
00731             if (desc->tag == ARM_UC_MM_ASN1_UTF8_STRING) {
00732                 DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_VALUES, "%c", (char)(*pos)[i]);
00733             } else {
00734                 DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_VALUES, "%X", (*pos)[i]);
00735             }
00736         }
00737     }
00738     DER_PARSER_LOG(DER_PARSER_LOG_LEVEL_TAGS, "\n");
00739 
00740     // TODO: At this point, it should be possible to exit parsing of this element early if no requested ID is owned by
00741     // this element or one of its children.
00742 
00743     // Update the end of the current element to pos+len
00744     ElementEnd = *pos + len;
00745     // If the element is a sequence, parse the sequence.
00746     if (desc->tag == (ARM_UC_MM_ASN1_CONSTRUCTED | ARM_UC_MM_ASN1_SEQUENCE)) {
00747         /* Sequences with only a single element are treated as a SEQUENCE OF, which has special semantics. In order to
00748          * extract the contents of a SEQUENCE OF, the caller must request the SEQUENCE OF element ID, then use
00749          * ARM_UC_mmDERGetSequenceElement to extract the contents of the sequence, passing each one to
00750          * ARM_UC_mmDERParseTree in order to extract any */
00751         if (desc->nSubElements != 1) { // SEQUENCE
00752             int i;
00753             end = *pos + len;
00754             arm_uc_mm_derRecurseDepth++;
00755             for (i = 0; rc == 0 && state->nValues != 0 && i < desc->nSubElements; i++) {
00756                 // Escape if the end has been reached and the parsing elements are optional
00757                 if (!(*pos >= end && desc->subElements[i].optional)) {
00758                     // Parse a sub-tree
00759                     rc = ARM_UC_mmDERGetValues(&desc->subElements[i], pos, end, state);
00760                 }
00761             }
00762             arm_uc_mm_derRecurseDepth--;
00763         }
00764     }
00765 
00766     if (*pos > ElementEnd) { // TODO: Add length mismatch check
00767         // Fail if there is a length mismatch
00768         return ARM_UC_DP_ERR_ASN1_LENGTH_MISMATCH;
00769     } else {
00770         // Update the current parsing position
00771         *pos = ElementEnd;
00772     }
00773     return rc;
00774 }
00775 
00776 /**
00777  * @brief Extracts elements from an ASN.1 SEQUENCE OF by index
00778  * @details Parses a SEQUENCE OF element, skipping elements until it finds the requested element.
00779  * When the last element has been parsed, a further call to `ARM_UC_mmDERGetSequenceElement` will cause element to be
00780  * populated with a NULL buffer pointer and 0 length, but `ARM_UC_mmDERGetSequenceElement` will still return success.
00781  *
00782  * @param[in]  buffer  The data to parse
00783  * @param[in]  index   The element index to extract
00784  * @param[out] element The buffer to populate with the extracted element
00785  *
00786  * @retval ARM_UC_DP_ERR_ASN1_OUT_OF_DATA     The parser has run out of data before running out of descriptors
00787  * @retval ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG  The parser has encountered an encoding error, or unsupported DER document
00788  * @retval ARM_UC_DP_ERR_ASN1_LENGTH_MISMATCH The elements of the DER tree do not have consistent lengths.
00789  * @retval 0                                Success!
00790  */
00791 int32_t ARM_UC_mmDERGetSequenceElement(arm_uc_buffer_t *buffer, uint32_t index, arm_uc_buffer_t *element)
00792 {
00793     uint8_t *pos      = buffer->ptr;
00794     uint8_t *end      = pos + buffer->size;
00795     int rc            = 0;
00796     size_t len        = 0;
00797     element->ptr      = NULL;
00798     element->size     = 0;
00799     element->size_max = 0;
00800     for (; !rc; index--) {
00801         int tag;
00802         rc = ARM_UC_mmDERPeekTag(pos, end, &tag);
00803         if (rc) {
00804             // Peek-tag can only fail if pos >= end, so there was no element
00805             // This is not an error, since the parser may not know how many elements are in the sequence.
00806             return 0;
00807         }
00808         if (!index) {
00809             element->ptr = pos;
00810         }
00811         rc = ARM_UC_MM_ASN1_get_tag(&pos, end, &len, tag);
00812         if (!index && !rc) {
00813             element->size     = len + pos - element->ptr;
00814             element->size_max = element->size;
00815             break;
00816         }
00817         if (rc) {
00818             element->ptr = NULL;
00819             break;
00820         }
00821         pos += len;
00822     }
00823     return rc;
00824 }
00825 
00826 /**
00827  * @brief Parses a tree of DER data by calling `ARM_UC_mmDERGetValues`
00828  * @details Populates a parser state with the IDs to be extracted, the number of values and the buffers to extract into
00829  * @param[in]  desc     Contains the current parsing descriptor
00830  * @param[in]  buffer   The data to parse
00831  * @param[in]  nValues  The number of values to search for
00832  * @param[in]  valueIDs Array of value identifiers
00833  * @param[out] buffers  Array of buffers to populate with the elements matching valueIDs
00834  * @retval ARM_UC_DP_ERR_ASN1_OUT_OF_DATA     The parser has run out of data before running out of descriptors
00835  * @retval ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG  The parser has encountered an encoding error, or unsupported DER document
00836  * @retval ARM_UC_DP_ERR_ASN1_LENGTH_MISMATCH The elements of the DER tree do not have consistent lengths.
00837  * @retval 0                                Success!
00838  * @retval >0                               Number of remaining elements
00839  */
00840 int32_t ARM_UC_mmDERParseTree(const struct arm_uc_mmDerElement *desc, arm_uc_buffer_t *buffer, uint32_t nValues,
00841                               const int32_t *valueIDs, arm_uc_buffer_t *buffers)
00842 {
00843     uint8_t *pos = buffer->ptr;
00844     uint8_t *end = pos + buffer->size;
00845     struct ARM_UC_MM_DERParserState state = {
00846         nValues, valueIDs, buffers
00847     };
00848     arm_uc_mm_derRecurseDepth = 0;
00849     int32_t rc = ARM_UC_mmDERGetValues(desc, &pos, end, &state);
00850     // printf("Failed at: index %lu: %lu with return code: %ld\n", nValues-state.nValues, *state.valueIDs, rc);
00851     if (rc == 0 && state.nValues != 0) {
00852         return state.nValues;
00853     }
00854     return rc;
00855 }
00856 /**
00857  * @brief Parses a tree of DER data by calling `ARM_UC_mmDERGetValues`
00858  * @details Populates a parser state with the IDs to be extracted, the number of values and the buffers to extract into
00859  * Calls `ARM_UC_mmDERParseTree` with `SignedResource`
00860  * @param[in]  buffer   The data to parse
00861  * @param[in]  nValues  The number of values to search for
00862  * @param[in]  valueIDs Array of value identifiers
00863  * @param[out] buffers  Array of buffers to populate with the elements matching valueIDs
00864  * @retval ARM_UC_DP_ERR_ASN1_OUT_OF_DATA     The parser has run out of data before running out of descriptors
00865  * @retval ARM_UC_DP_ERR_ASN1_UNEXPECTED_TAG  The parser has encountered an encoding error, or unsupported DER document
00866  * @retval ARM_UC_DP_ERR_ASN1_LENGTH_MISMATCH The elements of the DER tree do not have consistent lengths.
00867  * @retval 0                                Success!
00868  * @retval >0                               Number of remaining elements
00869  */
00870 int32_t ARM_UC_mmDERGetSignedResourceValues(arm_uc_buffer_t *buffer, uint32_t nValues, const int32_t *valueIDs,
00871                                             arm_uc_buffer_t *buffers)
00872 {
00873     return ARM_UC_mmDERParseTree(&SignedResource, buffer, nValues, valueIDs, buffers);
00874 }