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

Commit a4730357 authored by David Howells's avatar David Howells
Browse files

PKCS#7: Find the right key in the PKCS#7 key list and verify the signature



Find the appropriate key in the PKCS#7 key list and verify the signature with
it.  There may be several keys in there forming a chain.  Any link in that
chain or the root of that chain may be in our keyrings.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Acked-by: default avatarVivek Goyal <vgoyal@redhat.com>
Reviewed-by: default avatarKees Cook <keescook@chromium.org>
parent 9f0d3314
Loading
Loading
Loading
Loading
+64 −0
Original line number Diff line number Diff line
@@ -120,6 +120,55 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
}

/*
 * Find the key (X.509 certificate) to use to verify a PKCS#7 message.  PKCS#7
 * uses the issuer's name and the issuing certificate serial number for
 * matching purposes.  These must match the certificate issuer's name (not
 * subject's name) and the certificate serial number [RFC 2315 6.7].
 */
static int pkcs7_find_key(struct pkcs7_message *pkcs7,
			  struct pkcs7_signed_info *sinfo)
{
	struct x509_certificate *x509;
	unsigned certix = 1;

	kenter("%u,%u,%u",
	       sinfo->index, sinfo->raw_serial_size, sinfo->raw_issuer_size);

	for (x509 = pkcs7->certs; x509; x509 = x509->next, certix++) {
		/* I'm _assuming_ that the generator of the PKCS#7 message will
		 * encode the fields from the X.509 cert in the same way in the
		 * PKCS#7 message - but I can't be 100% sure of that.  It's
		 * possible this will need element-by-element comparison.
		 */
		if (x509->raw_serial_size != sinfo->raw_serial_size ||
		    memcmp(x509->raw_serial, sinfo->raw_serial,
			   sinfo->raw_serial_size) != 0)
			continue;
		pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
			 sinfo->index, certix);

		if (x509->raw_issuer_size != sinfo->raw_issuer_size ||
		    memcmp(x509->raw_issuer, sinfo->raw_issuer,
			   sinfo->raw_issuer_size) != 0) {
			pr_warn("Sig %u: X.509 subject and PKCS#7 issuer don't match\n",
				sinfo->index);
			continue;
		}

		if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) {
			pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n",
				sinfo->index);
			continue;
		}

		sinfo->signer = x509;
		return 0;
	}
	pr_warn("Sig %u: Issuing X.509 cert not found (#%*ph)\n",
		sinfo->index, sinfo->raw_serial_size, sinfo->raw_serial);
	return -ENOKEY;
}

/*
 * Verify one signed information block from a PKCS#7 message.
 */
@@ -137,6 +186,21 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
	if (ret < 0)
		return ret;

	/* Find the key for the signature */
	ret = pkcs7_find_key(pkcs7, sinfo);
	if (ret < 0)
		return ret;

	pr_devel("Using X.509[%u] for sig %u\n",
		 sinfo->signer->index, sinfo->index);

	/* Verify the PKCS#7 binary against the key */
	ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig);
	if (ret < 0)
		return ret;

	pr_devel("Verified signature %u\n", sinfo->index);

	return 0;
}

+5 −0
Original line number Diff line number Diff line
@@ -21,3 +21,8 @@ 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,
				  bool want_wrapper);

/*
 * pkcs7_verify.c
 */
extern int pkcs7_verify(struct pkcs7_message *pkcs7);