139beb93cSSam Leffler /*
239beb93cSSam Leffler * ASN.1 DER parsing
35b9c547cSRui Paulo * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler *
5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo * See README for more details.
739beb93cSSam Leffler */
839beb93cSSam Leffler
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler
1139beb93cSSam Leffler #include "common.h"
12*c1d255d3SCy Schubert #include "utils/wpabuf.h"
1339beb93cSSam Leffler #include "asn1.h"
1439beb93cSSam Leffler
15*c1d255d3SCy Schubert const struct asn1_oid asn1_sha1_oid = {
165b9c547cSRui Paulo .oid = { 1, 3, 14, 3, 2, 26 },
175b9c547cSRui Paulo .len = 6
185b9c547cSRui Paulo };
195b9c547cSRui Paulo
20*c1d255d3SCy Schubert const struct asn1_oid asn1_sha256_oid = {
215b9c547cSRui Paulo .oid = { 2, 16, 840, 1, 101, 3, 4, 2, 1 },
225b9c547cSRui Paulo .len = 9
235b9c547cSRui Paulo };
245b9c547cSRui Paulo
25*c1d255d3SCy Schubert const struct asn1_oid asn1_ec_public_key_oid = {
26*c1d255d3SCy Schubert .oid = { 1, 2, 840, 10045, 2, 1 },
27*c1d255d3SCy Schubert .len = 6
28*c1d255d3SCy Schubert };
29*c1d255d3SCy Schubert
30*c1d255d3SCy Schubert const struct asn1_oid asn1_prime256v1_oid = {
31*c1d255d3SCy Schubert .oid = { 1, 2, 840, 10045, 3, 1, 7 },
32*c1d255d3SCy Schubert .len = 7
33*c1d255d3SCy Schubert };
34*c1d255d3SCy Schubert
35*c1d255d3SCy Schubert const struct asn1_oid asn1_secp384r1_oid = {
36*c1d255d3SCy Schubert .oid = { 1, 3, 132, 0, 34 },
37*c1d255d3SCy Schubert .len = 5
38*c1d255d3SCy Schubert };
39*c1d255d3SCy Schubert
40*c1d255d3SCy Schubert const struct asn1_oid asn1_secp521r1_oid = {
41*c1d255d3SCy Schubert .oid = { 1, 3, 132, 0, 35 },
42*c1d255d3SCy Schubert .len = 5
43*c1d255d3SCy Schubert };
44*c1d255d3SCy Schubert
45*c1d255d3SCy Schubert const struct asn1_oid asn1_brainpoolP256r1_oid = {
46*c1d255d3SCy Schubert .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 7 },
47*c1d255d3SCy Schubert .len = 10
48*c1d255d3SCy Schubert };
49*c1d255d3SCy Schubert
50*c1d255d3SCy Schubert const struct asn1_oid asn1_brainpoolP384r1_oid = {
51*c1d255d3SCy Schubert .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 11 },
52*c1d255d3SCy Schubert .len = 10
53*c1d255d3SCy Schubert };
54*c1d255d3SCy Schubert
55*c1d255d3SCy Schubert const struct asn1_oid asn1_brainpoolP512r1_oid = {
56*c1d255d3SCy Schubert .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 13 },
57*c1d255d3SCy Schubert .len = 10
58*c1d255d3SCy Schubert };
59*c1d255d3SCy Schubert
60*c1d255d3SCy Schubert const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid = {
61*c1d255d3SCy Schubert .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 22 },
62*c1d255d3SCy Schubert .len = 9
63*c1d255d3SCy Schubert };
64*c1d255d3SCy Schubert
65*c1d255d3SCy Schubert const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid = {
66*c1d255d3SCy Schubert .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 23 },
67*c1d255d3SCy Schubert .len = 9
68*c1d255d3SCy Schubert };
69*c1d255d3SCy Schubert
70*c1d255d3SCy Schubert const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid = {
71*c1d255d3SCy Schubert .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 24 },
72*c1d255d3SCy Schubert .len = 9
73*c1d255d3SCy Schubert };
74*c1d255d3SCy Schubert
75*c1d255d3SCy Schubert const struct asn1_oid asn1_pbkdf2_oid = {
76*c1d255d3SCy Schubert .oid = { 1, 2, 840, 113549, 1, 5, 12 },
77*c1d255d3SCy Schubert .len = 7
78*c1d255d3SCy Schubert };
79*c1d255d3SCy Schubert
80*c1d255d3SCy Schubert const struct asn1_oid asn1_pbkdf2_hmac_sha256_oid = {
81*c1d255d3SCy Schubert .oid = { 1, 2, 840, 113549, 2, 9 },
82*c1d255d3SCy Schubert .len = 6
83*c1d255d3SCy Schubert };
84*c1d255d3SCy Schubert
85*c1d255d3SCy Schubert const struct asn1_oid asn1_pbkdf2_hmac_sha384_oid = {
86*c1d255d3SCy Schubert .oid = { 1, 2, 840, 113549, 2, 10 },
87*c1d255d3SCy Schubert .len = 6
88*c1d255d3SCy Schubert };
89*c1d255d3SCy Schubert
90*c1d255d3SCy Schubert const struct asn1_oid asn1_pbkdf2_hmac_sha512_oid = {
91*c1d255d3SCy Schubert .oid = { 1, 2, 840, 113549, 2, 11 },
92*c1d255d3SCy Schubert .len = 6
93*c1d255d3SCy Schubert };
94*c1d255d3SCy Schubert
95*c1d255d3SCy Schubert const struct asn1_oid asn1_dpp_config_params_oid = {
96*c1d255d3SCy Schubert .oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 1 },
97*c1d255d3SCy Schubert .len = 10
98*c1d255d3SCy Schubert };
99*c1d255d3SCy Schubert
100*c1d255d3SCy Schubert const struct asn1_oid asn1_dpp_asymmetric_key_package_oid = {
101*c1d255d3SCy Schubert .oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 2 },
102*c1d255d3SCy Schubert .len = 10
103*c1d255d3SCy Schubert };
104*c1d255d3SCy Schubert
1055b9c547cSRui Paulo
asn1_valid_der_boolean(struct asn1_hdr * hdr)106206b73d0SCy Schubert static int asn1_valid_der_boolean(struct asn1_hdr *hdr)
107206b73d0SCy Schubert {
108206b73d0SCy Schubert /* Enforce DER requirements for a single way of encoding a BOOLEAN */
109206b73d0SCy Schubert if (hdr->length != 1) {
110206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "ASN.1: Unexpected BOOLEAN length (%u)",
111206b73d0SCy Schubert hdr->length);
112206b73d0SCy Schubert return 0;
113206b73d0SCy Schubert }
114206b73d0SCy Schubert
115206b73d0SCy Schubert if (hdr->payload[0] != 0 && hdr->payload[0] != 0xff) {
116206b73d0SCy Schubert wpa_printf(MSG_DEBUG,
117206b73d0SCy Schubert "ASN.1: Invalid BOOLEAN value 0x%x (DER requires 0 or 0xff)",
118206b73d0SCy Schubert hdr->payload[0]);
119206b73d0SCy Schubert return 0;
120206b73d0SCy Schubert }
121206b73d0SCy Schubert
122206b73d0SCy Schubert return 1;
123206b73d0SCy Schubert }
124206b73d0SCy Schubert
125206b73d0SCy Schubert
asn1_valid_der(struct asn1_hdr * hdr)126206b73d0SCy Schubert static int asn1_valid_der(struct asn1_hdr *hdr)
127206b73d0SCy Schubert {
128206b73d0SCy Schubert if (hdr->class != ASN1_CLASS_UNIVERSAL)
129206b73d0SCy Schubert return 1;
130206b73d0SCy Schubert if (hdr->tag == ASN1_TAG_BOOLEAN && !asn1_valid_der_boolean(hdr))
131206b73d0SCy Schubert return 0;
132*c1d255d3SCy Schubert if (hdr->tag == ASN1_TAG_NULL && hdr->length != 0)
133*c1d255d3SCy Schubert return 0;
134*c1d255d3SCy Schubert
135*c1d255d3SCy Schubert /* Check for allowed primitive/constructed values */
136*c1d255d3SCy Schubert if (hdr->constructed &&
137*c1d255d3SCy Schubert (hdr->tag == ASN1_TAG_BOOLEAN ||
138*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_INTEGER ||
139*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_NULL ||
140*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_OID ||
141*c1d255d3SCy Schubert hdr->tag == ANS1_TAG_RELATIVE_OID ||
142*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_REAL ||
143*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_ENUMERATED ||
144*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_BITSTRING ||
145*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_OCTETSTRING ||
146*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_NUMERICSTRING ||
147*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_PRINTABLESTRING ||
148*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_T61STRING ||
149*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_VIDEOTEXSTRING ||
150*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_VISIBLESTRING ||
151*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_IA5STRING ||
152*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_GRAPHICSTRING ||
153*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_GENERALSTRING ||
154*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_UNIVERSALSTRING ||
155*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_UTF8STRING ||
156*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_BMPSTRING ||
157*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_CHARACTERSTRING ||
158*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_UTCTIME ||
159*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_GENERALIZEDTIME ||
160*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_TIME))
161*c1d255d3SCy Schubert return 0;
162*c1d255d3SCy Schubert if (!hdr->constructed &&
163*c1d255d3SCy Schubert (hdr->tag == ASN1_TAG_SEQUENCE ||
164*c1d255d3SCy Schubert hdr->tag == ASN1_TAG_SET))
165*c1d255d3SCy Schubert return 0;
166*c1d255d3SCy Schubert
167206b73d0SCy Schubert return 1;
168206b73d0SCy Schubert }
169206b73d0SCy Schubert
170206b73d0SCy Schubert
asn1_get_next(const u8 * buf,size_t len,struct asn1_hdr * hdr)17139beb93cSSam Leffler int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
17239beb93cSSam Leffler {
17339beb93cSSam Leffler const u8 *pos, *end;
17439beb93cSSam Leffler u8 tmp;
17539beb93cSSam Leffler
17639beb93cSSam Leffler os_memset(hdr, 0, sizeof(*hdr));
17739beb93cSSam Leffler pos = buf;
17839beb93cSSam Leffler end = buf + len;
17939beb93cSSam Leffler
1804bc52338SCy Schubert if (pos >= end) {
1814bc52338SCy Schubert wpa_printf(MSG_DEBUG, "ASN.1: No room for Identifier");
1824bc52338SCy Schubert return -1;
1834bc52338SCy Schubert }
18439beb93cSSam Leffler hdr->identifier = *pos++;
18539beb93cSSam Leffler hdr->class = hdr->identifier >> 6;
18639beb93cSSam Leffler hdr->constructed = !!(hdr->identifier & (1 << 5));
18739beb93cSSam Leffler
18839beb93cSSam Leffler if ((hdr->identifier & 0x1f) == 0x1f) {
189*c1d255d3SCy Schubert size_t ext_len = 0;
190*c1d255d3SCy Schubert
19139beb93cSSam Leffler hdr->tag = 0;
192*c1d255d3SCy Schubert if (pos == end || (*pos & 0x7f) == 0) {
193*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
194*c1d255d3SCy Schubert "ASN.1: Invalid extended tag (first octet has to be included with at least one nonzero bit for the tag value)");
195*c1d255d3SCy Schubert return -1;
196*c1d255d3SCy Schubert }
19739beb93cSSam Leffler do {
19839beb93cSSam Leffler if (pos >= end) {
19939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
20039beb93cSSam Leffler "underflow");
20139beb93cSSam Leffler return -1;
20239beb93cSSam Leffler }
203*c1d255d3SCy Schubert ext_len++;
20439beb93cSSam Leffler tmp = *pos++;
20539beb93cSSam Leffler wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: "
20639beb93cSSam Leffler "0x%02x", tmp);
20739beb93cSSam Leffler hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
20839beb93cSSam Leffler } while (tmp & 0x80);
209*c1d255d3SCy Schubert wpa_printf(MSG_MSGDUMP, "ASN.1: Extended Tag: 0x%x (len=%zu)",
210*c1d255d3SCy Schubert hdr->tag, ext_len);
211*c1d255d3SCy Schubert if ((hdr->class != ASN1_CLASS_PRIVATE && hdr->tag < 31) ||
212*c1d255d3SCy Schubert ext_len * 7 > sizeof(hdr->tag) * 8) {
213*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
214*c1d255d3SCy Schubert "ASN.1: Invalid or unsupported (too large) extended Tag: 0x%x (len=%zu)",
215*c1d255d3SCy Schubert hdr->tag, ext_len);
216*c1d255d3SCy Schubert return -1;
217*c1d255d3SCy Schubert }
21839beb93cSSam Leffler } else
21939beb93cSSam Leffler hdr->tag = hdr->identifier & 0x1f;
22039beb93cSSam Leffler
2214bc52338SCy Schubert if (pos >= end) {
2224bc52338SCy Schubert wpa_printf(MSG_DEBUG, "ASN.1: No room for Length");
2234bc52338SCy Schubert return -1;
2244bc52338SCy Schubert }
22539beb93cSSam Leffler tmp = *pos++;
22639beb93cSSam Leffler if (tmp & 0x80) {
22739beb93cSSam Leffler if (tmp == 0xff) {
22839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ASN.1: Reserved length "
22939beb93cSSam Leffler "value 0xff used");
23039beb93cSSam Leffler return -1;
23139beb93cSSam Leffler }
23239beb93cSSam Leffler tmp &= 0x7f; /* number of subsequent octets */
23339beb93cSSam Leffler hdr->length = 0;
234*c1d255d3SCy Schubert if (tmp == 0 || pos == end || *pos == 0) {
235*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
236*c1d255d3SCy Schubert "ASN.1: Definite long form of the length does not start with a nonzero value");
237*c1d255d3SCy Schubert return -1;
238*c1d255d3SCy Schubert }
23939beb93cSSam Leffler if (tmp > 4) {
24039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
24139beb93cSSam Leffler return -1;
24239beb93cSSam Leffler }
24339beb93cSSam Leffler while (tmp--) {
24439beb93cSSam Leffler if (pos >= end) {
24539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ASN.1: Length "
24639beb93cSSam Leffler "underflow");
24739beb93cSSam Leffler return -1;
24839beb93cSSam Leffler }
24939beb93cSSam Leffler hdr->length = (hdr->length << 8) | *pos++;
25039beb93cSSam Leffler }
251*c1d255d3SCy Schubert if (hdr->length < 128) {
252*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
253*c1d255d3SCy Schubert "ASN.1: Definite long form of the length used with too short length");
254*c1d255d3SCy Schubert return -1;
255*c1d255d3SCy Schubert }
25639beb93cSSam Leffler } else {
25739beb93cSSam Leffler /* Short form - length 0..127 in one octet */
25839beb93cSSam Leffler hdr->length = tmp;
25939beb93cSSam Leffler }
26039beb93cSSam Leffler
26139beb93cSSam Leffler if (end < pos || hdr->length > (unsigned int) (end - pos)) {
26239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow");
26339beb93cSSam Leffler return -1;
26439beb93cSSam Leffler }
26539beb93cSSam Leffler
26639beb93cSSam Leffler hdr->payload = pos;
267206b73d0SCy Schubert
268*c1d255d3SCy Schubert if (!asn1_valid_der(hdr)) {
269*c1d255d3SCy Schubert asn1_print_hdr(hdr, "ASN.1: Invalid DER encoding: ");
270*c1d255d3SCy Schubert return -1;
271*c1d255d3SCy Schubert }
272*c1d255d3SCy Schubert return 0;
273*c1d255d3SCy Schubert }
274*c1d255d3SCy Schubert
275*c1d255d3SCy Schubert
asn1_print_hdr(const struct asn1_hdr * hdr,const char * title)276*c1d255d3SCy Schubert void asn1_print_hdr(const struct asn1_hdr *hdr, const char *title)
277*c1d255d3SCy Schubert {
278*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "%sclass %d constructed %d tag 0x%x",
279*c1d255d3SCy Schubert title, hdr->class, hdr->constructed, hdr->tag);
280*c1d255d3SCy Schubert }
281*c1d255d3SCy Schubert
282*c1d255d3SCy Schubert
asn1_unexpected(const struct asn1_hdr * hdr,const char * title)283*c1d255d3SCy Schubert void asn1_unexpected(const struct asn1_hdr *hdr, const char *title)
284*c1d255d3SCy Schubert {
285*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "%s - found class %d constructed %d tag 0x%x",
286*c1d255d3SCy Schubert title, hdr->class, hdr->constructed, hdr->tag);
28739beb93cSSam Leffler }
28839beb93cSSam Leffler
28939beb93cSSam Leffler
asn1_parse_oid(const u8 * buf,size_t len,struct asn1_oid * oid)290e28a4053SRui Paulo int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid)
29139beb93cSSam Leffler {
29239beb93cSSam Leffler const u8 *pos, *end;
29339beb93cSSam Leffler unsigned long val;
29439beb93cSSam Leffler u8 tmp;
29539beb93cSSam Leffler
29639beb93cSSam Leffler os_memset(oid, 0, sizeof(*oid));
29739beb93cSSam Leffler
298e28a4053SRui Paulo pos = buf;
299e28a4053SRui Paulo end = buf + len;
30039beb93cSSam Leffler
30139beb93cSSam Leffler while (pos < end) {
30239beb93cSSam Leffler val = 0;
30339beb93cSSam Leffler
30439beb93cSSam Leffler do {
30539beb93cSSam Leffler if (pos >= end)
30639beb93cSSam Leffler return -1;
30739beb93cSSam Leffler tmp = *pos++;
30839beb93cSSam Leffler val = (val << 7) | (tmp & 0x7f);
30939beb93cSSam Leffler } while (tmp & 0x80);
31039beb93cSSam Leffler
31139beb93cSSam Leffler if (oid->len >= ASN1_MAX_OID_LEN) {
31239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value");
31339beb93cSSam Leffler return -1;
31439beb93cSSam Leffler }
31539beb93cSSam Leffler if (oid->len == 0) {
31639beb93cSSam Leffler /*
31739beb93cSSam Leffler * The first octet encodes the first two object
31839beb93cSSam Leffler * identifier components in (X*40) + Y formula.
31939beb93cSSam Leffler * X = 0..2.
32039beb93cSSam Leffler */
32139beb93cSSam Leffler oid->oid[0] = val / 40;
32239beb93cSSam Leffler if (oid->oid[0] > 2)
32339beb93cSSam Leffler oid->oid[0] = 2;
32439beb93cSSam Leffler oid->oid[1] = val - oid->oid[0] * 40;
32539beb93cSSam Leffler oid->len = 2;
32639beb93cSSam Leffler } else
32739beb93cSSam Leffler oid->oid[oid->len++] = val;
32839beb93cSSam Leffler }
32939beb93cSSam Leffler
33039beb93cSSam Leffler return 0;
33139beb93cSSam Leffler }
33239beb93cSSam Leffler
33339beb93cSSam Leffler
asn1_get_oid(const u8 * buf,size_t len,struct asn1_oid * oid,const u8 ** next)334e28a4053SRui Paulo int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
335e28a4053SRui Paulo const u8 **next)
336e28a4053SRui Paulo {
337e28a4053SRui Paulo struct asn1_hdr hdr;
338e28a4053SRui Paulo
339*c1d255d3SCy Schubert if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0 ||
340*c1d255d3SCy Schubert !asn1_is_oid(&hdr)) {
341*c1d255d3SCy Schubert asn1_unexpected(&hdr, "ASN.1: Expected OID");
342e28a4053SRui Paulo return -1;
343e28a4053SRui Paulo }
344e28a4053SRui Paulo
345e28a4053SRui Paulo *next = hdr.payload + hdr.length;
346e28a4053SRui Paulo
347e28a4053SRui Paulo return asn1_parse_oid(hdr.payload, hdr.length, oid);
348e28a4053SRui Paulo }
349e28a4053SRui Paulo
350e28a4053SRui Paulo
asn1_oid_to_str(const struct asn1_oid * oid,char * buf,size_t len)3515b9c547cSRui Paulo void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len)
35239beb93cSSam Leffler {
35339beb93cSSam Leffler char *pos = buf;
35439beb93cSSam Leffler size_t i;
35539beb93cSSam Leffler int ret;
35639beb93cSSam Leffler
35739beb93cSSam Leffler if (len == 0)
35839beb93cSSam Leffler return;
35939beb93cSSam Leffler
36039beb93cSSam Leffler buf[0] = '\0';
36139beb93cSSam Leffler
36239beb93cSSam Leffler for (i = 0; i < oid->len; i++) {
36339beb93cSSam Leffler ret = os_snprintf(pos, buf + len - pos,
36439beb93cSSam Leffler "%s%lu",
36539beb93cSSam Leffler i == 0 ? "" : ".", oid->oid[i]);
3665b9c547cSRui Paulo if (os_snprintf_error(buf + len - pos, ret))
36739beb93cSSam Leffler break;
36839beb93cSSam Leffler pos += ret;
36939beb93cSSam Leffler }
37039beb93cSSam Leffler buf[len - 1] = '\0';
37139beb93cSSam Leffler }
37239beb93cSSam Leffler
37339beb93cSSam Leffler
rotate_bits(u8 octet)37439beb93cSSam Leffler static u8 rotate_bits(u8 octet)
37539beb93cSSam Leffler {
37639beb93cSSam Leffler int i;
37739beb93cSSam Leffler u8 res;
37839beb93cSSam Leffler
37939beb93cSSam Leffler res = 0;
38039beb93cSSam Leffler for (i = 0; i < 8; i++) {
38139beb93cSSam Leffler res <<= 1;
38239beb93cSSam Leffler if (octet & 1)
38339beb93cSSam Leffler res |= 1;
38439beb93cSSam Leffler octet >>= 1;
38539beb93cSSam Leffler }
38639beb93cSSam Leffler
38739beb93cSSam Leffler return res;
38839beb93cSSam Leffler }
38939beb93cSSam Leffler
39039beb93cSSam Leffler
asn1_bit_string_to_long(const u8 * buf,size_t len)39139beb93cSSam Leffler unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)
39239beb93cSSam Leffler {
39339beb93cSSam Leffler unsigned long val = 0;
39439beb93cSSam Leffler const u8 *pos = buf;
39539beb93cSSam Leffler
39639beb93cSSam Leffler /* BER requires that unused bits are zero, so we can ignore the number
39739beb93cSSam Leffler * of unused bits */
39839beb93cSSam Leffler pos++;
39939beb93cSSam Leffler
40039beb93cSSam Leffler if (len >= 2)
40139beb93cSSam Leffler val |= rotate_bits(*pos++);
40239beb93cSSam Leffler if (len >= 3)
40339beb93cSSam Leffler val |= ((unsigned long) rotate_bits(*pos++)) << 8;
40439beb93cSSam Leffler if (len >= 4)
40539beb93cSSam Leffler val |= ((unsigned long) rotate_bits(*pos++)) << 16;
40639beb93cSSam Leffler if (len >= 5)
40739beb93cSSam Leffler val |= ((unsigned long) rotate_bits(*pos++)) << 24;
40839beb93cSSam Leffler if (len >= 6)
40939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored "
41039beb93cSSam Leffler "(BIT STRING length %lu)",
41139beb93cSSam Leffler __func__, (unsigned long) len);
41239beb93cSSam Leffler
41339beb93cSSam Leffler return val;
41439beb93cSSam Leffler }
4155b9c547cSRui Paulo
4165b9c547cSRui Paulo
asn1_oid_equal(const struct asn1_oid * a,const struct asn1_oid * b)4175b9c547cSRui Paulo int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b)
4185b9c547cSRui Paulo {
4195b9c547cSRui Paulo size_t i;
4205b9c547cSRui Paulo
4215b9c547cSRui Paulo if (a->len != b->len)
4225b9c547cSRui Paulo return 0;
4235b9c547cSRui Paulo
4245b9c547cSRui Paulo for (i = 0; i < a->len; i++) {
4255b9c547cSRui Paulo if (a->oid[i] != b->oid[i])
4265b9c547cSRui Paulo return 0;
4275b9c547cSRui Paulo }
4285b9c547cSRui Paulo
4295b9c547cSRui Paulo return 1;
4305b9c547cSRui Paulo }
431*c1d255d3SCy Schubert
432*c1d255d3SCy Schubert
asn1_get_integer(const u8 * buf,size_t len,int * integer,const u8 ** next)433*c1d255d3SCy Schubert int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next)
434*c1d255d3SCy Schubert {
435*c1d255d3SCy Schubert struct asn1_hdr hdr;
436*c1d255d3SCy Schubert size_t left;
437*c1d255d3SCy Schubert const u8 *pos;
438*c1d255d3SCy Schubert int value;
439*c1d255d3SCy Schubert
440*c1d255d3SCy Schubert if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0 ||
441*c1d255d3SCy Schubert !asn1_is_integer(&hdr)) {
442*c1d255d3SCy Schubert asn1_unexpected(&hdr, "ASN.1: Expected INTEGER");
443*c1d255d3SCy Schubert return -1;
444*c1d255d3SCy Schubert }
445*c1d255d3SCy Schubert
446*c1d255d3SCy Schubert *next = hdr.payload + hdr.length;
447*c1d255d3SCy Schubert pos = hdr.payload;
448*c1d255d3SCy Schubert left = hdr.length;
449*c1d255d3SCy Schubert if (left > sizeof(value)) {
450*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "ASN.1: Too large INTEGER (len %u)",
451*c1d255d3SCy Schubert hdr.length);
452*c1d255d3SCy Schubert return -1;
453*c1d255d3SCy Schubert }
454*c1d255d3SCy Schubert value = 0;
455*c1d255d3SCy Schubert while (left) {
456*c1d255d3SCy Schubert value <<= 8;
457*c1d255d3SCy Schubert value |= *pos++;
458*c1d255d3SCy Schubert left--;
459*c1d255d3SCy Schubert }
460*c1d255d3SCy Schubert
461*c1d255d3SCy Schubert *integer = value;
462*c1d255d3SCy Schubert return 0;
463*c1d255d3SCy Schubert }
464*c1d255d3SCy Schubert
465*c1d255d3SCy Schubert
asn1_get_sequence(const u8 * buf,size_t len,struct asn1_hdr * hdr,const u8 ** next)466*c1d255d3SCy Schubert int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr,
467*c1d255d3SCy Schubert const u8 **next)
468*c1d255d3SCy Schubert {
469*c1d255d3SCy Schubert if (asn1_get_next(buf, len, hdr) < 0 || !asn1_is_sequence(hdr)) {
470*c1d255d3SCy Schubert asn1_unexpected(hdr, "ASN.1: Expected SEQUENCE");
471*c1d255d3SCy Schubert return -1;
472*c1d255d3SCy Schubert }
473*c1d255d3SCy Schubert
474*c1d255d3SCy Schubert if (next)
475*c1d255d3SCy Schubert *next = hdr->payload + hdr->length;
476*c1d255d3SCy Schubert return 0;
477*c1d255d3SCy Schubert }
478*c1d255d3SCy Schubert
479*c1d255d3SCy Schubert
asn1_get_alg_id(const u8 * buf,size_t len,struct asn1_oid * oid,const u8 ** params,size_t * params_len,const u8 ** next)480*c1d255d3SCy Schubert int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid,
481*c1d255d3SCy Schubert const u8 **params, size_t *params_len, const u8 **next)
482*c1d255d3SCy Schubert {
483*c1d255d3SCy Schubert const u8 *pos = buf, *end = buf + len;
484*c1d255d3SCy Schubert struct asn1_hdr hdr;
485*c1d255d3SCy Schubert
486*c1d255d3SCy Schubert /*
487*c1d255d3SCy Schubert * AlgorithmIdentifier ::= SEQUENCE {
488*c1d255d3SCy Schubert * algorithm OBJECT IDENTIFIER,
489*c1d255d3SCy Schubert * parameters ANY DEFINED BY algorithm OPTIONAL}
490*c1d255d3SCy Schubert */
491*c1d255d3SCy Schubert if (asn1_get_sequence(pos, end - pos, &hdr, next) < 0 ||
492*c1d255d3SCy Schubert asn1_get_oid(hdr.payload, hdr.length, oid, &pos) < 0)
493*c1d255d3SCy Schubert return -1;
494*c1d255d3SCy Schubert
495*c1d255d3SCy Schubert if (params && params_len) {
496*c1d255d3SCy Schubert *params = pos;
497*c1d255d3SCy Schubert *params_len = hdr.payload + hdr.length - pos;
498*c1d255d3SCy Schubert }
499*c1d255d3SCy Schubert
500*c1d255d3SCy Schubert return 0;
501*c1d255d3SCy Schubert }
502*c1d255d3SCy Schubert
503*c1d255d3SCy Schubert
asn1_put_integer(struct wpabuf * buf,int val)504*c1d255d3SCy Schubert void asn1_put_integer(struct wpabuf *buf, int val)
505*c1d255d3SCy Schubert {
506*c1d255d3SCy Schubert u8 bin[4];
507*c1d255d3SCy Schubert int zeros;
508*c1d255d3SCy Schubert
509*c1d255d3SCy Schubert WPA_PUT_BE32(bin, val);
510*c1d255d3SCy Schubert zeros = 0;
511*c1d255d3SCy Schubert while (zeros < 3 && bin[zeros] == 0)
512*c1d255d3SCy Schubert zeros++;
513*c1d255d3SCy Schubert wpabuf_put_u8(buf, ASN1_TAG_INTEGER);
514*c1d255d3SCy Schubert wpabuf_put_u8(buf, 4 - zeros);
515*c1d255d3SCy Schubert wpabuf_put_data(buf, &bin[zeros], 4 - zeros);
516*c1d255d3SCy Schubert }
517*c1d255d3SCy Schubert
518*c1d255d3SCy Schubert
asn1_put_len(struct wpabuf * buf,size_t len)519*c1d255d3SCy Schubert static void asn1_put_len(struct wpabuf *buf, size_t len)
520*c1d255d3SCy Schubert {
521*c1d255d3SCy Schubert if (len <= 0x7f) {
522*c1d255d3SCy Schubert wpabuf_put_u8(buf, len);
523*c1d255d3SCy Schubert } else if (len <= 0xff) {
524*c1d255d3SCy Schubert wpabuf_put_u8(buf, 0x80 | 1);
525*c1d255d3SCy Schubert wpabuf_put_u8(buf, len);
526*c1d255d3SCy Schubert } else if (len <= 0xffff) {
527*c1d255d3SCy Schubert wpabuf_put_u8(buf, 0x80 | 2);
528*c1d255d3SCy Schubert wpabuf_put_be16(buf, len);
529*c1d255d3SCy Schubert } else if (len <= 0xffffff) {
530*c1d255d3SCy Schubert wpabuf_put_u8(buf, 0x80 | 3);
531*c1d255d3SCy Schubert wpabuf_put_be24(buf, len);
532*c1d255d3SCy Schubert } else {
533*c1d255d3SCy Schubert wpabuf_put_u8(buf, 0x80 | 4);
534*c1d255d3SCy Schubert wpabuf_put_be32(buf, len);
535*c1d255d3SCy Schubert }
536*c1d255d3SCy Schubert }
537*c1d255d3SCy Schubert
538*c1d255d3SCy Schubert
asn1_put_octet_string(struct wpabuf * buf,const struct wpabuf * val)539*c1d255d3SCy Schubert void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val)
540*c1d255d3SCy Schubert {
541*c1d255d3SCy Schubert wpabuf_put_u8(buf, ASN1_TAG_OCTETSTRING);
542*c1d255d3SCy Schubert asn1_put_len(buf, wpabuf_len(val));
543*c1d255d3SCy Schubert wpabuf_put_buf(buf, val);
544*c1d255d3SCy Schubert }
545*c1d255d3SCy Schubert
546*c1d255d3SCy Schubert
asn1_put_oid(struct wpabuf * buf,const struct asn1_oid * oid)547*c1d255d3SCy Schubert void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid)
548*c1d255d3SCy Schubert {
549*c1d255d3SCy Schubert u8 *len;
550*c1d255d3SCy Schubert size_t i;
551*c1d255d3SCy Schubert
552*c1d255d3SCy Schubert if (oid->len < 2)
553*c1d255d3SCy Schubert return;
554*c1d255d3SCy Schubert wpabuf_put_u8(buf, ASN1_TAG_OID);
555*c1d255d3SCy Schubert len = wpabuf_put(buf, 1);
556*c1d255d3SCy Schubert wpabuf_put_u8(buf, 40 * oid->oid[0] + oid->oid[1]);
557*c1d255d3SCy Schubert for (i = 2; i < oid->len; i++) {
558*c1d255d3SCy Schubert unsigned long val = oid->oid[i];
559*c1d255d3SCy Schubert u8 bytes[8];
560*c1d255d3SCy Schubert int idx = 0;
561*c1d255d3SCy Schubert
562*c1d255d3SCy Schubert while (val) {
563*c1d255d3SCy Schubert bytes[idx] = (idx ? 0x80 : 0x00) | (val & 0x7f);
564*c1d255d3SCy Schubert idx++;
565*c1d255d3SCy Schubert val >>= 7;
566*c1d255d3SCy Schubert }
567*c1d255d3SCy Schubert if (idx == 0) {
568*c1d255d3SCy Schubert bytes[idx] = 0;
569*c1d255d3SCy Schubert idx = 1;
570*c1d255d3SCy Schubert }
571*c1d255d3SCy Schubert while (idx > 0) {
572*c1d255d3SCy Schubert idx--;
573*c1d255d3SCy Schubert wpabuf_put_u8(buf, bytes[idx]);
574*c1d255d3SCy Schubert }
575*c1d255d3SCy Schubert }
576*c1d255d3SCy Schubert *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
577*c1d255d3SCy Schubert }
578*c1d255d3SCy Schubert
579*c1d255d3SCy Schubert
asn1_put_hdr(struct wpabuf * buf,u8 class,int constructed,u8 tag,size_t len)580*c1d255d3SCy Schubert void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag,
581*c1d255d3SCy Schubert size_t len)
582*c1d255d3SCy Schubert {
583*c1d255d3SCy Schubert wpabuf_put_u8(buf, class << 6 | (constructed ? 0x20 : 0x00) | tag);
584*c1d255d3SCy Schubert asn1_put_len(buf, len);
585*c1d255d3SCy Schubert }
586*c1d255d3SCy Schubert
587*c1d255d3SCy Schubert
asn1_put_sequence(struct wpabuf * buf,const struct wpabuf * payload)588*c1d255d3SCy Schubert void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload)
589*c1d255d3SCy Schubert {
590*c1d255d3SCy Schubert asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SEQUENCE,
591*c1d255d3SCy Schubert wpabuf_len(payload));
592*c1d255d3SCy Schubert wpabuf_put_buf(buf, payload);
593*c1d255d3SCy Schubert }
594*c1d255d3SCy Schubert
595*c1d255d3SCy Schubert
asn1_put_set(struct wpabuf * buf,const struct wpabuf * payload)596*c1d255d3SCy Schubert void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload)
597*c1d255d3SCy Schubert {
598*c1d255d3SCy Schubert asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SET,
599*c1d255d3SCy Schubert wpabuf_len(payload));
600*c1d255d3SCy Schubert wpabuf_put_buf(buf, payload);
601*c1d255d3SCy Schubert }
602*c1d255d3SCy Schubert
603*c1d255d3SCy Schubert
asn1_put_utf8string(struct wpabuf * buf,const char * val)604*c1d255d3SCy Schubert void asn1_put_utf8string(struct wpabuf *buf, const char *val)
605*c1d255d3SCy Schubert {
606*c1d255d3SCy Schubert asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 0, ASN1_TAG_UTF8STRING,
607*c1d255d3SCy Schubert os_strlen(val));
608*c1d255d3SCy Schubert wpabuf_put_str(buf, val);
609*c1d255d3SCy Schubert }
610*c1d255d3SCy Schubert
611*c1d255d3SCy Schubert
asn1_build_alg_id(const struct asn1_oid * oid,const struct wpabuf * params)612*c1d255d3SCy Schubert struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid,
613*c1d255d3SCy Schubert const struct wpabuf *params)
614*c1d255d3SCy Schubert {
615*c1d255d3SCy Schubert struct wpabuf *buf;
616*c1d255d3SCy Schubert size_t len;
617*c1d255d3SCy Schubert
618*c1d255d3SCy Schubert /*
619*c1d255d3SCy Schubert * AlgorithmIdentifier ::= SEQUENCE {
620*c1d255d3SCy Schubert * algorithm OBJECT IDENTIFIER,
621*c1d255d3SCy Schubert * parameters ANY DEFINED BY algorithm OPTIONAL}
622*c1d255d3SCy Schubert */
623*c1d255d3SCy Schubert
624*c1d255d3SCy Schubert len = 100;
625*c1d255d3SCy Schubert if (params)
626*c1d255d3SCy Schubert len += wpabuf_len(params);
627*c1d255d3SCy Schubert buf = wpabuf_alloc(len);
628*c1d255d3SCy Schubert if (!buf)
629*c1d255d3SCy Schubert return NULL;
630*c1d255d3SCy Schubert asn1_put_oid(buf, oid);
631*c1d255d3SCy Schubert if (params)
632*c1d255d3SCy Schubert wpabuf_put_buf(buf, params);
633*c1d255d3SCy Schubert return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
634*c1d255d3SCy Schubert }
635*c1d255d3SCy Schubert
636*c1d255d3SCy Schubert
asn1_encaps(struct wpabuf * buf,u8 class,u8 tag)637*c1d255d3SCy Schubert struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag)
638*c1d255d3SCy Schubert {
639*c1d255d3SCy Schubert struct wpabuf *res;
640*c1d255d3SCy Schubert
641*c1d255d3SCy Schubert if (!buf)
642*c1d255d3SCy Schubert return NULL;
643*c1d255d3SCy Schubert res = wpabuf_alloc(10 + wpabuf_len(buf));
644*c1d255d3SCy Schubert if (res) {
645*c1d255d3SCy Schubert asn1_put_hdr(res, class, 1, tag, wpabuf_len(buf));
646*c1d255d3SCy Schubert wpabuf_put_buf(res, buf);
647*c1d255d3SCy Schubert }
648*c1d255d3SCy Schubert wpabuf_clear_free(buf);
649*c1d255d3SCy Schubert return res;
650*c1d255d3SCy Schubert }
651