From: James Bottomley Signers may add any information they like in signed attributes and sometimes this information turns out to be relevant to specific signing cases, so add an api pkcs7_get_authattr() to extract the value of an authenticated attribute by specific OID. The current implementation is designed for the single signer use case and simply terminates the search when it finds the relevant OID. Signed-off-by: James Bottomley --- crypto/asymmetric_keys/Makefile | 4 +- crypto/asymmetric_keys/pkcs7_aa.asn1 | 18 ++++++ crypto/asymmetric_keys/pkcs7_parser.c | 81 +++++++++++++++++++++++++++ include/crypto/pkcs7.h | 4 ++ 4 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 crypto/asymmetric_keys/pkcs7_aa.asn1 diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index bc65d3b98dcb..f99b7169ae7c 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile @@ -53,12 +53,14 @@ clean-files += pkcs8.asn1.c pkcs8.asn1.h obj-$(CONFIG_PKCS7_MESSAGE_PARSER) += pkcs7_message.o pkcs7_message-y := \ pkcs7.asn1.o \ + pkcs7_aa.asn1.o \ pkcs7_parser.o \ pkcs7_trust.o \ pkcs7_verify.o -$(obj)/pkcs7_parser.o: $(obj)/pkcs7.asn1.h +$(obj)/pkcs7_parser.o: $(obj)/pkcs7.asn1.h $(obj)/pkcs7_aa.asn1.h $(obj)/pkcs7.asn1.o: $(obj)/pkcs7.asn1.c $(obj)/pkcs7.asn1.h +$(obj)/pkcs7_aa.asn1.o: $(obj)/pkcs7_aa.asn1.c $(obj)/pkcs7_aa.asn1.h # # PKCS#7 parser testing key diff --git a/crypto/asymmetric_keys/pkcs7_aa.asn1 b/crypto/asymmetric_keys/pkcs7_aa.asn1 new file mode 100644 index 000000000000..7a8857bdf56e --- /dev/null +++ b/crypto/asymmetric_keys/pkcs7_aa.asn1 @@ -0,0 +1,18 @@ +-- SPDX-License-Identifier: BSD-3-Clause +-- +-- Copyright (C) 2009 IETF Trust and the persons identified as authors +-- of the code +-- +-- https://www.rfc-editor.org/rfc/rfc5652#section-3 + +AA ::= CHOICE { + aaSet [0] IMPLICIT AASet, + aaSequence [2] EXPLICIT SEQUENCE OF AuthenticatedAttribute +} + +AASet ::= SET OF AuthenticatedAttribute + +AuthenticatedAttribute ::= SEQUENCE { + type OBJECT IDENTIFIER ({ pkcs7_aa_note_OID }), + values SET OF ANY ({ pkcs7_aa_note_attr }) +} diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c index 6e3ffdac83ac..d467866f7d93 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c @@ -15,6 +15,7 @@ #include #include "pkcs7_parser.h" #include "pkcs7.asn1.h" +#include "pkcs7_aa.asn1.h" MODULE_DESCRIPTION("PKCS#7 parser"); MODULE_AUTHOR("Red Hat, Inc."); @@ -211,6 +212,86 @@ int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, } EXPORT_SYMBOL_GPL(pkcs7_get_content_data); +struct pkcs7_aa_context { + bool found; + enum OID oid_to_find; + const void *data; + size_t len; +}; + +int pkcs7_aa_note_OID(void *context, size_t hdrlen, + unsigned char tag, + const void *value, size_t vlen) +{ + struct pkcs7_aa_context *ctx = context; + enum OID oid = look_up_OID(value, vlen); + + ctx->found = (oid == ctx->oid_to_find); + + return 0; +} + +int pkcs7_aa_note_attr(void *context, size_t hdrlen, + unsigned char tag, + const void *value, size_t vlen) +{ + struct pkcs7_aa_context *ctx = context; + + if (ctx->found) { + ctx->data = value; + ctx->len = vlen; + } + + return 0; +} + +/** + * pkcs7_get_authattr - get authenticated attribute by OID + * @pkcs7: The preparsed PKCS#7 message + * @oid: the enum value of the OID to find + * @_data: Place to return a pointer to the attribute value + * @_len: length of the attribute value + * + * Searches the authenticated attributes until one is found with a + * matching OID. Note that because the attributes are per signer + * there could be multiple signers with different values, but this + * routine will simply return the first one in parse order. + * + * Returns -ENODATA if the attribute can't be found + */ +int pkcs7_get_authattr(const struct pkcs7_message *pkcs7, + enum OID oid, + const void **_data, size_t *_len) +{ + struct pkcs7_signed_info *sinfo = pkcs7->signed_infos; + struct pkcs7_aa_context ctx; + + ctx.data = NULL; + ctx.oid_to_find = oid; + + for (; sinfo; sinfo = sinfo->next) { + int ret; + + /* only extract OIDs from validated signers */ + if (!sinfo->verified) + continue; + + ret = asn1_ber_decoder(&pkcs7_aa_decoder, &ctx, + sinfo->authattrs, sinfo->authattrs_len); + if (ret < 0 || ctx.data != NULL) + break; + } + + if (!ctx.data) + return -ENODATA; + + *_data = ctx.data; + *_len = ctx.len; + + return 0; +} +EXPORT_SYMBOL_GPL(pkcs7_get_authattr); + /* * Note an OID when we find one for later processing when we know how * to interpret it. diff --git a/include/crypto/pkcs7.h b/include/crypto/pkcs7.h index 38ec7f5f9041..bd83202cd805 100644 --- a/include/crypto/pkcs7.h +++ b/include/crypto/pkcs7.h @@ -25,6 +25,10 @@ extern void pkcs7_free_message(struct pkcs7_message *pkcs7); extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7, const void **_data, size_t *_datalen, size_t *_headerlen); +extern int pkcs7_get_authattr(const struct pkcs7_message *pkcs7, + enum OID oid, + const void **_data, size_t *_len); + /* * pkcs7_trust.c -- 2.52.0