Skip to contentSkip to conversation

KEYS: x509: various cleanups

PATCH Superseded Eric Biggers 2 participants 9 messages Jan 14, 2022 – Jan 15, 2022

Subsystems (3)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover KEYS: x509: various cleanups

This series cleans up a few things in the X.509 certificate parser.

Eric Biggers (4):
KEYS: x509: clearly distinguish between key and signature algorithms
KEYS: x509: remove unused fields
KEYS: x509: remove never-set ->unsupported_key flag
KEYS: x509: remove dead code that set ->unsupported_sig

 crypto/asymmetric_keys/pkcs7_verify.c     |  3 --
 crypto/asymmetric_keys/x509.asn1          |  2 +-
 crypto/asymmetric_keys/x509_cert_parser.c | 34 ++++++++++++-----------
 crypto/asymmetric_keys/x509_parser.h      |  1 -
 crypto/asymmetric_keys/x509_public_key.c  | 18 ------------
 5 files changed, 19 insertions(+), 39 deletions(-)

base-commit: feb7a43de5ef625ad74097d8fd3481d5dbc06a59

Signature · 1 line
2.34.1
#1 lore raw

PATCH 1/4 KEYS: x509: clearly distinguish between key and signature algorithms

From: Eric Biggers <[email protected]>

An X.509 certificate has two, potentially different public key
algorithms: the one used by the certificate's key, and the one that was used to sign the certificate. Some of the naming made it unclear which algorithm was meant. Rename things appropriately:

- x509_note_pkey_algo() => x509_note_sig_algo()
- algo_oid => sig_algo

---
 crypto/asymmetric_keys/x509.asn1          |  2 +-
 crypto/asymmetric_keys/x509_cert_parser.c | 32 +++++++++++++----------
 2 files changed, 19 insertions(+), 15 deletions(-)
