summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/asn1/asn1_lib.c
diff options
context:
space:
mode:
authorjsing <>2021-12-25 07:04:03 +0000
committerjsing <>2021-12-25 07:04:03 +0000
commit45bffde06d55be8341ae2ab97fd9f6d173eea785 (patch)
treedfd17445518096186f837cbf0acabb25662aebab /src/lib/libcrypto/asn1/asn1_lib.c
parent6142c0431dc485679ae167b6cb887a9afafb3427 (diff)
downloadopenbsd-45bffde06d55be8341ae2ab97fd9f6d173eea785.tar.gz
openbsd-45bffde06d55be8341ae2ab97fd9f6d173eea785.tar.bz2
openbsd-45bffde06d55be8341ae2ab97fd9f6d173eea785.zip
Rewrite ASN.1 identifier/length parsing in CBS.
Provide internal asn1_get_identifier_cbs() and asn1_get_length_cbs() functions that are called from asn1_get_object_cbs(). Convert the existing ASN1_get_object() function so that it calls asn1_get_object_cbs(), before mapping the result into the API that it implements. ok tb@
Diffstat (limited to 'src/lib/libcrypto/asn1/asn1_lib.c')
-rw-r--r--src/lib/libcrypto/asn1/asn1_lib.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/lib/libcrypto/asn1/asn1_lib.c b/src/lib/libcrypto/asn1/asn1_lib.c
new file mode 100644
index 0000000000..542a72f6f1
--- /dev/null
+++ b/src/lib/libcrypto/asn1/asn1_lib.c
@@ -0,0 +1,171 @@
1/* $OpenBSD: asn1_lib.c,v 1.51 2021/12/25 07:04:03 jsing Exp $ */
2/*
3 * Copyright (c) 2021 Joel Sing <jsing@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <limits.h>
19
20#include "bytestring.h"
21
22static int
23asn1_get_identifier_cbs(CBS *cbs, int der_mode, uint8_t *out_class,
24 int *out_constructed, uint32_t *out_tag_number)
25{
26 uint8_t tag_class, tag_val;
27 int tag_constructed;
28 uint32_t tag_number;
29
30 /*
31 * Decode ASN.1 identifier octets - see ITU-T X.690 section 8.1.2.
32 */
33
34 *out_class = 0;
35 *out_constructed = 0;
36 *out_tag_number = 0;
37
38 if (!CBS_get_u8(cbs, &tag_val))
39 return 0;
40
41 /*
42 * ASN.1 tag class, encoding (primitive or constructed) and tag number
43 * are encoded in one or more identifier octets - the first octet
44 * contains the 2 bit tag class, the 1 bit encoding type and 5 bits
45 * of tag number.
46 *
47 * For tag numbers larger than 30 (0x1e) the 5 bit tag number in the
48 * first octet is set to all ones (0x1f) - the tag number is then
49 * encoded in subsequent octets - each of which have a one bit
50 * continuation flag and 7 bits of tag number in big-endian form.
51 * The encoding should not contain leading zeros but can for BER.
52 */
53 tag_class = (tag_val >> 6) & 0x3;
54 tag_constructed = (tag_val >> 5) & 0x1;
55 tag_number = tag_val & 0x1f;
56
57 /* Long form. */
58 if (tag_number == 0x1f) {
59 tag_number = 0;
60 do {
61 if (!CBS_get_u8(cbs, &tag_val))
62 return 0;
63 if (der_mode && tag_number == 0 && tag_val == 0x80)
64 return 0;
65 if (tag_number > (UINT32_MAX >> 7))
66 return 0;
67 tag_number = tag_number << 7 | (tag_val & 0x7f);
68 } while ((tag_val & 0x80) != 0);
69 }
70
71 *out_class = tag_class;
72 *out_constructed = tag_constructed;
73 *out_tag_number = tag_number;
74
75 return 1;
76}
77
78static int
79asn1_get_length_cbs(CBS *cbs, int der_mode, int *out_indefinite,
80 uint32_t *out_length)
81{
82 uint8_t len_bytes;
83 uint32_t length;
84 uint8_t val;
85
86 /*
87 * Decode ASN.1 length octets - see ITU-T X.690 section 8.1.3.
88 */
89
90 *out_length = 0;
91 *out_indefinite = 0;
92
93 if (!CBS_get_u8(cbs, &val))
94 return 0;
95
96 /*
97 * Short form - length is encoded in the lower 7 bits of a single byte.
98 */
99 if (val < 0x80) {
100 *out_length = val;
101 return 1;
102 }
103
104 /*
105 * Indefinite length - content continues until an End of Content (EOC)
106 * marker is reached. Must be used with constructed encoding.
107 */
108 if (val == 0x80) {
109 *out_indefinite = 1;
110 return 1;
111 }
112
113 /*
114 * Long form - the lower 7 bits of the first byte specifies the number
115 * of bytes used to encode the length, the following bytes specify the
116 * length in big-endian form. The encoding should not contain leading
117 * zeros but can for BER. A length value of 0x7f is invalid.
118 */
119 if ((len_bytes = val & 0x7f) == 0x7f)
120 return 0;
121
122 length = 0;
123
124 while (len_bytes-- > 0) {
125 if (!CBS_get_u8(cbs, &val))
126 return 0;
127 if (der_mode && length == 0 && val == 0)
128 return 0;
129 if (length > (UINT32_MAX >> 8))
130 return 0;
131 length = (length << 8) | val;
132 }
133
134 *out_length = length;
135
136 return 1;
137}
138
139int
140asn1_get_object_cbs(CBS *cbs, int der_mode, uint8_t *out_tag_class,
141 int *out_constructed, uint32_t *out_tag_number, int *out_indefinite,
142 uint32_t *out_length)
143{
144 int constructed, indefinite;
145 uint32_t tag_number, length;
146 uint8_t tag_class;
147
148 *out_tag_class = 0;
149 *out_constructed = 0;
150 *out_tag_number = 0;
151 *out_indefinite = 0;
152 *out_length = 0;
153
154 if (!asn1_get_identifier_cbs(cbs, der_mode, &tag_class, &constructed,
155 &tag_number))
156 return 0;
157 if (!asn1_get_length_cbs(cbs, der_mode, &indefinite, &length))
158 return 0;
159
160 /* Indefinite length can only be used with constructed encoding. */
161 if (indefinite && !constructed)
162 return 0;
163
164 *out_tag_class = tag_class;
165 *out_constructed = constructed;
166 *out_tag_number = tag_number;
167 *out_indefinite = indefinite;
168 *out_length = length;
169
170 return 1;
171}