diff options
Diffstat (limited to 'src/lib/libssl/bs_cbs.c')
-rw-r--r-- | src/lib/libssl/bs_cbs.c | 68 |
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 | |||
205 | CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, | 205 | CBS_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 | */ | ||
221 | int | ||
222 | cbs_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)) { |