All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Zaborowski <andrew.zaborowski@intel.com>
To: ell@lists.01.org
Subject: [PATCH 3/8] asn1-private: Handle Context-specific tag class
Date: Fri, 23 Aug 2019 02:41:33 +0200	[thread overview]
Message-ID: <20190823004138.5480-3-andrew.zaborowski@intel.com> (raw)
In-Reply-To: <20190823004138.5480-1-andrew.zaborowski@intel.com>

[-- Attachment #1: Type: text/plain, Size: 5962 bytes --]

In asn1_der_find_elem(_by_path) add a way to properly handle the
optional elements in x509 certificates.  Until now we were lucky we
never needed to handle the parts of certificates where some
OPTIONAL/DEFAULT element was absent (such as Version in
v1 certificates) but we would be misparsing the certificates in
those cases.

In the general case an asn1 parser will need the full syntax
definition to locate an element inside the structure.  To avoid adding
a lot of .asn1 files like those contained in the kernel, and a parser
compiler, assume that OPTIONAL/DEFAULT elements use Context-specific
tags which is mostly the case in the x509 syntax (this is evens noted
in ftp://ftp.rsasecurity.com/pub/pkcs/ascii/layman.asc).  This way we
can handle Univeral tags that are always present and optional elements
that use Context-specific tags and get by with the same few #defines
we had regarding the x509 structure.
---
 ell/asn1-private.h | 74 ++++++++++++++++++++++++++++++++++++++--------
 ell/cert.c         | 20 ++++++-------
 2 files changed, 72 insertions(+), 22 deletions(-)

diff --git a/ell/asn1-private.h b/ell/asn1-private.h
index 71a4ae6..7c382ec 100644
--- a/ell/asn1-private.h
+++ b/ell/asn1-private.h
@@ -21,6 +21,7 @@
 #define ASN1_ID(class, pc, tag)	(((class) << 6) | ((pc) << 5) | (tag))
 
 #define ASN1_CLASS_UNIVERSAL	0
+#define ASN1_CLASS_CONTEXT	2
 
 #define ASN1_ID_SEQUENCE	ASN1_ID(ASN1_CLASS_UNIVERSAL, 1, 0x10)
 #define ASN1_ID_SET		ASN1_ID(ASN1_CLASS_UNIVERSAL, 1, 0x11)
@@ -89,14 +90,24 @@ static inline void asn1_write_definite_length(uint8_t **buf, size_t len)
 		*(*buf)++ = len >> (n * 8);
 }
 
-/* Return index'th element in a DER SEQUENCE */
+#define ASN1_CONTEXT_IMPLICIT(tag) (0x1000 | (tag))
+#define ASN1_CONTEXT_EXPLICIT(tag) (0x2000 | (tag))
+
+/*
+ * Return the tag, length and value of the @index'th
+ * non-context-specific-tagged element in a DER SEQUENCE or one who's
+ * ASN1_CONTEXT_IMPLICIT(tag) matches @index or the inner element of
+ * the one who's ASN1_CONTEXT_EXPLICIT(tag) matches @index.
+ */
 static inline const uint8_t *asn1_der_find_elem(const uint8_t *buf,
 						size_t len_in, int index,
 						uint8_t *tag, size_t *len_out)
 {
-	int tlv_len;
+	int n = 0;
 
 	while (1) {
+		int tlv_len;
+
 		if (len_in < 2)
 			return NULL;
 
@@ -107,9 +118,36 @@ static inline const uint8_t *asn1_der_find_elem(const uint8_t *buf,
 		if (tlv_len < 0 || (size_t) tlv_len > len_in)
 			return NULL;
 
-		if (index-- == 0) {
-			*len_out = tlv_len;
-			return buf;
+		if (*tag >> 6 != ASN1_CLASS_CONTEXT) {
+			if (n++ == index) {
+				*len_out = tlv_len;
+				return buf;
+			}
+		} else if ((*tag & 0x1f) == (index & 0xfff)) {
+			/* Context-specific tag */
+			if (index & 0x1000) {		/* Implicit */
+				*len_out = tlv_len;
+				return buf;
+			} else if (index & 0x2000) {	/* Explicit */
+				const uint8_t *outer = buf;
+				int inner_len;
+
+				if (!(*tag & 0x20))	/* Primitive */
+					return NULL;
+
+				if (unlikely(tlv_len < 2))
+					return NULL;
+
+				*tag = *buf++;
+
+				inner_len = asn1_parse_definite_length(
+							(void *) &buf, &len_in);
+				if (outer + tlv_len != buf + inner_len)
+					return NULL;
+
+				*len_out = inner_len;
+				return buf;
+			}
 		}
 
 		buf += tlv_len;
@@ -122,20 +160,32 @@ static inline const uint8_t *asn1_der_find_elem_by_path(const uint8_t *buf,
 						size_t len_in, uint8_t tag,
 						size_t *len_out, ...)
 {
-	uint8_t elem_tag;
-	int pos;
+	int index;
 	va_list vl;
 
 	va_start(vl, len_out);
 
-	pos = va_arg(vl, int);
+	index = va_arg(vl, int);
+
+	while (index != -1) {
+		uint8_t elem_tag;
+		uint8_t expect_tag;
+		int prev_index = index;
+
+		buf = asn1_der_find_elem(buf, len_in, index,
+						&elem_tag, &len_in);
 
-	while (pos != -1) {
-		buf = asn1_der_find_elem(buf, len_in, pos, &elem_tag, &len_in);
+		index = va_arg(vl, int);
 
-		pos = va_arg(vl, int);
+		if (prev_index & 0x1000)
+			expect_tag = ASN1_ID(ASN1_CLASS_CONTEXT,
+						index != -1 ? 1 :
+						((elem_tag >> 5) & 1),
+						prev_index & 0xfff);
+		else
+			expect_tag = (index == -1) ? tag : ASN1_ID_SEQUENCE;
 
-		if (!buf || elem_tag != (pos == -1 ? tag : ASN1_ID_SEQUENCE)) {
+		if (!buf || elem_tag != expect_tag) {
 			va_end(vl);
 			return NULL;
 		}
diff --git a/ell/cert.c b/ell/cert.c
index d52bfd0..950e562 100644
--- a/ell/cert.c
+++ b/ell/cert.c
@@ -34,20 +34,20 @@
 
 #define X509_CERTIFICATE_POS			0
 #define   X509_TBSCERTIFICATE_POS		  0
-#define     X509_TBSCERT_VERSION_POS		    0
-#define     X509_TBSCERT_SERIAL_POS		    1
-#define     X509_TBSCERT_SIGNATURE_POS		    2
+#define     X509_TBSCERT_VERSION_POS		    ASN1_CONTEXT_EXPLICIT(0)
+#define     X509_TBSCERT_SERIAL_POS		    0
+#define     X509_TBSCERT_SIGNATURE_POS		    1
 #define       X509_ALGORITHM_ID_ALGORITHM_POS	      0
 #define       X509_ALGORITHM_ID_PARAMS_POS	      1
-#define     X509_TBSCERT_ISSUER_DN_POS		    3
-#define     X509_TBSCERT_VALIDITY_POS		    4
-#define     X509_TBSCERT_SUBJECT_DN_POS		    5
-#define     X509_TBSCERT_SUBJECT_KEY_POS	    6
+#define     X509_TBSCERT_ISSUER_DN_POS		    2
+#define     X509_TBSCERT_VALIDITY_POS		    3
+#define     X509_TBSCERT_SUBJECT_DN_POS		    4
+#define     X509_TBSCERT_SUBJECT_KEY_POS	    5
 #define       X509_SUBJECT_KEY_ALGORITHM_POS	      0
 #define       X509_SUBJECT_KEY_VALUE_POS	      1
-#define     X509_TBSCERT_ISSUER_UID_POS		    7
-#define     X509_TBSCERT_SUBJECT_UID_POS	    8
-#define     X509_TBSCERT_EXTENSIONS_POS		    9
+#define     X509_TBSCERT_ISSUER_UID_POS		    ASN1_CONTEXT_IMPLICIT(1)
+#define     X509_TBSCERT_SUBJECT_UID_POS	    ASN1_CONTEXT_IMPLICIT(2)
+#define     X509_TBSCERT_EXTENSIONS_POS		    ASN1_CONTEXT_EXPLICIT(3)
 #define   X509_SIGNATURE_ALGORITHM_POS		  1
 #define   X509_SIGNATURE_VALUE_POS		  2
 
-- 
2.20.1


  parent reply	other threads:[~2019-08-23  0:41 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-08-23  0:41 [PATCH 1/8] tls: Implement l_tls_set_domain_mask Andrew Zaborowski
2019-08-23  0:41 ` [PATCH 2/8] unit: Add l_tls_set_domain_mask tests Andrew Zaborowski
2019-08-23  0:41 ` Andrew Zaborowski [this message]
2019-08-23  0:41 ` [PATCH 4/8] cert: Implement l_cert_get_extension Andrew Zaborowski
2019-08-23  0:41 ` [PATCH 5/8] strv: Implement l_strv_copy Andrew Zaborowski
2019-08-23 14:16   ` Denis Kenzior
2019-08-23  0:41 ` [PATCH 6/8] tls: Validate peer certificate's DNSNames against mask Andrew Zaborowski
2019-08-23 14:27   ` Denis Kenzior
2019-08-23 17:51     ` Andrew Zaborowski
2019-08-23 20:21       ` Denis Kenzior
2019-08-23 23:50         ` Andrew Zaborowski
2019-08-23  0:41 ` [PATCH 7/8] build: Add DNSNames to the test server cert Andrew Zaborowski
2019-08-23 14:29   ` Denis Kenzior
2019-08-23  0:41 ` [PATCH 8/8] unit: Add TLS tests for cert's DNSName matching Andrew Zaborowski
2019-08-23 14:28 ` [PATCH 1/8] tls: Implement l_tls_set_domain_mask Denis Kenzior
2019-08-23  1:24 [PATCH 3/8] asn1-private: Handle Context-specific tag class Andrew Zaborowski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190823004138.5480-3-andrew.zaborowski@intel.com \
    --to=andrew.zaborowski@intel.com \
    --cc=ell@lists.01.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.