// SPDX-License-Identifier: GPL-2.0-or-later /* PKCS#7 parser * * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com)
*/
MODULE_DESCRIPTION("PKCS#7 parser");
MODULE_AUTHOR("Red Hat, Inc.");
MODULE_LICENSE("GPL");
struct pkcs7_parse_context { struct pkcs7_message *msg; /* Message being constructed */ struct pkcs7_signed_info *sinfo; /* SignedInfo being constructed */ struct pkcs7_signed_info **ppsinfo; struct x509_certificate *certs; /* Certificate cache */ struct x509_certificate **ppcerts; unsignedlong data; /* Start of data */ enum OID last_oid; /* Last OID encountered */ unsigned x509_index; unsigned sinfo_index; constvoid *raw_serial; unsigned raw_serial_size; unsigned raw_issuer_size; constvoid *raw_issuer; constvoid *raw_skid; unsigned raw_skid_size; bool expect_skid;
};
/* * Free a signed information block.
*/ staticvoid pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
{ if (sinfo) {
public_key_signature_free(sinfo->sig);
kfree(sinfo);
}
}
/** * pkcs7_free_message - Free a PKCS#7 message * @pkcs7: The PKCS#7 message to free
*/ void pkcs7_free_message(struct pkcs7_message *pkcs7)
{ struct x509_certificate *cert; struct pkcs7_signed_info *sinfo;
if (pkcs7) { while (pkcs7->certs) {
cert = pkcs7->certs;
pkcs7->certs = cert->next;
x509_free_certificate(cert);
} while (pkcs7->crl) {
cert = pkcs7->crl;
pkcs7->crl = cert->next;
x509_free_certificate(cert);
} while (pkcs7->signed_infos) {
sinfo = pkcs7->signed_infos;
pkcs7->signed_infos = sinfo->next;
pkcs7_free_signed_info(sinfo);
}
kfree(pkcs7);
}
}
EXPORT_SYMBOL_GPL(pkcs7_free_message);
/* * Check authenticatedAttributes are provided or not provided consistently.
*/ staticint pkcs7_check_authattrs(struct pkcs7_message *msg)
{ struct pkcs7_signed_info *sinfo; bool want = false;
sinfo = msg->signed_infos; if (!sinfo) goto inconsistent;
if (sinfo->authattrs) {
want = true;
msg->have_authattrs = true;
}
for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next) if (!!sinfo->authattrs != want) goto inconsistent; return 0;
/** * pkcs7_parse_message - Parse a PKCS#7 message * @data: The raw binary ASN.1 encoded message to be parsed * @datalen: The size of the encoded message
*/ struct pkcs7_message *pkcs7_parse_message(constvoid *data, size_t datalen)
{ struct pkcs7_parse_context *ctx; struct pkcs7_message *msg = ERR_PTR(-ENOMEM); int ret;
ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL); if (!ctx) goto out_no_ctx;
ctx->msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL); if (!ctx->msg) goto out_no_msg;
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL); if (!ctx->sinfo) goto out_no_sinfo;
ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
GFP_KERNEL); if (!ctx->sinfo->sig) goto out_no_sig;
/** * pkcs7_get_content_data - Get access to the PKCS#7 content * @pkcs7: The preparsed PKCS#7 message to access * @_data: Place to return a pointer to the data * @_data_len: Place to return the data length * @_headerlen: Size of ASN.1 header not included in _data * * Get access to the data content of the PKCS#7 message. The size of the * header of the ASN.1 object that contains it is also provided and can be used * to adjust *_data and *_data_len to get the entire object. * * Returns -ENODATA if the data object was missing from the message.
*/ int pkcs7_get_content_data(conststruct pkcs7_message *pkcs7, constvoid **_data, size_t *_data_len,
size_t *_headerlen)
{ if (!pkcs7->data) return -ENODATA;
/* * Note an OID when we find one for later processing when we know how * to interpret it.
*/ int pkcs7_note_OID(void *context, size_t hdrlen, unsignedchar tag, constvoid *value, size_t vlen)
{ struct pkcs7_parse_context *ctx = context;
/* * Note the digest algorithm for the signature.
*/ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen, unsignedchar tag, constvoid *value, size_t vlen)
{ struct pkcs7_parse_context *ctx = context;
switch (ctx->last_oid) { case OID_sha1:
ctx->sinfo->sig->hash_algo = "sha1"; break; case OID_sha256:
ctx->sinfo->sig->hash_algo = "sha256"; break; case OID_sha384:
ctx->sinfo->sig->hash_algo = "sha384"; break; case OID_sha512:
ctx->sinfo->sig->hash_algo = "sha512"; break; case OID_sha224:
ctx->sinfo->sig->hash_algo = "sha224"; break; case OID_sm3:
ctx->sinfo->sig->hash_algo = "sm3"; break; case OID_gost2012Digest256:
ctx->sinfo->sig->hash_algo = "streebog256"; break; case OID_gost2012Digest512:
ctx->sinfo->sig->hash_algo = "streebog512"; break; case OID_sha3_256:
ctx->sinfo->sig->hash_algo = "sha3-256"; break; case OID_sha3_384:
ctx->sinfo->sig->hash_algo = "sha3-384"; break; case OID_sha3_512:
ctx->sinfo->sig->hash_algo = "sha3-512"; break; default:
printk("Unsupported digest algo: %u\n", ctx->last_oid); return -ENOPKG;
} return 0;
}
/* * Note the public key algorithm for the signature.
*/ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen, unsignedchar tag, constvoid *value, size_t vlen)
{ struct pkcs7_parse_context *ctx = context;
switch (ctx->last_oid) { case OID_rsaEncryption:
ctx->sinfo->sig->pkey_algo = "rsa";
ctx->sinfo->sig->encoding = "pkcs1"; break; case OID_id_ecdsa_with_sha1: case OID_id_ecdsa_with_sha224: case OID_id_ecdsa_with_sha256: case OID_id_ecdsa_with_sha384: case OID_id_ecdsa_with_sha512: case OID_id_ecdsa_with_sha3_256: case OID_id_ecdsa_with_sha3_384: case OID_id_ecdsa_with_sha3_512:
ctx->sinfo->sig->pkey_algo = "ecdsa";
ctx->sinfo->sig->encoding = "x962"; break; case OID_gost2012PKey256: case OID_gost2012PKey512:
ctx->sinfo->sig->pkey_algo = "ecrdsa";
ctx->sinfo->sig->encoding = "raw"; break; default:
printk("Unsupported pkey algo: %u\n", ctx->last_oid); return -ENOPKG;
} return 0;
}
/* * We only support signed data [RFC2315 sec 9].
*/ int pkcs7_check_content_type(void *context, size_t hdrlen, unsignedchar tag, constvoid *value, size_t vlen)
{ struct pkcs7_parse_context *ctx = context;
if (ctx->last_oid != OID_signed_data) {
pr_warn("Only support pkcs7_signedData type\n"); return -EINVAL;
}
return 0;
}
/* * Note the SignedData version
*/ int pkcs7_note_signeddata_version(void *context, size_t hdrlen, unsignedchar tag, constvoid *value, size_t vlen)
{ struct pkcs7_parse_context *ctx = context; unsigned version;
if (vlen != 1) goto unsupported;
ctx->msg->version = version = *(const u8 *)value; switch (version) { case 1: /* PKCS#7 SignedData [RFC2315 sec 9.1] * CMS ver 1 SignedData [RFC5652 sec 5.1]
*/ break; case 3: /* CMS ver 3 SignedData [RFC2315 sec 5.1] */ break; default: goto unsupported;
}
/* * Extract a certificate and store it in the context.
*/ int pkcs7_extract_cert(void *context, size_t hdrlen, unsignedchar tag, constvoid *value, size_t vlen)
{ struct pkcs7_parse_context *ctx = context; struct x509_certificate *x509;
if (tag != ((ASN1_UNIV << 6) | ASN1_CONS_BIT | ASN1_SEQ)) {
pr_debug("Cert began with tag %02x at %lu\n",
tag, (unsignedlong)ctx - ctx->data); return -EBADMSG;
}
/* We have to correct for the header so that the X.509 parser can start * from the beginning. Note that since X.509 stipulates DER, there * probably shouldn't be an EOC trailer - but it is in PKCS#7 (which * stipulates BER).
*/
value -= hdrlen;
vlen += hdrlen;
if (((u8*)value)[1] == 0x80)
vlen += 2; /* Indefinite length - there should be an EOC */
x509 = x509_cert_parse(value, vlen); if (IS_ERR(x509)) return PTR_ERR(x509);
if (ctx->last_oid != OID_data &&
ctx->last_oid != OID_msIndirectData) {
pr_warn("Unsupported data type %d\n", ctx->last_oid); return -EINVAL;
}
ctx->msg->data_type = ctx->last_oid; return 0;
}
/* * Extract the data from the message and store that and its content type OID in * the context.
*/ int pkcs7_note_data(void *context, size_t hdrlen, unsignedchar tag, constvoid *value, size_t vlen)
{ struct pkcs7_parse_context *ctx = context;
switch (ctx->last_oid) { case OID_contentType: if (__test_and_set_bit(sinfo_has_content_type, &sinfo->aa_set)) goto repeated;
content_type = look_up_OID(value, vlen); if (content_type != ctx->msg->data_type) {
pr_warn("Mismatch between global data type (%d) and sinfo %u (%d)\n",
ctx->msg->data_type, sinfo->index,
content_type); return -EBADMSG;
} return 0;
case OID_signingTime: if (__test_and_set_bit(sinfo_has_signing_time, &sinfo->aa_set)) goto repeated; /* Should we check that the signing time is consistent * with the signer's X.509 cert?
*/ return x509_decode_time(&sinfo->signing_time,
hdrlen, tag, value, vlen);
case OID_messageDigest: if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set)) goto repeated; if (tag != ASN1_OTS) return -EBADMSG;
sinfo->msgdigest = value;
sinfo->msgdigest_len = vlen; return 0;
case OID_smimeCapabilites: if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set)) goto repeated; if (ctx->msg->data_type != OID_msIndirectData) {
pr_warn("S/MIME Caps only allowed with Authenticode\n"); return -EKEYREJECTED;
} return 0;
/* Microsoft SpOpusInfo seems to be contain cont[0] 16-bit BE * char URLs and cont[1] 8-bit char URLs. * * Microsoft StatementType seems to contain a list of OIDs that * are also used as extendedKeyUsage types in X.509 certs.
*/ case OID_msSpOpusInfo: if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) goto repeated; goto authenticode_check; case OID_msStatementType: if (__test_and_set_bit(sinfo_has_ms_statement_type, &sinfo->aa_set)) goto repeated;
authenticode_check: if (ctx->msg->data_type != OID_msIndirectData) {
pr_warn("Authenticode AuthAttrs only allowed with Authenticode\n"); return -EKEYREJECTED;
} /* I'm not sure how to validate these */ return 0; default: return 0;
}
repeated: /* We permit max one item per AuthenticatedAttribute and no repeats */
pr_warn("Repeated/multivalue AuthAttrs not permitted\n"); return -EKEYREJECTED;
}
/* * Note the set of auth attributes for digestion purposes [RFC2315 sec 9.3]
*/ int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen, unsignedchar tag, constvoid *value, size_t vlen)
{ struct pkcs7_parse_context *ctx = context; struct pkcs7_signed_info *sinfo = ctx->sinfo;
/* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
sinfo->authattrs = value - (hdrlen - 1);
sinfo->authattrs_len = vlen + (hdrlen - 1); return 0;
}
/* * Note the issuing certificate serial number
*/ int pkcs7_sig_note_serial(void *context, size_t hdrlen, unsignedchar tag, constvoid *value, size_t vlen)
{ struct pkcs7_parse_context *ctx = context;
ctx->raw_serial = value;
ctx->raw_serial_size = vlen; return 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.