summaryrefslogtreecommitdiff
path: root/src/lib/libssl/bs_cbs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libssl/bs_cbs.c')
-rw-r--r--src/lib/libssl/bs_cbs.c68
1 files changed, 51 insertions, 17 deletions
diff --git a/src/lib/libssl/bs_cbs.c b/src/lib/libssl/bs_cbs.c
index c37f81dd60..ba38303c18 100644
--- a/src/lib/libssl/bs_cbs.c
+++ b/src/lib/libssl/bs_cbs.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: bs_cbs.c,v 1.8 2015/06/13 08:46:00 doug Exp $ */ 1/* $OpenBSD: bs_cbs.c,v 1.9 2015/06/15 07:35:49 doug Exp $ */
2/* 2/*
3 * Copyright (c) 2014, Google Inc. 3 * Copyright (c) 2014, Google Inc.
4 * 4 *
@@ -205,24 +205,45 @@ int
205CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, 205CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
206 size_t *out_header_len) 206 size_t *out_header_len)
207{ 207{
208 return cbs_get_any_asn1_element_internal(cbs, out, out_tag,
209 out_header_len, 1);
210}
211
212/*
213 * Review X.690 for details on ASN.1 DER encoding.
214 *
215 * If non-strict mode is enabled, then DER rules are relaxed
216 * for indefinite constructs (violates DER but a little closer to BER).
217 * Non-strict mode should only be used by bs_ber.c
218 *
219 * Sections 8, 10 and 11 for DER encoding
220 */
221int
222cbs_get_any_asn1_element_internal(CBS *cbs, CBS *out, unsigned *out_tag,
223 size_t *out_header_len, int strict)
224{
208 uint8_t tag, length_byte; 225 uint8_t tag, length_byte;
209 CBS header = *cbs; 226 CBS header = *cbs;
210 CBS throwaway; 227 CBS throwaway;
228 size_t len;
211 229
212 if (out == NULL) 230 if (out == NULL)
213 out = &throwaway; 231 out = &throwaway;
214 232
233 /*
234 * Get identifier octet and length octet. Only 1 octet for each
235 * is a CBS limitation.
236 */
215 if (!CBS_get_u8(&header, &tag) || !CBS_get_u8(&header, &length_byte)) 237 if (!CBS_get_u8(&header, &tag) || !CBS_get_u8(&header, &length_byte))
216 return 0; 238 return 0;
217 239
240 /* CBS limitation: long form tags are not supported. */
218 if ((tag & 0x1f) == 0x1f) 241 if ((tag & 0x1f) == 0x1f)
219 /* Long form tags are not supported. */
220 return 0; 242 return 0;
221 243
222 if (out_tag != NULL) 244 if (out_tag != NULL)
223 *out_tag = tag; 245 *out_tag = tag;
224 246
225 size_t len;
226 if ((length_byte & 0x80) == 0) { 247 if ((length_byte & 0x80) == 0) {
227 /* Short form length. */ 248 /* Short form length. */
228 len = ((size_t) length_byte) + 2; 249 len = ((size_t) length_byte) + 2;
@@ -234,21 +255,40 @@ CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
234 const size_t num_bytes = length_byte & 0x7f; 255 const size_t num_bytes = length_byte & 0x7f;
235 uint32_t len32; 256 uint32_t len32;
236 257
237 if ((tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) { 258 /* ASN.1 reserved value for future extensions */
238 /* indefinite length */ 259 if (num_bytes == 0x7f)
239 if (out_header_len != NULL) 260 return 0;
240 *out_header_len = 2; 261
241 return CBS_get_bytes(cbs, out, 2); 262 /* Handle indefinite form length */
263 if (num_bytes == 0) {
264 /* DER encoding doesn't allow for indefinite form. */
265 if (strict) {
266 return 0;
267
268 } else {
269 if ((tag & CBS_ASN1_CONSTRUCTED) != 0 &&
270 num_bytes == 0) {
271 /* indefinite length */
272 if (out_header_len != NULL)
273 *out_header_len = 2;
274 return CBS_get_bytes(cbs, out, 2);
275 } else {
276 /* Primitive cannot use indefinite. */
277 return 0;
278 }
279 }
242 } 280 }
243 281
244 if (num_bytes == 0 || num_bytes > 4) 282 /* CBS limitation. */
283 if (num_bytes > 4)
245 return 0; 284 return 0;
246 285
247 if (!cbs_get_u(&header, &len32, num_bytes)) 286 if (!cbs_get_u(&header, &len32, num_bytes))
248 return 0; 287 return 0;
249 288
289 /* DER has a minimum length octet requirements. */
250 if (len32 < 128) 290 if (len32 < 128)
251 /* Length should have used short-form encoding. */ 291 /* Should have used short form instead */
252 return 0; 292 return 0;
253 293
254 if ((len32 >> ((num_bytes - 1) * 8)) == 0) 294 if ((len32 >> ((num_bytes - 1) * 8)) == 0)
@@ -279,13 +319,7 @@ cbs_get_asn1(CBS *cbs, CBS *out, unsigned tag_value, int skip_header)
279 out = &throwaway; 319 out = &throwaway;
280 320
281 if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) || 321 if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) ||
282 tag != tag_value || (header_len > 0 && 322 tag != tag_value)
283 /*
284 * This ensures that the tag is either zero length or
285 * indefinite-length.
286 */
287 CBS_len(out) == header_len &&
288 CBS_data(out)[header_len - 1] == 0x80))
289 return 0; 323 return 0;
290 324
291 if (skip_header && !CBS_skip(out, header_len)) { 325 if (skip_header && !CBS_skip(out, header_len)) {