From c633c8239dd0e1482196aa4ea754cda14c571de1 Mon Sep 17 00:00:00 2001 From: Joakim Sindholt Date: Tue, 21 Feb 2023 11:43:00 +0100 Subject: [PATCH 1/2] pkcs7: add support for signed attributes --- include/mbedtls/oid.h | 1 + include/mbedtls/pkcs7.h | 2 + library/pkcs7.c | 150 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 152 insertions(+), 1 deletion(-) diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h index a592e63c4..7af50d93b 100644 --- a/include/mbedtls/oid.h +++ b/include/mbedtls/oid.h @@ -316,6 +316,7 @@ #define MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA MBEDTLS_OID_PKCS7 "\x04" /**< Content type is Signed and Enveloped Data OBJECT IDENTIFIER ::= {pkcs-7 4} */ #define MBEDTLS_OID_PKCS7_DIGESTED_DATA MBEDTLS_OID_PKCS7 "\x05" /**< Content type is Digested Data OBJECT IDENTIFIER ::= {pkcs-7 5} */ #define MBEDTLS_OID_PKCS7_ENCRYPTED_DATA MBEDTLS_OID_PKCS7 "\x06" /**< Content type is Encrypted Data OBJECT IDENTIFIER ::= {pkcs-7 6} */ +#define MBEDTLS_OID_PKCS9_MESSAGE_DIGEST MBEDTLS_OID_PKCS9 "\x04" /**< id-messageDigest OCTET STRING ::= {pkcs-9 4} */ /* * PKCS#8 OIDs diff --git a/include/mbedtls/pkcs7.h b/include/mbedtls/pkcs7.h index 5ddd5a3d7..45d77c76e 100644 --- a/include/mbedtls/pkcs7.h +++ b/include/mbedtls/pkcs7.h @@ -129,6 +129,8 @@ typedef struct mbedtls_pkcs7_signer_info { mbedtls_x509_name MBEDTLS_PRIVATE(issuer); mbedtls_x509_buf MBEDTLS_PRIVATE(issuer_raw); mbedtls_x509_buf MBEDTLS_PRIVATE(alg_identifier); + mbedtls_asn1_named_data MBEDTLS_PRIVATE(signed_attrs); + mbedtls_x509_buf MBEDTLS_PRIVATE(signed_attrs_raw); mbedtls_x509_buf MBEDTLS_PRIVATE(sig_alg_identifier); mbedtls_x509_buf MBEDTLS_PRIVATE(sig); struct mbedtls_pkcs7_signer_info *MBEDTLS_PRIVATE(next); diff --git a/library/pkcs7.c b/library/pkcs7.c index 4fdbe3628..32b7267b9 100644 --- a/library/pkcs7.c +++ b/library/pkcs7.c @@ -167,6 +167,91 @@ static int pkcs7_get_digest_algorithm_set(unsigned char **p, return 0; } +/** + * SignedAttributes ::= SET SIZE (1..MAX) OF Attribute + * + * Attribute ::= SEQUENCE { + * attrType OBJECT IDENTIFIER, + * attrValues SET OF AttributeValue } + **/ +static int pkcs7_get_signed_attrs(unsigned char **p, + unsigned char *end, + mbedtls_x509_buf *attrs_raw, + mbedtls_asn1_named_data *attrs) +{ + mbedtls_asn1_named_data *cur = attrs; + unsigned char *seq_end; + size_t len; + int ret = 0; + + attrs_raw->p = *p; + attrs_raw->len = 0; + + ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_CONTEXT_SPECIFIC); + if (ret != 0) { + *p = attrs_raw->p; + attrs_raw->p = NULL; + return 0; + } + end = *p + len; + + while (*p < end) { + ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SEQUENCE); + if (ret != 0) { + goto err; + } + seq_end = *p + len; + + ret = mbedtls_asn1_get_tag(p, seq_end, &len, MBEDTLS_ASN1_OID); + if (ret != 0) { + goto err; + } + cur->oid.p = *p; + cur->oid.len = len; + *p += len; + + ret = mbedtls_asn1_get_tag(p, seq_end, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SET); + if (ret != 0) { + goto err; + } + cur->val.tag = MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET; + cur->val.p = *p; + cur->val.len = len; + *p += len; + + if (*p != seq_end) { + ret = MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + goto err; + } + if (*p != end) { + cur->next = mbedtls_calloc(1, sizeof(*cur->next)); + if (cur->next == NULL) { + ret = MBEDTLS_ERR_PKCS7_ALLOC_FAILED; + goto err; + } + cur = cur->next; + } + } + + if (*p != end) { + ret = MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + goto err; + } + + attrs_raw->len = *p - attrs_raw->p; + + return 0; + +err: + mbedtls_asn1_free_named_data_list_shallow(attrs->next); + attrs->next = NULL; + + return ret; +} + /** * certificates :: SET OF ExtendedCertificateOrCertificate, * ExtendedCertificateOrCertificate ::= CHOICE { @@ -266,6 +351,9 @@ static void pkcs7_free_signer_info(mbedtls_pkcs7_signer_info *signer) mbedtls_free(name_prv); } signer->issuer.next = NULL; + + mbedtls_asn1_free_named_data_list_shallow(signer->signed_attrs.next); + signer->signed_attrs.next = NULL; } /** @@ -343,7 +431,11 @@ static int pkcs7_get_signer_info(unsigned char **p, unsigned char *end, goto out; } - /* Assume authenticatedAttributes is nonexistent */ + ret = pkcs7_get_signed_attrs(p, end_signer, &signer->signed_attrs_raw, + &signer->signed_attrs); + if (ret != 0) { + goto out; + } ret = pkcs7_get_digest_algorithm(p, end_signer, &signer->sig_alg_identifier); if (ret != 0) { @@ -631,6 +723,37 @@ out: return ret; } + +static int pkcs7_signed_attrs_match(mbedtls_asn1_named_data *attrs, + const unsigned char *hash, + size_t hashlen) +{ + mbedtls_asn1_named_data *attr; + unsigned char *p; + size_t len; + int has_digest = 0; + + for (attr = attrs; attr != NULL; attr = attr->next) { + if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS9_MESSAGE_DIGEST, &attr->oid) == 0) { + p = attr->val.p; + if (mbedtls_asn1_get_tag(&p, p + attr->val.len, &len, + MBEDTLS_ASN1_OCTET_STRING) != 0) { + return MBEDTLS_ERR_PKCS7_VERIFY_FAIL; + } + if (len != hashlen || memcmp(p, hash, hashlen) != 0) { + return MBEDTLS_ERR_PKCS7_VERIFY_FAIL; + } + has_digest = 1; + } + } + + if (!has_digest) { + return MBEDTLS_ERR_PKCS7_VERIFY_FAIL; + } + + return 0; +} + static int mbedtls_pkcs7_data_or_hash_verify(mbedtls_pkcs7 *pkcs7, const mbedtls_x509_crt *cert, const unsigned char *data, @@ -642,6 +765,7 @@ static int mbedtls_pkcs7_data_or_hash_verify(mbedtls_pkcs7 *pkcs7, mbedtls_pk_context pk_cxt = cert->pk; const mbedtls_md_info_t *md_info; mbedtls_md_type_t md_alg; + mbedtls_md_context_t md_ctx; mbedtls_pkcs7_signer_info *signer; if (pkcs7->signed_data.no_of_signers == 0) { @@ -699,6 +823,30 @@ static int mbedtls_pkcs7_data_or_hash_verify(mbedtls_pkcs7 *pkcs7, continue; } + if (signer->signed_attrs_raw.len > 0) + { + ret = pkcs7_signed_attrs_match(&signer->signed_attrs, hash, + mbedtls_md_get_size(md_info)); + if (ret != 0) { + mbedtls_free(hash); + continue; + } + + mbedtls_md_init(&md_ctx); + if (mbedtls_md_setup(&md_ctx, md_info, 0) != 0 || + mbedtls_md_starts(&md_ctx) != 0 || + mbedtls_md_update(&md_ctx, &(unsigned char){0x31}, 1) != 0 || + mbedtls_md_update(&md_ctx, signer->signed_attrs_raw.p + 1, + signer->signed_attrs_raw.len - 1) != 0 || + mbedtls_md_finish(&md_ctx, hash) != 0) { + mbedtls_md_free(&md_ctx); + mbedtls_free(hash); + ret = MBEDTLS_ERR_PKCS7_VERIFY_FAIL; + continue; + } + mbedtls_md_free(&md_ctx); + } + ret = mbedtls_pk_verify(&pk_cxt, md_alg, hash, mbedtls_md_get_size(md_info), signer->sig.p, signer->sig.len); -- 2.26.3