Browse Source

[tls] Accept certificates without a version number

The version field of an X.509 certificate appears to be optional.

Reported-by: Sebastiano Manusia <Sebastiano.Manusia@chuv.ch>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 years ago
parent
commit
1691cf50bc
3 changed files with 61 additions and 28 deletions
  1. 48
    27
      src/crypto/asn1.c
  2. 1
    1
      src/crypto/x509.c
  3. 12
    0
      src/include/ipxe/asn1.h

+ 48
- 27
src/crypto/asn1.c View File

@@ -29,6 +29,20 @@ FILE_LICENCE ( GPL2_OR_LATER );
29 29
  *
30 30
  */
31 31
 
32
+/* Disambiguate the various error causes */
33
+#define EINVAL_ASN1_EMPTY \
34
+	__einfo_error ( EINFO_EINVAL_ASN1_EMPTY )
35
+#define EINFO_EINVAL_ASN1_EMPTY \
36
+	__einfo_uniqify ( EINFO_EINVAL, 0x01, "Empty or underlength cursor" )
37
+#define EINVAL_ASN1_LEN_LEN \
38
+	__einfo_error ( EINFO_EINVAL_ASN1_LEN_LEN )
39
+#define EINFO_EINVAL_ASN1_LEN_LEN \
40
+	__einfo_uniqify ( EINFO_EINVAL, 0x02, "Length field overruns cursor" )
41
+#define EINVAL_ASN1_LEN \
42
+	__einfo_error ( EINFO_EINVAL_ASN1_LEN )
43
+#define EINFO_EINVAL_ASN1_LEN \
44
+	__einfo_uniqify ( EINFO_EINVAL, 0x03, "Field overruns cursor" )
45
+
32 46
 /**
33 47
  * Start parsing ASN.1 object
34 48
  *
@@ -40,32 +54,23 @@ FILE_LICENCE ( GPL2_OR_LATER );
40 54
  * object body (i.e. the first byte following the length byte(s)), and
41 55
  * the length of the object body (i.e. the number of bytes until the
42 56
  * following object tag, if any) is returned.
43
- *
44
- * If any error occurs (i.e. if the object is not of the expected
45
- * type, or if we overflow beyond the end of the ASN.1 object), then
46
- * the cursor will be invalidated and a negative value will be
47
- * returned.
48 57
  */
49
-static int asn1_start ( struct asn1_cursor *cursor,
50
-			       unsigned int type ) {
58
+static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) {
51 59
 	unsigned int len_len;
52 60
 	unsigned int len;
53
-	int rc;
54 61
 
55 62
 	/* Sanity check */
56 63
 	if ( cursor->len < 2 /* Tag byte and first length byte */ ) {
57 64
 		if ( cursor->len )
58 65
 			DBGC ( cursor, "ASN1 %p too short\n", cursor );
59
-		rc = -EINVAL;
60
-		goto notfound;
66
+		return -EINVAL_ASN1_EMPTY;
61 67
 	}
62 68
 
63 69
 	/* Check the tag byte */
64 70
 	if ( *( ( uint8_t * ) cursor->data ) != type ) {
65 71
 		DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
66 72
 		       cursor, type, *( ( uint8_t * ) cursor->data ) );
67
-		rc = -ENXIO;
68
-		goto notfound;
73
+		return -ENXIO;
69 74
 	}
70 75
 	cursor->data++;
71 76
 	cursor->len--;
@@ -82,8 +87,7 @@ static int asn1_start ( struct asn1_cursor *cursor,
82 87
 	if ( cursor->len < len_len ) {
83 88
 		DBGC ( cursor, "ASN1 %p bad length field length %d (max "
84 89
 		       "%zd)\n", cursor, len_len, cursor->len );
85
-		rc = -EINVAL;
86
-		goto notfound;
90
+		return -EINVAL_ASN1_LEN_LEN;
87 91
 	}
88 92
 
89 93
 	/* Extract the length and sanity check */
@@ -96,16 +100,10 @@ static int asn1_start ( struct asn1_cursor *cursor,
96 100
 	if ( cursor->len < len ) {
97 101
 		DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n",
98 102
 		       cursor, len, cursor->len );
99
-		rc = -EINVAL;
100
-		goto notfound;
103
+		return -EINVAL_ASN1_LEN;
101 104
 	}
102 105
 
103 106
 	return len;
104
-
105
- notfound:
106
-	cursor->data = NULL;
107
-	cursor->len = 0;
108
-	return rc;
109 107
 }
