projects/linux/asn1/dme/x509_extension_builder_openssl_dme.c (165 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #include <stdlib.h> #include <stddef.h> #include <string.h> #include <openssl/asn1t.h> #include <openssl/err.h> #include <openssl/x509v3.h> #include "platform_api.h" #include "x509_extension_builder_openssl_dme.h" #include "asn1/x509_openssl.h" #include "asn1/dme/x509_extension_builder_dme.h" #include "common/unused.h" /** * Structure of the DME extension. */ typedef struct dme_extension_st { X509_PUBKEY *dme_key; /**< The DME public key for the device. */ ASN1_OBJECT *struct_format; /**< Format of the DME structure. */ ASN1_OCTET_STRING *dme_struct; /**< The DME structure data used for key endorsement. */ X509_ALGOR *sig_alg; /**< Algorithm used to generate signature for the DME structure. */ ASN1_BIT_STRING *signature; /**< Signature of the DME structure. */ ASN1_OBJECT *device_type; /**< Identifier for the type of device that generated the DME structure. */ ASN1_BIT_STRING *renewal_counter; /**< Current value of the renewal counter for the DME key. */ ASN1_ENCODING enc; /**< ASN1 encoding. */ } DME_EXTENSION; ASN1_SEQUENCE_enc (DME_EXTENSION, enc, 0) = { ASN1_SIMPLE (DME_EXTENSION, dme_key, X509_PUBKEY), ASN1_SIMPLE (DME_EXTENSION, struct_format, ASN1_OBJECT), ASN1_SIMPLE (DME_EXTENSION, dme_struct, ASN1_OCTET_STRING), ASN1_SIMPLE (DME_EXTENSION, sig_alg, X509_ALGOR), ASN1_SIMPLE (DME_EXTENSION, signature, ASN1_BIT_STRING), ASN1_IMP_OPT (DME_EXTENSION, device_type, ASN1_OBJECT, 0), ASN1_IMP_OPT (DME_EXTENSION, renewal_counter, ASN1_BIT_STRING, 1) } ASN1_SEQUENCE_END_enc (DME_EXTENSION, DME_EXTENSION) IMPLEMENT_ASN1_FUNCTIONS (DME_EXTENSION) int x509_extension_builder_openssl_dme_build (const struct x509_extension_builder *builder, struct x509_extension *extension) { const struct x509_extension_builder_openssl_dme *dme_build = (const struct x509_extension_builder_openssl_dme*) builder; DME_EXTENSION *dme_ext; EVP_PKEY *pubkey; ASN1_OBJECT *oid; int status; uint8_t *ext_der = NULL; int ext_der_len; if ((dme_build == NULL) || (extension == NULL)) { return DME_EXTENSION_INVALID_ARGUMENT; } if (dme_build->dme == NULL) { return DME_EXTENSION_INVALID_ARGUMENT; } if (dme_build->dme->data_oid == NULL) { return DME_EXTENSION_NO_TYPE_OID; } if (dme_build->dme->data == NULL) { return DME_EXTENSION_NO_DATA; } if (dme_build->dme->sig_oid == NULL) { return DME_EXTENSION_NO_SIG_TYPE_OID; } if (dme_build->dme->signature == NULL) { return DME_EXTENSION_NO_SIGNATURE; } if (dme_build->dme->dme_pub_key == NULL) { return DME_EXTENSION_NO_DME_KEY; } dme_ext = DME_EXTENSION_new (); if (dme_ext == NULL) { status = -ERR_get_error (); goto err_ext; } pubkey = d2i_PUBKEY (NULL, (const uint8_t**) &dme_build->dme->dme_pub_key, dme_build->dme->key_length); if (pubkey == NULL) { status = -ERR_get_error (); goto err_build; } status = X509_PUBKEY_set (&dme_ext->dme_key, pubkey); EVP_PKEY_free (pubkey); if (status == 0) { status = -ERR_get_error (); goto err_build; } status = x509_openssl_parse_encoded_oid (dme_build->dme->data_oid, dme_build->dme->data_oid_length, &oid); if (status != 0) { goto err_build; } ASN1_OBJECT_free (dme_ext->struct_format); dme_ext->struct_format = oid; status = ASN1_OCTET_STRING_set (dme_ext->dme_struct, dme_build->dme->data, dme_build->dme->data_length); if (status == 0) { status = -ERR_get_error (); goto err_build; } status = x509_openssl_parse_encoded_oid (dme_build->dme->sig_oid, dme_build->dme->sig_oid_length, &oid); if (status != 0) { goto err_build; } status = X509_ALGOR_set0 (dme_ext->sig_alg, oid, V_ASN1_UNDEF, NULL); if (status == 0) { status = -ERR_get_error (); ASN1_OBJECT_free (oid); goto err_build; } status = x509_openssl_set_bit_string (dme_build->dme->signature, dme_build->dme->signature_length, dme_ext->signature); if (status != 0) { goto err_build; } if (dme_build->dme->device_oid != NULL) { status = x509_openssl_parse_encoded_oid (dme_build->dme->device_oid, dme_build->dme->dev_oid_length, &dme_ext->device_type); if (status != 0) { goto err_build; } } if (dme_build->dme->renewal_counter != NULL) { dme_ext->renewal_counter = ASN1_BIT_STRING_new (); if (dme_ext->renewal_counter == NULL) { status = DME_EXTENSION_NO_MEMORY; goto err_build; } status = x509_openssl_set_bit_string (dme_build->dme->renewal_counter, dme_build->dme->counter_length, dme_ext->renewal_counter); if (status != 0) { goto err_build; } } ext_der_len = i2d_DME_EXTENSION (dme_ext, &ext_der); if (ext_der_len < 0) { status = -ERR_get_error (); goto err_build; } x509_extension_builder_init_extension_descriptor (extension, false, X509_EXTENSION_BUILDER_DME_OID, X509_EXTENSION_BUILDER_DME_OID_LENGTH, ext_der, ext_der_len); status = 0; err_build: DME_EXTENSION_free (dme_ext); err_ext: return status; } void x509_extension_builder_openssl_dme_free (const struct x509_extension_builder *builder, struct x509_extension *extension) { UNUSED (builder); platform_free ((void*) extension->data); } /** * Initialize an extension builder for a DME extension. * * @param builder The extension builder to initialize. * @param dme The DME structure to encode in the extension. This does not need to be constant. The * contents can be externally modified after initialization to change what will be encoded in the * extension. * * @return 0 if the extension builder was initialized successfully or an error code. */ int x509_extension_builder_openssl_dme_init (struct x509_extension_builder_openssl_dme *builder, const struct dme_structure *dme) { if ((builder == NULL) || (dme == NULL)) { return DME_EXTENSION_INVALID_ARGUMENT; } memset (builder, 0, sizeof (struct x509_extension_builder_openssl_dme)); builder->base.build = x509_extension_builder_openssl_dme_build; builder->base.free = x509_extension_builder_openssl_dme_free; builder->dme = dme; return 0; } /** * Release the resources used by a DME extension builder. * * @param builder The extension builder to release. */ void x509_extension_builder_openssl_dme_release ( const struct x509_extension_builder_openssl_dme *builder) { UNUSED (builder); }