crypto/asymmetric_keys/x509.asn1 +1 -1
index 5c9f4e4a5231..92d59c32f96a 100644
@@ -7,7 +7,7 @@ Certificate ::= SEQUENCE {
 TBSCertificate ::= SEQUENCE {
 	version           [ 0 ]	Version DEFAULT,
 	serialNumber		CertificateSerialNumber ({ x509_note_serial }),
-	signature		AlgorithmIdentifier ({ x509_note_pkey_algo }),
+	signature		AlgorithmIdentifier ({ x509_note_sig_algo }),
 	issuer			Name ({ x509_note_issuer }),
 	validity		Validity,
 	subject			Name ({ x509_note_subject }),
crypto/asymmetric_keys/x509_cert_parser.c +18 -14
index 083405eb80c3..aec2396a7f7e 100644
@@ -24,9 +24,9 @@ struct x509_parse_context {
 	size_t		key_size;		/* Size of key data */
 	const void	*params;		/* Key parameters */
 	size_t		params_size;		/* Size of key parameters */
-	enum OID	key_algo;		/* Public key algorithm */
+	enum OID	key_algo;		/* Algorithm used by the cert's key */
 	enum OID	last_oid;		/* Last OID encountered */
-	enum OID	algo_oid;		/* Algorithm OID */
+	enum OID	sig_algo;		/* Algorithm used to sign the cert */
 	unsigned char	nr_mpi;			/* Number of MPIs stored */
 	u8		o_size;			/* Size of organizationName (O) */
 	u8		cn_size;		/* Size of commonName (CN) */
@@ -187,11 +187,10 @@ int x509_note_tbs_certificate(void *context, size_t hdrlen,
 }
 
 /*
- * Record the public key algorithm
+ * Record the algorithm that was used to sign this certificate.
  */
-int x509_note_pkey_algo(void *context, size_t hdrlen,
-			unsigned char tag,
-			const void *value, size_t vlen)
+int x509_note_sig_algo(void *context, size_t hdrlen, unsigned char tag,
+		       const void *value, size_t vlen)
 {
 	struct x509_parse_context *ctx = context;
 
@@ -263,22 +262,22 @@ int x509_note_pkey_algo(void *context, size_t hdrlen,
 rsa_pkcs1:
 	ctx->cert->sig->pkey_algo = "rsa";
 	ctx->cert->sig->encoding = "pkcs1";
-	ctx->algo_oid = ctx->last_oid;
+	ctx->sig_algo = ctx->last_oid;
 	return 0;
 ecrdsa:
 	ctx->cert->sig->pkey_algo = "ecrdsa";
 	ctx->cert->sig->encoding = "raw";
-	ctx->algo_oid = ctx->last_oid;
+	ctx->sig_algo = ctx->last_oid;
 	return 0;
 sm2:
 	ctx->cert->sig->pkey_algo = "sm2";
 	ctx->cert->sig->encoding = "raw";
-	ctx->algo_oid = ctx->last_oid;
+	ctx->sig_algo = ctx->last_oid;
 	return 0;
 ecdsa:
 	ctx->cert->sig->pkey_algo = "ecdsa";
 	ctx->cert->sig->encoding = "x962";
-	ctx->algo_oid = ctx->last_oid;
+	ctx->sig_algo = ctx->last_oid;
 	return 0;
 }
 
@@ -291,11 +290,16 @@ int x509_note_signature(void *context, size_t hdrlen,
 {
 	struct x509_parse_context *ctx = context;
 
-	pr_debug("Signature type: %u size %zu\n", ctx->last_oid, vlen);
+	pr_debug("Signature: alg=%u, size=%zu\n", ctx->last_oid, vlen);
 
-	if (ctx->last_oid != ctx->algo_oid) {
-		pr_warn("Got cert with pkey (%u) and sig (%u) algorithm OIDs\n",
-			ctx->algo_oid, ctx->last_oid);
+	/*
+	 * In X.509 certificates, the signature's algorithm is stored in two
+	 * places: inside the TBSCertificate (the data that is signed), and
+	 * alongside the signature.  These *must* match.
+	 */
+	if (ctx->last_oid != ctx->sig_algo) {
+		pr_warn("signatureAlgorithm (%u) differs from tbsCertificate.signature (%u)\n",
+			ctx->last_oid, ctx->sig_algo);
 		return -EINVAL;
 	}
 
Signature · 1 line
2.34.1
maintainer Acked-by on v1 1/4
#2 lore raw

Re: [PATCH 1/4] KEYS: x509: clearly distinguish between key and signature algorithms

Quoted 11 lines · Eric Biggers

From: Eric Biggers <[email protected]>

An X.509 certificate has two, potentially different public key
algorithms: the one used by the certificate's key, and the one that was used to sign the certificate. Some of the naming made it unclear which algorithm was meant. Rename things appropriately:

- x509_note_pkey_algo() => x509_note_sig_algo()
- algo_oid => sig_algo

BR, Jarkko

#3 lore raw

PATCH 2/4 KEYS: x509: remove unused fields

In reply to Eric Biggers

From: Eric Biggers <[email protected]>

Remove unused fields from struct x509_parse_context.

---
 crypto/asymmetric_keys/x509_cert_parser.c | 2 --
 1 file changed, 2 deletions(-)
crypto/asymmetric_keys/x509_cert_parser.c +0 -2
index aec2396a7f7e..2899ed80bb18 100644
@@ -19,7 +19,6 @@
 struct x509_parse_context {
 	struct x509_certificate	*cert;		/* Certificate being constructed */
 	unsigned long	data;			/* Start of data */
-	const void	*cert_start;		/* Start of cert content */
 	const void	*key;			/* Key data */
 	size_t		key_size;		/* Size of key data */
 	const void	*params;		/* Key parameters */
@@ -27,7 +26,6 @@ struct x509_parse_context {
 	enum OID	key_algo;		/* Algorithm used by the cert's key */
 	enum OID	last_oid;		/* Last OID encountered */
 	enum OID	sig_algo;		/* Algorithm used to sign the cert */
-	unsigned char	nr_mpi;			/* Number of MPIs stored */
 	u8		o_size;			/* Size of organizationName (O) */
 	u8		cn_size;		/* Size of commonName (CN) */
 	u8		email_size;		/* Size of emailAddress */
Signature · 1 line
2.34.1
#5 lore raw

PATCH 3/4 KEYS: x509: remove never-set ->unsupported_key flag

In reply to Eric Biggers

From: Eric Biggers <[email protected]>

The X.509 parser always sets cert->pub->pkey_algo on success, since x509_extract_key_data() is a mandatory action in the X.509 ASN.1 grammar, and it returns an error if the algorithm is unknown. Thus, remove the dead code which handled this field being NULL. This results in the ->unsupported_key flag never being set, so remove that too.

---
 crypto/asymmetric_keys/pkcs7_verify.c    | 3 ---
 crypto/asymmetric_keys/x509_parser.h     | 1 -
 crypto/asymmetric_keys/x509_public_key.c | 9 ---------
 3 files changed, 13 deletions(-)
crypto/asymmetric_keys/pkcs7_verify.c +0 -3
index 0b4d07aa8811..4ba81be3cd77 100644
@@ -226,9 +226,6 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 			return 0;
 		}
 
-		if (x509->unsupported_key)
-			goto unsupported_crypto_in_x509;
-
 		pr_debug("- issuer %s\n", x509->issuer);
 		sig = x509->sig;
 		if (sig->auth_ids[0])
crypto/asymmetric_keys/x509_parser.h +0 -1
index c233f136fb35..da854c94f111 100644
@@ -36,7 +36,6 @@ struct x509_certificate {
 	bool		seen;			/* Infinite recursion prevention */
 	bool		verified;
 	bool		self_signed;		/* T if self-signed (check unsupported_sig too) */
-	bool		unsupported_key;	/* T if key uses unsupported crypto */
 	bool		unsupported_sig;	/* T if signature uses unsupported crypto */
 	bool		blacklisted;
 };
crypto/asymmetric_keys/x509_public_key.c +0 -9
index fe14cae115b5..b03d04d78eb9 100644
@@ -33,9 +33,6 @@ int x509_get_sig_params(struct x509_certificate *cert)
 	sig->data = cert->tbs;
 	sig->data_size = cert->tbs_size;
 
-	if (!cert->pub->pkey_algo)
-		cert->unsupported_key = true;
-
 	if (!sig->pkey_algo)
 		cert->unsupported_sig = true;
 
@@ -173,12 +170,6 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 
 	pr_devel("Cert Issuer: %s\n", cert->issuer);
 	pr_devel("Cert Subject: %s\n", cert->subject);
-
-	if (cert->unsupported_key) {
-		ret = -ENOPKG;
-		goto error_free_cert;
-	}
-
 	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);
 
Signature · 1 line
2.34.1
maintainer
#6 lore raw

Re: [PATCH 3/4] KEYS: x509: remove never-set ->unsupported_key flag

Quoted 20 lines · Eric Biggers

From: Eric Biggers <[email protected]>

The X.509 parser always sets cert->pub->pkey_algo on success, since x509_extract_key_data() is a mandatory action in the X.509 ASN.1 grammar, and it returns an error if the algorithm is unknown. Thus, remove the dead code which handled this field being NULL. This results in the ->unsupported_key flag never being set, so remove that too.

---
 crypto/asymmetric_keys/pkcs7_verify.c    | 3 ---
 crypto/asymmetric_keys/x509_parser.h     | 1 -
 crypto/asymmetric_keys/x509_public_key.c | 9 ---------
 3 files changed, 13 deletions(-)
crypto/asymmetric_keys/pkcs7_verify.c +0 -0
index 0b4d07aa8811..4ba81be3cd77 100644

crypto/asymmetric_keys/pkcs7_verify.c static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, · line 230

Quoted 5 lines
crypto/asymmetric_keys/pkcs7_verify.c +0 -2
@@ -226,9 +226,6 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 			return 0;
 		}
 
-		if (x509->unsupported_key)
-			goto unsupported_crypto_in_x509;

Just a minor nit.

You see now there is only this statement left with a ref to that label:

	/* If there's no authority certificate specified, then
         * the certificate must be self-signed and is the root
         * of the chain.  Likewise if the cert is its own
         * authority.
         */
        if (x509->unsupported_sig)
                goto unsupported_crypto_in_x509;

I'd suggest to rename this as unsupported_sig_in_x509.

Quoted 46 lines
crypto/asymmetric_keys/pkcs7_verify.c +0 -1
-
 		pr_debug("- issuer %s\n", x509->issuer);
 		sig = x509->sig;
 		if (sig->auth_ids[0])
crypto/asymmetric_keys/x509_parser.h +0 -1
index c233f136fb35..da854c94f111 100644
@@ -36,7 +36,6 @@ struct x509_certificate {
 	bool		seen;			/* Infinite recursion prevention */
 	bool		verified;
 	bool		self_signed;		/* T if self-signed (check unsupported_sig too) */
-	bool		unsupported_key;	/* T if key uses unsupported crypto */
 	bool		unsupported_sig;	/* T if signature uses unsupported crypto */
 	bool		blacklisted;
 };
crypto/asymmetric_keys/x509_public_key.c +0 -9
index fe14cae115b5..b03d04d78eb9 100644
@@ -33,9 +33,6 @@ int x509_get_sig_params(struct x509_certificate *cert)
 	sig->data = cert->tbs;
 	sig->data_size = cert->tbs_size;
 
-	if (!cert->pub->pkey_algo)
-		cert->unsupported_key = true;
-
 	if (!sig->pkey_algo)
 		cert->unsupported_sig = true;
 
@@ -173,12 +170,6 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 
 	pr_devel("Cert Issuer: %s\n", cert->issuer);
 	pr_devel("Cert Subject: %s\n", cert->subject);
-
-	if (cert->unsupported_key) {
-		ret = -ENOPKG;
-		goto error_free_cert;
-	}
-
 	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);
 
Signature · 1 line
2.34.1

/Jarkko

#7 lore raw

PATCH 4/4 KEYS: x509: remove dead code that set ->unsupported_sig

In reply to Eric Biggers

From: Eric Biggers <[email protected]>

The X.509 parser always sets cert->sig->pkey_algo and cert->sig->hash_algo on success, since x509_note_sig_algo() is a mandatory action in the X.509 ASN.1 grammar, and it returns an error if the signature's algorithm is unknown. Thus, remove the dead code which handled these fields being NULL.

---
 crypto/asymmetric_keys/x509_public_key.c | 9 ---------
 1 file changed, 9 deletions(-)
crypto/asymmetric_keys/x509_public_key.c +0 -9
index b03d04d78eb9..8c77a297a82d 100644
@@ -33,15 +33,6 @@ int x509_get_sig_params(struct x509_certificate *cert)
 	sig->data = cert->tbs;
 	sig->data_size = cert->tbs_size;
 
-	if (!sig->pkey_algo)
-		cert->unsupported_sig = true;
-
-	/* We check the hash if we can - even if we can't then verify it */
-	if (!sig->hash_algo) {
-		cert->unsupported_sig = true;
-		return 0;
-	}
-
 	sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL);
 	if (!sig->s)
 		return -ENOMEM;
Signature · 1 line
2.34.1
maintainer Acked-by on v1 4/4
#8 lore raw

Re: [PATCH 4/4] KEYS: x509: remove dead code that set ->unsupported_sig

Quoted 9 lines · Eric Biggers

From: Eric Biggers <[email protected]>

The X.509 parser always sets cert->sig->pkey_algo and cert->sig->hash_algo on success, since x509_note_sig_algo() is a mandatory action in the X.509 ASN.1 grammar, and it returns an error if the signature's algorithm is unknown. Thus, remove the dead code which handled these fields being NULL.

/Jarkko