110 108
 
111 109
 /**
@@ -123,8 +121,10 @@ int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
123 121
 	int len;
124 122
 
125 123
 	len = asn1_start ( cursor, type );
126
-	if ( len < 0 )
124
+	if ( len < 0 ) {
125
+		asn1_invalidate_cursor ( cursor );
127 126
 		return len;
127
+	}
128 128
 
129 129
 	cursor->len = len;
130 130
 	DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n",
@@ -134,17 +134,17 @@ int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
134 134
 }
135 135
 
136 136
 /**
137
- * Skip ASN.1 object
137
+ * Skip ASN.1 object if present
138 138
  *
139 139
  * @v cursor		ASN.1 object cursor
140 140
  * @v type		Expected type
141 141
  * @ret rc		Return status code
142 142
  *
143 143
  * The object cursor will be updated to point to the next ASN.1
144
- * object.  If any error occurs, the object cursor will be
145
- * invalidated.
144
+ * object.  If any error occurs, the object cursor will not be
145
+ * modified.
146 146
  */
147
-int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
147
+int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) {
148 148
 	int len;
149 149
 
150 150
 	len = asn1_start ( cursor, type );
@@ -158,9 +158,30 @@ int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
158 158
 
159 159
 	if ( ! cursor->len ) {
160 160
 		DBGC ( cursor, "ASN1 %p reached end of object\n", cursor );
161
-		cursor->data = NULL;
162 161
 		return -ENOENT;
163 162
 	}
164 163
 
165 164
 	return 0;
166 165
 }
166
+
167
+/**
168
+ * Skip ASN.1 object
169
+ *
170
+ * @v cursor		ASN.1 object cursor
171
+ * @v type		Expected type
172
+ * @ret rc		Return status code
173
+ *
174
+ * The object cursor will be updated to point to the next ASN.1
175
+ * object.  If any error occurs, the object cursor will be
176
+ * invalidated.
177
+ */
178
+int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
179
+	int rc;
180
+
181
+	if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) < 0 ) {
182
+		asn1_invalidate_cursor ( cursor );
183
+		return rc;
184
+	}
185
+
186
+	return 0;
187
+}

+ 1
- 1
src/crypto/x509.c View File

@@ -55,7 +55,7 @@ static int x509_public_key ( const struct asn1_cursor *certificate,
55 55
 	memcpy ( &cursor, certificate, sizeof ( cursor ) );
56 56
 	rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */
57 57
 	       asn1_enter ( &cursor, ASN1_SEQUENCE ), /* tbsCertificate */
58
-	       asn1_skip ( &cursor, ASN1_EXPLICIT_TAG ), /* version */
58
+	       asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ), /* version */
59 59
 	       asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */
60 60
 	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */
61 61
 	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */

+ 12
- 0
src/include/ipxe/asn1.h View File

@@ -28,7 +28,19 @@ struct asn1_cursor {
28 28
 	size_t len;
29 29
 };
30 30
 
31
+/**
32
+ * Invalidate ASN.1 object cursor
33
+ *
34
+ * @v cursor		ASN.1 object cursor
35
+ */
36
+static inline __attribute__ (( always_inline )) void
37
+asn1_invalidate_cursor ( struct asn1_cursor *cursor ) {
38
+	cursor->len = 0;
39
+}
40
+
31 41
 extern int asn1_enter ( struct asn1_cursor *cursor, unsigned int type );
42
+extern int asn1_skip_if_exists ( struct asn1_cursor *cursor,
43
+				 unsigned int type );
32 44
 extern int asn1_skip ( struct asn1_cursor *cursor, unsigned int type );
33 45
 
34 46
 #endif /* _IPXE_ASN1_H */

Loading…
Cancel
Save