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 13 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
  *
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
  * Start parsing ASN.1 object
47
  * Start parsing ASN.1 object
34
  *
48
  *
40
  * object body (i.e. the first byte following the length byte(s)), and
54
  * object body (i.e. the first byte following the length byte(s)), and
41
  * the length of the object body (i.e. the number of bytes until the
55
  * the length of the object body (i.e. the number of bytes until the
42
  * following object tag, if any) is returned.
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
 	unsigned int len_len;
59
 	unsigned int len_len;
52
 	unsigned int len;
60
 	unsigned int len;
53
-	int rc;
54
 
61
 
55
 	/* Sanity check */
62
 	/* Sanity check */
56
 	if ( cursor->len < 2 /* Tag byte and first length byte */ ) {
63
 	if ( cursor->len < 2 /* Tag byte and first length byte */ ) {
57
 		if ( cursor->len )
64
 		if ( cursor->len )
58
 			DBGC ( cursor, "ASN1 %p too short\n", cursor );
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
 	/* Check the tag byte */
69
 	/* Check the tag byte */
64
 	if ( *( ( uint8_t * ) cursor->data ) != type ) {
70
 	if ( *( ( uint8_t * ) cursor->data ) != type ) {
65
 		DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
71
 		DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
66
 		       cursor, type, *( ( uint8_t * ) cursor->data ) );
72
 		       cursor, type, *( ( uint8_t * ) cursor->data ) );
67
-		rc = -ENXIO;
68
-		goto notfound;
73
+		return -ENXIO;
69
 	}
74
 	}
70
 	cursor->data++;
75
 	cursor->data++;
71
 	cursor->len--;
76
 	cursor->len--;
82
 	if ( cursor->len < len_len ) {
87
 	if ( cursor->len < len_len ) {
83
 		DBGC ( cursor, "ASN1 %p bad length field length %d (max "
88
 		DBGC ( cursor, "ASN1 %p bad length field length %d (max "
84
 		       "%zd)\n", cursor, len_len, cursor->len );
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
 	/* Extract the length and sanity check */
93
 	/* Extract the length and sanity check */
96
 	if ( cursor->len < len ) {
100
 	if ( cursor->len < len ) {
97
 		DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n",
101
 		DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n",
98
 		       cursor, len, cursor->len );
102
 		       cursor, len, cursor->len );
99
-		rc = -EINVAL;
100
-		goto notfound;
103
+		return -EINVAL_ASN1_LEN;
101
 	}
104
 	}
102
 
105
 
103
 	return len;
106
 	return len;
104
-
105
- notfound:
106
-	cursor->data = NULL;
107
-	cursor->len = 0;
108
-	return rc;
109
 }
107
 }
110
 
108
 
111
 /**
109
 /**
123
 	int len;
121
 	int len;
124
 
122
 
125
 	len = asn1_start ( cursor, type );
123
 	len = asn1_start ( cursor, type );
126
-	if ( len < 0 )
124
+	if ( len < 0 ) {
125
+		asn1_invalidate_cursor ( cursor );
127
 		return len;
126
 		return len;
127
+	}
128
 
128
 
129
 	cursor->len = len;
129
 	cursor->len = len;
130
 	DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n",
130
 	DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n",
134
 }
134
 }
135
 
135
 
136
 /**
136
 /**
137
- * Skip ASN.1 object
137
+ * Skip ASN.1 object if present
138
  *
138
  *
139
  * @v cursor		ASN.1 object cursor
139
  * @v cursor		ASN.1 object cursor
140
  * @v type		Expected type
140
  * @v type		Expected type
141
  * @ret rc		Return status code
141
  * @ret rc		Return status code
142
  *
142
  *
143
  * The object cursor will be updated to point to the next ASN.1
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
 	int len;
148
 	int len;
149
 
149
 
150
 	len = asn1_start ( cursor, type );
150
 	len = asn1_start ( cursor, type );
158
 
158
 
159
 	if ( ! cursor->len ) {
159
 	if ( ! cursor->len ) {
160
 		DBGC ( cursor, "ASN1 %p reached end of object\n", cursor );
160
 		DBGC ( cursor, "ASN1 %p reached end of object\n", cursor );
161
-		cursor->data = NULL;
162
 		return -ENOENT;
161
 		return -ENOENT;
163
 	}
162
 	}
164
 
163
 
165
 	return 0;
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
 	memcpy ( &cursor, certificate, sizeof ( cursor ) );
55
 	memcpy ( &cursor, certificate, sizeof ( cursor ) );
56
 	rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */
56
 	rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */
57
 	       asn1_enter ( &cursor, ASN1_SEQUENCE ), /* tbsCertificate */
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
 	       asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */
59
 	       asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */
60
 	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */
60
 	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */
61
 	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */
61
 	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */

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

28
 	size_t len;
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
 extern int asn1_enter ( struct asn1_cursor *cursor, unsigned int type );
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
 extern int asn1_skip ( struct asn1_cursor *cursor, unsigned int type );
44
 extern int asn1_skip ( struct asn1_cursor *cursor, unsigned int type );
33
 
45
 
34
 #endif /* _IPXE_ASN1_H */
46
 #endif /* _IPXE_ASN1_H */

Loading…
Cancel
Save