diff --git a/crypto/x509/build.info b/crypto/x509/build.info index 62e701dd5e..204239f838 100644 --- a/crypto/x509/build.info +++ b/crypto/x509/build.info @@ -18,7 +18,7 @@ SOURCE[../../libcrypto]=\ v3_soa_id.c v3_no_ass.c v3_group_ac.c v3_single_use.c v3_ind_iss.c \ x509_acert.c x509aset.c t_acert.c x_ietfatt.c v3_ac_tgt.c v3_sda.c \ v3_usernotice.c v3_battcons.c v3_audit_id.c v3_iobo.c v3_authattid.c \ - v3_rolespec.c v3_attrdesc.c v3_timespec.c + v3_rolespec.c v3_attrdesc.c v3_timespec.c v3_attrmap.c IF[{- !$disabled{'deprecated-3.0'} -}] SOURCE[../../libcrypto]=x509type.c diff --git a/crypto/x509/ext_dat.h b/crypto/x509/ext_dat.h index efe8abb104..d1ec387793 100644 --- a/crypto/x509/ext_dat.h +++ b/crypto/x509/ext_dat.h @@ -46,3 +46,4 @@ extern const X509V3_EXT_METHOD ossl_v3_authority_attribute_identifier; extern const X509V3_EXT_METHOD ossl_v3_role_spec_cert_identifier; extern const X509V3_EXT_METHOD ossl_v3_attribute_descriptor; extern const X509V3_EXT_METHOD ossl_v3_time_specification; +extern const X509V3_EXT_METHOD ossl_v3_attribute_mappings; diff --git a/crypto/x509/standard_exts.h b/crypto/x509/standard_exts.h index 4ed059bd61..9bf6a77d81 100644 --- a/crypto/x509/standard_exts.h +++ b/crypto/x509/standard_exts.h @@ -91,6 +91,7 @@ static const X509V3_EXT_METHOD *standard_exts[] = { &ossl_v3_issued_on_behalf_of, &ossl_v3_single_use, &ossl_v3_group_ac, + &ossl_v3_attribute_mappings, &ossl_v3_holder_name_constraints, &ossl_v3_associated_info, }; diff --git a/crypto/x509/v3_attrmap.c b/crypto/x509/v3_attrmap.c new file mode 100644 index 0000000000..a01e6556ea --- /dev/null +++ b/crypto/x509/v3_attrmap.c @@ -0,0 +1,117 @@ +/* + * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include "ext_dat.h" + +ASN1_SEQUENCE(OSSL_ATAV) = { + ASN1_SIMPLE(OSSL_ATAV, type, ASN1_OBJECT), + ASN1_SIMPLE(OSSL_ATAV, value, ASN1_ANY) +} ASN1_SEQUENCE_END(OSSL_ATAV) + +ASN1_SEQUENCE(OSSL_ATTRIBUTE_TYPE_MAPPING) = { + ASN1_IMP(OSSL_ATTRIBUTE_TYPE_MAPPING, local, ASN1_OBJECT, 0), + ASN1_IMP(OSSL_ATTRIBUTE_TYPE_MAPPING, remote, ASN1_OBJECT, 1), +} ASN1_SEQUENCE_END(OSSL_ATTRIBUTE_TYPE_MAPPING) + +ASN1_SEQUENCE(OSSL_ATTRIBUTE_VALUE_MAPPING) = { + ASN1_IMP(OSSL_ATTRIBUTE_VALUE_MAPPING, local, OSSL_ATAV, 0), + ASN1_IMP(OSSL_ATTRIBUTE_VALUE_MAPPING, remote, OSSL_ATAV, 1), +} ASN1_SEQUENCE_END(OSSL_ATTRIBUTE_VALUE_MAPPING) + +ASN1_CHOICE(OSSL_ATTRIBUTE_MAPPING) = { + ASN1_IMP(OSSL_ATTRIBUTE_MAPPING, choice.typeMappings, + OSSL_ATTRIBUTE_TYPE_MAPPING, OSSL_ATTR_MAP_TYPE), + ASN1_IMP(OSSL_ATTRIBUTE_MAPPING, choice.typeValueMappings, + OSSL_ATTRIBUTE_VALUE_MAPPING, OSSL_ATTR_MAP_VALUE), +} ASN1_CHOICE_END(OSSL_ATTRIBUTE_MAPPING) + +ASN1_ITEM_TEMPLATE(OSSL_ATTRIBUTE_MAPPINGS) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0, OSSL_ATTRIBUTE_MAPPINGS, OSSL_ATTRIBUTE_MAPPING) +ASN1_ITEM_TEMPLATE_END(OSSL_ATTRIBUTE_MAPPINGS) + +IMPLEMENT_ASN1_FUNCTIONS(OSSL_ATAV) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_ATTRIBUTE_TYPE_MAPPING) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_ATTRIBUTE_VALUE_MAPPING) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_ATTRIBUTE_MAPPING) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_ATTRIBUTE_MAPPINGS) + +static int i2r_ATTRIBUTE_MAPPING(X509V3_EXT_METHOD *method, + OSSL_ATTRIBUTE_MAPPING *am, + BIO *out, int indent) +{ + ASN1_OBJECT *local_type, *remote_type; + int local_attr_nid, remote_attr_nid; + ASN1_TYPE *local_val, *remote_val; + + switch (am->type) { + case (OSSL_ATTR_MAP_TYPE): + if (i2a_ASN1_OBJECT(out, am->choice.typeMappings->local) <= 0) + return 0; + if (BIO_puts(out, " == ") <= 0) + return 0; + return i2a_ASN1_OBJECT(out, am->choice.typeMappings->remote); + case (OSSL_ATTR_MAP_VALUE): + local_type = am->choice.typeValueMappings->local->type; + remote_type = am->choice.typeValueMappings->remote->type; + local_val = am->choice.typeValueMappings->local->value; + remote_val = am->choice.typeValueMappings->remote->value; + local_attr_nid = OBJ_obj2nid(local_type); + remote_attr_nid = OBJ_obj2nid(remote_type); + if (i2a_ASN1_OBJECT(out, local_type) <= 0) + return 0; + if (BIO_puts(out, ":") <= 0) + return 0; + if (ossl_print_attribute_value(out, local_attr_nid, local_val, 0) <= 0) + return 0; + if (BIO_puts(out, " == ") <= 0) + return 0; + if (i2a_ASN1_OBJECT(out, remote_type) <= 0) + return 0; + if (BIO_puts(out, ":") <= 0) + return 0; + return ossl_print_attribute_value(out, remote_attr_nid, remote_val, 0); + default: + return 0; + } + return 1; +} + +static int i2r_ATTRIBUTE_MAPPINGS(X509V3_EXT_METHOD *method, + OSSL_ATTRIBUTE_MAPPINGS *ams, + BIO *out, int indent) +{ + int i; + OSSL_ATTRIBUTE_MAPPING *am; + + for (i = 0; i < sk_OSSL_ATTRIBUTE_MAPPING_num(ams); i++) { + am = sk_OSSL_ATTRIBUTE_MAPPING_value(ams, i); + if (BIO_printf(out, "%*s", indent, "") <= 0) + return 0; + if (i2r_ATTRIBUTE_MAPPING(method, am, out, indent + 4) <= 0) + return 0; + if (BIO_puts(out, "\n") <= 0) + return 0; + } + return 1; +} + +const X509V3_EXT_METHOD ossl_v3_attribute_mappings = { + NID_attribute_mappings, X509V3_EXT_MULTILINE, + ASN1_ITEM_ref(OSSL_ATTRIBUTE_MAPPINGS), + 0, 0, 0, 0, + 0, 0, + 0, + 0, + (X509V3_EXT_I2R)i2r_ATTRIBUTE_MAPPINGS, + 0, + NULL +}; diff --git a/include/openssl/x509v3.h.in b/include/openssl/x509v3.h.in index 557054c630..dd23a11420 100644 --- a/include/openssl/x509v3.h.in +++ b/include/openssl/x509v3.h.in @@ -1278,6 +1278,44 @@ DECLARE_ASN1_FUNCTIONS(OSSL_TIME_PERIOD) generate_stack_macros("OSSL_DAY_TIME_BAND"); -} +/* Attribute Type and Value */ +typedef struct atav_st { + ASN1_OBJECT *type; + ASN1_TYPE *value; +} OSSL_ATAV; + +typedef struct ATTRIBUTE_TYPE_MAPPING_st { + ASN1_OBJECT *local; + ASN1_OBJECT *remote; +} OSSL_ATTRIBUTE_TYPE_MAPPING; + +typedef struct ATTRIBUTE_VALUE_MAPPING_st { + OSSL_ATAV *local; + OSSL_ATAV *remote; +} OSSL_ATTRIBUTE_VALUE_MAPPING; + +# define OSSL_ATTR_MAP_TYPE 0 +# define OSSL_ATTR_MAP_VALUE 1 + +typedef struct ATTRIBUTE_MAPPING_st { + int type; + union { + OSSL_ATTRIBUTE_TYPE_MAPPING *typeMappings; + OSSL_ATTRIBUTE_VALUE_MAPPING *typeValueMappings; + } choice; +} OSSL_ATTRIBUTE_MAPPING; + +typedef STACK_OF(OSSL_ATTRIBUTE_MAPPING) OSSL_ATTRIBUTE_MAPPINGS; +DECLARE_ASN1_FUNCTIONS(OSSL_ATAV) +DECLARE_ASN1_FUNCTIONS(OSSL_ATTRIBUTE_TYPE_MAPPING) +DECLARE_ASN1_FUNCTIONS(OSSL_ATTRIBUTE_VALUE_MAPPING) +DECLARE_ASN1_FUNCTIONS(OSSL_ATTRIBUTE_MAPPING) +DECLARE_ASN1_FUNCTIONS(OSSL_ATTRIBUTE_MAPPINGS) + +{- + generate_stack_macros("OSSL_ATTRIBUTE_MAPPING"); +-} + # ifdef __cplusplus } # endif diff --git a/util/libcrypto.num b/util/libcrypto.num index 663fbfbbaf..8da730bb69 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5836,3 +5836,28 @@ EVP_CipherPipelineEncryptInit ? 3_5_0 EXIST::FUNCTION: EVP_CipherPipelineDecryptInit ? 3_5_0 EXIST::FUNCTION: EVP_CipherPipelineUpdate ? 3_5_0 EXIST::FUNCTION: EVP_CipherPipelineFinal ? 3_5_0 EXIST::FUNCTION: +d2i_OSSL_ATTRIBUTE_TYPE_MAPPING ? 3_5_0 EXIST::FUNCTION: +i2d_OSSL_ATTRIBUTE_TYPE_MAPPING ? 3_5_0 EXIST::FUNCTION: +OSSL_ATTRIBUTE_TYPE_MAPPING_free ? 3_5_0 EXIST::FUNCTION: +OSSL_ATTRIBUTE_TYPE_MAPPING_new ? 3_5_0 EXIST::FUNCTION: +OSSL_ATTRIBUTE_TYPE_MAPPING_it ? 3_5_0 EXIST::FUNCTION: +d2i_OSSL_ATTRIBUTE_VALUE_MAPPING ? 3_5_0 EXIST::FUNCTION: +i2d_OSSL_ATTRIBUTE_VALUE_MAPPING ? 3_5_0 EXIST::FUNCTION: +OSSL_ATTRIBUTE_VALUE_MAPPING_free ? 3_5_0 EXIST::FUNCTION: +OSSL_ATTRIBUTE_VALUE_MAPPING_new ? 3_5_0 EXIST::FUNCTION: +OSSL_ATTRIBUTE_VALUE_MAPPING_it ? 3_5_0 EXIST::FUNCTION: +d2i_OSSL_ATTRIBUTE_MAPPING ? 3_5_0 EXIST::FUNCTION: +i2d_OSSL_ATTRIBUTE_MAPPING ? 3_5_0 EXIST::FUNCTION: +OSSL_ATTRIBUTE_MAPPING_free ? 3_5_0 EXIST::FUNCTION: +OSSL_ATTRIBUTE_MAPPING_new ? 3_5_0 EXIST::FUNCTION: +OSSL_ATTRIBUTE_MAPPING_it ? 3_5_0 EXIST::FUNCTION: +d2i_OSSL_ATTRIBUTE_MAPPINGS ? 3_5_0 EXIST::FUNCTION: +i2d_OSSL_ATTRIBUTE_MAPPINGS ? 3_5_0 EXIST::FUNCTION: +OSSL_ATTRIBUTE_MAPPINGS_free ? 3_5_0 EXIST::FUNCTION: +OSSL_ATTRIBUTE_MAPPINGS_new ? 3_5_0 EXIST::FUNCTION: +OSSL_ATTRIBUTE_MAPPINGS_it ? 3_5_0 EXIST::FUNCTION: +d2i_OSSL_ATAV ? 3_5_0 EXIST::FUNCTION: +i2d_OSSL_ATAV ? 3_5_0 EXIST::FUNCTION: +OSSL_ATAV_free ? 3_5_0 EXIST::FUNCTION: +OSSL_ATAV_new ? 3_5_0 EXIST::FUNCTION: +OSSL_ATAV_it ? 3_5_0 EXIST::FUNCTION: