Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 77d0910d authored by David Howells's avatar David Howells
Browse files

X.509: Retain the key verification data



Retain the key verification data (ie. the struct public_key_signature)
including the digest and the key identifiers.

Note that this means that we need to take a separate copy of the digest in
x509_get_sig_params() rather than lumping it in with the crypto layer data.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent a022ec02
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -80,16 +80,16 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,

		might_sleep();
		last = x509;
		sig = &last->sig;
		sig = last->sig;
	}

	/* No match - see if the root certificate has a signer amongst the
	 * trusted keys.
	 */
	if (last && (last->akid_id || last->akid_skid)) {
	if (last && (last->sig->auth_ids[0] || last->sig->auth_ids[1])) {
		key = x509_request_asymmetric_key(trust_keyring,
						  last->akid_id,
						  last->akid_skid,
						  last->sig->auth_ids[0],
						  last->sig->auth_ids[1],
						  false);
		if (!IS_ERR(key)) {
			x509 = last;
+11 −9
Original line number Diff line number Diff line
@@ -174,6 +174,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
				  struct pkcs7_signed_info *sinfo)
{
	struct public_key_signature *sig;
	struct x509_certificate *x509 = sinfo->signer, *p;
	struct asymmetric_key_id *auth;
	int ret;
@@ -193,14 +194,15 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
			goto maybe_missing_crypto_in_x509;

		pr_debug("- issuer %s\n", x509->issuer);
		if (x509->akid_id)
		sig = x509->sig;
		if (sig->auth_ids[0])
			pr_debug("- authkeyid.id %*phN\n",
				 x509->akid_id->len, x509->akid_id->data);
		if (x509->akid_skid)
				 sig->auth_ids[0]->len, sig->auth_ids[0]->data);
		if (sig->auth_ids[1])
			pr_debug("- authkeyid.skid %*phN\n",
				 x509->akid_skid->len, x509->akid_skid->data);
				 sig->auth_ids[1]->len, sig->auth_ids[1]->data);

		if ((!x509->akid_id && !x509->akid_skid) ||
		if ((!x509->sig->auth_ids[0] && !x509->sig->auth_ids[1]) ||
		    strcmp(x509->subject, x509->issuer) == 0) {
			/* If there's no authority certificate specified, then
			 * the certificate must be self-signed and is the root
@@ -224,7 +226,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
		/* Look through the X.509 certificates in the PKCS#7 message's
		 * list to see if the next one is there.
		 */
		auth = x509->akid_id;
		auth = sig->auth_ids[0];
		if (auth) {
			pr_debug("- want %*phN\n", auth->len, auth->data);
			for (p = pkcs7->certs; p; p = p->next) {
@@ -234,7 +236,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
					goto found_issuer_check_skid;
			}
		} else {
			auth = x509->akid_skid;
			auth = sig->auth_ids[1];
			pr_debug("- want %*phN\n", auth->len, auth->data);
			for (p = pkcs7->certs; p; p = p->next) {
				if (!p->skid)
@@ -254,8 +256,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
		/* We matched issuer + serialNumber, but if there's an
		 * authKeyId.keyId, that must match the CA subjKeyId also.
		 */
		if (x509->akid_skid &&
		    !asymmetric_key_id_same(p->skid, x509->akid_skid)) {
		if (sig->auth_ids[1] &&
		    !asymmetric_key_id_same(p->skid, sig->auth_ids[1])) {
			pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n",
				sinfo->index, x509->index, p->index);
			return -EKEYREJECTED;
+20 −20
Original line number Diff line number Diff line
@@ -48,14 +48,11 @@ void x509_free_certificate(struct x509_certificate *cert)
{
	if (cert) {
		public_key_free(cert->pub);
		public_key_signature_free(cert->sig);
		kfree(cert->issuer);
		kfree(cert->subject);
		kfree(cert->id);
		kfree(cert->skid);
		kfree(cert->akid_id);
		kfree(cert->akid_skid);
		kfree(cert->sig.digest);
		kfree(cert->sig.s);
		kfree(cert);
	}
}
@@ -78,6 +75,9 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
	cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
	if (!cert->pub)
		goto error_no_ctx;
	cert->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL);
	if (!cert->sig)
		goto error_no_ctx;
	ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL);
	if (!ctx)
		goto error_no_ctx;
@@ -188,33 +188,33 @@ int x509_note_pkey_algo(void *context, size_t hdrlen,
		return -ENOPKG; /* Unsupported combination */

	case OID_md4WithRSAEncryption:
		ctx->cert->sig.hash_algo = "md4";
		ctx->cert->sig.pkey_algo = "rsa";
		ctx->cert->sig->hash_algo = "md4";
		ctx->cert->sig->pkey_algo = "rsa";
		break;

	case OID_sha1WithRSAEncryption:
		ctx->cert->sig.hash_algo = "sha1";
		ctx->cert->sig.pkey_algo = "rsa";
		ctx->cert->sig->hash_algo = "sha1";
		ctx->cert->sig->pkey_algo = "rsa";
		break;

	case OID_sha256WithRSAEncryption:
		ctx->cert->sig.hash_algo = "sha256";
		ctx->cert->sig.pkey_algo = "rsa";
		ctx->cert->sig->hash_algo = "sha256";
		ctx->cert->sig->pkey_algo = "rsa";
		break;

	case OID_sha384WithRSAEncryption:
		ctx->cert->sig.hash_algo = "sha384";
		ctx->cert->sig.pkey_algo = "rsa";
		ctx->cert->sig->hash_algo = "sha384";
		ctx->cert->sig->pkey_algo = "rsa";
		break;

	case OID_sha512WithRSAEncryption:
		ctx->cert->sig.hash_algo = "sha512";
		ctx->cert->sig.pkey_algo = "rsa";
		ctx->cert->sig->hash_algo = "sha512";
		ctx->cert->sig->pkey_algo = "rsa";
		break;

	case OID_sha224WithRSAEncryption:
		ctx->cert->sig.hash_algo = "sha224";
		ctx->cert->sig.pkey_algo = "rsa";
		ctx->cert->sig->hash_algo = "sha224";
		ctx->cert->sig->pkey_algo = "rsa";
		break;
	}

@@ -572,14 +572,14 @@ int x509_akid_note_kid(void *context, size_t hdrlen,

	pr_debug("AKID: keyid: %*phN\n", (int)vlen, value);

	if (ctx->cert->akid_skid)
	if (ctx->cert->sig->auth_ids[1])
		return 0;

	kid = asymmetric_key_generate_id(value, vlen, "", 0);
	if (IS_ERR(kid))
		return PTR_ERR(kid);
	pr_debug("authkeyid %*phN\n", kid->len, kid->data);
	ctx->cert->akid_skid = kid;
	ctx->cert->sig->auth_ids[1] = kid;
	return 0;
}

@@ -611,7 +611,7 @@ int x509_akid_note_serial(void *context, size_t hdrlen,

	pr_debug("AKID: serial: %*phN\n", (int)vlen, value);

	if (!ctx->akid_raw_issuer || ctx->cert->akid_id)
	if (!ctx->akid_raw_issuer || ctx->cert->sig->auth_ids[0])
		return 0;

	kid = asymmetric_key_generate_id(value,
@@ -622,6 +622,6 @@ int x509_akid_note_serial(void *context, size_t hdrlen,
		return PTR_ERR(kid);

	pr_debug("authkeyid %*phN\n", kid->len, kid->data);
	ctx->cert->akid_id = kid;
	ctx->cert->sig->auth_ids[0] = kid;
	return 0;
}
+1 −3
Original line number Diff line number Diff line
@@ -17,13 +17,11 @@ struct x509_certificate {
	struct x509_certificate *next;
	struct x509_certificate *signer;	/* Certificate that signed this one */
	struct public_key *pub;			/* Public key details */
	struct public_key_signature sig;	/* Signature parameters */
	struct public_key_signature *sig;	/* Signature parameters */
	char		*issuer;		/* Name of certificate issuer */
	char		*subject;		/* Name of certificate subject */
	struct asymmetric_key_id *id;		/* Issuer + Serial number */
	struct asymmetric_key_id *skid;		/* Subject + subjectKeyId (optional) */
	struct asymmetric_key_id *akid_id;	/* CA AuthKeyId matching ->id (optional) */
	struct asymmetric_key_id *akid_skid;	/* CA AuthKeyId matching ->skid (optional) */
	time64_t	valid_from;
	time64_t	valid_to;
	const void	*tbs;			/* Signed data */
+31 −30
Original line number Diff line number Diff line
@@ -153,30 +153,29 @@ EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
 */
int x509_get_sig_params(struct x509_certificate *cert)
{
	struct public_key_signature *sig = cert->sig;
	struct crypto_shash *tfm;
	struct shash_desc *desc;
	size_t digest_size, desc_size;
	void *digest;
	size_t desc_size;
	int ret;

	pr_devel("==>%s()\n", __func__);

	if (cert->unsupported_crypto)
		return -ENOPKG;
	if (cert->sig.s)
	if (sig->s)
		return 0;

	cert->sig.s = kmemdup(cert->raw_sig, cert->raw_sig_size,
			      GFP_KERNEL);
	if (!cert->sig.s)
	sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL);
	if (!sig->s)
		return -ENOMEM;

	cert->sig.s_size = cert->raw_sig_size;
	sig->s_size = cert->raw_sig_size;

	/* Allocate the hashing algorithm we're going to need and find out how
	 * big the hash operational data will be.
	 */
	tfm = crypto_alloc_shash(cert->sig.hash_algo, 0, 0);
	tfm = crypto_alloc_shash(sig->hash_algo, 0, 0);
	if (IS_ERR(tfm)) {
		if (PTR_ERR(tfm) == -ENOENT) {
			cert->unsupported_crypto = true;
@@ -186,29 +185,28 @@ int x509_get_sig_params(struct x509_certificate *cert)
	}

	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
	digest_size = crypto_shash_digestsize(tfm);
	sig->digest_size = crypto_shash_digestsize(tfm);

	/* We allocate the hash operational data storage on the end of the
	 * digest storage space.
	 */
	ret = -ENOMEM;
	digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size,
			 GFP_KERNEL);
	if (!digest)
	sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
	if (!sig->digest)
		goto error;

	cert->sig.digest = digest;
	cert->sig.digest_size = digest_size;
	desc = kzalloc(desc_size, GFP_KERNEL);
	if (!desc)
		goto error;

	desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc));
	desc->tfm = tfm;
	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;

	ret = crypto_shash_init(desc);
	if (ret < 0)
		goto error;
		goto error_2;
	might_sleep();
	ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest);
	ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest);

error_2:
	kfree(desc);
error:
	crypto_free_shash(tfm);
	pr_devel("<==%s() = %d\n", __func__, ret);
@@ -230,7 +228,7 @@ int x509_check_signature(const struct public_key *pub,
	if (ret < 0)
		return ret;

	ret = public_key_verify_signature(pub, &cert->sig);
	ret = public_key_verify_signature(pub, cert->sig);
	if (ret == -ENOPKG)
		cert->unsupported_crypto = true;
	pr_debug("Cert Verification: %d\n", ret);
@@ -250,17 +248,18 @@ EXPORT_SYMBOL_GPL(x509_check_signature);
static int x509_validate_trust(struct x509_certificate *cert,
			       struct key *trust_keyring)
{
	struct public_key_signature *sig = cert->sig;
	struct key *key;
	int ret = 1;

	if (!trust_keyring)
		return -EOPNOTSUPP;

	if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid))
	if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
		return -EPERM;

	key = x509_request_asymmetric_key(trust_keyring,
					  cert->akid_id, cert->akid_skid,
					  sig->auth_ids[0], sig->auth_ids[1],
					  false);
	if (!IS_ERR(key))  {
		if (!use_builtin_keys
@@ -292,8 +291,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
	pr_devel("Cert Subject: %s\n", cert->subject);

	if (!cert->pub->pkey_algo ||
	    !cert->sig.pkey_algo ||
	    !cert->sig.hash_algo) {
	    !cert->sig->pkey_algo ||
	    !cert->sig->hash_algo) {
		ret = -ENOPKG;
		goto error_free_cert;
	}
@@ -301,15 +300,15 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
	pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo);
	pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to);
	pr_devel("Cert Signature: %s + %s\n",
		 cert->sig.pkey_algo,
		 cert->sig.hash_algo);
		 cert->sig->pkey_algo,
		 cert->sig->hash_algo);

	cert->pub->id_type = "X509";

	/* Check the signature on the key if it appears to be self-signed */
	if ((!cert->akid_skid && !cert->akid_id) ||
	    asymmetric_key_id_same(cert->skid, cert->akid_skid) ||
	    asymmetric_key_id_same(cert->id, cert->akid_id)) {
	if ((!cert->sig->auth_ids[0] && !cert->sig->auth_ids[1]) ||
	    asymmetric_key_id_same(cert->skid, cert->sig->auth_ids[1]) ||
	    asymmetric_key_id_same(cert->id, cert->sig->auth_ids[0])) {
		ret = x509_check_signature(cert->pub, cert); /* self-signed */
		if (ret < 0)
			goto error_free_cert;
@@ -353,6 +352,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
	prep->payload.data[asym_subtype] = &public_key_subtype;
	prep->payload.data[asym_key_ids] = kids;
	prep->payload.data[asym_crypto] = cert->pub;
	prep->payload.data[asym_auth] = cert->sig;
	prep->description = desc;
	prep->quotalen = 100;

@@ -360,6 +360,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
	cert->pub = NULL;
	cert->id = NULL;
	cert->skid = NULL;
	cert->sig = NULL;
	desc = NULL;
	ret = 0;